diff --git a/previews/PR1023/404.html b/previews/PR1023/404.html new file mode 100644 index 0000000000..db24c8a82f --- /dev/null +++ b/previews/PR1023/404.html @@ -0,0 +1,31 @@ + + + + + + 404 | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Accelerator_Support/MLDataDevices.html b/previews/PR1023/api/Accelerator_Support/MLDataDevices.html new file mode 100644 index 0000000000..71c58140cf --- /dev/null +++ b/previews/PR1023/api/Accelerator_Support/MLDataDevices.html @@ -0,0 +1,58 @@ + + + + + + MLDataDevices | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

MLDataDevices

MLDataDevices.jl is a lightweight package defining rules for transferring data across devices.

Preferences

MLDataDevices.gpu_backend! Function
julia
gpu_backend!() = gpu_backend!("")
+gpu_backend!(backend) = gpu_backend!(string(backend))
+gpu_backend!(backend::AbstractGPUDevice)
+gpu_backend!(backend::String)

Creates a LocalPreferences.toml file with the desired GPU backend.

If backend == "", then the gpu_backend preference is deleted. Otherwise, backend is validated to be one of the possible backends and the preference is set to backend.

If a new backend is successfully set, then the Julia session must be restarted for the change to take effect.

source

Data Transfer

MLDataDevices.cpu_device Function
julia
cpu_device() -> CPUDevice()

Return a CPUDevice object which can be used to transfer data to CPU.

source

MLDataDevices.gpu_device Function
julia
gpu_device(device_id::Union{Nothing, Integer}=nothing;
+    force::Bool=false) -> AbstractDevice

Selects GPU device based on the following criteria:

  1. If gpu_backend preference is set and the backend is functional on the system, then that device is selected.

  2. Otherwise, an automatic selection algorithm is used. We go over possible device backends in the order specified by supported_gpu_backends() and select the first functional backend.

  3. If no GPU device is functional and force is false, then cpu_device() is invoked.

  4. If nothing works, an error is thrown.

Arguments

  • device_id::Union{Nothing, Integer}: The device id to select. If nothing, then we return the last selected device or if none was selected then we run the autoselection and choose the current device using CUDA.device() or AMDGPU.device() or similar. If Integer, then we select the device with the given id. Note that this is 1-indexed, in contrast to the 0-indexed CUDA.jl. For example, id = 4 corresponds to CUDA.device!(3).

Warning

device_id is only applicable for CUDA and AMDGPU backends. For Metal, oneAPI and CPU backends, device_id is ignored and a warning is printed.

Warning

gpu_device won't select a CUDA device unless both CUDA.jl and cuDNN.jl are loaded. This is to ensure that deep learning operations work correctly. Nonetheless, if cuDNN is not loaded you can still manually create a CUDADevice object and use it (e.g. dev = CUDADevice()).

Keyword Arguments

  • force::Bool: If true, then an error is thrown if no functional GPU device is found.

source

MLDataDevices.xla_device Function
julia
xla_device(; force::Bool=false) -> Union{XLADevice, CPUDevice}

Return a XLADevice object if functional. Otherwise, throw an error if force is true. Falls back to CPUDevice if force is false.

Danger

This is an experimental feature and might change without deprecations

source

Miscellaneous

MLDataDevices.reset_gpu_device! Function
julia
reset_gpu_device!()

Resets the selected GPU device. This is useful when automatic GPU selection needs to be run again.

source

MLDataDevices.supported_gpu_backends Function
julia
supported_gpu_backends() -> Tuple{String, ...}

Return a tuple of supported GPU backends.

Warning

This is not the list of functional backends on the system, but rather backends which MLDataDevices.jl supports.

source

MLDataDevices.default_device_rng Function
julia
default_device_rng(::AbstractDevice)

Returns the default RNG for the device. This can be used to directly generate parameters and states on the device using WeightInitializers.jl.

source

MLDataDevices.get_device Function
julia
get_device(x) -> dev::AbstractDevice | Exception | Nothing

If all arrays (on the leaves of the structure) are on the same device, we return that device. Otherwise, we throw an error. If the object is device agnostic, we return nothing.

Note

Trigger Packages must be loaded for this to return the correct device.

Special Retuened Values

  • nothing – denotes that the object is device agnostic. For example, scalar, abstract range, etc.

  • UnknownDevice() – denotes that the device type is unknown

See also get_device_type for a faster alternative that can be used for dispatch based on device type.

source

MLDataDevices.get_device_type Function
julia
get_device_type(x) -> Type{<:AbstractDevice} | Exception | Type{Nothing}

Similar to get_device but returns the type of the device instead of the device itself. This value is often a compile time constant and is recommended to be used instead of get_device where ever defining dispatches based on the device type.

Note

Trigger Packages must be loaded for this to return the correct device.

Special Retuened Values

  • Nothing – denotes that the object is device agnostic. For example, scalar, abstract range, etc.

  • UnknownDevice – denotes that the device type is unknown

source

MLDataDevices.loaded Function
julia
loaded(x::AbstractDevice) -> Bool
+loaded(::Type{<:AbstractDevice}) -> Bool

Checks if the trigger package for the device is loaded. Trigger packages are as follows:

  • CUDA.jl and cuDNN.jl (or just LuxCUDA.jl) for NVIDIA CUDA Support.

  • AMDGPU.jl for AMD GPU ROCM Support.

  • Metal.jl for Apple Metal GPU Support.

  • oneAPI.jl for Intel oneAPI GPU Support.

source

MLDataDevices.functional Function
julia
functional(x::AbstractDevice) -> Bool
+functional(::Type{<:AbstractDevice}) -> Bool

Checks if the device is functional. This is used to determine if the device can be used for computation. Note that even if the backend is loaded (as checked via MLDataDevices.loaded), the device may not be functional.

Note that while this function is not exported, it is considered part of the public API.

source

MLDataDevices.isleaf Function
julia
isleaf(x) -> Bool

Returns true if x is a leaf node in the data structure.

Defining MLDataDevices.isleaf(x::T) = true for custom types can be used to customize the behavior the data movement behavior when an object with nested structure containing the type is transferred to a device.

Adapt.adapt_structure(::AbstractDevice, x::T) or Adapt.adapt_structure(::AbstractDevice, x::T) will be called during data movement if isleaf(x::T) == true.

If MLDataDevices.isleaf(x::T) is not defined, then it will fall back to Functors.isleaf(x).

source

Multi-GPU Support

MLDataDevices.set_device! Function
julia
set_device!(T::Type{<:AbstractDevice}, dev_or_id)

Set the device for the given type. This is a no-op for CPUDevice. For CUDADevice and AMDGPUDevice, it prints a warning if the corresponding trigger package is not loaded.

Currently, MetalDevice and oneAPIDevice don't support setting the device.

Arguments

  • T::Type{<:AbstractDevice}: The device type to set.

  • dev_or_id: Can be the device from the corresponding package. For example for CUDA it can be a CuDevice. If it is an integer, it is the device id to set. This is 1-indexed.

Danger

This specific function should be considered experimental at this point and is currently provided to support distributed training in Lux. As such please use Lux.DistributedUtils instead of using this function.

source

julia
set_device!(T::Type{<:AbstractDevice}, ::Nothing, rank::Integer)

Set the device for the given type. This is a no-op for CPUDevice. For CUDADevice and AMDGPUDevice, it prints a warning if the corresponding trigger package is not loaded.

Currently, MetalDevice and oneAPIDevice don't support setting the device.

Arguments

  • T::Type{<:AbstractDevice}: The device type to set.

  • rank::Integer: Local Rank of the process. This is applicable for distributed training and must be 0-indexed.

Danger

This specific function should be considered experimental at this point and is currently provided to support distributed training in Lux. As such please use Lux.DistributedUtils instead of using this function.

source

Iteration

MLDataDevices.DeviceIterator Type
julia
DeviceIterator(dev::AbstractDevice, iterator)

Create a DeviceIterator that iterates through the provided iterator via iterate. Upon each iteration, the current batch is copied to the device dev, and the previous iteration is marked as freeable from GPU memory (via unsafe_free!) (no-op for a CPU device).

The conversion follows the same semantics as dev(<item from iterator>).

Similarity to CUDA.CuIterator

The design inspiration was taken from CUDA.CuIterator and was generalized to work with other backends and more complex iterators (using Functors).

MLUtils.DataLoader

Calling dev(::MLUtils.DataLoader) will automatically convert the dataloader to use the same semantics as DeviceIterator. This is generally preferred over looping over the dataloader directly and transferring the data to the device.

Examples

The following was run on a computer with an NVIDIA GPU.

julia
julia> using MLDataDevices, MLUtils
+
+julia> X = rand(Float64, 3, 33);
+
+julia> dataloader = DataLoader(X; batchsize=13, shuffle=false);
+
+julia> for (i, x) in enumerate(dataloader)
+           @show i, summary(x)
+       end
+(i, summary(x)) = (1, "3×13 Matrix{Float64}")
+(i, summary(x)) = (2, "3×13 Matrix{Float64}")
+(i, summary(x)) = (3, "3×7 Matrix{Float64}")
+
+julia> for (i, x) in enumerate(CUDADevice()(dataloader))
+           @show i, summary(x)
+       end
+(i, summary(x)) = (1, "3×13 CuArray{Float32, 2, CUDA.DeviceMemory}")
+(i, summary(x)) = (2, "3×13 CuArray{Float32, 2, CUDA.DeviceMemory}")
+(i, summary(x)) = (3, "3×7 CuArray{Float32, 2, CUDA.DeviceMemory}")

source

+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Building_Blocks/LuxCore.html b/previews/PR1023/api/Building_Blocks/LuxCore.html new file mode 100644 index 0000000000..5d013707a1 --- /dev/null +++ b/previews/PR1023/api/Building_Blocks/LuxCore.html @@ -0,0 +1,34 @@ + + + + + + LuxCore | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

LuxCore

LuxCore.jl defines the abstract layers for Lux. Allows users to be compatible with the entirely of Lux.jl without having such a heavy dependency. If you are depending on Lux.jl directly, you do not need to depend on LuxCore.jl (all the functionality is exported via Lux.jl).

Abstract Types

LuxCore.AbstractLuxLayer Type
julia
abstract type AbstractLuxLayer

Abstract Type for all Lux Layers

Users implementing their custom layer, must implement

  • initialparameters(rng::AbstractRNG, layer::CustomAbstractLuxLayer) – This returns a NamedTuple containing the trainable parameters for the layer.

  • initialstates(rng::AbstractRNG, layer::CustomAbstractLuxLayer) – This returns a NamedTuple containing the current state for the layer. For most layers this is typically empty. Layers that would potentially contain this include BatchNorm, LSTM, GRU, etc.

Optionally:

  • parameterlength(layer::CustomAbstractLuxLayer) – These can be automatically calculated, but it is recommended that the user defines these.

  • statelength(layer::CustomAbstractLuxLayer) – These can be automatically calculated, but it is recommended that the user defines these.

See also AbstractLuxContainerLayer

source

LuxCore.AbstractLuxWrapperLayer Type
julia
abstract type AbstractLuxWrapperLayer{layer} <: AbstractLuxLayer

See AbstractLuxContainerLayer for detailed documentation. This abstract type is very similar to AbstractLuxContainerLayer except that it allows for a single layer to be wrapped in a container.

Additionally, on calling initialparameters and initialstates, the parameters and states are not wrapped in a NamedTuple with the same name as the field.

As a convenience, we define the fallback call (::AbstractLuxWrapperLayer)(x, ps, st), which calls getfield(x, layer)(x, ps, st).

source

LuxCore.AbstractLuxContainerLayer Type
julia
abstract type AbstractLuxContainerLayer{layers} <: AbstractLuxLayer

Abstract Container Type for certain Lux Layers. layers is a tuple containing fieldnames for the layer, and constructs the parameters and states using those.

Users implementing their custom layer can extend the same functions as in AbstractLuxLayer.

Advanced Structure Manipulation

Advanced structure manipulation of these layers post construction is possible via Functors.fmap. For a more flexible interface, we recommend using Lux.Experimental.@layer_map.

fmap Support

fmap support needs to be explicitly enabled by loading Functors.jl and Setfield.jl.

Changes from Pre-1.0 Behavior

Previously if layers was a singleton tuple, initialparameters and initialstates would return the parameters and states for the single field layers. From v1.0.0 onwards, even for singleton tuples, the parameters/states are wrapped in a NamedTuple with the same name as the field. See AbstractLuxWrapperLayer to replicate the previous behavior of singleton tuples.

source

General

LuxCore.apply Function
julia
apply(model, x, ps, st)

In most cases this function simply calls model(x, ps, st). However, it is still recommended to call apply instead of model(x, ps, st) directly. Some of the reasons for this include:

  1. For certain types of inputs x, we might want to perform preprocessing before calling model. For eg, if x is an Array of ReverseDiff.TrackedReals this can cause significant regressions in model(x, ps, st) (since it won't hit any of the BLAS dispatches). In those cases, we would automatically convert x to a ReverseDiff.TrackedArray.

  2. Certain user defined inputs need to be applied to specific layers but we want the datatype of propagate through all the layers (even unsupported ones). In these cases, we can unpack the input in apply and pass it to the appropriate layer and then repack it before returning. See the Lux manual on Custom Input Types for a motivating example.

Tip

apply is integrated with DispatchDoctor.jl that allows automatic verification of type stability. By default this is "disable"d. For more information, see the documentation.

source

LuxCore.stateless_apply Function
julia
stateless_apply(model, x, ps)

Calls apply and only returns the first argument. This function requires that model has an empty state of NamedTuple(). Behavior of other kinds of models are undefined and it is the responsibility of the user to ensure that the model has an empty state.

source

LuxCore.check_fmap_condition Function
julia
check_fmap_condition(cond, tmatch::Union{Type, Nothing}, x) -> Bool

fmaps into the structure x and see if cond is satisfied for any of the leaf elements.

Arguments

  • cond - A function that takes a single argument and returns a Bool.

  • tmatch - A shortcut to check if x is of type tmatch. Can be disabled by passing nothing.

  • x - The structure to check.

Returns

A Boolean Value

source

LuxCore.contains_lux_layer Function
julia
contains_lux_layer(l) -> Bool

Check if the structure l is a Lux AbstractLuxLayer or a container of such a layer.

source

LuxCore.display_name Function
julia
display_name(layer::AbstractLuxLayer)

Printed Name of the layer. If the layer has a field name that is used, else the type name is used.

source

LuxCore.replicate Function
julia
replicate(rng::AbstractRNG)

Creates a copy of the rng state depending on its type.

source

LuxCore.setup Function
julia
setup(rng::AbstractRNG, layer)

Shorthand for getting the parameters and states of the layer l. Is equivalent to (initialparameters(rng, l), initialstates(rng, l)).

Warning

This function is not pure, it mutates rng.

source

Parameters

LuxCore.initialparameters Function
julia
initialparameters(rng::AbstractRNG, layer)

Generate the initial parameters of the layer l.

source

LuxCore.parameterlength Function
julia
parameterlength(layer)

Return the total number of parameters of the layer l.

source

States

LuxCore.initialstates Function
julia
initialstates(rng::AbstractRNG, layer)

Generate the initial states of the layer l.

source

LuxCore.statelength Function
julia
statelength(layer)

Return the total number of states of the layer l.

source

LuxCore.testmode Function
julia
testmode(st::NamedTuple)

Make all occurrences of training in state stVal(false).

source

LuxCore.trainmode Function
julia
trainmode(st::NamedTuple)

Make all occurrences of training in state stVal(true).

source

LuxCore.update_state Function
julia
update_state(st::NamedTuple, key::Symbol, value; exclude=Internal.isleaf)

Recursively update all occurrences of the key in the state st with the value. exclude is a function that is passed to Functors.fmap_with_path's exclude keyword.

Needs Functors.jl

This function requires Functors.jl to be loaded.

source

Layer size

LuxCore.outputsize Function
julia
outputsize(layer, x, rng)

Return the output size of the layer.

The fallback implementation of this function assumes the inputs were batched, i.e., if any of the outputs are Arrays, with ndims(A) > 1, it will return size(A)[1:(end - 1)]. If this behavior is undesirable, provide a custom outputsize(layer, x, rng) implementation).

Fallback Implementation

The fallback implementation of this function is defined once Lux.jl is loaded.

Changes from Pre-1.0 Behavior

Previously it was possible to override this function by defining outputsize(layer). However, this can potentially introduce a bug that is hard to bypass. See this PR for more information.

source

+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Building_Blocks/LuxLib.html b/previews/PR1023/api/Building_Blocks/LuxLib.html new file mode 100644 index 0000000000..af8c9f6654 --- /dev/null +++ b/previews/PR1023/api/Building_Blocks/LuxLib.html @@ -0,0 +1,46 @@ + + + + + + LuxLib | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

LuxLib

Backend for Lux.jl

Apply Activation

LuxLib.API.fast_activation Function
julia
fast_activation::F, x::AbstractArray) where {F}

Compute σ.(x) with the best possible implementation available. On CPUs we unroll the loop and use LoopVectorization.jl to vectorize the computation. On GPUs we use simply use broadcasting.

Note

This function doesn't replace σ with NNlib.fast_act(σ, ...), that needs to be done by the user if needed.

Arguments

  • σ: Activation function

  • x: Input array

Returns

  • Output Array with the same size as x

source

LuxLib.API.fast_activation!! Function
julia
fast_activation!!::F, x::AbstractArray) where {F}

Compute σ.(x) with the best possible implementation available. If it is possible to rewrite x in-place, it does so. If x is an immutable array, it falls back to the generic implementation.

Note

This function doesn't replace σ with NNlib.fast_act(σ, ...), that needs to be done by the user if needed.

Load SLEEFPirates.jl to get faster activations

Certain activation functions are replaced with specialized implementations from SLEEFPirates.jl for FP32. This might lead to faster performance but can cause slight decrease in accuracy (in the floating point limit).

Arguments

  • σ: Activation function

  • x: Input array

Returns

  • Output Array with the same size as x

source

Batched Operations

LuxLib.API.batched_matmul Function
julia
batched_matmul(x, y)

Computes the batched matrix multiplication of x and y. For more details see the NNlib documentation on NNlib.batched_mul. This function is mostly a wrapper around batched_mul but attempts to be faster on CPUs.

Load LoopVectorization.jl to get faster batched matrix multiplication

On CPUs loading LoopVectorization adds faster implementations of batched matrix multiplication.

source

Bias Activation

LuxLib.API.bias_activation Function
julia
bias_activation(σ, x, bias)

Applies the activation function σ elementwise to the result of broadcasted addition of x and bias along the penultimate dimension. A vector x is treated as a matrix with a single last dimension.

Arguments

  • σ: Activation function

  • x: Input to be transformed

  • bias: Bias to be added. Can be nothing.

See also bias_activation!!, fast_activation.

source

LuxLib.API.bias_activation!! Function
julia
bias_activation!!(σ, x, bias)

Same as bias_activation but might update x in-place if possible. Users should not rely on x being mutated, it is recommended to use it like y = bias_activation!!(σ, x, bias). If x is updated in-place, y aliases x.

See also bias_activation, fast_activation!!.

source

Convolutional Layers

LuxLib.API.fused_conv_bias_activation Function
julia
fused_conv_bias_activation::F, weight::AbstractArray, x::AbstractArray,
+    b::Optional{<:AbstractVector}, cdims::ConvDims) where {F}

Computes σ.(conv(x, weight, cdims) .+ b) (b is not exactly broadcasted like this, rather it is reshaped and broadcasted to the penultimate dimension) with the best possible implementation available. This operation fuses operations into a single kernel if possible, and minimizes reallocations by reusing the output buffer for multiple operations.

Arguments

  • σ: Activation function

  • weight: Weight tensor

  • x: Input tensor

  • b: Bias tensor (can be nothing)

  • cdims: ConvDims object

Notes on implementation

  • For CUDA Arrays, this uses fused CUDNN kernels when the activation is identity or relu. For other activations, it tries to fuse the operations on the Julia side.

  • If any of the inputs, don't support setindexing (aka immutable arrays) we fallback to the generic non-mutating implementation.

  • Maximum memory reuse and operation fusion is guaranteed for ChainRules compatible AD backends or backends that support mutation. Backends like Tracker and ReverseDiff fallback to the generic implementation.

  • For Mixed-Precision Inputs on GPU, we type promote the inputs to the highest precision, with a warning.

source

Dropout

LuxLib.API.alpha_dropout Function
julia
alpha_dropout(rng::AbstractRNG, x, p, training)
+alpha_dropout(rng::AbstractRNG, x, p, training, α, A, B)

Alpha Dropout: Dropout ensuring that the mean and variance of the output remains same as the input. For details see [1]. Use the second call signature to avoid recomputing the constants for a fixed dropout probability.

Arguments

  • rng: Random number generator

  • x: Input Array

  • p: Probability of an element to be dropped out

  • training: Set to Val(true) or True() if running in training mode. Can be set to nothing to automatically determine if the function is being called within an autodiff context`

  • α: -1.7580993408473766. Computed at limit x tends to infinity, selu(x) = -λβ = α

  • A: Scaling factor for the mean

  • B: Scaling factor for the variance

Returns

  • Output Array after applying alpha dropout

  • Updated state for the random number generator

References

[1] Klambauer, Günter, et al. "Self-normalizing neural networks." Advances in neural information processing systems 30 (2017).

source

LuxLib.API.dropout Function
julia
dropout(rng::AbstractRNG, x, p, training, invp, dims)
+dropout(rng::AbstractRNG, x, mask, p, training, update_mask::Union{Val, StaticBool},
+    invp, dims)

Dropout: Simple Way to prevent Neural Networks for Overfitting. For details see [1].

Arguments

  • rng: Random number generator

  • x: Input Array

  • mask: Dropout Mask. If not used then it is constructed automatically

  • p: Probability of an element to be dropped out

  • training: Set to Val(true) or True() if running in training mode. Can be set to nothing to automatically determine if the function is being called within an autodiff context

  • update_mask: If Val(true) or True() then the mask is generated and used. Else, the mask provided is directly used

  • invp: Inverse multiplied to the mask. Calculated as invp = 1 / (1 - p).

Returns

  • Output Array after applying dropout

  • Dropout Mask (if training == false, the returned value is meaningless)

  • Updated state for the random number generator

References

[1] Srivastava, Nitish, et al. "Dropout: a simple way to prevent neural networks from overfitting." The journal of machine learning research 15.1 (2014): 1929-1958.

source

Fully Connected Layers

LuxLib.API.fused_dense_bias_activation Function
julia
fused_dense_bias_activation::F, weight::AbstractMatrix, x::AbstractMatrix,
+    b::Optional{<:AbstractVector}) where {F}

Compute σ.(weight * x .+ b) with the best possible implementation available. Currently this implementation attempts to minimize reallocations by reusing the output buffer for multiple operations.

Arguments

  • σ: Activation function

  • weight: Weight matrix

  • x: Input matrix

  • b: Bias vector (can be nothing)

Notes on implementation

  • If any of the inputs, don't support setindexing (aka immutable arrays) we fallback to the generic non-mutating implementation.

  • Maximum memory reuse and operation fusion is guaranteed for ChainRules compatible AD backends or backends that support mutation. Backends like Tracker and ReverseDiff fallback to the generic implementation.

  • For CUDA Arrays, this uses a special fused implementation via cuBLASLt.

  • For small CPU Arrays, we use LoopVectorization.jl. On x86_64 we use Octavian for medium sized matrices. This is overridden if special BLAS implementations are loaded (currently MKL, AppleAccelerate, and BLISBLAS).

!!! tip "Load Octavian.jl

Loading `Octavian.jl` enables a polyalgorithm that uses different backends based on the
+input sizes.

source

Normalization

LuxLib.API.batchnorm Function
julia
batchnorm(x, scale, bias, running_mean, running_var, training,
+    σ=identity, momentum = 0.1f0, epsilon = eps(eltype(x)) ^ (5 // 7))

Batch Normalization. For details see [1].

Batch Normalization computes the mean and variance for each D1×...×DN2×1×DN input slice and normalises the input accordingly.

Arguments

  • x: Input to be Normalized

  • scale: Scale factor (γ) (can be nothing)

  • bias: Bias factor (β) (can be nothing)

  • running_mean: Running mean (can be nothing)

  • running_var: Running variance (can be nothing)

  • training: Set to Val(true) or True() if running in training mode. Can be set to nothing to automatically determine if the function is being called within an autodiff context

  • σ: Activation function (default: identity)

  • momentum: Momentum for updating running mean and variance (default: 0.1f0)

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

Returns

Normalized Array of same size as x. And a Named Tuple containing the updated running mean and variance.

References

[1] Ioffe, Sergey, and Christian Szegedy. "Batch normalization: Accelerating deep network training by reducing internal covariate shift." International conference on machine learning. PMLR, 2015.

source

LuxLib.API.groupnorm Function
julia
groupnorm(x, scale, bias, groups::Int, σ::F=identity,
+    epsilon::Real=eps(eltype(x)) ^ (5 // 7))

Group Normalization. For details see [1].

This op is similar to batch normalization, but statistics are shared across equally-sized groups of channels and not shared across batch dimension. Thus, group normalization does not depend on the batch composition and does not require maintaining internal state for storing statistics.

Arguments

  • x: Input to be Normalized

  • scale: Scale factor (γ) (can be nothing)

  • bias: Bias factor (β) (can be nothing)

  • groups: Number of groups

  • σ: Activation function (default: identity)

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

Returns

The normalized array is returned.

References

[1] Wu, Yuxin, and Kaiming He. "Group normalization." Proceedings of the European conference on computer vision (ECCV). 2018.

source

LuxLib.API.instancenorm Function
julia
instancenorm(x, scale, bias, training, act, epsilon = eps(eltype(x)) ^ (5 // 7))
+instancenorm(x, scale, bias, running_mean, running_var, training, act, momentum,
+    epsilon = eps(eltype(x)) ^ (5 // 7))

Instance Normalization. For details see [1].

Instance Normalization computes the mean and variance for each D1×...×DN2×1×1 input slice and normalises the input accordingly.

Arguments

  • x: Input to be Normalized (must be atleast 3D)

  • scale: Scale factor (γ) (can be nothing)

  • bias: Bias factor (β) (can be nothing)

  • running_mean: Running mean (can be nothing)

  • running_var: Running variance (can be nothing)

  • training: Set to Val(true) or True() if running in training mode. Can be set to nothing to automatically determine if the function is being called within an autodiff context

  • σ: Activation function (default: identity)

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

  • momentum: Momentum for updating running mean and variance (default: 0.1f0)

Returns

Normalized Array of same size as x. And a Named Tuple containing the updated running mean and variance.

References

[1] Ulyanov, Dmitry, Andrea Vedaldi, and Victor Lempitsky. "Instance normalization: The missing ingredient for fast stylization." arXiv preprint arXiv:1607.08022 (2016).

source

LuxLib.API.layernorm Function
julia
layernorm(x::AbstractArray{xT, N}, scale, bias, σ = identity, dims=1:(N - 1),
+    epsilon = eps(eltype(x)) ^ (5 / 7)) where {xT, N}

Layer Normalization. For details see [1].

Given an input array x, this layer computes

y=xE[x]Var[x]+ϵγ+β

and applies the activation function σ elementwise to y.

Arguments

  • x: Input to be Normalized

  • scale: Scale factor (γ) (can be nothing)

  • bias: Bias factor (β) (can be nothing)

  • σ: Activation function (default: identity)

  • dims: Dimensions along which the mean and std of x is computed. If nothing is passed, the dims are inferred based on the dimensions of scale and bias. For example, if x is N dimensional and scale and bias are M dimensional, then the dims will be 1:(N - M).

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

Returns

Normalized Array of same size as x.

References

[1] Ba, Jimmy Lei, Jamie Ryan Kiros, and Geoffrey E. Hinton. "Layer normalization." arXiv preprint arXiv:1607.06450 (2016).

source

Helper Functions

LuxLib.internal_operation_mode Function
julia
internal_operation_mode(xs::Tuple)
+internal_operation_mode(x::AbstractArray)

Returns the internal operation mode for the given array(s). This is useful to define custom implementations using different backends like simple Julia broadcasting, Kernel Abstractions, Loop Vectorization, etc.

Currently supported modes are:

  • GenericBroadcastOp: This is the fallback for most types. For the following types this is the preferred mode:

    • Arrays with fast_scalar_indexing set to False.

    • Static Arrays

    • ReverseDiff Arrays

    • Tracker Arrays

    • ForwardDiff.Dual Arrays

  • GPUBroadcastOp{dev}: GPU Arrays where dev is obtained from get_device_type(xs). This option dispatches should preferably use KernelAbstractions or specialized vendor dispatches.

  • LoopedArrayOp: CPU arrays that can be optimized using SIMD Loops, ideally using LoopVectorization.jl or Polyester.jl.

source

+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Building_Blocks/WeightInitializers.html b/previews/PR1023/api/Building_Blocks/WeightInitializers.html new file mode 100644 index 0000000000..c7203baa17 --- /dev/null +++ b/previews/PR1023/api/Building_Blocks/WeightInitializers.html @@ -0,0 +1,85 @@ + + + + + + WeightInitializers | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

WeightInitializers

This package is a light dependency providing common weight initialization schemes for deep learning models.

Supported RNG Types

RNG Type / PackageReturned Array TypeUnsupported Functions
Random.jlArray
StableRNGs.jlArray
CUDA.default_rng()CuArray
GPUArrays.default_rng(CuArray)CuArray
AMDGPU.rocrand_rng()ROCArray
AMDGPU.gpuarrays_rng()ROCArray
GPUArrays.default_rng(ROCArray)ROCArray
Metal.gpuarrays_rng()MtlArrayorthogonal
GPUArrays.default_rng(MtlArray)MtlArrayorthogonal
oneAPI.gpuarrays_rng()oneArrayorthogonal, truncated_normal
GPUArrays.default_rng(oneArray)oneArrayorthogonal, truncated_normal

API Reference

Main Functions

WeightInitializers.glorot_normal Function
julia
glorot_normal([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
+    gain = 1) -> AbstractArray{T, length(size)}

Return an AbstractArray{T} of the given size containing random numbers drawn from a normal distribution with standard deviation gain * sqrt(2 / (fan_in + fan_out)). This method is described in [1] and also known as Xavier initialization.

References

[1] Glorot, Xavier, and Yoshua Bengio. "Understanding the difficulty of training deep feedforward neural networks." Proceedings of the thirteenth international conference on artificial intelligence and statistics. 2010.

source

WeightInitializers.glorot_uniform Function
julia
glorot_uniform([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
+    gain = 1) -> AbstractArray{T, length(size)}

Return an AbstractArray{T} of the given size containing random numbers drawn from a uniform distribution on the interval [x,x], where x = gain * sqrt(6 / (fan_in + fan_out)). This method is described in [1] and also known as Xavier initialization.

References

[1] Glorot, Xavier, and Yoshua Bengio. "Understanding the difficulty of training deep feedforward neural networks." Proceedings of the thirteenth international conference on artificial intelligence and statistics. 2010.

source

WeightInitializers.identity_init Function
julia
identity_init([::AbstractRNG=Utils.default_rng()], [T=Float32], size...; gain::Number=1,
+    shift::Union{Integer, Tuple{Integer, Integer}}=0) -> AbstractArray{T}

Constructs an array that aims to provide an identity mapping when used as parameters in most layers of a neural network. The identity mapping is scaled by the gain parameter.

Behavior

  • 1D: Returns a Vector of zeros (useful for biases in layers where input_size == output_size).

  • 2D: Returns an identity matrix (useful for fully connected layers with equal input and output sizes).

  • More than 2D: Returns a tensor where the central slice along the last two dimensions is an identity matrix, and the rest are zeros (useful for convolutional layers, simulating an identity convolution).

Caveats

  • Not all layers will result in an identity mapping when using this initializer. Exceptions include recurrent and normalization layers.

  • Layers must have input_size == output_size for a perfect identity mapping. In cases where this condition is not met, the function pads extra dimensions with zeros.

  • For convolutional layers to achieve an identity mapping, kernel sizes must be odd, and appropriate padding must be applied to ensure the output feature maps are the same size as the input feature maps.

Arguments

  • rng::AbstractRNG: An optional random number generator, included for consistency with other initializers but ignored since the output is deterministic.

  • T::Type{<:Number}: The numeric type of the array elements.

  • size...: The dimensions of the array to be initialized.

  • gain::Number=1: A scaling factor applied to the identity mapping.

  • shift::Union{Integer, Tuple{Integer, Integer}}=0: An integer or a tuple specifying the circular shift applied to the output array.

Returns

  • AbstractArray{T}: An array initialized to represent an identity mapping, scaled by gain and optionally shifted by shift.

Examples

julia
julia> identity_init(Xoshiro(123), Float32, 5, 5)
+5×5 Matrix{Float32}:
+ 1.0  1.0  1.0  1.0  1.0
+ 1.0  1.0  1.0  1.0  1.0
+ 1.0  1.0  1.0  1.0  1.0
+ 1.0  1.0  1.0  1.0  1.0
+ 1.0  1.0  1.0  1.0  1.0
+
+julia> identity_init(Xoshiro(123), Float32, 3, 3, 1, 1; gain=1.5)
+3×3×1×1 Array{Float32, 4}:
+[:, :, 1, 1] =
+ 0.0  0.0  0.0
+ 0.0  1.5  0.0
+ 0.0  0.0  0.0

source

WeightInitializers.kaiming_normal Function
julia
kaiming_normal([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
+    gain =T(2)) -> AbstractArray{T, length(size)}

Return an AbstractArray{T} of the given size containing random numbers taken from a normal distribution standard deviation gain / sqrt(fan_in)

References

[1] He, Kaiming, et al. "Delving deep into rectifiers: Surpassing human-level performance on imagenet classification." Proceedings of the IEEE international conference on computer vision. 2015.

source

WeightInitializers.kaiming_uniform Function
julia
kaiming_uniform([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
+    gain =T(2)) -> AbstractArray{T, length(size)}

Return an AbstractArray{T} of the given size containing random numbers drawn from a uniform distribution on the interval [-x, x], where x = gain * sqrt(3/fan_in).

References

[1] He, Kaiming, et al. "Delving deep into rectifiers: Surpassing human-level performance on imagenet classification." Proceedings of the IEEE international conference on computer vision. 2015.

source

WeightInitializers.sparse_init Function
julia
sparse_init([::AbstractRNG=Utils.default_rng()], [T=Float32], dims::Integer...;
+    sparsity::Number, std::Number=0.01) -> AbstractArray{T}

Creates a sparsely initialized weight matrix with a specified proportion of zeroed elements, using random numbers drawn from a normal distribution for the non-zero elements. This method was introduced in [1].

Note

The sparsity parameter controls the proportion of the matrix that will be zeroed. For example, a sparsity of 0.3 means that approximately 30% of the elements will be set to zero. The non-zero elements are distributed according to a normal distribution, scaled by the std parameter.

Arguments

  • rng::AbstractRNG: The random number generator to use.

  • T::Type{<:Number}: The numeric type of the elements in the returned array.

  • dims::Integer...: The dimensions of the weight matrix to be generated.

  • sparsity::Number: The proportion of elements to be zeroed. Must be between 0 and 1.

  • std::Number=0.01: The standard deviation of the normal distribution before applying gain.

Returns

  • AbstractArray{T}: A sparsely initialized weight matrix of dimensions dims and type T.

Examples

julia
julia> y = sparse_init(Xoshiro(123), Float32, 5, 5; sparsity=0.3, std=0.01);
+
+julia> y isa Matrix{Float32}
+true
+
+julia> size(y) == (5, 5)
+true

References

[1] Martens, J, "Deep learning via Hessian-free optimization" Proceedings of the 27th International Conference on International Conference on Machine Learning. 2010.

source

WeightInitializers.truncated_normal Function
julia
truncated_normal([::AbstractRNG=Utils.default_rng()], [T=Float32], size...; mean = 0,
+    std = 1, lo = -2, hi = 2) -> AbstractArray{T, length(size)}

Return an AbstractArray{T} of the given size where each element is drawn from a truncated normal distribution. The numbers are distributed like filter(x -> lo ≤ x ≤ hi, mean .+ std .* randn(100)).

source

WeightInitializers.orthogonal Function
julia
orthogonal([::AbstractRNG=Utils.default_rng()], [T=Float32], dims::Integer...;
+    gain = 1)  -> AbstractArray{T, length(dims)}

Return an AbstractArray{T} of the given dimensions (dims) which is a (semi) orthogonal matrix, as described in [1].

The function constructs an orthogonal or semi-orthogonal matrix depending on the specified dimensions. For two dimensions, it returns a matrix where dims = (rows, cols). For more than two dimensions, it computes an orthogonal matrix of size prod(dims[1:(end - 1)]) by dims[end] before reshaping it to the original dimensions.

Cannot construct a vector, i.e., length(dims) == 1 is forbidden.

Arguments

  • rng::AbstractRNG: Random number generator.

  • T::Type{<:Real}: The type of the elements in the array.

  • dims::Integer...: The dimensions of the array.

  • gain::Number: Scaling factor for the elements of the orthogonal matrix.

References

[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

source

Other Convenience Functions

Beware

Unlike the other functions these ones don't take a type argument.

WeightInitializers.zeros16 Function
julia
zeros16([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float16, length(size)}

Return an AbstractArray{Float16} of the given size containing an AbstractArray of zeros.

source

WeightInitializers.ones16 Function
julia
ones16([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float16, length(size)}

Return an AbstractArray{Float16} of the given size containing an AbstractArray of ones.

source

WeightInitializers.rand16 Function
julia
rand16([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float16, length(size)}

Return an AbstractArray{Float16} of the given size containing random numbers from a uniform distribution.

source

WeightInitializers.randn16 Function
julia
randn16([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float16, length(size)}

Return an AbstractArray{Float16} of the given size containing random numbers from a standard normal distribution.

source

WeightInitializers.zeros32 Function
julia
zeros32([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float32, length(size)}

Return an AbstractArray{Float32} of the given size containing an AbstractArray of zeros.

source

WeightInitializers.ones32 Function
julia
ones32([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float32, length(size)}

Return an AbstractArray{Float32} of the given size containing an AbstractArray of ones.

source

WeightInitializers.rand32 Function
julia
rand32([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float32, length(size)}

Return an AbstractArray{Float32} of the given size containing random numbers from a uniform distribution.

source

WeightInitializers.randn32 Function
julia
randn32([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float32, length(size)}

Return an AbstractArray{Float32} of the given size containing random numbers from a standard normal distribution.

source

WeightInitializers.zeros64 Function
julia
zeros64([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float64, length(size)}

Return an AbstractArray{Float64} of the given size containing an AbstractArray of zeros.

source

WeightInitializers.ones64 Function
julia
ones64([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float64, length(size)}

Return an AbstractArray{Float64} of the given size containing an AbstractArray of ones.

source

WeightInitializers.rand64 Function
julia
rand64([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float64, length(size)}

Return an AbstractArray{Float64} of the given size containing random numbers from a uniform distribution.

source

WeightInitializers.randn64 Function
julia
randn64([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{Float64, length(size)}

Return an AbstractArray{Float64} of the given size containing random numbers from a standard normal distribution.

source

WeightInitializers.zerosC16 Function
julia
zerosC16([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF16, length(size)}

Return an AbstractArray{ComplexF16} of the given size containing an AbstractArray of zeros.

source

WeightInitializers.onesC16 Function
julia
onesC16([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF16, length(size)}

Return an AbstractArray{ComplexF16} of the given size containing an AbstractArray of ones.

source

WeightInitializers.randC16 Function
julia
randC16([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF16, length(size)}

Return an AbstractArray{ComplexF16} of the given size containing random numbers from a uniform distribution.

source

WeightInitializers.randnC16 Function
julia
randnC16([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF16, length(size)}

Return an AbstractArray{ComplexF16} of the given size containing random numbers from a standard normal distribution.

source

WeightInitializers.zerosC32 Function
julia
zerosC32([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF32, length(size)}

Return an AbstractArray{ComplexF32} of the given size containing an AbstractArray of zeros.

source

WeightInitializers.onesC32 Function
julia
onesC32([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF32, length(size)}

Return an AbstractArray{ComplexF32} of the given size containing an AbstractArray of ones.

source

WeightInitializers.randC32 Function
julia
randC32([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF32, length(size)}

Return an AbstractArray{ComplexF32} of the given size containing random numbers from a uniform distribution.

source

WeightInitializers.randnC32 Function
julia
randnC32([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF32, length(size)}

Return an AbstractArray{ComplexF32} of the given size containing random numbers from a standard normal distribution.

source

WeightInitializers.zerosC64 Function
julia
zerosC64([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF64, length(size)}

Return an AbstractArray{ComplexF64} of the given size containing an AbstractArray of zeros.

source

WeightInitializers.onesC64 Function
julia
onesC64([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF64, length(size)}

Return an AbstractArray{ComplexF64} of the given size containing an AbstractArray of ones.

source

WeightInitializers.randC64 Function
julia
randC64([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF64, length(size)}

Return an AbstractArray{ComplexF64} of the given size containing random numbers from a uniform distribution.

source

WeightInitializers.randnC64 Function
julia
randnC64([::AbstractRNG=Utils.default_rng()], size...;
+    kwargs...) -> AbstractArray{ComplexF64, length(size)}

Return an AbstractArray{ComplexF64} of the given size containing random numbers from a standard normal distribution.

source

+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Lux/autodiff.html b/previews/PR1023/api/Lux/autodiff.html new file mode 100644 index 0000000000..8034a4b684 --- /dev/null +++ b/previews/PR1023/api/Lux/autodiff.html @@ -0,0 +1,34 @@ + + + + + + Automatic Differentiation Helpers | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

Automatic Differentiation Helpers

JVP & VJP Wrappers

Lux.jacobian_vector_product Function
julia
jacobian_vector_product(f, backend::AbstractADType, x, u)

Compute the Jacobian-Vector Product (fx)u. This is a wrapper around AD backends but allows us to compute gradients of jacobian-vector products efficiently using mixed-mode AD.

Backends & AD Packages

Supported BackendsPackages Needed
AutoForwardDiff

Warning

Gradient wrt u in the reverse pass is always dropped.

Arguments

  • f: The function to compute the jacobian of.

  • backend: The backend to use for computing the JVP.

  • x: The input to the function.

  • u: An object of the same structure as x.

Returns

  • v: The Jacobian Vector Product.

source

Lux.vector_jacobian_product Function
julia
vector_jacobian_product(f, backend::AbstractADType, x, u)

Compute the Vector-Jacobian Product (fx)Tu. This is a wrapper around AD backends but allows us to compute gradients of vector-jacobian products efficiently using mixed-mode AD.

Backends & AD Packages

Supported BackendsPackages Needed
AutoZygoteZygote.jl

Warning

Gradient wrt u in the reverse pass is always dropped.

Arguments

  • f: The function to compute the jacobian of.

  • backend: The backend to use for computing the VJP.

  • x: The input to the function.

  • u: An object of the same structure as f(x).

Returns

  • v: The Vector Jacobian Product.

source

Batched AD

Lux.batched_jacobian Function
julia
batched_jacobian(f, backend::AbstractADType, x::AbstractArray)

Computes the Jacobian of a function f with respect to a batch of inputs x. This expects the following properties for y = f(x):

  1. ndims(y) ≥ 2

  2. size(y, ndims(y)) == size(x, ndims(x))

Backends & AD Packages

Supported BackendsPackages Needed
AutoForwardDiff
AutoZygoteZygote.jl

Arguments

  • f: The function to compute the jacobian of.

  • backend: The backend to use for computing the jacobian.

  • x: The input to the function. Must have ndims(x) ≥ 2.

Returns

  • J: The Jacobian of f with respect to x. This will be a 3D Array. If the dimensions of x are (N₁, N₂, ..., Nₙ, B) and of y are (M₁, M₂, ..., Mₘ, B), then J will be a ((M₁ × M₂ × ... × Mₘ), (N₁ × N₂ × ... × Nₙ), B) Array.

Danger

f(x) must not be inter-mixing the batch dimensions, else the result will be incorrect. For example, if f contains operations like batch normalization, then the result will be incorrect.

source

Nested 2nd Order AD

Consult the manual page on Nested AD for information on nested automatic differentiation.

+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Lux/contrib.html b/previews/PR1023/api/Lux/contrib.html new file mode 100644 index 0000000000..c5e005144b --- /dev/null +++ b/previews/PR1023/api/Lux/contrib.html @@ -0,0 +1,88 @@ + + + + + + Experimental Features | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

Experimental Features

All features listed on this page are experimental which means:

  1. No SemVer Guarantees. We use code here to iterate fast. That said, historically we have never broken any code in this module and have always provided a deprecation period.

  2. Expect edge-cases and report them. It will help us move these features out of experimental sooner.

  3. None of the features are exported.

Parameter Freezing

Lux.Experimental.FrozenLayer Type
julia
FrozenLayer(l::AbstractLuxLayer, which_params::Optional{Tuple})

Freeze the parameters with name which_params of the layer l.

Use Lux.Experimental.freeze instead

It is always recommended to use the Lux.Experimental.freeze function instead of directly using the FrozenLayer constructor.

No checks for which_params

There are no checks for which_params. For example, if the original layer has parameters named (:weight, :bias), and which_params is set to (:myweight,) then none of the parameters are frozen and no error is thrown.

Arguments

  • l: Lux AbstractLuxLayer.

  • which_params: Parameter Names to be Frozen. Can be set to nothing, in which case all parameters are frozen.

Extended Help

Parameters

  • Parameters of the layer l excluding which_params.

States

  • frozen_params: Parameters that are frozen, i.e., which_params.

  • states: The state of the inner layer l.

Note on Internal Layer Implementation

The inner layer should work with NamedTuple parameters. In order to support custom parameter types, users need to implement Lux.Utils.merge(::CustomParamType, ::NamedTuple) or extend Lux.Utils.named_tuple(::CustomParamType) to return a NamedTuple.

Example

julia
julia> Lux.Experimental.FrozenLayer(Dense(2 => 2), (:weight,))
+FrozenLayer(Dense(2 => 2), (:weight,))  # 2 parameters, plus 4 non-trainable

See also Lux.Experimental.freeze, Lux.Experimental.unfreeze.

source

Lux.Experimental.freeze Function
julia
freeze(l::AbstractLuxLayer, which_params::Optional{Tuple} = nothing)

Constructs a version of l with which_params frozen. If which_params is nothing, then all parameters are frozen.

source

julia
freeze(l::AbstractLuxLayer, ps, st::NamedTuple,
+    which_params::Optional{Tuple} = nothing)

Construct a Lux.Experimental.FrozenLayer for l with the current parameters and states. If which_params is nothing, then all parameters are frozen.

source

Lux.Experimental.unfreeze Function
julia
unfreeze(l::FrozenLayer)

Unfreezes the layer l.

source

julia
unfreeze(l::FrozenLayer, ps, st::NamedTuple)

Unwraps a Lux.Experimental.FrozenLayer l with the current parameters and states.

source

For detailed usage example look at the manual page.

Map over Layer

Lux.Experimental.layer_map Function
julia
layer_map(f, l::AbstractLuxLayer, ps, st::NamedTuple)

Map the function f over the model l, with the parameters ps and states st. This is different from Functors.fmap since it zips the layers, parameters, and states and invokes the function on all of them together.

KeyPath provided to the function

The KeyPath depths on the structure of the parameters and states. This is of consequence exclusively for AbstractLuxWrapperLayer where the structure of the layer doesn't match the structure of the parameters and states. In the example, provided below, the KeyPath is (:chain, :dense_1) for the first layer (following the structure in ps) while accessing the same layer in the chain is done with ( :chain, :layers, :dense_1).

Call Signature for f

  • Must take 4 inputs – AbstractLuxLayer, Corresponding Parameters, Corresponding States, and the Functors.KeyPath to the layer.

  • Must return a tuple of 3 elements – AbstractLuxLayer, new parameters and the new states.

Extended Help

Example

julia
julia> using Lux, Random
+
+julia> c = Parallel(
+           +; chain=Chain(; dense_1=Dense(2 => 3), bn=BatchNorm(3), dense_2=Dense(3 => 5)),
+           dense_3=Dense(5 => 1));
+
+julia> rng = Random.default_rng();
+
+julia> ps, st = Lux.setup(rng, c);
+
+julia> # Makes parameters of Dense Layers inside Chain zero
+       function zero_dense_params(l, ps, st, name)
+           if l isa Dense
+               println("zeroing params of $name")
+               ps = merge(ps, (; weight=zero.(ps.weight), bias=zero.(ps.bias)))
+           end
+           return l, ps, st
+       end;
+
+julia> _, ps_new, _ = Lux.Experimental.layer_map(zero_dense_params, c, ps, st);
+zeroing params of KeyPath(:chain, :dense_1)
+zeroing params of KeyPath(:chain, :dense_2)
+zeroing params of KeyPath(:dense_3,)
+
+julia> all(iszero, (ps_new.chain.dense_1.weight, ps_new.chain.dense_1.bias,
+                    ps_new.chain.dense_2.weight, ps_new.chain.dense_2.bias,
+                    ps_new.dense_3.weight, ps_new.dense_3.bias))
+true

source

Debugging Functionality

Model not working properly! Here are some functionalities to help you debug you Lux model.

Lux.Experimental.@debug_mode Macro
julia
@debug_mode layer kwargs...

Recurses into the layer and replaces the inner most non Container Layers with a Lux.Experimental.DebugLayer.

See Lux.Experimental.DebugLayer for details about the Keyword Arguments.

source

Lux.Experimental.DebugLayer Type
julia
DebugLayer(layer::AbstractLuxLayer;
+    nan_check::Union{Symbol, StaticSymbol, Val}=static(:both),
+    error_check::Union{StaticBool, Bool, Val{true}, Val{false}}=True(),
+    location::KeyPath=KeyPath())

A wrapper over Lux layers that adds checks for NaNs and errors. This is useful for debugging.

Arguments

  • layer: The layer to be wrapped.

Extended Help

Keyword Arguments

  • nan_check: Whether to check for NaNs in the input, parameters, and states. Can be :both, :forward, :backward, or :none.

  • error_check: Whether to check for errors in the layer. If true, will throw an error if the layer fails.

  • location: The location of the layer. Use Lux.Experimental.@debug_mode to construct this layer to populate this value correctly.

Input / Output

Inputs and outputs are the same as the layer unless one of the nan_check or error_check criteria is met.

If nan_check is enabled and NaNs are detected then a DomainError is thrown. If error_check is enabled, then any errors in the layer are thrown with useful information to track where the error originates.

ChainRules Compatible Reverse Mode AD Tools

nan_check for the backward mode only works with ChainRules Compatible Reverse Mode AD Tools currently.

Disable After Debugging

This layer is only meant to be used for debugging. If used for actual training or inference, will lead to extremely bad performance.

See Lux.Experimental.@debug_mode to construct this layer.

source

Tied Parameters

Lux.Experimental.share_parameters Function
julia
share_parameters(ps, sharing)
+share_parameters(ps, sharing, new_parameters)

Updates the parameters in ps with a common set of parameters new_parameters that are shared between each list in the nested list sharing. (That was kind of a mouthful, the example should make it clear).

Arguments

  • ps: Original parameters.

  • sharing: A nested list of lists of accessors of ps which need to shate the parameters (See the example for details). (Each list in the list must be disjoint)

  • new_parameters: If passed the length of new_parameters must be equal to the length of sharing. For each vector in sharing the corresponding parameter in new_parameters will be used. (If not passed, the parameters corresponding to the first element of each vector in sharing will be used).

Returns

Updated Parameters having the same structure as ps.

Example

julia
julia> model = Chain(; d1=Dense(2 => 4, tanh),
+           d3=Chain(; l1=Dense(4 => 2), l2=Dense(2 => 4)), d2=Dense(4 => 2))
+Chain(
+    d1 = Dense(2 => 4, tanh),           # 12 parameters
+    d3 = Chain(
+        l1 = Dense(4 => 2),             # 10 parameters
+        l2 = Dense(2 => 4),             # 12 parameters
+    ),
+    d2 = Dense(4 => 2),                 # 10 parameters
+)         # Total: 44 parameters,
+          #        plus 0 states.
+
+julia> ps, st = Lux.setup(Xoshiro(0), model);
+
+julia> # share parameters of (d1 and d3.l1) and (d3.l2 and d2)
+       ps = Lux.Experimental.share_parameters(ps, (("d3.l2", "d1"), ("d2", "d3.l1")));
+
+julia> ps.d3.l2.weight === ps.d1.weight &&
+           ps.d3.l2.bias === ps.d1.bias &&
+           ps.d2.weight === ps.d3.l1.weight &&
+           ps.d2.bias === ps.d3.l1.bias
+true

ComponentArrays

ComponentArrays doesn't allow sharing parameters. Converting the returned parameters to a ComponentArray will silently cause the parameter sharing to be undone.

source

+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Lux/distributed_utils.html b/previews/PR1023/api/Lux/distributed_utils.html new file mode 100644 index 0000000000..3fb7deb4ed --- /dev/null +++ b/previews/PR1023/api/Lux/distributed_utils.html @@ -0,0 +1,37 @@ + + + + + + Distributed Utils | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

Distributed Utils

Note

These functionalities are available via the Lux.DistributedUtils module.

Backends

Lux.MPIBackend Type
julia
MPIBackend(comm = nothing)

Create an MPI backend for distributed training. Users should not use this function directly. Instead use DistributedUtils.get_distributed_backend(MPIBackend).

source

Lux.NCCLBackend Type
julia
NCCLBackend(comm = nothing, mpi_backend = nothing)

Create an NCCL backend for distributed training. Users should not use this function directly. Instead use DistributedUtils.get_distributed_backend(NCCLBackend).

source

Initialization

Lux.DistributedUtils.initialize Function
julia
initialize(backend::Type{<:AbstractLuxDistributedBackend}; kwargs...)

Initialize the given backend. Users can supply cuda_devices and amdgpu_devices to initialize the backend with the given devices. These can be set to missing to prevent initialization of the given device type. If set to nothing, and the backend is functional we assign GPUs in a round-robin fashion. Finally, a list of integers can be supplied to initialize the backend with the given devices.

Possible values for backend are:

  • MPIBackend: MPI backend for distributed training. Requires MPI.jl to be installed.

  • NCCLBackend: NCCL backend for CUDA distributed training. Requires CUDA.jl, MPI.jl, and NCCL.jl to be installed. This also wraps MPI backend for non-CUDA communications.

source

Lux.DistributedUtils.initialized Function
julia
initialized(backend::Type{<:AbstractLuxDistributedBackend})

Check if the given backend is initialized.

source

Lux.DistributedUtils.get_distributed_backend Function
julia
get_distributed_backend(backend::Type{<:AbstractLuxDistributedBackend})

Get the distributed backend for the given backend type. Possible values are:

  • MPIBackend: MPI backend for distributed training. Requires MPI.jl to be installed.

  • NCCLBackend: NCCL backend for CUDA distributed training. Requires CUDA.jl, MPI.jl, and NCCL.jl to be installed. This also wraps MPI backend for non-CUDA communications.

Danger

initialize(backend; kwargs...) must be called before calling this function.

source

Helper Functions

Lux.DistributedUtils.local_rank Function
julia
local_rank(backend::AbstractLuxDistributedBackend)

Get the local rank for the given backend.

source

Lux.DistributedUtils.total_workers Function
julia
total_workers(backend::AbstractLuxDistributedBackend)

Get the total number of workers for the given backend.

source

Communication Primitives

Lux.DistributedUtils.allreduce! Function
julia
allreduce!(backend::AbstractLuxDistributedBackend, sendrecvbuf, op)
+allreduce!(backend::AbstractLuxDistributedBackend, sendbuf, recvbuf, op)

Backend Agnostic API to perform an allreduce operation on the given buffer sendrecvbuf or sendbuf and store the result in recvbuf.

op allows a special DistributedUtils.avg operation that averages the result across all workers.

source

Lux.DistributedUtils.bcast! Function
julia
bcast!(backend::AbstractLuxDistributedBackend, sendrecvbuf; root::Int=0)
+bcast!(backend::AbstractLuxDistributedBackend, sendbuf, recvbuf; root::Int=0)

Backend Agnostic API to broadcast the given buffer sendrecvbuf or sendbuf to all workers into recvbuf. The value at root will be broadcasted to all other workers.

source

Lux.DistributedUtils.reduce! Function
julia
reduce!(backend::AbstractLuxDistributedBackend, sendrecvbuf, op; root::Int=0)
+reduce!(backend::AbstractLuxDistributedBackend, sendbuf, recvbuf, op; root::Int=0)

Backend Agnostic API to perform a reduce operation on the given buffer sendrecvbuf or sendbuf and store the result in recvbuf.

op allows a special DistributedUtils.avg operation that averages the result across all workers.

source

Lux.DistributedUtils.synchronize!! Function
julia
synchronize!!(backend::AbstractLuxDistributedBackend, ps; root::Int=0)

Synchronize the given structure ps using the given backend. The value at root will be broadcasted to all other workers.

source

Optimizers.jl Integration

Lux.DistributedUtils.DistributedOptimizer Type
julia
DistributedOptimizer(backend::AbstractLuxDistributedBacked, optimizer)

Wrap the optimizer in a DistributedOptimizer. Before updating the parameters, this averages the gradients across the processes using Allreduce.

Arguments

  • optimizer: An Optimizer compatible with the Optimisers.jl package

source

MLUtils.jl Integration

Lux.DistributedUtils.DistributedDataContainer Type
julia
DistributedDataContainer(backend::AbstractLuxDistributedBackend, data)

data must be compatible with MLUtils interface. The returned container is compatible with MLUtils interface and is used to partition the dataset across the available processes.

Load MLUtils.jl

MLUtils.jl must be installed and loaded before using this.

source

+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Lux/interop.html b/previews/PR1023/api/Lux/interop.html new file mode 100644 index 0000000000..338f28bdf4 --- /dev/null +++ b/previews/PR1023/api/Lux/interop.html @@ -0,0 +1,65 @@ + + + + + + Interoperability between Lux and other packages | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

Interoperability between Lux and other packages

Switching from older frameworks

Flux Models to Lux Models

Flux.jl has been around in the Julia ecosystem for a long time and has a large userbase, hence we provide a way to convert Flux models to Lux models.

Tip

Accessing these functions require manually loading Flux, i.e., using Flux must be present somewhere in the code for these to be used.

Adapt.adapt Method
julia
Adapt.adapt(from::FromFluxAdaptor, L)

Adapt a Flux model L to Lux model. See FromFluxAdaptor for more details.

source

Lux.FromFluxAdaptor Type
julia
FromFluxAdaptor(preserve_ps_st::Bool=false, force_preserve::Bool=false)

Convert a Flux Model to Lux Model.

active field

This always ignores the active field of some of the Flux layers. This is almost never going to be supported.

Keyword Arguments

  • preserve_ps_st: Set to true to preserve the states and parameters of the layer. This attempts the best possible way to preserve the original model. But it might fail. If you need to override possible failures, set force_preserve to true.

  • force_preserve: Some of the transformations with state and parameters preservation haven't been implemented yet, in these cases, if force_transform is false a warning will be printed and a core Lux layer will be returned. Else, it will create a FluxLayer.

Example

julia
julia> import Flux
+
+julia> using Adapt, Lux, Random
+
+julia> m = Flux.Chain(Flux.Dense(2 => 3, relu), Flux.Dense(3 => 2));
+
+julia> m2 = adapt(FromFluxAdaptor(), m); # or FromFluxAdaptor()(m.layers)
+
+julia> x = randn(Float32, 2, 32);
+
+julia> ps, st = Lux.setup(Random.default_rng(), m2);
+
+julia> size(first(m2(x, ps, st)))
+(2, 32)

source

Lux.FluxLayer Type
julia
FluxLayer(layer)

Serves as a compatibility layer between Flux and Lux. This uses Optimisers.destructure API internally.

Warning

Lux was written to overcome the limitations of destructure + Flux. It is recommended to rewrite your layer in Lux instead of using this layer.

Warning

Introducing this Layer in your model will lead to type instabilities, given the way Optimisers.destructure works.

Arguments

  • layer: Flux layer

Parameters

  • p: Flattened parameters of the layer

source

Using a different backend for Lux

Lux Models to Simple Chains

SimpleChains.jl provides a way to train Small Neural Networks really fast on CPUs. See this blog post for more details. This section describes how to convert Lux models to SimpleChains models while preserving the layer interface.

Tip

Accessing these functions require manually loading SimpleChains, i.e., using SimpleChains must be present somewhere in the code for these to be used.

Adapt.adapt Method
julia
Adapt.adapt(from::ToSimpleChainsAdaptor, L::AbstractLuxLayer)

Adapt a Simple Chains model to Lux model. See ToSimpleChainsAdaptor for more details.

source

Lux.ToSimpleChainsAdaptor Type
julia
ToSimpleChainsAdaptor(input_dims, convert_to_array::Bool=false)

Adaptor for converting a Lux Model to SimpleChains. The returned model is still a Lux model, and satisfies the AbstractLuxLayer interfacem but all internal calculations are performed using SimpleChains.

Warning

There is no way to preserve trained parameters and states when converting to SimpleChains.jl.

Warning

Any kind of initialization function is not preserved when converting to SimpleChains.jl.

Arguments

  • input_dims: Tuple of input dimensions excluding the batch dimension. These must be of static type as SimpleChains expects.

  • convert_to_array: SimpleChains.jl by default outputs StrideArraysCore.StrideArray, but this might not compose well with other packages. If convert_to_array is set to true, the output will be converted to a regular Array.

Example

julia
julia> import SimpleChains
+
+julia> using Adapt, Lux, Random
+
+julia> lux_model = Chain(Conv((5, 5), 1 => 6, relu), MaxPool((2, 2)),
+           Conv((5, 5), 6 => 16, relu), MaxPool((2, 2)), FlattenLayer(3),
+           Chain(Dense(256 => 128, relu), Dense(128 => 84, relu), Dense(84 => 10)));
+
+julia> adaptor = ToSimpleChainsAdaptor((28, 28, 1));
+
+julia> simple_chains_model = adapt(adaptor, lux_model); # or adaptor(lux_model)
+
+julia> ps, st = Lux.setup(Random.default_rng(), simple_chains_model);
+
+julia> x = randn(Float32, 28, 28, 1, 1);
+
+julia> size(first(simple_chains_model(x, ps, st)))
+(10, 1)

source

Lux.SimpleChainsLayer Type
julia
SimpleChainsLayer(layer, to_array::Union{Bool, Val}=Val(false))
+SimpleChainsLayer(layer, lux_layer, to_array)

Wraps a SimpleChains layer into a Lux layer. All operations are performed using SimpleChains but the layer satisfies the AbstractLuxLayer interface.

ToArray is a boolean flag that determines whether the output should be converted to a regular Array or not. Default is false.

Arguments

  • layer: SimpleChains layer

  • lux_layer: Potentially equivalent Lux layer that is used for printing

source

+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Lux/layers.html b/previews/PR1023/api/Lux/layers.html new file mode 100644 index 0000000000..10c1411386 --- /dev/null +++ b/previews/PR1023/api/Lux/layers.html @@ -0,0 +1,182 @@ + + + + + + Built-In Layers | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

Built-In Layers

Containers

Lux.BranchLayer Type
julia
BranchLayer(layers...)
+BranchLayer(; name=nothing, layers...)

Takes an input x and passes it through all the layers and returns a tuple of the outputs.

Arguments

  • Layers can be specified in two formats:
    • A list of N Lux layers

    • Specified as N keyword arguments.

Extended Help

Inputs

  • x: Will be directly passed to each of the layers

Returns

  • Tuple: (layer_1(x), layer_2(x), ..., layer_N(x)) (naming changes if using the kwargs API)

  • Updated state of the layers

Parameters

  • Parameters of each layer wrapped in a NamedTuple with fields = layer_1, layer_2, ..., layer_N (naming changes if using the kwargs API)

States

  • States of each layer wrapped in a NamedTuple with fields = layer_1, layer_2, ..., layer_N (naming changes if using the kwargs API)

Comparison with Parallel

This is slightly different from Parallel(nothing, layers...)

  • If the input is a tuple, Parallel will pass each element individually to each layer.

  • BranchLayer essentially assumes 1 input comes in and is branched out into N outputs.

Example

An easy way to replicate an input to an NTuple is to do

julia
julia> BranchLayer(NoOpLayer(), NoOpLayer(), NoOpLayer())
+BranchLayer(
+    layer_1 = NoOpLayer(),
+    layer_2 = NoOpLayer(),
+    layer_3 = NoOpLayer(),
+)         # Total: 0 parameters,
+          #        plus 0 states.

source

Lux.Chain Type
julia
Chain(layers...; name=nothing)
+Chain(; layers..., name=nothing)

Collects multiple layers / functions to be called in sequence on a given input.

Arguments

  • Layers can be specified in two formats:
    • A list of N Lux layers

    • Specified as N keyword arguments.

Extended Help

Inputs

Input x is passed sequentially to each layer, and must conform to the input requirements of the internal layers.

Returns

  • Output after sequentially applying all the layers to x

  • Updated model states

Parameters

  • Parameters of each layer wrapped in a NamedTuple with fields = layer_1, layer_2, ..., layer_N (naming changes if using the kwargs API)

States

  • States of each layer wrapped in a NamedTuple with fields = layer_1, layer_2, ..., layer_N (naming changes if using the kwargs API)

Miscellaneous Properties

  • Allows indexing and field access syntax. We can access the ith layer by m[i] or m.layer_i. We can also index using ranges or arrays.

Example

julia
julia> Chain(Dense(2, 3, relu), BatchNorm(3), Dense(3, 2))
+Chain(
+    layer_1 = Dense(2 => 3, relu),      # 9 parameters
+    layer_2 = BatchNorm(3, affine=true, track_stats=true),  # 6 parameters, plus 7
+    layer_3 = Dense(3 => 2),            # 8 parameters
+)         # Total: 23 parameters,
+          #        plus 7 states.
+
+julia> Chain(Dense(2, 3, relu), BatchNorm(3), Dense(3, 2); name="MyFancyChain")
+MyFancyChain(
+    layer_1 = Dense(2 => 3, relu),      # 9 parameters
+    layer_2 = BatchNorm(3, affine=true, track_stats=true),  # 6 parameters, plus 7
+    layer_3 = Dense(3 => 2),            # 8 parameters
+)         # Total: 23 parameters,
+          #        plus 7 states.

source

Lux.PairwiseFusion Type
julia
PairwiseFusion(connection, layers...; name=nothing)
+PairwiseFusion(connection; name=nothing, layers...)
+PairwiseFusion(; connection, layers..., name=nothing)
x1 → layer1 → y1 ↘
+                  connection → layer2 → y2 ↘
+              x2 ↗                          connection → y3
+                                        x3 ↗

Arguments

  • connection: Takes 2 inputs and combines them

  • layers: AbstractLuxLayers. Layers can be specified in two formats:

    • A list of N Lux layers

    • Specified as N keyword arguments.

Extended Help

Inputs

Layer behaves differently based on input type:

  1. If the input x is a tuple of length N + 1, then the layers must be a tuple of length N. The computation is as follows
julia
y = x[1]
+for i in 1:N
+    y = connection(x[i + 1], layers[i](y))
+end
  1. Any other kind of input
julia
y = x
+for i in 1:N
+    y = connection(x, layers[i](y))
+end

Returns

  • See Inputs section for how the return value is computed

  • Updated model state for all the contained layers

Parameters

  • Parameters of each layer wrapped in a NamedTuple with fields = layer_1, layer_2, ..., layer_N (naming changes if using the kwargs API)

States

  • States of each layer wrapped in a NamedTuple with fields = layer_1, layer_2, ..., layer_N (naming changes if using the kwargs API)

source

Lux.Parallel Type
julia
Parallel(connection, layers...; name=nothing)
+Parallel(connection; name=nothing, layers...)
+Parallel(; connection, layers..., name=nothing)

Create a layer which passes an input to each path in layers, before reducing the output with connection.

Arguments

  • connection: An N-argument function that is called after passing the input through each layer. If connection = nothing, we return a tuple Parallel(nothing, f, g)(x, y) = (f(x), g(y))

  • Layers can be specified in two formats:

    • A list of N Lux layers

    • Specified as N keyword arguments.

Extended Help

Inputs

  • x: If x is not a tuple, then return is computed as connection([l(x) for l in layers]...). Else one is passed to each layer, thus Parallel(+, f, g)(x, y) = f(x) + g(y).

Returns

  • See the Inputs section for how the output is computed

  • Updated state of the layers

Parameters

  • Parameters of each layer wrapped in a NamedTuple with fields = layer_1, layer_2, ..., layer_N (naming changes if using the kwargs API)

States

  • States of each layer wrapped in a NamedTuple with fields = layer_1, layer_2, ..., layer_N (naming changes if using the kwargs API)

See also SkipConnection which is Parallel with one identity.

Example

julia
julia> model = Parallel(nothing, Dense(2, 1), Dense(2, 1))
+Parallel(
+    layer_1 = Dense(2 => 1),            # 3 parameters
+    layer_2 = Dense(2 => 1),            # 3 parameters
+)         # Total: 6 parameters,
+          #        plus 0 states.
+
+julia> using Random;
+       rng = Random.seed!(123);
+       ps, st = Lux.setup(rng, model);
+       x1 = randn(rng, Float32, 2);
+       x2 = randn(rng, Float32, 2);
+
+julia> size.(first(model((x1, x2), ps, st)))
+((1,), (1,))

source

Lux.SkipConnection Type
julia
SkipConnection(layers, connection; name=nothing)
+SkipConnection(; layers, connection, name=nothing)

Create a skip connection which consists of a layer or Chain of consecutive layers and a shortcut connection linking the block's input to the output through a user-supplied 2-argument callable. The first argument to the callable will be propagated through the given layer while the second is the unchanged, "skipped" input.

The simplest "ResNet"-type connection is just SkipConnection(layer, +).

Arguments

  • layer: Layer or Chain of layers to be applied to the input

  • connection:

    • A 2-argument function that takes layer(input) and the input OR

    • An AbstractLuxLayer that takes (layer(input), input) as input

Extended Help

Inputs

  • x: Will be passed directly to layer

Returns

  • Output of connection(layer(input), input)

  • Updated state of layer

Parameters

  • Parameters of layer OR

  • If connection is an AbstractLuxLayer, then NamedTuple with fields :layers and :connection

States

  • States of layer OR

  • If connection is an AbstractLuxLayer, then NamedTuple with fields :layers and :connection

See Parallel for a more general implementation.

source

Lux.RepeatedLayer Type
julia
RepeatedLayer(model; repeats::Val = Val(10), input_injection::Val = Val(false))

Iteratively applies model for repeats number of times. The initial input is passed into the model repeatedly if input_injection = Val(true). This layer unrolls the computation, however, semantically this is same as:

  • input_injection = Val(false)
julia
res = x
+for i in 1:repeats
+    res, st = model(res, ps, st)
+end
  • input_injection = Val(true)
julia
res = x
+for i in 1:repeats
+    res, st = model((res, x), ps, st)
+end

It is expected that repeats will be a reasonable number below 20, beyond that compile times for gradients might be unreasonably high.

Arguments

  • model must be an AbstractLuxLayer

Keyword Arguments

  • repeats: Number of times to apply the model

  • input_injection: If true, then the input is passed to the model along with the output

Extended Help

Inputs

  • x: Input as described above

Returns

  • Output is computed by as described above

  • Updated state of the model

Parameters

  • Parameters of model

States

  • State of model

source

Convolutional Layers

Lux.Conv Type
julia
Conv(k::NTuple{N,Integer}, (in_chs => out_chs)::Pair{<:Integer,<:Integer},
+     activation=identity; init_weight=nothing, init_bias=nothing, stride=1,
+     pad=0, dilation=1, groups=1, use_bias=True(), cross_correlation=False())

Standard convolutional layer.

Conv 2D

Image data should be stored in WHCN order (width, height, channels, batch). In other words, a 100 x 100 RGB image would be a 100 x 100 x 3 x 1 array, and a batch of 50 would be a 100 x 100 x 3 x 50 array. This has N = 2 spatial dimensions, and needs a kernel size like (5, 5), a 2-tuple of integers. To take convolutions along N feature dimensions, this layer expects as input an array with ndims(x) == N + 2, where size(x, N + 1) == in_chs is the number of input channels, and size(x, ndims(x)) is the number of observations in a batch.

Warning

Frameworks like Pytorch perform cross-correlation in their convolution layers. Pass cross_correlation=true to use cross-correlation instead.

Arguments

  • k: Tuple of integers specifying the size of the convolutional kernel. Eg, for 2D convolutions length(k) == 2

  • in_chs: Number of input channels

  • out_chs: Number of input and output channels

  • activation: Activation Function

Extended Help

Keyword Arguments

  • init_weight: Controls the initialization of the weight parameter. If nothing, then we use kaiming_uniform with gain computed on the basis of the activation function (taken from Pytorch nn.init.calculate_gain).

  • init_bias: Controls the initialization of the bias parameter. If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(fan_in)).

  • stride: Should each be either single integer, or a tuple with N integers

  • dilation: Should each be either single integer, or a tuple with N integers

  • pad: Specifies the number of elements added to the borders of the data array. It can be

    • a single integer for equal padding all around,

    • a tuple of N integers, to apply the same padding at begin/end of each spatial dimension,

    • a tuple of 2*N integers, for asymmetric padding, or

    • the singleton SamePad(), to calculate padding such that size(output,d) == size(x,d) / stride (possibly rounded) for each spatial dimension.

    • Periodic padding can achieved by pre-empting the layer with a WrappedFunction(x -> NNlib.circular_pad(x, N_pad; dims=pad_dims))

  • groups: Expected to be an Int. It specifies the number of groups to divide a convolution into (set groups = in_chs for Depthwise Convolutions). in_chs and out_chs must be divisible by groups.

  • use_bias: Trainable bias can be disabled entirely by setting this to false.

  • cross_correlation: If true, perform cross-correlation instead of convolution. Prior to v1, Lux used to have a CrossCor layer which performed cross-correlation. This was removed in v1 in favor of Conv with cross_correlation=true.

Inputs

  • x: Data satisfying ndims(x) == N + 2 && size(x, N - 1) == in_chs, i.e. size(x) = (I_N, ..., I_1, C_in, N)

Returns

  • Output of the convolution y of size (O_N, ..., O_1, C_out, N) where
Oi=Ii+pi+p(i+N)%|p|di×(ki1)si+1
  • Empty NamedTuple()

Parameters

  • weight: Convolution kernel

  • bias: Bias (present if use_bias=true)

source

Lux.ConvTranspose Type
julia
ConvTranspose(k::NTuple{N,Integer}, (in_chs => out_chs)::Pair{<:Integer,<:Integer},
+              activation=identity; init_weight=glorot_uniform, init_bias=zeros32,
+              stride=1, pad=0, outpad=0, dilation=1, groups=1, use_bias=True(),
+              cross_correlation=False())

Standard convolutional transpose layer.

Arguments

  • k: Tuple of integers specifying the size of the convolutional kernel. Eg, for 2D convolutions length(k) == 2

  • in_chs: Number of input channels

  • out_chs: Number of input and output channels

  • activation: Activation Function

Keyword Arguments

  • init_weight: Controls the initialization of the weight parameter. If nothing, then we use kaiming_uniform with gain computed on the basis of the activation function (taken from Pytorch nn.init.calculate_gain).

  • init_bias: Controls the initialization of the bias parameter. If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(fan_in)).

  • stride: Should each be either single integer, or a tuple with N integers

  • dilation: Should each be either single integer, or a tuple with N integers

  • pad: Specifies the number of elements added to the borders of the data array. It can be

    • a single integer for equal padding all around,

    • a tuple of N integers, to apply the same padding at begin/end of each spatial dimension,

    • a tuple of 2*N integers, for asymmetric padding, or

    • the singleton SamePad(), to calculate padding such that size(output,d) == size(x,d) * stride (possibly rounded) for each spatial dimension.

  • groups: Expected to be an Int. It specifies the number of groups to divide a convolution into (set groups = in_chs for Depthwise Convolutions). in_chs and out_chs must be divisible by groups.

  • use_bias: Trainable bias can be disabled entirely by setting this to false.

  • cross_correlation: If true, perform transposed cross-correlation instead of transposed convolution.

  • outpad: To converse Conv inversability when stride > 1, outpad can be used to increase the size of the output in the desired dimensions. Whereas pad is used to zero-pad the input, outpad only affects the output shape.

Extended Help

Inputs

  • x: Data satisfying ndims(x) == N + 2 && size(x, N - 1) == in_chs, i.e. size(x) = (I_N, ..., I_1, C_in, N)

Returns

  • Output of the convolution transpose y of size (O_N, ..., O_1, C_out, N) where

  • Empty NamedTuple()

Parameters

  • weight: Convolution Transpose kernel

  • bias: Bias (present if use_bias=true)

source

Dropout Layers

Lux.AlphaDropout Type
julia
AlphaDropout(p::Real)

AlphaDropout layer.

Arguments

  • p: Probability of Dropout
    • if p = 0 then NoOpLayer is returned.

    • if p = 1 then WrappedLayer(Base.Fix1(broadcast, zero)) is returned.

Inputs

  • x: Must be an AbstractArray

Returns

  • x with dropout mask applied if training=Val(true) else just x

  • State with updated rng

States

  • rng: Pseudo Random Number Generator

  • training: Used to check if training/inference mode

Call Lux.testmode to switch to test mode.

See also Dropout, VariationalHiddenDropout

source

Lux.Dropout Type
julia
Dropout(p; dims=:)

Dropout layer.

Arguments

  • p: Probability of Dropout (if p = 0 then NoOpLayer is returned)

Keyword Arguments

  • To apply dropout along certain dimension(s), specify the dims keyword. e.g. Dropout(p; dims = (3,4)) will randomly zero out entire channels on WHCN input (also called 2D dropout).

Inputs

  • x: Must be an AbstractArray

Returns

  • x with dropout mask applied if training=Val(true) else just x

  • State with updated rng

States

  • rng: Pseudo Random Number Generator

  • training: Used to check if training/inference mode

Call Lux.testmode to switch to test mode.

See also AlphaDropout, VariationalHiddenDropout

source

Lux.VariationalHiddenDropout Type
julia
VariationalHiddenDropout(p; dims=:)

VariationalHiddenDropout layer. The only difference from Dropout is that the mask is retained until Lux.update_state(l, :update_mask, Val(true)) is called.

Arguments

  • p: Probability of Dropout (if p = 0 then NoOpLayer is returned)

Keyword Arguments

  • To apply dropout along certain dimension(s), specify the dims keyword. e.g. VariationalHiddenDropout(p; dims = 3) will randomly zero out entire channels on WHCN input (also called 2D dropout).

Inputs

  • x: Must be an AbstractArray

Returns

  • x with dropout mask applied if training=Val(true) else just x

  • State with updated rng

States

  • rng: Pseudo Random Number Generator

  • training: Used to check if training/inference mode

  • mask: Dropout mask. Initilly set to nothing. After every run, contains the mask applied in that call

  • update_mask: Stores whether new mask needs to be generated in the current call

Call Lux.testmode to switch to test mode.

See also AlphaDropout, Dropout

source

Pooling Layers

Lux.AdaptiveLPPool Type
julia
AdaptiveLPPool(output_size; p=2)

Adaptive LP Pooling layer. Calculates the necessary window size such that its output has size(y)[1:N] == output_size.

Arguments

  • output_size: Size of the first N dimensions for the output

GPU Support

This layer is currently only supported on CPU.

Inputs

  • x: Expects as input an array with ndims(x) == N + 2, i.e. channel and batch dimensions, after the N feature dimensions, where N = length(output_size).

Returns

  • Output of size (out..., C, N)

  • Empty NamedTuple()

source

Lux.AdaptiveMaxPool Type
julia
AdaptiveMaxPool(output_size)

Adaptive Max Pooling layer. Calculates the necessary window size such that its output has size(y)[1:N] == output_size.

Arguments

  • output_size: Size of the first N dimensions for the output

Inputs

  • x: Expects as input an array with ndims(x) == N + 2, i.e. channel and batch dimensions, after the N feature dimensions, where N = length(output_size).

Returns

  • Output of size (out..., C, N)

  • Empty NamedTuple()

source

Lux.AdaptiveMeanPool Type
julia
AdaptiveMeanPool(output_size)

Adaptive Mean Pooling layer. Calculates the necessary window size such that its output has size(y)[1:N] == output_size.

Arguments

  • output_size: Size of the first N dimensions for the output

Inputs

  • x: Expects as input an array with ndims(x) == N + 2, i.e. channel and batch dimensions, after the N feature dimensions, where N = length(output_size).

Returns

  • Output of size (out..., C, N)

  • Empty NamedTuple()

source

Lux.GlobalLPPool Type
julia
GlobalLPPool(; p=2)

Global LP Pooling layer. Transforms (w, h, c, b)-shaped input into (1, 1, c, b)-shaped output, by performing mean pooling on the complete (w, h)-shaped feature maps.

GPU Support

This layer is currently only supported on CPU.

Inputs

  • x: Data satisfying ndims(x) > 2, i.e. size(x) = (I_N, ..., I_1, C, N)

Returns

  • Output of the pooling y of size (1, ..., 1, C, N)

  • Empty NamedTuple()

source

Lux.GlobalMaxPool Type
julia
GlobalMaxPool()

Global Max Pooling layer. Transforms (w, h, c, b)-shaped input into (1, 1, c, b)-shaped output, by performing mean pooling on the complete (w, h)-shaped feature maps.

Inputs

  • x: Data satisfying ndims(x) > 2, i.e. size(x) = (I_N, ..., I_1, C, N)

Returns

  • Output of the pooling y of size (1, ..., 1, C, N)

  • Empty NamedTuple()

source

Lux.GlobalMeanPool Type
julia
GlobalMeanPool()

Global Mean Pooling layer. Transforms (w, h, c, b)-shaped input into (1, 1, c, b)-shaped output, by performing mean pooling on the complete (w, h)-shaped feature maps.

Inputs

  • x: Data satisfying ndims(x) > 2, i.e. size(x) = (I_N, ..., I_1, C, N)

Returns

  • Output of the pooling y of size (1, ..., 1, C, N)

  • Empty NamedTuple()

source

Lux.LPPool Type
julia
LPPool(window; stride=window, pad=0, dilation=1, p=2)

LP Pooling layer, which replaces all pixels in a block of size window with the reduction operation: lp.

Arguments

  • window: Tuple of integers specifying the size of the window. Eg, for 2D pooling length(window) == 2

Keyword Arguments

  • stride: Should each be either single integer, or a tuple with N integers

  • dilation: Should each be either single integer, or a tuple with N integers

  • pad: Specifies the number of elements added to the borders of the data array. It can be

    • a single integer for equal padding all around,

    • a tuple of N integers, to apply the same padding at begin/end of each spatial dimension,

    • a tuple of 2*N integers, for asymmetric padding, or

    • the singleton SamePad(), to calculate padding such that size(output,d) == size(x,d) / stride (possibly rounded) for each spatial dimension.

GPU Support

This layer is currently only supported on CPU.

Extended Help

Inputs

  • x: Data satisfying ndims(x) == N + 2, i.e. size(x) = (I_N, ..., I_1, C, N)

Returns

  • Output of the pooling y of size (O_N, ..., O_1, C, N) where
Oi=Ii+pi+p(i+N)%|p|di×(ki1)si+1
  • Empty NamedTuple()

source

Lux.MaxPool Type
julia
MaxPool(window; stride=window, pad=0, dilation=1)

Max Pooling layer, which replaces all pixels in a block of size window with the reduction operation: max.

Arguments

  • window: Tuple of integers specifying the size of the window. Eg, for 2D pooling length(window) == 2

Keyword Arguments

  • stride: Should each be either single integer, or a tuple with N integers

  • dilation: Should each be either single integer, or a tuple with N integers

  • pad: Specifies the number of elements added to the borders of the data array. It can be

    • a single integer for equal padding all around,

    • a tuple of N integers, to apply the same padding at begin/end of each spatial dimension,

    • a tuple of 2*N integers, for asymmetric padding, or

    • the singleton SamePad(), to calculate padding such that size(output,d) == size(x,d) / stride (possibly rounded) for each spatial dimension.

Extended Help

Inputs

  • x: Data satisfying ndims(x) == N + 2, i.e. size(x) = (I_N, ..., I_1, C, N)

Returns

  • Output of the pooling y of size (O_N, ..., O_1, C, N) where
Oi=Ii+pi+p(i+N)%|p|di×(ki1)si+1
  • Empty NamedTuple()

source

Lux.MeanPool Type
julia
MeanPool(window; stride=window, pad=0, dilation=1)

Mean Pooling layer, which replaces all pixels in a block of size window with the reduction operation: mean.

Arguments

  • window: Tuple of integers specifying the size of the window. Eg, for 2D pooling length(window) == 2

Keyword Arguments

  • stride: Should each be either single integer, or a tuple with N integers

  • dilation: Should each be either single integer, or a tuple with N integers

  • pad: Specifies the number of elements added to the borders of the data array. It can be

    • a single integer for equal padding all around,

    • a tuple of N integers, to apply the same padding at begin/end of each spatial dimension,

    • a tuple of 2*N integers, for asymmetric padding, or

    • the singleton SamePad(), to calculate padding such that size(output,d) == size(x,d) / stride (possibly rounded) for each spatial dimension.

Extended Help

Inputs

  • x: Data satisfying ndims(x) == N + 2, i.e. size(x) = (I_N, ..., I_1, C, N)

Returns

  • Output of the pooling y of size (O_N, ..., O_1, C, N) where
Oi=Ii+pi+p(i+N)%|p|di×(ki1)si+1
  • Empty NamedTuple()

source

Recurrent Layers

Lux.GRUCell Type
julia
GRUCell((in_dims, out_dims)::Pair{<:Int,<:Int}; use_bias=true, train_state::Bool=false,
+        init_weight=nothing, init_bias=nothing, init_state=zeros32)

Gated Recurrent Unit (GRU) Cell

r=σ(Wir×x+bir+Whr×hprev+bhr)z=σ(Wiz×x+biz+Whz×hprev+bhz)n=tanh(Win×x+bin+r(Whn×hprev+bhn))hnew=(1z)n+zhprev

Arguments

  • in_dims: Input Dimension

  • out_dims: Output (Hidden State) Dimension

  • use_bias: Set to false to deactivate bias

  • train_state: Trainable initial hidden state can be activated by setting this to true

  • init_bias: Initializer for bias. Must be a tuple containing 3 functions. If a single value is passed, it is copied into a 3 element tuple. If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(out_dims)).

  • init_weight: Initializer for weight. Must be a tuple containing 3 functions. If a single value is passed, it is copied into a 3 element tuple. If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(out_dims)).

  • init_state: Initializer for hidden state

Inputs

  • Case 1a: Only a single input x of shape (in_dims, batch_size), train_state is set to false - Creates a hidden state using init_state and proceeds to Case 2.

  • Case 1b: Only a single input x of shape (in_dims, batch_size), train_state is set to true - Repeats hidden_state from parameters to match the shape of x and proceeds to Case 2.

  • Case 2: Tuple (x, (h, )) is provided, then the output and a tuple containing the updated hidden state is returned.

Returns

  • Tuple containing

    • Output hnew of shape (out_dims, batch_size)

    • Tuple containing new hidden state hnew

  • Updated model state

Parameters

  • weight_ih: Concatenated Weights to map from input space {Wir,Wiz,Win}.

  • weight_hh: Concatenated Weights to map from hidden space {Whr,Whz,Whn}.

  • bias_ih: Concatenated Bias vector for the input space {bir,biz,bin} (not present if use_bias=false).

  • bias_hh: Concatenated Bias vector for the hidden space {bhr,bhz,bhn} (not present if use_bias=false).

  • hidden_state: Initial hidden state vector (not present if train_state=false) {bhr,bhz,bhn}.

States

  • rng: Controls the randomness (if any) in the initial state generation

source

Lux.LSTMCell Type
julia
LSTMCell(in_dims => out_dims; use_bias::Bool=true, train_state::Bool=false,
+         train_memory::Bool=false, init_weight=nothing, init_bias=nothing,
+         init_state=zeros32, init_memory=zeros32)

Long Short-Term (LSTM) Cell

i=σ(Wii×x+Whi×hprev+bi)f=σ(Wif×x+Whf×hprev+bf)g=tanh(Wig×x+Whg×hprev+bg)o=σ(Wio×x+Who×hprev+bo)cnew=fcprev+ighnew=otanh(cnew)

Arguments

  • in_dims: Input Dimension

  • out_dims: Output (Hidden State & Memory) Dimension

  • use_bias: Set to false to deactivate bias

  • train_state: Trainable initial hidden state can be activated by setting this to true

  • train_memory: Trainable initial memory can be activated by setting this to true

  • init_bias: Initializer for bias. Must be a tuple containing 4 functions. If a single value is passed, it is copied into a 4 element tuple. If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(out_dims)).

  • init_weight: Initializer for weight. Must be a tuple containing 4 functions. If a single value is passed, it is copied into a 4 element tuple. If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(out_dims)).

  • init_state: Initializer for hidden state

  • init_memory: Initializer for memory

Inputs

  • Case 1a: Only a single input x of shape (in_dims, batch_size), train_state is set to false, train_memory is set to false - Creates a hidden state using init_state, hidden memory using init_memory and proceeds to Case 2.

  • Case 1b: Only a single input x of shape (in_dims, batch_size), train_state is set to true, train_memory is set to false - Repeats hidden_state vector from the parameters to match the shape of x, creates hidden memory using init_memory and proceeds to Case 2.

  • Case 1c: Only a single input x of shape (in_dims, batch_size), train_state is set to false, train_memory is set to true - Creates a hidden state using init_state, repeats the memory vector from parameters to match the shape of x and proceeds to Case 2.

  • Case 1d: Only a single input x of shape (in_dims, batch_size), train_state is set to true, train_memory is set to true - Repeats the hidden state and memory vectors from the parameters to match the shape of x and proceeds to Case 2.

  • Case 2: Tuple (x, (h, c)) is provided, then the output and a tuple containing the updated hidden state and memory is returned.

Returns

  • Tuple Containing

    • Output hnew of shape (out_dims, batch_size)

    • Tuple containing new hidden state hnew and new memory cnew

  • Updated model state

Parameters

  • weight_ih: Concatenated Weights to map from input space {Wii,Wif,Wig,Wio}.

  • weight_hh: Concatenated Weights to map from hidden space {Whi,Whf,Whg,Who}

  • bias_ih: Bias vector for the input-hidden connection (not present if use_bias=false)

  • bias_hh: Concatenated Bias vector for the hidden-hidden connection (not present if use_bias=false)

  • hidden_state: Initial hidden state vector (not present if train_state=false)

  • memory: Initial memory vector (not present if train_memory=false)

States

  • rng: Controls the randomness (if any) in the initial state generation

source

Lux.RNNCell Type
julia
RNNCell(in_dims => out_dims, activation=tanh; use_bias=True(), train_state=False(),
+    init_bias=nothing, init_weight=nothing, init_state=zeros32)

An Elman RNNCell cell with activation (typically set to tanh or relu).

hnew=activation(weightih×x+biasih+weighthh×hprev+biashh)

Arguments

  • in_dims: Input Dimension

  • out_dims: Output (Hidden State) Dimension

  • activation: Activation function

  • use_bias: Set to false to deactivate bias

  • train_state: Trainable initial hidden state can be activated by setting this to true

  • init_bias: Initializer for bias. If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(out_dims)).

  • init_weight: Initializer for weight. If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(out_dims)).

  • init_state: Initializer for hidden state

Inputs

  • Case 1a: Only a single input x of shape (in_dims, batch_size), train_state is set to false - Creates a hidden state using init_state and proceeds to Case 2.

  • Case 1b: Only a single input x of shape (in_dims, batch_size), train_state is set to true - Repeats hidden_state from parameters to match the shape of x and proceeds to Case 2.

  • Case 2: Tuple (x, (h, )) is provided, then the output and a tuple containing the updated hidden state is returned.

Returns

  • Tuple containing

    • Output hnew of shape (out_dims, batch_size)

    • Tuple containing new hidden state hnew

  • Updated model state

Parameters

  • weight_ih: Maps the input to the hidden state.

  • weight_hh: Maps the hidden state to the hidden state.

  • bias_ih: Bias vector for the input-hidden connection (not present if use_bias=false)

  • bias_hh: Bias vector for the hidden-hidden connection (not present if use_bias=false)

  • hidden_state: Initial hidden state vector (not present if train_state=false)

States

  • rng: Controls the randomness (if any) in the initial state generation

source

Lux.Recurrence Type
julia
Recurrence(cell;
+    ordering::AbstractTimeSeriesDataBatchOrdering=BatchLastIndex(),
+    return_sequence::Bool=false)

Wraps a recurrent cell (like RNNCell, LSTMCell, GRUCell) to automatically operate over a sequence of inputs.

Relation to Flux.Recur

This is completely distinct from Flux.Recur. It doesn't make the cell stateful, rather allows operating on an entire sequence of inputs at once. See StatefulRecurrentCell for functionality similar to Flux.Recur.

Arguments

  • cell: A recurrent cell. See RNNCell, LSTMCell, GRUCell, for how the inputs/outputs of a recurrent cell must be structured.

Keyword Arguments

  • return_sequence: If true returns the entire sequence of outputs, else returns only the last output. Defaults to false.

  • ordering: The ordering of the batch and time dimensions in the input. Defaults to BatchLastIndex(). Alternatively can be set to TimeLastIndex().

Extended Help

Inputs

  • If x is a
    • Tuple or Vector: Each element is fed to the cell sequentially.

    • Array (except a Vector): It is spliced along the penultimate dimension and each slice is fed to the cell sequentially.

Returns

  • Output of the cell for the entire sequence.

  • Update state of the cell.

Tip

Frameworks like Tensorflow have special implementation of StackedRNNCells to handle sequentially composed RNN Cells. In Lux, one can simple stack multiple Recurrence blocks in a Chain to achieve the same.

Chain(
+    Recurrence(RNNCell(inputsize => latentsize); return_sequence=true),
+    Recurrence(RNNCell(latentsize => latentsize); return_sequence=true),
+    :
+    x -> stack(x; dims=2)
+)

For some discussion on this topic, see https://github.com/LuxDL/Lux.jl/issues/472.

source

Lux.StatefulRecurrentCell Type
julia
StatefulRecurrentCell(cell)

Wraps a recurrent cell (like RNNCell, LSTMCell, GRUCell) and makes it stateful.

To avoid undefined behavior, once the processing of a single sequence of data is complete, update the state with Lux.update_state(st, :carry, nothing).

Arguments

  • cell: A recurrent cell. See RNNCell, LSTMCell, GRUCell, for how the inputs/outputs of a recurrent cell must be structured.

Inputs

  • Input to the cell.

Returns

  • Output of the cell for the entire sequence.

  • Update state of the cell and updated carry.

States

  • NamedTuple containing:
    • cell: Same as cell.

    • carry: The carry state of the cell.

source

Lux.BidirectionalRNN Type
julia
BidirectionalRNN(cell::AbstractRecurrentCell,
+    backward_cell::Union{AbstractRecurrentCell, Nothing}=nothing;
+    merge_mode::Union{Function, Nothing}=vcat,
+    ordering::AbstractTimeSeriesDataBatchOrdering=BatchLastIndex())

Bidirectional RNN wrapper.

Arguments

  • cell: A recurrent cell. See RNNCell, LSTMCell, GRUCell, for how the inputs/outputs of a recurrent cell must be structured.

  • backward_cell: A optional backward recurrent cell. If backward_cell is nothing, the rnn layer instance passed as the cell argument will be used to generate the backward layer automatically. in_dims of backward_cell should be consistent with in_dims of cell

Keyword Arguments

  • merge_mode: Function by which outputs of the forward and backward RNNs will be combined. default value is vcat. If nothing, the outputs will not be combined.

  • ordering: The ordering of the batch and time dimensions in the input. Defaults to BatchLastIndex(). Alternatively can be set to TimeLastIndex().

Extended Help

Inputs

  • If x is a
    • Tuple or Vector: Each element is fed to the cell sequentially.

    • Array (except a Vector): It is spliced along the penultimate dimension and each slice is fed to the cell sequentially.

Returns

  • Merged output of the cell and backward_cell for the entire sequence.

  • Update state of the cell and backward_cell.

Parameters

  • NamedTuple with cell and backward_cell.

States

  • Same as cell and backward_cell.

source

Linear Layers

Lux.Bilinear Type
julia
Bilinear((in1_dims, in2_dims) => out, activation=identity; init_weight=nothing,
+         init_bias=nothing, use_bias=True())
+Bilinear(in12_dims => out, activation=identity; init_weight=nothing,
+         init_bias=nothing, use_bias=True())

Create a fully connected layer between two inputs and an output, and otherwise similar to Dense. Its output, given vectors x & y, is another vector z with, for all i in 1:out:

z[i] = activation(x' * W[i, :, :] * y + bias[i])

If x and y are matrices, then each column of the output z = B(x, y) is of this form, with B the Bilinear layer.

Arguments

  • in1_dims: number of input dimensions of x

  • in2_dims: number of input dimensions of y

  • in12_dims: If specified, then in1_dims = in2_dims = in12_dims

  • out: number of output dimensions

  • activation: activation function

Keyword Arguments

  • init_weight: initializer for the weight matrix (weight = init_weight(rng, out_dims, in1_dims, in2_dims)). If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(in1_dims)).

  • init_bias: initializer for the bias vector (ignored if use_bias=false). If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(in1_dims)).

  • use_bias: Trainable bias can be disabled entirely by setting this to false

Input

  • A 2-Tuple containing

    • x must be an AbstractArray with size(x, 1) == in1_dims

    • y must be an AbstractArray with size(y, 1) == in2_dims

  • If the input is an AbstractArray, then x = y

Returns

  • AbstractArray with dimensions (out_dims, size(x, 2))

  • Empty NamedTuple()

Parameters

  • weight: Weight Matrix of size (out_dims, in1_dims, in2_dims)

  • bias: Bias of size (out_dims, 1) (present if use_bias=true)

source

Lux.Dense Type
julia
Dense(in_dims => out_dims, activation=identity; init_weight=nothing,
+      init_bias=nothing, use_bias=True())

Create a traditional fully connected layer, whose forward pass is given by: y = activation.(weight * x .+ bias)

Arguments

  • in_dims: number of input dimensions

  • out_dims: number of output dimensions

  • activation: activation function

Keyword Arguments

  • init_weight: initializer for the weight matrix (weight = init_weight(rng, out_dims, in_dims)). If nothing, then we use kaiming_uniform with gain computed on the basis of the activation function (taken from Pytorch nn.init.calculate_gain).

  • init_bias: initializer for the bias vector (ignored if use_bias=false). If nothing, then we use uniform distribution with bounds -bound and bound where bound = inv(sqrt(in_dims)).

  • use_bias: Trainable bias can be disabled entirely by setting this to false

Input

  • x must be an AbstractArray with size(x, 1) == in_dims

Returns

  • AbstractArray with dimensions (out_dims, ...) where ... are the dimensions of x

  • Empty NamedTuple()

Parameters

  • weight: Weight Matrix of size (out_dims, in_dims)

  • bias: Bias of size (out_dims, 1) (present if use_bias=true)

source

Lux.Embedding Type
julia
Embedding(in_dims => out_dims; init_weight=rand32)

A lookup table that stores embeddings of dimension out_dims for a vocabulary of size in_dims. When the vocabulary is multi-dimensional, the input is expected to be a tuple of Cartesian indices.

This layer is often used to store word embeddings and retrieve them using indices.

Arguments

  • in_dims: number(s) of input dimensions

  • out_dims: number of output dimensions

Keyword Arguments

  • init_weight: initializer for the weight matrix (weight = init_weight(rng, out_dims, in_dims...))

Input

  • Integer OR

  • Abstract Vector of Integers OR

  • Abstract Array of Integers OR

  • Tuple of Integers OR

  • Tuple of Abstract Vectors of Integers OR

  • Tuple of Abstract Arrays of Integers

Returns

  • Returns the embedding corresponding to each index in the input. For an N dimensional input, an N + 1 dimensional output is returned.

  • Empty NamedTuple()

source

Lux.Scale Type
julia
Scale(dims, activation=identity; init_weight=ones32, init_bias=zeros32, use_bias=True())

Create a Sparsely Connected Layer with a very specific structure (only Diagonal Elements are non-zero). The forward pass is given by: y = activation.(weight .* x .+ bias)

Arguments

  • dims: size of the learnable scale and bias parameters.

  • activation: activation function

Keyword Arguments

  • init_weight: initializer for the weight matrix (weight = init_weight(rng, out_dims, in_dims))

  • init_bias: initializer for the bias vector (ignored if use_bias=false)

  • use_bias: Trainable bias can be disabled entirely by setting this to false

Input

  • x must be an Array of size (dims..., B) or (dims...[0], ..., dims[k]) for k ≤ size(dims)

Returns

  • Array of size (dims..., B) or (dims...[0], ..., dims[k]) for k ≤ size(dims)

  • Empty NamedTuple()

Parameters

  • weight: Weight Array of size (dims...)

  • bias: Bias of size (dims...)

source

Misc. Helper Layers

Lux.FlattenLayer Type
julia
FlattenLayer(; N = nothing)

Flattens the passed array into a matrix.

Keyword Arguments

  • N: Flatten the first N dimensions of the input array. If nothing, then all dimensions (except the last) are flattened. Note that the batch dimension is never flattened.

Inputs

  • x: AbstractArray

Returns

  • AbstractMatrix of size (:, size(x, ndims(x))) if N is nothing else the first N dimensions of the input array are flattened.

  • Empty NamedTuple()

Example

julia
julia> model = FlattenLayer()
+FlattenLayer{Nothing}(nothing)
+
+julia> rng = Random.default_rng();
+       Random.seed!(rng, 0);
+       ps, st = Lux.setup(rng, model);
+       x = randn(rng, Float32, (2, 2, 2, 2));
+
+julia> y, st_new = model(x, ps, st);
+       size(y)
+(8, 2)

source

Lux.Maxout Type
julia
Maxout(layers...)
+Maxout(; layers...)
+Maxout(f::Function, n_alts::Int)

This contains a number of internal layers, each of which receives the same input. Its output is the elementwise maximum of the the internal layers' outputs.

Maxout over linear dense layers satisfies the universal approximation theorem. See [1].

See also Parallel to reduce with other operators.

Arguments

  • Layers can be specified in three formats:
    • A list of N Lux layers

    • Specified as N keyword arguments.

    • A no argument function f and an integer n_alts which specifies the number of layers.

Extended Help

Inputs

  • x: Input that is passed to each of the layers

Returns

  • Output is computed by taking elementwise max of the outputs of the individual layers.

  • Updated state of the layers

Parameters

  • Parameters of each layer wrapped in a NamedTuple with fields = layer_1, layer_2, ..., layer_N (naming changes if using the kwargs API)

States

  • States of each layer wrapped in a NamedTuple with fields = layer_1, layer_2, ..., layer_N (naming changes if using the kwargs API)

References

[1] Goodfellow, Warde-Farley, Mirza, Courville & Bengio "Maxout Networks" https://arxiv.org/abs/1302.4389

source

Lux.NoOpLayer Type
julia
NoOpLayer()

As the name suggests does nothing but allows pretty printing of layers. Whatever input is passed is returned.

Example

julia
julia> model = NoOpLayer()
+NoOpLayer()
+
+julia> rng = Random.default_rng();
+       Random.seed!(rng, 0);
+       ps, st = Lux.setup(rng, model);
+       x = 1
+1
+
+julia> y, st_new = model(x, ps, st)
+(1, NamedTuple())

source

Lux.ReshapeLayer Type
julia
ReshapeLayer(dims)

Reshapes the passed array to have a size of (dims..., :)

Arguments

  • dims: The new dimensions of the array (excluding the last dimension).

Inputs

  • x: AbstractArray of any shape which can be reshaped in (dims..., size(x, ndims(x)))

Returns

  • AbstractArray of size (dims..., size(x, ndims(x)))

  • Empty NamedTuple()

Example

julia
julia> model = ReshapeLayer((2, 2))
+ReshapeLayer(output_dims = (2, 2, :))
+
+julia> rng = Random.default_rng();
+       Random.seed!(rng, 0);
+       ps, st = Lux.setup(rng, model);
+       x = randn(rng, Float32, (4, 1, 3));
+
+julia> y, st_new = model(x, ps, st);
+       size(y)
+(2, 2, 3)

source

Lux.SelectDim Type
julia
SelectDim(dim, i)

Return a view of all the data of the input x where the index for dimension dim equals i. Equivalent to view(x,:,:,...,i,:,:,...) where i is in position d.

Arguments

  • dim: Dimension for indexing

  • i: Index for dimension dim

Inputs

  • x: AbstractArray that can be indexed with view(x,:,:,...,i,:,:,...)

Returns

  • view(x,:,:,...,i,:,:,...) where i is in position d

  • Empty NamedTuple()

source

Lux.WrappedFunction Type
julia
WrappedFunction(f)

Wraps a stateless and parameter less function. Might be used when a function is added to Chain. For example, Chain(x -> relu.(x)) would not work and the right thing to do would be Chain((x, ps, st) -> (relu.(x), st)). An easier thing to do would be Chain(WrappedFunction(Base.Fix1(broadcast, relu)))

Arguments

  • f: Some function.

Inputs

  • x: will be directly passed to f

Returns

  • Output of f(x)

  • Empty NamedTuple()

source

Lux.ReverseSequence Type
julia
ReverseSequence(dim = nothing)

Reverse the specified dimension dims of the passed array

Arguments

  • dim: Dimension that need to be reversed. If nothing, for AbstractVector{T} it reverses itself (dimension 1), for other arrays, reverse the dimension ndims(x) - 1.

Inputs

  • x: AbstractArray.

Returns

  • AbstractArray with the same dimensions as the input

  • Empty NamedTuple()

Example

julia
julia> model = ReverseSequence()
+ReverseSequence{Nothing}(nothing)
+
+julia> rng = Random.default_rng();
+       Random.seed!(rng, 0);
+       ps, st = Lux.setup(rng, model);
+       x = [1.0, 2.0, 3.0];
+
+julia> y, st_new = model(x, ps, st)
+([3.0, 2.0, 1.0], NamedTuple())

source

Normalization Layers

Lux.BatchNorm Type
julia
BatchNorm(chs::Integer, activation=identity; init_bias=zeros32, init_scale=ones32,
+          affine=True(), track_stats=True(), epsilon=1f-5, momentum=0.1f0)

Batch Normalization layer.

BatchNorm computes the mean and variance for each D1×...×DN2×1×DN input slice and normalises the input accordingly.

Arguments

  • chs: Size of the channel dimension in your data. Given an array with N dimensions, call the N-1th the channel dimension. For a batch of feature vectors this is just the data dimension, for WHCN images it's the usual channel dimension.

  • activation: After normalization, elementwise activation activation is applied.

Keyword Arguments

  • If track_stats=true, accumulates mean and variance statistics in training phase that will be used to renormalize the input in test phase.

  • epsilon: a value added to the denominator for numerical stability

  • momentum: the value used for the running_mean and running_var computation

  • If affine=true, it also applies a shift and a rescale to the input through to learnable per-channel bias and scale parameters.

    • init_bias: Controls how the bias is initialized

    • init_scale: Controls how the scale is initialized

Extended Help

Inputs

  • x: Array where size(x, N - 1) = chs

Returns

  • y: Normalized Array

  • Update model state

Parameters

  • affine=true

    • bias: Bias of shape (chs,)

    • scale: Scale of shape (chs,)

  • affine=false - Empty NamedTuple()

States

  • Statistics if track_stats=true

    • running_mean: Running mean of shape (chs,)

    • running_var: Running variance of shape (chs,)

  • Statistics if track_stats=false

    • running_mean: nothing

    • running_var: nothing

  • training: Used to check if training/inference mode

Use Lux.testmode during inference.

Example

julia
julia> Chain(Dense(784 => 64), BatchNorm(64, relu), Dense(64 => 10), BatchNorm(10))
+Chain(
+    layer_1 = Dense(784 => 64),         # 50_240 parameters
+    layer_2 = BatchNorm(64, relu, affine=true, track_stats=true),  # 128 parameters, plus 129
+    layer_3 = Dense(64 => 10),          # 650 parameters
+    layer_4 = BatchNorm(10, affine=true, track_stats=true),  # 20 parameters, plus 21
+)         # Total: 51_038 parameters,
+          #        plus 150 states.

Warning

Passing a batch size of 1, during training will result in an error.

See also BatchNorm, InstanceNorm, LayerNorm, WeightNorm

source

Lux.GroupNorm Type
julia
GroupNorm(chs::Integer, groups::Integer, activation=identity; init_bias=zeros32,
+          init_scale=ones32, affine=true, epsilon=1f-5)

Group Normalization layer.

Arguments

  • chs: Size of the channel dimension in your data. Given an array with N dimensions, call the N-1th the channel dimension. For a batch of feature vectors this is just the data dimension, for WHCN images it's the usual channel dimension.

  • groups is the number of groups along which the statistics are computed. The number of channels must be an integer multiple of the number of groups.

  • activation: After normalization, elementwise activation activation is applied.

Keyword Arguments

  • epsilon: a value added to the denominator for numerical stability

  • If affine=true, it also applies a shift and a rescale to the input through to learnable per-channel bias and scale parameters.

    • init_bias: Controls how the bias is initialized

    • init_scale: Controls how the scale is initialized

Extended Help

Inputs

  • x: Array where size(x, N - 1) = chs and ndims(x) > 2

Returns

  • y: Normalized Array

  • Update model state

Parameters

  • affine=true

    • bias: Bias of shape (chs,)

    • scale: Scale of shape (chs,)

  • affine=false - Empty NamedTuple()

States

  • training: Used to check if training/inference mode

Use Lux.testmode during inference.

Example

julia
julia> Chain(Dense(784 => 64), GroupNorm(64, 4, relu), Dense(64 => 10), GroupNorm(10, 5))
+Chain(
+    layer_1 = Dense(784 => 64),         # 50_240 parameters
+    layer_2 = GroupNorm(64, 4, relu, affine=true),  # 128 parameters
+    layer_3 = Dense(64 => 10),          # 650 parameters
+    layer_4 = GroupNorm(10, 5, affine=true),  # 20 parameters
+)         # Total: 51_038 parameters,
+          #        plus 0 states.

See also GroupNorm, InstanceNorm, LayerNorm, WeightNorm

source

Lux.InstanceNorm Type
julia
InstanceNorm(chs::Integer, activation=identity; init_bias=zeros32, init_scale=ones32,
+             affine=False(), track_stats=False(), epsilon=1f-5, momentum=0.1f0)

Instance Normalization. For details see [1].

Instance Normalization computes the mean and variance for each D1×...×DN2×1×1` input slice and normalises the input accordingly.

Arguments

  • chs: Size of the channel dimension in your data. Given an array with N dimensions, call the N-1th the channel dimension. For a batch of feature vectors this is just the data dimension, for WHCN images it's the usual channel dimension.

  • activation: After normalization, elementwise activation activation is applied.

Keyword Arguments

  • If track_stats=true, accumulates mean and variance statistics in training phase that will be used to renormalize the input in test phase.

  • epsilon: a value added to the denominator for numerical stability

  • momentum: the value used for the running_mean and running_var computation

  • If affine=true, it also applies a shift and a rescale to the input through to learnable per-channel bias and scale parameters.

    • init_bias: Controls how the bias is initialized

    • init_scale: Controls how the scale is initialized

Extended Help

Inputs

  • x: Array where size(x, N - 1) = chs and ndims(x) > 2

Returns

  • y: Normalized Array

  • Update model state

Parameters

  • affine=true

    • bias: Bias of shape (chs,)

    • scale: Scale of shape (chs,)

  • affine=false - Empty NamedTuple()

States

  • Statistics if track_stats=true

    • running_mean: Running mean of shape (chs,)

    • running_var: Running variance of shape (chs,)

  • Statistics if track_stats=false

    • running_mean: nothing

    • running_var: nothing

  • training: Used to check if training/inference mode

Use Lux.testmode during inference.

Example

julia
julia> Chain(Dense(784 => 64), InstanceNorm(64, relu; affine=true), Dense(64 => 10),
+           InstanceNorm(10, relu; affine=true))
+Chain(
+    layer_1 = Dense(784 => 64),         # 50_240 parameters
+    layer_2 = InstanceNorm(64, relu, affine=true, track_stats=false),  # 128 parameters, plus 1
+    layer_3 = Dense(64 => 10),          # 650 parameters
+    layer_4 = InstanceNorm(10, relu, affine=true, track_stats=false),  # 20 parameters, plus 1
+)         # Total: 51_038 parameters,
+          #        plus 2 states.

References

[1] Ulyanov, Dmitry, Andrea Vedaldi, and Victor Lempitsky. "Instance normalization: The missing ingredient for fast stylization." arXiv preprint arXiv:1607.08022 (2016).

See also BatchNorm, GroupNorm, LayerNorm, WeightNorm

source

Lux.LayerNorm Type
julia
LayerNorm(shape::NTuple{N, Int}, activation=identity; epsilon=1f-5, dims=Colon(),
+          affine=true, init_bias=zeros32, init_scale=ones32)

Computes mean and standard deviation over the whole input array, and uses these to normalize the whole array. Optionally applies an elementwise affine transformation afterwards.

Given an input array x, this layer computes

y=xE[x]Var[x]+ϵγ+β

where γ & β are trainable parameters if affine=true.

Arguments

  • shape: Broadcastable shape of input array excluding the batch dimension.

  • activation: After normalization, elementwise activation activation is applied.

Keyword Arguments

  • epsilon: a value added to the denominator for numerical stability.

  • dims: Dimensions to normalize the array over.

  • If affine=true, it also applies a shift and a rescale to the input through to learnable per-element bias and scale parameters.

    • init_bias: Controls how the bias is initialized

    • init_scale: Controls how the scale is initialized

Extended Help

Inputs

  • x: AbstractArray

Returns

  • y: Normalized Array

  • Empty NamedTuple()

Parameters

  • affine=false: Empty NamedTuple()

  • affine=true

    • bias: Bias of shape (shape..., 1)

    • scale: Scale of shape (shape..., 1)

source

Lux.WeightNorm Type
julia
WeightNorm(layer::AbstractLuxLayer, which_params::NTuple{N, Symbol},
+           dims::Union{Tuple, Nothing}=nothing)

Applies weight normalization to a parameter in the given layer.

w=gvv

Weight normalization is a reparameterization that decouples the magnitude of a weight tensor from its direction. This updates the parameters in which_params (e.g. weight) using two parameters: one specifying the magnitude (e.g. weight_g) and one specifying the direction (e.g. weight_v).

Arguments

  • layer whose parameters are being reparameterized

  • which_params: parameter names for the parameters being reparameterized

  • By default, a norm over the entire array is computed. Pass dims to modify the dimension.

Inputs

  • x: Should be of valid type for input to layer

Returns

  • Output from layer

  • Updated model state of layer

Parameters

  • normalized: Parameters of layer that are being normalized

  • unnormalized: Parameters of layer that are not being normalized

States

  • Same as that of layer

source

Upsampling

Lux.PixelShuffle Type
julia
PixelShuffle(r::Int)

Pixel shuffling layer with upscale factor r. Usually used for generating higher resolution images while upscaling them.

See NNlib.pixel_shuffle for more details.

Arguments

  • r: Upscale factor

Inputs

  • x: For 4D-arrays representing N images, the operation converts input size(x) == (W, H, r² x C, N) to output of size (r x W, r x H, C, N). For D-dimensional data, it expects ndims(x) == D + 2 with channel and batch dimensions, and divides the number of channels by rᴰ.

Returns

  • Output of size (r x W, r x H, C, N) for 4D-arrays, and (r x W, r x H, ..., C, N) for D-dimensional data, where D = ndims(x) - 2

source

Lux.Upsample Type
julia
Upsample(mode = :nearest; [scale, size, align_corners=false])
+Upsample(scale, mode = :nearest)

Upsampling Layer.

Layer Construction

Option 1

  • mode: Set to :nearest, :linear, :bilinear or :trilinear

Exactly one of two keywords must be specified:

  • If scale is a number, this applies to all but the last two dimensions (channel and batch) of the input. It may also be a tuple, to control dimensions individually.

  • Alternatively, keyword size accepts a tuple, to directly specify the leading dimensions of the output.

Option 2

  • If scale is a number, this applies to all but the last two dimensions (channel and batch) of the input. It may also be a tuple, to control dimensions individually.

  • mode: Set to :nearest, :bilinear or :trilinear

Currently supported upsampling modes and corresponding NNlib's methods are:

  • :nearest -> NNlib.upsample_nearest

  • :bilinear -> NNlib.upsample_bilinear

  • :trilinear -> NNlib.upsample_trilinear

Extended Help

Other Keyword Arguments

  • align_corners: If true, the corner pixels of the input and output tensors are aligned, and thus preserving the values at those pixels. This only has effect when mode is one of :bilinear or :trilinear.

Inputs

  • x: For the input dimensions look into the documentation for the corresponding NNlib function
    • As a rule of thumb, :nearest should work with arrays of arbitrary dimensions

    • :bilinear works with 4D Arrays

    • :trilinear works with 5D Arrays

Returns

  • Upsampled Input of size size or of size (I_1 x scale[1], ..., I_N x scale[N], C, N)

  • Empty NamedTuple()

source

+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Lux/utilities.html b/previews/PR1023/api/Lux/utilities.html new file mode 100644 index 0000000000..eb28ad11d3 --- /dev/null +++ b/previews/PR1023/api/Lux/utilities.html @@ -0,0 +1,347 @@ + + + + + + Utilities | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

Utilities

Training API

Helper Functions making it easier to train Lux.jl models.

Training is meant to be simple and provide extremely basic functionality. We provide basic building blocks which can be seamlessly composed to create complex training pipelines.

Lux.Training.TrainState Type
julia
TrainState

Training State containing:

  • model: Lux model.

  • parameters: Trainable Variables of the model.

  • states: Non-trainable Variables of the model.

  • optimizer: Optimizer from Optimisers.jl.

  • optimizer_state: Optimizer State.

  • step: Number of updates of the parameters made.

Internal fields:

  • cache: Cached values. Implementations are free to use this for whatever they want.

  • objective_function: Objective function might be cached.

Warning

Constructing this object directly shouldn't be considered a stable API. Use the version with the Optimisers API.

source

Lux.Training.compute_gradients Function
julia
compute_gradients(ad::AbstractADType, objective_function::Function, data,
+    ts::TrainState)

Compute the gradients of the objective function wrt parameters stored in ts.

Backends & AD Packages

Supported BackendsPackages Needed
AutoZygoteZygote.jl
AutoReverseDiff(; compile)ReverseDiff.jl
AutoTrackerTracker.jl
AutoEnzymeEnzyme.jl

Arguments

  • ad: Backend (from ADTypes.jl) used to compute the gradients.

  • objective_function: Objective function. The function must take 4 inputs – model, parameters, states and data. The function must return 3 values – loss, updated_state, and any computed statistics.

  • data: Data used to compute the gradients.

  • ts: Current Training State. See TrainState.

Return

A 4-Tuple containing:

  • grads: Computed Gradients.

  • loss: Loss from the objective function.

  • stats: Any computed statistics from the objective function.

  • ts: Updated Training State.

Known Limitations

  • AutoReverseDiff(; compile=true) is not supported for Lux models with non-empty state st. Additionally the returned stats must be empty (NamedTuple()). We catch these issues in most cases and throw an error.

Aliased Gradients

grads returned by this function might be aliased by the implementation of the gradient backend. For example, if you cache the grads from step i, the new gradients returned in step i + 1 might be aliased by the old gradients. If you want to prevent this, simply use copy(grads) or deepcopy(grads) to make a copy of the gradients.

source

Lux.Training.apply_gradients Function
julia
apply_gradients(ts::TrainState, grads)

Update the parameters stored in ts using the gradients grads.

Arguments

  • ts: TrainState object.

  • grads: Gradients of the loss function wrt ts.params.

Returns

Updated TrainState object.

source

Lux.Training.apply_gradients! Function
julia
apply_gradients!(ts::TrainState, grads)

Update the parameters stored in ts using the gradients grads. This is an inplace version of apply_gradients.

Arguments

  • ts: TrainState object.

  • grads: Gradients of the loss function wrt ts.params.

Returns

Updated TrainState object.

source

Lux.Training.single_train_step Function
julia
single_train_step(backend, obj_fn::F, data, ts::TrainState)

Perform a single training step. Computes the gradients using compute_gradients and updates the parameters using apply_gradients. All backends supported via compute_gradients are supported here.

In most cases you should use single_train_step! instead of this function.

Return

Returned values are the same as compute_gradients.

source

Lux.Training.single_train_step! Function
julia
single_train_step!(backend, obj_fn::F, data, ts::TrainState)

Perform a single training step. Computes the gradients using compute_gradients and updates the parameters using apply_gradients!. All backends supported via compute_gradients are supported here.

Return

Returned values are the same as compute_gradients. Note that despite the !, only the parameters in ts are updated inplace. Users should be using the returned ts object for further training steps, else there is no caching and performance will be suboptimal (and absolutely terrible for backends like AutoReactant).

source

Loss Functions

Loss Functions Objects take 2 forms of inputs:

  1. and y where is the predicted output and y is the target output.

  2. model, ps, st, (x, y) where model is the model, ps are the parameters, st are the states and (x, y) are the input and target pair. Then it returns the loss, updated states, and an empty named tuple. This makes them compatible with the Training API.

Warning

When using ChainRules.jl compatible AD (like Zygote), we only compute the gradients wrt the inputs and drop any gradients wrt the targets.

Lux.GenericLossFunction Type
julia
GenericLossFunction(loss_fn; agg = mean)

Takes any function loss_fn that maps 2 number inputs to a single number output. Additionally, array inputs are efficiently broadcasted and aggregated using agg.

julia
julia> mseloss = GenericLossFunction((ŷ, y) -> abs2(ŷ - y));
+
+julia> y_model = [1.1, 1.9, 3.1];
+
+julia> mseloss(y_model, 1:3)  0.01
+true

Special Note

This function takes any of the LossFunctions.jl public functions into the Lux Losses API with efficient aggregation.

source

Lux.BinaryCrossEntropyLoss Type
julia
BinaryCrossEntropyLoss(; agg = mean, epsilon = nothing,
+    label_smoothing::Union{Nothing, Real}=nothing,
+    logits::Union{Bool, Val}=Val(false))

Binary Cross Entropy Loss with optional label smoothing and fused logit computation.

Returns the binary cross entropy loss computed as:

  • If logits is either false or Val(false):
agg(y~log(y^+ϵ)(1y~)log(1y^+ϵ))
  • If logits is true or Val(true):
agg((1y~)y^logσ(y^))

The value of y~ is computed using label smoothing. If label_smoothing is nothing, then no label smoothing is applied. If label_smoothing is a real number [0,1], then the value of y~ is:

y~=(1α)y+α0.5

where α is the value of label_smoothing.

Extended Help

Example

julia
julia> bce = BinaryCrossEntropyLoss();
+
+julia> y_bin = Bool[1, 0, 1];
+
+julia> y_model = Float32[2, -1, pi]
+3-element Vector{Float32}:
+  2.0
+ -1.0
+  3.1415927
+
+julia> logitbce = BinaryCrossEntropyLoss(; logits=Val(true));
+
+julia> logitbce(y_model, y_bin)  0.160832f0
+true
+
+julia> bce(sigmoid.(y_model), y_bin)  0.16083185f0
+true
+
+julia> bce_ls = BinaryCrossEntropyLoss(label_smoothing=0.1);
+
+julia> bce_ls(sigmoid.(y_model), y_bin) > bce(sigmoid.(y_model), y_bin)
+true
+
+julia> logitbce_ls = BinaryCrossEntropyLoss(label_smoothing=0.1, logits=Val(true));
+
+julia> logitbce_ls(y_model, y_bin) > logitbce(y_model, y_bin)
+true

source

Lux.BinaryFocalLoss Type
julia
BinaryFocalLoss(; gamma = 2, agg = mean, epsilon = nothing)

Return the binary focal loss [1]. The model input, y^, is expected to be normalized (i.e. softmax output).

For γ=0 this is equivalent to BinaryCrossEntropyLoss.

Example

julia
julia> y = [0  1  0
+            1  0  1];
+
+julia> ŷ = [0.268941  0.5  0.268941
+            0.731059  0.5  0.731059];
+
+julia> BinaryFocalLoss()(ŷ, y)  0.0728675615927385
+true
+
+julia> BinaryFocalLoss(gamma=0)(ŷ, y)  BinaryCrossEntropyLoss()(ŷ, y)
+true

References

[1] Lin, Tsung-Yi, et al. "Focal loss for dense object detection." Proceedings of the IEEE international conference on computer vision. 2017.

source

Lux.CrossEntropyLoss Type
julia
CrossEntropyLoss(; agg=mean, epsilon=nothing, dims=1,
+    label_smoothing::Union{Nothing, Real}=nothing)

Return the cross entropy loss which is used in multi-class classification tasks. The input, y^, is expected to be normalized (i.e. softmax output) if logits is false or Val(false).

The loss is calculated as:

agg(y~log(y^+ϵ))

where ϵ is added for numerical stability. The value of y~ is computed using label smoothing. If label_smoothing is nothing, then no label smoothing is applied. If label_smoothing is a real number [0,1], then the value of y~ is calculated as:

y~=(1α)y+αsize along dim

where α is the value of label_smoothing.

Extended Help

Example

julia
julia> y = [1  0  0  0  1
+            0  1  0  1  0
+            0  0  1  0  0]
+3×5 Matrix{Int64}:
+ 1  0  0  0  1
+ 0  1  0  1  0
+ 0  0  1  0  0
+
+julia> y_model = softmax(reshape(-7:7, 3, 5) .* 1f0)
+3×5 Matrix{Float32}:
+ 0.0900306  0.0900306  0.0900306  0.0900306  0.0900306
+ 0.244728   0.244728   0.244728   0.244728   0.244728
+ 0.665241   0.665241   0.665241   0.665241   0.665241
+
+julia> CrossEntropyLoss()(y_model, y)  1.6076053f0
+true
+
+julia> 5 * 1.6076053f0 CrossEntropyLoss(; agg=sum)(y_model, y)
+true
+
+julia> CrossEntropyLoss(label_smoothing=0.15)(y_model, y)  1.5776052f0
+true

source

Lux.DiceCoeffLoss Type
julia
DiceCoeffLoss(; smooth = true, agg = mean)

Return the Dice Coefficient loss [1] which is used in segmentation tasks. The dice coefficient is similar to the F1_score. Loss calculated as:

agg(12yy^+αy2+y^2+α)

where α is the smoothing factor (smooth).

Example

julia
julia> y_pred = [1.1, 2.1, 3.1];
+
+julia> DiceCoeffLoss()(y_pred, 1:3)   0.000992391663909964
+true
+
+julia> 1 - DiceCoeffLoss()(y_pred, 1:3)   0.99900760833609
+true
+
+julia> DiceCoeffLoss()(reshape(y_pred, 3, 1), reshape(1:3, 3, 1))  0.000992391663909964
+true

References

[1] Milletari, Fausto, Nassir Navab, and Seyed-Ahmad Ahmadi. "V-net: Fully convolutional neural networks for volumetric medical image segmentation." 2016 fourth international conference on 3D vision (3DV). Ieee, 2016.

source

Lux.FocalLoss Type
julia
FocalLoss(; gamma = 2, dims = 1, agg = mean, epsilon = nothing)

Return the focal loss [1] which can be used in classification tasks with highly imbalanced classes. It down-weights well-classified examples and focuses on hard examples. The input, y^, is expected to be normalized (i.e. softmax output).

The modulating factor γ, controls the down-weighting strength. For γ=0 this is equivalent to CrossEntropyLoss.

Example

julia
julia> y = [1  0  0  0  1
+            0  1  0  1  0
+            0  0  1  0  0]
+3×5 Matrix{Int64}:
+ 1  0  0  0  1
+ 0  1  0  1  0
+ 0  0  1  0  0
+
+julia> ŷ = softmax(reshape(-7:7, 3, 5) .* 1f0)
+3×5 Matrix{Float32}:
+ 0.0900306  0.0900306  0.0900306  0.0900306  0.0900306
+ 0.244728   0.244728   0.244728   0.244728   0.244728
+ 0.665241   0.665241   0.665241   0.665241   0.665241
+
+julia> FocalLoss()(ŷ, y)  1.1277556f0
+true

References

[1] Lin, Tsung-Yi, et al. "Focal loss for dense object detection." Proceedings of the IEEE international conference on computer vision. 2017.

source

Lux.HingeLoss Function
julia
HingeLoss(; agg = mean)

Return the hinge loss loss given the prediction and true labels y (containing 1 or -1); calculated as:

agg(max(0,1yy^))

Usually used with classifiers like Support Vector Machines.

Example

julia
julia> loss = HingeLoss();
+
+julia> y_true = [1, -1, 1, 1];
+
+julia> y_pred = [0.1, 0.3, 1, 1.5];
+
+julia> loss(y_pred, y_true)  0.55
+true

source

Lux.HuberLoss Function
julia
HuberLoss(; delta = 1, agg = mean)

Returns the Huber loss, calculated as:

L={0.5|yy^|2if |yy^|δδ(|yy^|0.5δ)otherwise

where δ is the delta parameter.

Example

julia
julia> y_model = [1.1, 2.1, 3.1];
+
+julia> HuberLoss()(y_model, 1:3)  0.005000000000000009
+true
+
+julia> HuberLoss(delta=0.05)(y_model, 1:3)  0.003750000000000005
+true

source

Lux.KLDivergenceLoss Type
julia
KLDivergenceLoss(; dims = 1, agg = mean, epsilon = nothing, label_smoothing = nothing)

Return the Kullback-Leibler Divergence loss between the predicted distribution y^ and the true distribution y:

The KL divergence is a measure of how much one probability distribution is different from the other. It is always non-negative, and zero only when both the distributions are equal.

For epsilon and label_smoothing, see CrossEntropyLoss.

Example

julia
julia> p1 = [1 0; 0 1]
+2×2 Matrix{Int64}:
+ 1  0
+ 0  1
+
+julia> p2 = fill(0.5, 2, 2)
+2×2 Matrix{Float64}:
+ 0.5  0.5
+ 0.5  0.5
+
+julia> KLDivergenceLoss()(p2, p1)  log(2)
+true
+
+julia> KLDivergenceLoss(; agg=sum)(p2, p1)  2 * log(2)
+true
+
+julia> KLDivergenceLoss(; epsilon=0)(p2, p2)
+0.0
+
+julia> KLDivergenceLoss(; epsilon=0)(p1, p2)
+Inf

source

Lux.MAELoss Function
julia
MAELoss(; agg = mean)

Returns the loss corresponding to mean absolute error:

agg(|y^y|)

Example

julia
julia> loss = MAELoss();
+
+julia> y_model = [1.1, 1.9, 3.1];
+
+julia> loss(y_model, 1:3)  0.1
+true

source

Lux.MSELoss Function
julia
MSELoss(; agg = mean)

Returns the loss corresponding to mean squared error:

agg((y^y)2)

Example

julia
julia> loss = MSELoss();
+
+julia> y_model = [1.1, 1.9, 3.1];
+
+julia> loss(y_model, 1:3)  0.01
+true

source

Lux.MSLELoss Function
julia
MSLELoss(; agg = mean, epsilon = nothing)

Returns the loss corresponding to mean squared logarithmic error:

agg((log(y^+ϵ)log(y+ϵ))2)

epsilon is added to both y and to prevent taking the logarithm of zero. If epsilon is nothing, then we set it to eps(<type of y and ŷ>).

Example

julia
julia> loss = MSLELoss();
+
+julia> loss(Float32[1.1, 2.2, 3.3], 1:3)  0.009084041f0
+true
+
+julia> loss(Float32[0.9, 1.8, 2.7], 1:3)  0.011100831f0
+true

source

Lux.PoissonLoss Function
julia
PoissonLoss(; agg = mean, epsilon = nothing)

Return how much the predicted distribution y^ diverges from the expected Poisson distribution y, calculated as:

agg(y^ylog(y^))

Example

julia
julia> y_model = [1, 3, 3];  # data should only take integral values
+
+julia> PoissonLoss()(y_model, 1:3)  0.502312852219817
+true

source

Lux.SiameseContrastiveLoss Function
julia
SiameseContrastiveLoss(; margin = true, agg = mean)

Return the contrastive loss [1] which can be useful for training Siamese Networks. It is given by:

agg((1y)y^2+ymax(0,marginy^)2)

Specify margin to set the baseline for distance at which pairs are dissimilar.

Example

julia
julia>= [0.5, 1.5, 2.5];
+
+julia> SiameseContrastiveLoss()(ŷ, 1:3)  -4.833333333333333
+true
+
+julia> SiameseContrastiveLoss(margin=2)(ŷ, 1:3)  -4.0
+true

References

[1] Hadsell, Raia, Sumit Chopra, and Yann LeCun. "Dimensionality reduction by learning an invariant mapping." 2006 IEEE computer society conference on computer vision and pattern recognition (CVPR'06). Vol. 2. IEEE, 2006.

source

Lux.SquaredHingeLoss Function
julia
SquaredHingeLoss(; agg = mean)

Return the squared hinge loss loss given the prediction and true labels y (containing 1 or -1); calculated as:

agg(max(0,1yy^)2)

Usually used with classifiers like Support Vector Machines.

Example

julia
julia> loss = SquaredHingeLoss();
+
+julia> y_true = [1, -1, 1, 1];
+
+julia> y_pred = [0.1, 0.3, 1, 1.5];
+
+julia> loss(y_pred, y_true)  0.625
+true

source

LuxOps Module

Lux.LuxOps Module
julia
LuxOps

This module is a part of Lux.jl. It contains operations that are useful in DL context. Additionally certain operations here alias Base functions to behave more sensibly with GPUArrays.

source

Lux.LuxOps.eachslice Function
julia
eachslice(x, dims::Val)

Same as Base.eachslice but doesn't produce a SubArray for the slices if x is a GPUArray.

Additional dispatches for RNN helpers are also provided for TimeLastIndex and BatchLastIndex.

source

Lux.LuxOps.foldl_init Function
julia
foldl_init(op, x)
+foldl_init(op, x, init)

Exactly same as foldl(op, x; init) in the forward pass. But, gives gradients wrt init in the backward pass.

source

Lux.LuxOps.getproperty Function
julia
getproperty(x, ::Val{v})
+getproperty(x, ::StaticSymbol{v})

Similar to Base.getproperty but requires a Val (or Static.StaticSymbol). Additionally, if v is not present in x, then nothing is returned.

source

Lux.LuxOps.xlogx Function
julia
xlogx(x::Number)

Return x * log(x) for x ≥ 0, handling x == 0 by taking the limit from above, to get zero.

source

Lux.LuxOps.xlogy Function
julia
xlogy(x::Number, y::Number)

Return x * log(y) for y > 0, and zero when x == 0.

source

Lux.LuxOps.istraining Function
julia
istraining(::Val{training})
+istraining(::StaticBool)
+istraining(::Bool)
+istraining(st::NamedTuple)

Returns true if training is true or if st contains a training field with value true. Else returns false.

source

Lux.LuxOps.multigate Function
julia
multigate(x::AbstractArray, ::Val{N})

Split up x into N equally sized chunks (along dimension 1).

source

Recursive Operations

Lux.recursive_map Function
julia
recursive_map(f, x, args...)

Similar to fmap(f, args...) but with restricted support for the notion of "leaf" types. However, this allows for more efficient and type stable implementations of recursive operations.

How this works?

For the following types it directly defines recursion rules:

  1. AbstractArray: If eltype is isbitstype, then f is applied to the array, else we recurse on the array.

  2. Tuple/NamedTuple: We recurse on the values.

  3. Number/Val/Nothing: We directly apply f.

  4. For all other types, we recurse on the fields using Functors.fmap.

Note

In most cases, users should gravitate towards Functors.fmap if it is being used outside of hot loops. Even for other cases, it is always recommended to verify the correctness of this implementation for specific usecases.

source

Lux.recursive_add!! Function
julia
recursive_add!!(x, y)

Recursively add the leaves of two nested structures x and y. In Functor language, this is equivalent to doing fmap(+, x, y), but this implementation uses type stable code for common cases.

Any leaves of x that are arrays and allow in-place addition will be modified in place.

source

Lux.recursive_copyto! Function
julia
recursive_copyto!(x, y)

Recursively copy the leaves of two nested structures x and y. In Functor language, this is equivalent to doing fmap(copyto!, x, y), but this implementation uses type stable code for common cases. Note that any immutable leaf will lead to an error.

source

Lux.recursive_eltype Function
julia
recursive_eltype(x, unwrap_ad_types = Val(false))

Recursively determine the element type of a nested structure x. This is equivalent to doing fmap(Lux.Utils.eltype, x), but this implementation uses type stable code for common cases.

For ambiguous inputs like nothing and Val types we return Bool as the eltype.

If unwrap_ad_types is set to Val(true) then for tracing and operator overloading based ADs (ForwardDiff, ReverseDiff, Tracker), this function will return the eltype of the unwrapped value.

source

Lux.recursive_make_zero Function
julia
recursive_make_zero(x)

Recursively create a zero value for a nested structure x. This is equivalent to doing fmap(zero, x), but this implementation uses type stable code for common cases.

See also Lux.recursive_make_zero!!.

source

Lux.recursive_make_zero!! Function
julia
recursive_make_zero!!(x)

Recursively create a zero value for a nested structure x. Leaves that can be mutated with in-place zeroing will be modified in place.

See also Lux.recursive_make_zero for fully out-of-place version.

source

Updating Floating Point Precision

By default, Lux uses Float32 for all parameters and states. To update the precision simply pass the parameters / states / arrays into one of the following functions.

Lux.f16 Function
julia
f16(m)

Converts the eltype of m floating point values to Float16. Recurses into structs marked with Functors.@functor.

source

Lux.f32 Function
julia
f32(m)

Converts the eltype of m floating point values to Float32. Recurses into structs marked with Functors.@functor.

source

Lux.f64 Function
julia
f64(m)

Converts the eltype of m floating point values to Float64. Recurses into structs marked with Functors.@functor.

source

Element Type Matching

Lux.match_eltype Function
julia
match_eltype(layer, ps, st, args...)

Helper function to "maybe" (see below) match the element type of args... with the element type of the layer's parameters and states. This is useful for debugging purposes, to track down accidental type-promotions inside Lux layers.

Extended Help

Controlling the Behavior via Preferences

Behavior of this function is controlled via the eltype_mismatch_handling preference. The following options are supported:

  • "none": This is the default behavior. In this case, this function is a no-op, i.e., it simply returns args....

  • "warn": This option will issue a warning if the element type of args... does not match the element type of the layer's parameters and states. The warning will contain information about the layer and the element type mismatch.

  • "convert": This option is same as "warn", but it will also convert the element type of args... to match the element type of the layer's parameters and states (for the cases listed below).

  • "error": Same as "warn", but instead of issuing a warning, it will throw an error.

Warning

We print the warning for type-mismatch only once.

Element Type Conversions

For "convert" only the following conversions are done:

Element Type of parameters/statesElement Type of args...Converted to
Float64IntegerFloat64
Float32Float64Float32
Float32IntegerFloat32
Float16Float64Float16
Float16Float32Float16
Float16IntegerFloat16

source

Stateful Layer

Lux.StatefulLuxLayer Type
julia
StatefulLuxLayer{FT}(model, ps, st)

Warning

This is not a Lux.AbstractLuxLayer

A convenience wrapper over Lux layers which stores the parameters and states internally. This is meant to be used in internal implementation of layers.

Usecases

  • Internal implementation of @compact heavily uses this layer.

  • In SciML codebases where propagating state might involving Boxing. For a motivating example, see the Neural ODE tutorial.

  • Facilitates Nested AD support in Lux. For more details on this feature, see the Nested AD Manual Page.

Static Parameters

  • If FT = true then the type of the state is fixed, i.e., typeof(last(model(x, ps, st))) == st.

  • If FT = false then type of the state might change. Note that while this works in all cases, it will introduce type instability.

Arguments

  • model: A Lux layer

  • ps: The parameters of the layer. This can be set to nothing, if the user provides the parameters on function call

  • st: The state of the layer

Inputs

  • x: The input to the layer

  • ps: The parameters of the layer. Optional, defaults to s.ps

Outputs

  • y: The output of the layer

source

Compact Layer

Lux.@compact Macro
julia
@compact(kw...) do x
+    ...
+    @return y # optional (but recommended for best performance)
+end
+@compact(kw...) do x, p
+    ...
+    @return y # optional (but recommended for best performance)
+end
+@compact(forward::Function; name=nothing, dispatch=nothing, parameters...)

Creates a layer by specifying some parameters, in the form of keywords, and (usually as a do block) a function for the forward pass. You may think of @compact as a specialized let block creating local variables that are trainable in Lux. Declared variable names may be used within the body of the forward function. Note that unlike typical Lux models, the forward function doesn't need to explicitly manage states.

Defining the version with p allows you to access the parameters in the forward pass. This is useful when using it with SciML tools which require passing in the parameters explicitly.

Reserved Kwargs:

  1. name: The name of the layer.

  2. dispatch: The constructed layer has the type Lux.CompactLuxLayer{dispatch} which can be used for custom dispatches.

Tip

Check the Lux tutorials for more examples of using @compact.

If you are passing in kwargs by splatting them, they will be passed as is to the function body. This means if your splatted kwargs contain a lux layer that won't be registered in the CompactLuxLayer.

Special Syntax

  • @return: This macro doesn't really exist, but is used to return a value from the @compact block. Without the presence of this macro, we need to rely on closures which can lead to performance penalties in the reverse pass.

    • Having statements after the last @return macro might lead to incorrect code.

    • Don't do things like @return return x. This will generate non-sensical code like <new var> = return x. Essentially, @return <expr> supports any expression, that can be assigned to a variable.

    • Since this macro doesn't "exist", it cannot be imported as using Lux: @return. Simply use it in code, and @compact will understand it.

  • @init_fn: Provide a function that will be used to initialize the layer's parameters or state. See the docs of @init_fn for more details.

  • @non_trainable: Mark a value as non-trainable. This bypasses the regular checks and places the value into the state of the layer. See the docs of @non_trainable for more details.

Extended Help

Examples

Here is a linear model:

julia
julia> using Lux, Random
+
+julia> r = @compact(w=ones(3)) do x
+           @return w .* x
+       end
+@compact(
+    w = 3-element Vector{Float64},
+) do x
+    return w .* x
+end       # Total: 3 parameters,
+          #        plus 0 states.
+
+julia> ps, st = Lux.setup(Xoshiro(0), r);
+
+julia> r([1, 2, 3], ps, st)  # x is set to [1, 1, 1].
+([1.0, 2.0, 3.0], NamedTuple())

Here is a linear model with bias and activation:

julia
julia> d_in = 5
+5
+
+julia> d_out = 3
+3
+
+julia> d = @compact(W=ones(d_out, d_in), b=zeros(d_out), act=relu) do x
+           y = W * x
+           @return act.(y .+ b)
+       end
+@compact(
+    W = 3×5 Matrix{Float64},
+    b = 3-element Vector{Float64},
+    act = relu,
+) do x
+    y = W * x
+    return act.(y .+ b)
+end       # Total: 18 parameters,
+          #        plus 1 states.
+
+julia> ps, st = Lux.setup(Xoshiro(0), d);
+
+julia> d(ones(5, 2), ps, st)[1] # 3×2 Matrix as output.
+3×2 Matrix{Float64}:
+ 5.0  5.0
+ 5.0  5.0
+ 5.0  5.0
+
+julia> ps_dense = (; weight=ps.W, bias=ps.b);
+
+julia> first(d([1, 2, 3, 4, 5], ps, st)) 
+       first(Dense(d_in => d_out, relu)([1, 2, 3, 4, 5], ps_dense, NamedTuple())) # Equivalent to a dense layer
+true

Finally, here is a simple MLP. We can train this model just like any Lux model:

julia
julia> n_in = 1;
+
+julia> n_out = 1;
+
+julia> nlayers = 3;
+
+julia> model = @compact(w1=Dense(n_in, 128),
+           w2=[Dense(128, 128) for i in 1:nlayers], w3=Dense(128, n_out), act=relu) do x
+           embed = act.(w1(x))
+           for w in w2
+               embed = act.(w(embed))
+           end
+           out = w3(embed)
+           @return out
+       end
+@compact(
+    w1 = Dense(1 => 128),               # 256 parameters
+    w2 = NamedTuple(
+        1 = Dense(128 => 128),          # 16_512 parameters
+        2 = Dense(128 => 128),          # 16_512 parameters
+        3 = Dense(128 => 128),          # 16_512 parameters
+    ),
+    w3 = Dense(128 => 1),               # 129 parameters
+    act = relu,
+) do x
+    embed = act.(w1(x))
+    for w = w2
+        embed = act.(w(embed))
+    end
+    out = w3(embed)
+    return out
+end       # Total: 49_921 parameters,
+          #        plus 1 states.
+
+julia> ps, st = Lux.setup(Xoshiro(0), model);
+
+julia> size(first(model(randn(n_in, 32), ps, st)))  # 1×32 Matrix as output.
+(1, 32)
+
+julia> using Optimisers, Zygote
+
+julia> x_data = collect(-2.0f0:0.1f0:2.0f0)';
+
+julia> y_data = 2 .* x_data .- x_data .^ 3;
+
+julia> optim = Optimisers.setup(Adam(), ps);
+
+julia> loss_initial = sum(abs2, first(model(x_data, ps, st)) .- y_data);
+
+julia> for epoch in 1:1000
+           loss, gs = Zygote.withgradient(
+               ps -> sum(abs2, first(model(x_data, ps, st)) .- y_data), ps)
+           Optimisers.update!(optim, ps, gs[1])
+       end;
+
+julia> loss_final = sum(abs2, first(model(x_data, ps, st)) .- y_data);
+
+julia> loss_initial > loss_final
+true

You may also specify a name for the model, which will be used instead of the default printout, which gives a verbatim representation of the code used to construct the model:

julia
julia> model = @compact(w=rand(3), name="Linear(3 => 1)") do x
+           @return sum(w .* x)
+       end
+Linear(3 => 1)      # 3 parameters

This can be useful when using @compact to hierarchically construct complex models to be used inside a Chain.

Type Stability

If your input function f is type-stable but the generated model is not type stable, it should be treated as a bug. We will appreciate issues if you find such cases.

Parameter Count

Array Parameter don't print the number of parameters on the side. However, they do account for the total number of parameters printed at the bottom.

source

Lux.@init_fn Macro
julia
@init_fn(fn, kind::Symbol = :parameter)

Create an initializer function for a parameter or state to be used for in a Compact Lux Layer created using @compact.

Arguments

  • fn: The function to be used for initializing the parameter or state. This only takes a single argument rng.

  • kind: If set to :parameter, the initializer function will be used to initialize the parameters of the layer. If set to :state, the initializer function will be used to initialize the states of the layer.

Examples

julia
julia> using Lux, Random
+
+julia> r = @compact(w=@init_fn(rng->randn32(rng, 3, 2)),
+           b=@init_fn(rng->randn32(rng, 3), :state)) do x
+           @return w * x .+ b
+       end;
+
+julia> ps, st = Lux.setup(Xoshiro(0), r);
+
+julia> size(ps.w)
+(3, 2)
+
+julia> size(st.b)
+(3,)
+
+julia> size(r([1, 2], ps, st)[1])
+(3,)

source

Lux.@non_trainable Macro
julia
@non_trainable(x)

Mark a value as non-trainable. This bypasses the regular checks and places the value into the state of the layer.

Arguments

  • x: The value to be marked as non-trainable.

Examples

julia
julia> using Lux, Random
+
+julia> r = @compact(w=ones(3), w_fixed=@non_trainable(rand(3))) do x
+           @return sum(w .* x .+ w_fixed)
+       end;
+
+julia> ps, st = Lux.setup(Xoshiro(0), r);
+
+julia> size(ps.w)
+(3,)
+
+julia> size(st.w_fixed)
+(3,)
+
+julia> res, st_ = r([1, 2, 3], ps, st);
+
+julia> st_.w_fixed == st.w_fixed
+true
+
+julia> res isa Number
+true

source

Miscellaneous

Lux.set_dispatch_doctor_preferences! Function
julia
set_dispatch_doctor_preferences!(mode::String)
+set_dispatch_doctor_preferences!(; luxcore::String="disable", luxlib::String="disable")

Set the dispatch doctor preference for LuxCore and LuxLib packages.

mode can be "disable", "warn", or "error". For details on the different modes, see the DispatchDoctor.jl documentation.

If the preferences are already set, then no action is taken. Otherwise the preference is set. For changes to take effect, the Julia session must be restarted.

source

+ + + + \ No newline at end of file diff --git a/previews/PR1023/api/Testing_Functionality/LuxTestUtils.html b/previews/PR1023/api/Testing_Functionality/LuxTestUtils.html new file mode 100644 index 0000000000..3c737dd6a3 --- /dev/null +++ b/previews/PR1023/api/Testing_Functionality/LuxTestUtils.html @@ -0,0 +1,45 @@ + + + + + + LuxTestUtils | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
Skip to content

LuxTestUtils

Warning

This is a testing package. Hence, we don't use features like weak dependencies to reduce load times. It is recommended that you exclusively use this package for testing and not add a dependency to it in your main package Project.toml.

Implements utilities for testing gradient correctness and dynamic dispatch of Lux.jl models.

Testing using JET.jl

LuxTestUtils.@jet Macro
julia
@jet f(args...) call_broken=false opt_broken=false

Run JET tests on the function f with the arguments args.... If JET.jl fails to compile, then the macro will be a no-op.

Keyword Arguments

  • call_broken: Marks the test_call as broken.

  • opt_broken: Marks the test_opt as broken.

All additional arguments will be forwarded to JET.@test_call and JET.@test_opt.

Tip

Instead of specifying target_modules with every call, you can set global target modules using jet_target_modules!.

julia
using LuxTestUtils
+
+jet_target_modules!(["Lux", "LuxLib"]) # Expects Lux and LuxLib to be present in the module calling `@jet`

Example

julia
julia> @jet sum([1, 2, 3]) target_modules=(Base, Core)
+Test Passed
+
+julia> @jet sum(1, 1) target_modules=(Base, Core) opt_broken=true call_broken=true
+Test Broken
+  Expression: #= REPL[21]:1 =# JET.@test_opt target_modules = (Base, Core) sum(1, 1)

source

LuxTestUtils.jet_target_modules! Function
julia
jet_target_modules!(list::Vector{String}; force::Bool=false)

This sets target_modules for all JET tests when using @jet.

source

Gradient Correctness

LuxTestUtils.test_gradients Function
julia
test_gradients(f, args...; skip_backends=[], broken_backends=[], kwargs...)

Test the gradients of f with respect to args using the specified backends.

BackendADTypeCPUGPUNotes
Zygote.jlAutoZygote()
Tracker.jlAutoTracker()
ReverseDiff.jlAutoReverseDiff()
ForwardDiff.jlAutoForwardDiff()len ≤ 100
FiniteDiff.jlAutoFiniteDiff()len ≤ 100
Enzyme.jlAutoEnzyme()Only Reverse Mode

Arguments

  • f: The function to test the gradients of.

  • args: The arguments to test the gradients of. Only AbstractArrays are considered for gradient computation. Gradients wrt all other arguments are assumed to be NoTangent().

Keyword Arguments

  • skip_backends: A list of backends to skip.

  • broken_backends: A list of backends to treat as broken.

  • soft_fail: If true, then the test will be recorded as a soft_fail test. This overrides any broken kwargs. Alternatively, a list of backends can be passed to soft_fail to allow soft_fail tests for only those backends.

  • enzyme_set_runtime_activity: If true, then activate runtime activity for Enzyme.

  • kwargs: Additional keyword arguments to pass to check_approx.

Example

julia
julia> f(x, y, z) = x .+ sum(abs2, y.t) + sum(y.x.z)
+
+julia> x = (; t=rand(10), x=(z=[2.0],))
+
+julia> test_gradients(f, 1.0, x, nothing)

source

LuxTestUtils.@test_gradients Macro
julia
@test_gradients(f, args...; kwargs...)

See the documentation of test_gradients for more details. This macro provides correct line information for the failing tests.

source

Extensions to @test

LuxTestUtils.@test_softfail Macro
julia
@test_softfail expr

Evaluate expr and record a test result. If expr throws an exception, the test result will be recorded as an error. If expr returns a value, and it is not a boolean, the test result will be recorded as an error.

If the test result is false then the test will be recorded as a broken test, else it will be recorded as a pass.

source

+ + + + \ No newline at end of file diff --git a/previews/PR1023/assets/api_Accelerator_Support_MLDataDevices.md.Ba-hugak.js b/previews/PR1023/assets/api_Accelerator_Support_MLDataDevices.md.Ba-hugak.js new file mode 100644 index 0000000000..ec0b96b22f --- /dev/null +++ b/previews/PR1023/assets/api_Accelerator_Support_MLDataDevices.md.Ba-hugak.js @@ -0,0 +1,25 @@ +import{_ as l,c as p,j as i,a as e,G as t,a2 as n,B as d,o as h}from"./chunks/framework.DFwXuivk.js";const T=JSON.parse('{"title":"MLDataDevices","description":"","frontmatter":{},"headers":[],"relativePath":"api/Accelerator_Support/MLDataDevices.md","filePath":"api/Accelerator_Support/MLDataDevices.md","lastUpdated":null}'),o={name:"api/Accelerator_Support/MLDataDevices.md"},r={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},k={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},v={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},D={class:"jldocstring custom-block"},F={class:"jldocstring custom-block"},C={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"};function L(j,s,A,x,M,B){const a=d("Badge");return h(),p("div",null,[s[42]||(s[42]=i("h1",{id:"MLDataDevices-API",tabindex:"-1"},[e("MLDataDevices "),i("a",{class:"header-anchor",href:"#MLDataDevices-API","aria-label":'Permalink to "MLDataDevices {#MLDataDevices-API}"'},"​")],-1)),s[43]||(s[43]=i("p",null,[i("code",null,"MLDataDevices.jl"),e(" is a lightweight package defining rules for transferring data across devices.")],-1)),s[44]||(s[44]=i("h2",{id:"preferences",tabindex:"-1"},[e("Preferences "),i("a",{class:"header-anchor",href:"#preferences","aria-label":'Permalink to "Preferences"'},"​")],-1)),i("details",r,[i("summary",null,[s[0]||(s[0]=i("a",{id:"MLDataDevices.gpu_backend!",href:"#MLDataDevices.gpu_backend!"},[i("span",{class:"jlbinding"},"MLDataDevices.gpu_backend!")],-1)),s[1]||(s[1]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[2]||(s[2]=n(`
julia
gpu_backend!() = gpu_backend!("")
+gpu_backend!(backend) = gpu_backend!(string(backend))
+gpu_backend!(backend::AbstractGPUDevice)
+gpu_backend!(backend::String)

Creates a LocalPreferences.toml file with the desired GPU backend.

If backend == "", then the gpu_backend preference is deleted. Otherwise, backend is validated to be one of the possible backends and the preference is set to backend.

If a new backend is successfully set, then the Julia session must be restarted for the change to take effect.

source

`,5))]),s[45]||(s[45]=i("h2",{id:"Data-Transfer",tabindex:"-1"},[e("Data Transfer "),i("a",{class:"header-anchor",href:"#Data-Transfer","aria-label":'Permalink to "Data Transfer {#Data-Transfer}"'},"​")],-1)),i("details",c,[i("summary",null,[s[3]||(s[3]=i("a",{id:"MLDataDevices.cpu_device",href:"#MLDataDevices.cpu_device"},[i("span",{class:"jlbinding"},"MLDataDevices.cpu_device")],-1)),s[4]||(s[4]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[5]||(s[5]=n('
julia
cpu_device() -> CPUDevice()

Return a CPUDevice object which can be used to transfer data to CPU.

source

',3))]),i("details",k,[i("summary",null,[s[6]||(s[6]=i("a",{id:"MLDataDevices.gpu_device",href:"#MLDataDevices.gpu_device"},[i("span",{class:"jlbinding"},"MLDataDevices.gpu_device")],-1)),s[7]||(s[7]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[8]||(s[8]=n(`
julia
gpu_device(device_id::Union{Nothing, Integer}=nothing;
+    force::Bool=false) -> AbstractDevice

Selects GPU device based on the following criteria:

  1. If gpu_backend preference is set and the backend is functional on the system, then that device is selected.

  2. Otherwise, an automatic selection algorithm is used. We go over possible device backends in the order specified by supported_gpu_backends() and select the first functional backend.

  3. If no GPU device is functional and force is false, then cpu_device() is invoked.

  4. If nothing works, an error is thrown.

Arguments

Warning

device_id is only applicable for CUDA and AMDGPU backends. For Metal, oneAPI and CPU backends, device_id is ignored and a warning is printed.

Warning

gpu_device won't select a CUDA device unless both CUDA.jl and cuDNN.jl are loaded. This is to ensure that deep learning operations work correctly. Nonetheless, if cuDNN is not loaded you can still manually create a CUDADevice object and use it (e.g. dev = CUDADevice()).

Keyword Arguments

source

`,10))]),i("details",g,[i("summary",null,[s[9]||(s[9]=i("a",{id:"MLDataDevices.xla_device",href:"#MLDataDevices.xla_device"},[i("span",{class:"jlbinding"},"MLDataDevices.xla_device")],-1)),s[10]||(s[10]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[11]||(s[11]=n('
julia
xla_device(; force::Bool=false) -> Union{XLADevice, CPUDevice}

Return a XLADevice object if functional. Otherwise, throw an error if force is true. Falls back to CPUDevice if force is false.

Danger

This is an experimental feature and might change without deprecations

source

',4))]),s[46]||(s[46]=i("h2",{id:"miscellaneous",tabindex:"-1"},[e("Miscellaneous "),i("a",{class:"header-anchor",href:"#miscellaneous","aria-label":'Permalink to "Miscellaneous"'},"​")],-1)),i("details",u,[i("summary",null,[s[12]||(s[12]=i("a",{id:"MLDataDevices.reset_gpu_device!",href:"#MLDataDevices.reset_gpu_device!"},[i("span",{class:"jlbinding"},"MLDataDevices.reset_gpu_device!")],-1)),s[13]||(s[13]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[14]||(s[14]=n('
julia
reset_gpu_device!()

Resets the selected GPU device. This is useful when automatic GPU selection needs to be run again.

source

',3))]),i("details",E,[i("summary",null,[s[15]||(s[15]=i("a",{id:"MLDataDevices.supported_gpu_backends",href:"#MLDataDevices.supported_gpu_backends"},[i("span",{class:"jlbinding"},"MLDataDevices.supported_gpu_backends")],-1)),s[16]||(s[16]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[17]||(s[17]=n('
julia
supported_gpu_backends() -> Tuple{String, ...}

Return a tuple of supported GPU backends.

Warning

This is not the list of functional backends on the system, but rather backends which MLDataDevices.jl supports.

source

',4))]),i("details",y,[i("summary",null,[s[18]||(s[18]=i("a",{id:"MLDataDevices.default_device_rng",href:"#MLDataDevices.default_device_rng"},[i("span",{class:"jlbinding"},"MLDataDevices.default_device_rng")],-1)),s[19]||(s[19]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[20]||(s[20]=n('
julia
default_device_rng(::AbstractDevice)

Returns the default RNG for the device. This can be used to directly generate parameters and states on the device using WeightInitializers.jl.

source

',3))]),i("details",v,[i("summary",null,[s[21]||(s[21]=i("a",{id:"MLDataDevices.get_device",href:"#MLDataDevices.get_device"},[i("span",{class:"jlbinding"},"MLDataDevices.get_device")],-1)),s[22]||(s[22]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[23]||(s[23]=n('
julia
get_device(x) -> dev::AbstractDevice | Exception | Nothing

If all arrays (on the leaves of the structure) are on the same device, we return that device. Otherwise, we throw an error. If the object is device agnostic, we return nothing.

Note

Trigger Packages must be loaded for this to return the correct device.

Special Retuened Values

See also get_device_type for a faster alternative that can be used for dispatch based on device type.

source

',7))]),i("details",f,[i("summary",null,[s[24]||(s[24]=i("a",{id:"MLDataDevices.get_device_type",href:"#MLDataDevices.get_device_type"},[i("span",{class:"jlbinding"},"MLDataDevices.get_device_type")],-1)),s[25]||(s[25]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[26]||(s[26]=n('
julia
get_device_type(x) -> Type{<:AbstractDevice} | Exception | Type{Nothing}

Similar to get_device but returns the type of the device instead of the device itself. This value is often a compile time constant and is recommended to be used instead of get_device where ever defining dispatches based on the device type.

Note

Trigger Packages must be loaded for this to return the correct device.

Special Retuened Values

source

',6))]),i("details",b,[i("summary",null,[s[27]||(s[27]=i("a",{id:"MLDataDevices.loaded",href:"#MLDataDevices.loaded"},[i("span",{class:"jlbinding"},"MLDataDevices.loaded")],-1)),s[28]||(s[28]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[29]||(s[29]=n(`
julia
loaded(x::AbstractDevice) -> Bool
+loaded(::Type{<:AbstractDevice}) -> Bool

Checks if the trigger package for the device is loaded. Trigger packages are as follows:

source

`,4))]),i("details",D,[i("summary",null,[s[30]||(s[30]=i("a",{id:"MLDataDevices.functional",href:"#MLDataDevices.functional"},[i("span",{class:"jlbinding"},"MLDataDevices.functional")],-1)),s[31]||(s[31]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[32]||(s[32]=n(`
julia
functional(x::AbstractDevice) -> Bool
+functional(::Type{<:AbstractDevice}) -> Bool

Checks if the device is functional. This is used to determine if the device can be used for computation. Note that even if the backend is loaded (as checked via MLDataDevices.loaded), the device may not be functional.

Note that while this function is not exported, it is considered part of the public API.

source

`,4))]),i("details",F,[i("summary",null,[s[33]||(s[33]=i("a",{id:"MLDataDevices.isleaf",href:"#MLDataDevices.isleaf"},[i("span",{class:"jlbinding"},"MLDataDevices.isleaf")],-1)),s[34]||(s[34]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[35]||(s[35]=n('
julia
isleaf(x) -> Bool

Returns true if x is a leaf node in the data structure.

Defining MLDataDevices.isleaf(x::T) = true for custom types can be used to customize the behavior the data movement behavior when an object with nested structure containing the type is transferred to a device.

Adapt.adapt_structure(::AbstractDevice, x::T) or Adapt.adapt_structure(::AbstractDevice, x::T) will be called during data movement if isleaf(x::T) == true.

If MLDataDevices.isleaf(x::T) is not defined, then it will fall back to Functors.isleaf(x).

source

',6))]),s[47]||(s[47]=i("h2",{id:"Multi-GPU-Support",tabindex:"-1"},[e("Multi-GPU Support "),i("a",{class:"header-anchor",href:"#Multi-GPU-Support","aria-label":'Permalink to "Multi-GPU Support {#Multi-GPU-Support}"'},"​")],-1)),i("details",C,[i("summary",null,[s[36]||(s[36]=i("a",{id:"MLDataDevices.set_device!",href:"#MLDataDevices.set_device!"},[i("span",{class:"jlbinding"},"MLDataDevices.set_device!")],-1)),s[37]||(s[37]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[38]||(s[38]=n('
julia
set_device!(T::Type{<:AbstractDevice}, dev_or_id)

Set the device for the given type. This is a no-op for CPUDevice. For CUDADevice and AMDGPUDevice, it prints a warning if the corresponding trigger package is not loaded.

Currently, MetalDevice and oneAPIDevice don't support setting the device.

Arguments

Danger

This specific function should be considered experimental at this point and is currently provided to support distributed training in Lux. As such please use Lux.DistributedUtils instead of using this function.

source

julia
set_device!(T::Type{<:AbstractDevice}, ::Nothing, rank::Integer)

Set the device for the given type. This is a no-op for CPUDevice. For CUDADevice and AMDGPUDevice, it prints a warning if the corresponding trigger package is not loaded.

Currently, MetalDevice and oneAPIDevice don't support setting the device.

Arguments

Danger

This specific function should be considered experimental at this point and is currently provided to support distributed training in Lux. As such please use Lux.DistributedUtils instead of using this function.

source

',14))]),s[48]||(s[48]=i("h2",{id:"iteration",tabindex:"-1"},[e("Iteration "),i("a",{class:"header-anchor",href:"#iteration","aria-label":'Permalink to "Iteration"'},"​")],-1)),i("details",m,[i("summary",null,[s[39]||(s[39]=i("a",{id:"MLDataDevices.DeviceIterator",href:"#MLDataDevices.DeviceIterator"},[i("span",{class:"jlbinding"},"MLDataDevices.DeviceIterator")],-1)),s[40]||(s[40]=e()),t(a,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[41]||(s[41]=n(`
julia
DeviceIterator(dev::AbstractDevice, iterator)

Create a DeviceIterator that iterates through the provided iterator via iterate. Upon each iteration, the current batch is copied to the device dev, and the previous iteration is marked as freeable from GPU memory (via unsafe_free!) (no-op for a CPU device).

The conversion follows the same semantics as dev(<item from iterator>).

Similarity to CUDA.CuIterator

The design inspiration was taken from CUDA.CuIterator and was generalized to work with other backends and more complex iterators (using Functors).

MLUtils.DataLoader

Calling dev(::MLUtils.DataLoader) will automatically convert the dataloader to use the same semantics as DeviceIterator. This is generally preferred over looping over the dataloader directly and transferring the data to the device.

Examples

The following was run on a computer with an NVIDIA GPU.

julia
julia> using MLDataDevices, MLUtils
+
+julia> X = rand(Float64, 3, 33);
+
+julia> dataloader = DataLoader(X; batchsize=13, shuffle=false);
+
+julia> for (i, x) in enumerate(dataloader)
+           @show i, summary(x)
+       end
+(i, summary(x)) = (1, "3×13 Matrix{Float64}")
+(i, summary(x)) = (2, "3×13 Matrix{Float64}")
+(i, summary(x)) = (3, "3×7 Matrix{Float64}")
+
+julia> for (i, x) in enumerate(CUDADevice()(dataloader))
+           @show i, summary(x)
+       end
+(i, summary(x)) = (1, "3×13 CuArray{Float32, 2, CUDA.DeviceMemory}")
+(i, summary(x)) = (2, "3×13 CuArray{Float32, 2, CUDA.DeviceMemory}")
+(i, summary(x)) = (3, "3×7 CuArray{Float32, 2, CUDA.DeviceMemory}")

source

`,9))])])}const w=l(o,[["render",L]]);export{T as __pageData,w as default}; diff --git a/previews/PR1023/assets/api_Accelerator_Support_MLDataDevices.md.Ba-hugak.lean.js b/previews/PR1023/assets/api_Accelerator_Support_MLDataDevices.md.Ba-hugak.lean.js new file mode 100644 index 0000000000..ec0b96b22f --- /dev/null +++ b/previews/PR1023/assets/api_Accelerator_Support_MLDataDevices.md.Ba-hugak.lean.js @@ -0,0 +1,25 @@ +import{_ as l,c as p,j as i,a as e,G as t,a2 as n,B as d,o as h}from"./chunks/framework.DFwXuivk.js";const T=JSON.parse('{"title":"MLDataDevices","description":"","frontmatter":{},"headers":[],"relativePath":"api/Accelerator_Support/MLDataDevices.md","filePath":"api/Accelerator_Support/MLDataDevices.md","lastUpdated":null}'),o={name:"api/Accelerator_Support/MLDataDevices.md"},r={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},k={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},v={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},D={class:"jldocstring custom-block"},F={class:"jldocstring custom-block"},C={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"};function L(j,s,A,x,M,B){const a=d("Badge");return h(),p("div",null,[s[42]||(s[42]=i("h1",{id:"MLDataDevices-API",tabindex:"-1"},[e("MLDataDevices "),i("a",{class:"header-anchor",href:"#MLDataDevices-API","aria-label":'Permalink to "MLDataDevices {#MLDataDevices-API}"'},"​")],-1)),s[43]||(s[43]=i("p",null,[i("code",null,"MLDataDevices.jl"),e(" is a lightweight package defining rules for transferring data across devices.")],-1)),s[44]||(s[44]=i("h2",{id:"preferences",tabindex:"-1"},[e("Preferences "),i("a",{class:"header-anchor",href:"#preferences","aria-label":'Permalink to "Preferences"'},"​")],-1)),i("details",r,[i("summary",null,[s[0]||(s[0]=i("a",{id:"MLDataDevices.gpu_backend!",href:"#MLDataDevices.gpu_backend!"},[i("span",{class:"jlbinding"},"MLDataDevices.gpu_backend!")],-1)),s[1]||(s[1]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[2]||(s[2]=n(`
julia
gpu_backend!() = gpu_backend!("")
+gpu_backend!(backend) = gpu_backend!(string(backend))
+gpu_backend!(backend::AbstractGPUDevice)
+gpu_backend!(backend::String)

Creates a LocalPreferences.toml file with the desired GPU backend.

If backend == "", then the gpu_backend preference is deleted. Otherwise, backend is validated to be one of the possible backends and the preference is set to backend.

If a new backend is successfully set, then the Julia session must be restarted for the change to take effect.

source

`,5))]),s[45]||(s[45]=i("h2",{id:"Data-Transfer",tabindex:"-1"},[e("Data Transfer "),i("a",{class:"header-anchor",href:"#Data-Transfer","aria-label":'Permalink to "Data Transfer {#Data-Transfer}"'},"​")],-1)),i("details",c,[i("summary",null,[s[3]||(s[3]=i("a",{id:"MLDataDevices.cpu_device",href:"#MLDataDevices.cpu_device"},[i("span",{class:"jlbinding"},"MLDataDevices.cpu_device")],-1)),s[4]||(s[4]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[5]||(s[5]=n('
julia
cpu_device() -> CPUDevice()

Return a CPUDevice object which can be used to transfer data to CPU.

source

',3))]),i("details",k,[i("summary",null,[s[6]||(s[6]=i("a",{id:"MLDataDevices.gpu_device",href:"#MLDataDevices.gpu_device"},[i("span",{class:"jlbinding"},"MLDataDevices.gpu_device")],-1)),s[7]||(s[7]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[8]||(s[8]=n(`
julia
gpu_device(device_id::Union{Nothing, Integer}=nothing;
+    force::Bool=false) -> AbstractDevice

Selects GPU device based on the following criteria:

  1. If gpu_backend preference is set and the backend is functional on the system, then that device is selected.

  2. Otherwise, an automatic selection algorithm is used. We go over possible device backends in the order specified by supported_gpu_backends() and select the first functional backend.

  3. If no GPU device is functional and force is false, then cpu_device() is invoked.

  4. If nothing works, an error is thrown.

Arguments

Warning

device_id is only applicable for CUDA and AMDGPU backends. For Metal, oneAPI and CPU backends, device_id is ignored and a warning is printed.

Warning

gpu_device won't select a CUDA device unless both CUDA.jl and cuDNN.jl are loaded. This is to ensure that deep learning operations work correctly. Nonetheless, if cuDNN is not loaded you can still manually create a CUDADevice object and use it (e.g. dev = CUDADevice()).

Keyword Arguments

source

`,10))]),i("details",g,[i("summary",null,[s[9]||(s[9]=i("a",{id:"MLDataDevices.xla_device",href:"#MLDataDevices.xla_device"},[i("span",{class:"jlbinding"},"MLDataDevices.xla_device")],-1)),s[10]||(s[10]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[11]||(s[11]=n('
julia
xla_device(; force::Bool=false) -> Union{XLADevice, CPUDevice}

Return a XLADevice object if functional. Otherwise, throw an error if force is true. Falls back to CPUDevice if force is false.

Danger

This is an experimental feature and might change without deprecations

source

',4))]),s[46]||(s[46]=i("h2",{id:"miscellaneous",tabindex:"-1"},[e("Miscellaneous "),i("a",{class:"header-anchor",href:"#miscellaneous","aria-label":'Permalink to "Miscellaneous"'},"​")],-1)),i("details",u,[i("summary",null,[s[12]||(s[12]=i("a",{id:"MLDataDevices.reset_gpu_device!",href:"#MLDataDevices.reset_gpu_device!"},[i("span",{class:"jlbinding"},"MLDataDevices.reset_gpu_device!")],-1)),s[13]||(s[13]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[14]||(s[14]=n('
julia
reset_gpu_device!()

Resets the selected GPU device. This is useful when automatic GPU selection needs to be run again.

source

',3))]),i("details",E,[i("summary",null,[s[15]||(s[15]=i("a",{id:"MLDataDevices.supported_gpu_backends",href:"#MLDataDevices.supported_gpu_backends"},[i("span",{class:"jlbinding"},"MLDataDevices.supported_gpu_backends")],-1)),s[16]||(s[16]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[17]||(s[17]=n('
julia
supported_gpu_backends() -> Tuple{String, ...}

Return a tuple of supported GPU backends.

Warning

This is not the list of functional backends on the system, but rather backends which MLDataDevices.jl supports.

source

',4))]),i("details",y,[i("summary",null,[s[18]||(s[18]=i("a",{id:"MLDataDevices.default_device_rng",href:"#MLDataDevices.default_device_rng"},[i("span",{class:"jlbinding"},"MLDataDevices.default_device_rng")],-1)),s[19]||(s[19]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[20]||(s[20]=n('
julia
default_device_rng(::AbstractDevice)

Returns the default RNG for the device. This can be used to directly generate parameters and states on the device using WeightInitializers.jl.

source

',3))]),i("details",v,[i("summary",null,[s[21]||(s[21]=i("a",{id:"MLDataDevices.get_device",href:"#MLDataDevices.get_device"},[i("span",{class:"jlbinding"},"MLDataDevices.get_device")],-1)),s[22]||(s[22]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[23]||(s[23]=n('
julia
get_device(x) -> dev::AbstractDevice | Exception | Nothing

If all arrays (on the leaves of the structure) are on the same device, we return that device. Otherwise, we throw an error. If the object is device agnostic, we return nothing.

Note

Trigger Packages must be loaded for this to return the correct device.

Special Retuened Values

See also get_device_type for a faster alternative that can be used for dispatch based on device type.

source

',7))]),i("details",f,[i("summary",null,[s[24]||(s[24]=i("a",{id:"MLDataDevices.get_device_type",href:"#MLDataDevices.get_device_type"},[i("span",{class:"jlbinding"},"MLDataDevices.get_device_type")],-1)),s[25]||(s[25]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[26]||(s[26]=n('
julia
get_device_type(x) -> Type{<:AbstractDevice} | Exception | Type{Nothing}

Similar to get_device but returns the type of the device instead of the device itself. This value is often a compile time constant and is recommended to be used instead of get_device where ever defining dispatches based on the device type.

Note

Trigger Packages must be loaded for this to return the correct device.

Special Retuened Values

source

',6))]),i("details",b,[i("summary",null,[s[27]||(s[27]=i("a",{id:"MLDataDevices.loaded",href:"#MLDataDevices.loaded"},[i("span",{class:"jlbinding"},"MLDataDevices.loaded")],-1)),s[28]||(s[28]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[29]||(s[29]=n(`
julia
loaded(x::AbstractDevice) -> Bool
+loaded(::Type{<:AbstractDevice}) -> Bool

Checks if the trigger package for the device is loaded. Trigger packages are as follows:

source

`,4))]),i("details",D,[i("summary",null,[s[30]||(s[30]=i("a",{id:"MLDataDevices.functional",href:"#MLDataDevices.functional"},[i("span",{class:"jlbinding"},"MLDataDevices.functional")],-1)),s[31]||(s[31]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[32]||(s[32]=n(`
julia
functional(x::AbstractDevice) -> Bool
+functional(::Type{<:AbstractDevice}) -> Bool

Checks if the device is functional. This is used to determine if the device can be used for computation. Note that even if the backend is loaded (as checked via MLDataDevices.loaded), the device may not be functional.

Note that while this function is not exported, it is considered part of the public API.

source

`,4))]),i("details",F,[i("summary",null,[s[33]||(s[33]=i("a",{id:"MLDataDevices.isleaf",href:"#MLDataDevices.isleaf"},[i("span",{class:"jlbinding"},"MLDataDevices.isleaf")],-1)),s[34]||(s[34]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[35]||(s[35]=n('
julia
isleaf(x) -> Bool

Returns true if x is a leaf node in the data structure.

Defining MLDataDevices.isleaf(x::T) = true for custom types can be used to customize the behavior the data movement behavior when an object with nested structure containing the type is transferred to a device.

Adapt.adapt_structure(::AbstractDevice, x::T) or Adapt.adapt_structure(::AbstractDevice, x::T) will be called during data movement if isleaf(x::T) == true.

If MLDataDevices.isleaf(x::T) is not defined, then it will fall back to Functors.isleaf(x).

source

',6))]),s[47]||(s[47]=i("h2",{id:"Multi-GPU-Support",tabindex:"-1"},[e("Multi-GPU Support "),i("a",{class:"header-anchor",href:"#Multi-GPU-Support","aria-label":'Permalink to "Multi-GPU Support {#Multi-GPU-Support}"'},"​")],-1)),i("details",C,[i("summary",null,[s[36]||(s[36]=i("a",{id:"MLDataDevices.set_device!",href:"#MLDataDevices.set_device!"},[i("span",{class:"jlbinding"},"MLDataDevices.set_device!")],-1)),s[37]||(s[37]=e()),t(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[38]||(s[38]=n('
julia
set_device!(T::Type{<:AbstractDevice}, dev_or_id)

Set the device for the given type. This is a no-op for CPUDevice. For CUDADevice and AMDGPUDevice, it prints a warning if the corresponding trigger package is not loaded.

Currently, MetalDevice and oneAPIDevice don't support setting the device.

Arguments

Danger

This specific function should be considered experimental at this point and is currently provided to support distributed training in Lux. As such please use Lux.DistributedUtils instead of using this function.

source

julia
set_device!(T::Type{<:AbstractDevice}, ::Nothing, rank::Integer)

Set the device for the given type. This is a no-op for CPUDevice. For CUDADevice and AMDGPUDevice, it prints a warning if the corresponding trigger package is not loaded.

Currently, MetalDevice and oneAPIDevice don't support setting the device.

Arguments

Danger

This specific function should be considered experimental at this point and is currently provided to support distributed training in Lux. As such please use Lux.DistributedUtils instead of using this function.

source

',14))]),s[48]||(s[48]=i("h2",{id:"iteration",tabindex:"-1"},[e("Iteration "),i("a",{class:"header-anchor",href:"#iteration","aria-label":'Permalink to "Iteration"'},"​")],-1)),i("details",m,[i("summary",null,[s[39]||(s[39]=i("a",{id:"MLDataDevices.DeviceIterator",href:"#MLDataDevices.DeviceIterator"},[i("span",{class:"jlbinding"},"MLDataDevices.DeviceIterator")],-1)),s[40]||(s[40]=e()),t(a,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[41]||(s[41]=n(`
julia
DeviceIterator(dev::AbstractDevice, iterator)

Create a DeviceIterator that iterates through the provided iterator via iterate. Upon each iteration, the current batch is copied to the device dev, and the previous iteration is marked as freeable from GPU memory (via unsafe_free!) (no-op for a CPU device).

The conversion follows the same semantics as dev(<item from iterator>).

Similarity to CUDA.CuIterator

The design inspiration was taken from CUDA.CuIterator and was generalized to work with other backends and more complex iterators (using Functors).

MLUtils.DataLoader

Calling dev(::MLUtils.DataLoader) will automatically convert the dataloader to use the same semantics as DeviceIterator. This is generally preferred over looping over the dataloader directly and transferring the data to the device.

Examples

The following was run on a computer with an NVIDIA GPU.

julia
julia> using MLDataDevices, MLUtils
+
+julia> X = rand(Float64, 3, 33);
+
+julia> dataloader = DataLoader(X; batchsize=13, shuffle=false);
+
+julia> for (i, x) in enumerate(dataloader)
+           @show i, summary(x)
+       end
+(i, summary(x)) = (1, "3×13 Matrix{Float64}")
+(i, summary(x)) = (2, "3×13 Matrix{Float64}")
+(i, summary(x)) = (3, "3×7 Matrix{Float64}")
+
+julia> for (i, x) in enumerate(CUDADevice()(dataloader))
+           @show i, summary(x)
+       end
+(i, summary(x)) = (1, "3×13 CuArray{Float32, 2, CUDA.DeviceMemory}")
+(i, summary(x)) = (2, "3×13 CuArray{Float32, 2, CUDA.DeviceMemory}")
+(i, summary(x)) = (3, "3×7 CuArray{Float32, 2, CUDA.DeviceMemory}")

source

`,9))])])}const w=l(o,[["render",L]]);export{T as __pageData,w as default}; diff --git a/previews/PR1023/assets/api_Building_Blocks_LuxCore.md.CF0jvmvx.js b/previews/PR1023/assets/api_Building_Blocks_LuxCore.md.CF0jvmvx.js new file mode 100644 index 0000000000..2103fdcd2e --- /dev/null +++ b/previews/PR1023/assets/api_Building_Blocks_LuxCore.md.CF0jvmvx.js @@ -0,0 +1 @@ +import{_ as o,c as n,a2 as a,j as s,a as t,G as l,B as r,o as p}from"./chunks/framework.DFwXuivk.js";const S=JSON.parse('{"title":"LuxCore","description":"","frontmatter":{},"headers":[],"relativePath":"api/Building_Blocks/LuxCore.md","filePath":"api/Building_Blocks/LuxCore.md","lastUpdated":null}'),d={name:"api/Building_Blocks/LuxCore.md"},c={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"},h={class:"jldocstring custom-block"},k={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},L={class:"jldocstring custom-block"},x={class:"jldocstring custom-block"},C={class:"jldocstring custom-block"},j={class:"jldocstring custom-block"},v={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},F={class:"jldocstring custom-block"},A={class:"jldocstring custom-block"},B={class:"jldocstring custom-block"};function T(w,e,D,P,R,N){const i=r("Badge");return p(),n("div",null,[e[54]||(e[54]=a('

LuxCore

LuxCore.jl defines the abstract layers for Lux. Allows users to be compatible with the entirely of Lux.jl without having such a heavy dependency. If you are depending on Lux.jl directly, you do not need to depend on LuxCore.jl (all the functionality is exported via Lux.jl).

Abstract Types

',3)),s("details",c,[s("summary",null,[e[0]||(e[0]=s("a",{id:"LuxCore.AbstractLuxLayer",href:"#LuxCore.AbstractLuxLayer"},[s("span",{class:"jlbinding"},"LuxCore.AbstractLuxLayer")],-1)),e[1]||(e[1]=t()),l(i,{type:"info",class:"jlObjectType jlType",text:"Type"})]),e[2]||(e[2]=a('
julia
abstract type AbstractLuxLayer

Abstract Type for all Lux Layers

Users implementing their custom layer, must implement

Optionally:

See also AbstractLuxContainerLayer

source

',8))]),s("details",u,[s("summary",null,[e[3]||(e[3]=s("a",{id:"LuxCore.AbstractLuxWrapperLayer",href:"#LuxCore.AbstractLuxWrapperLayer"},[s("span",{class:"jlbinding"},"LuxCore.AbstractLuxWrapperLayer")],-1)),e[4]||(e[4]=t()),l(i,{type:"info",class:"jlObjectType jlType",text:"Type"})]),e[5]||(e[5]=a('
julia
abstract type AbstractLuxWrapperLayer{layer} <: AbstractLuxLayer

See AbstractLuxContainerLayer for detailed documentation. This abstract type is very similar to AbstractLuxContainerLayer except that it allows for a single layer to be wrapped in a container.

Additionally, on calling initialparameters and initialstates, the parameters and states are not wrapped in a NamedTuple with the same name as the field.

As a convenience, we define the fallback call (::AbstractLuxWrapperLayer)(x, ps, st), which calls getfield(x, layer)(x, ps, st).

source

',5))]),s("details",h,[s("summary",null,[e[6]||(e[6]=s("a",{id:"LuxCore.AbstractLuxContainerLayer",href:"#LuxCore.AbstractLuxContainerLayer"},[s("span",{class:"jlbinding"},"LuxCore.AbstractLuxContainerLayer")],-1)),e[7]||(e[7]=t()),l(i,{type:"info",class:"jlObjectType jlType",text:"Type"})]),e[8]||(e[8]=a('
julia
abstract type AbstractLuxContainerLayer{layers} <: AbstractLuxLayer

Abstract Container Type for certain Lux Layers. layers is a tuple containing fieldnames for the layer, and constructs the parameters and states using those.

Users implementing their custom layer can extend the same functions as in AbstractLuxLayer.

Advanced Structure Manipulation

Advanced structure manipulation of these layers post construction is possible via Functors.fmap. For a more flexible interface, we recommend using Lux.Experimental.@layer_map.

fmap Support

fmap support needs to be explicitly enabled by loading Functors.jl and Setfield.jl.

Changes from Pre-1.0 Behavior

Previously if layers was a singleton tuple, initialparameters and initialstates would return the parameters and states for the single field layers. From v1.0.0 onwards, even for singleton tuples, the parameters/states are wrapped in a NamedTuple with the same name as the field. See AbstractLuxWrapperLayer to replicate the previous behavior of singleton tuples.

source

',7))]),e[55]||(e[55]=s("h2",{id:"general",tabindex:"-1"},[t("General "),s("a",{class:"header-anchor",href:"#general","aria-label":'Permalink to "General"'},"​")],-1)),s("details",k,[s("summary",null,[e[9]||(e[9]=s("a",{id:"LuxCore.apply",href:"#LuxCore.apply"},[s("span",{class:"jlbinding"},"LuxCore.apply")],-1)),e[10]||(e[10]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[11]||(e[11]=a('
julia
apply(model, x, ps, st)

In most cases this function simply calls model(x, ps, st). However, it is still recommended to call apply instead of model(x, ps, st) directly. Some of the reasons for this include:

  1. For certain types of inputs x, we might want to perform preprocessing before calling model. For eg, if x is an Array of ReverseDiff.TrackedReals this can cause significant regressions in model(x, ps, st) (since it won't hit any of the BLAS dispatches). In those cases, we would automatically convert x to a ReverseDiff.TrackedArray.

  2. Certain user defined inputs need to be applied to specific layers but we want the datatype of propagate through all the layers (even unsupported ones). In these cases, we can unpack the input in apply and pass it to the appropriate layer and then repack it before returning. See the Lux manual on Custom Input Types for a motivating example.

Tip

apply is integrated with DispatchDoctor.jl that allows automatic verification of type stability. By default this is "disable"d. For more information, see the documentation.

source

',5))]),s("details",g,[s("summary",null,[e[12]||(e[12]=s("a",{id:"LuxCore.stateless_apply",href:"#LuxCore.stateless_apply"},[s("span",{class:"jlbinding"},"LuxCore.stateless_apply")],-1)),e[13]||(e[13]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[14]||(e[14]=a('
julia
stateless_apply(model, x, ps)

Calls apply and only returns the first argument. This function requires that model has an empty state of NamedTuple(). Behavior of other kinds of models are undefined and it is the responsibility of the user to ensure that the model has an empty state.

source

',3))]),s("details",f,[s("summary",null,[e[15]||(e[15]=s("a",{id:"LuxCore.check_fmap_condition",href:"#LuxCore.check_fmap_condition"},[s("span",{class:"jlbinding"},"LuxCore.check_fmap_condition")],-1)),e[16]||(e[16]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[17]||(e[17]=a('
julia
check_fmap_condition(cond, tmatch::Union{Type, Nothing}, x) -> Bool

fmaps into the structure x and see if cond is satisfied for any of the leaf elements.

Arguments

Returns

A Boolean Value

source

',7))]),s("details",b,[s("summary",null,[e[18]||(e[18]=s("a",{id:"LuxCore.contains_lux_layer",href:"#LuxCore.contains_lux_layer"},[s("span",{class:"jlbinding"},"LuxCore.contains_lux_layer")],-1)),e[19]||(e[19]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[20]||(e[20]=a('
julia
contains_lux_layer(l) -> Bool

Check if the structure l is a Lux AbstractLuxLayer or a container of such a layer.

source

',3))]),s("details",y,[s("summary",null,[e[21]||(e[21]=s("a",{id:"LuxCore.display_name",href:"#LuxCore.display_name"},[s("span",{class:"jlbinding"},"LuxCore.display_name")],-1)),e[22]||(e[22]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[23]||(e[23]=a('
julia
display_name(layer::AbstractLuxLayer)

Printed Name of the layer. If the layer has a field name that is used, else the type name is used.

source

',3))]),s("details",m,[s("summary",null,[e[24]||(e[24]=s("a",{id:"LuxCore.replicate",href:"#LuxCore.replicate"},[s("span",{class:"jlbinding"},"LuxCore.replicate")],-1)),e[25]||(e[25]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[26]||(e[26]=a('
julia
replicate(rng::AbstractRNG)

Creates a copy of the rng state depending on its type.

source

',3))]),s("details",L,[s("summary",null,[e[27]||(e[27]=s("a",{id:"LuxCore.setup",href:"#LuxCore.setup"},[s("span",{class:"jlbinding"},"LuxCore.setup")],-1)),e[28]||(e[28]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[29]||(e[29]=a('
julia
setup(rng::AbstractRNG, layer)

Shorthand for getting the parameters and states of the layer l. Is equivalent to (initialparameters(rng, l), initialstates(rng, l)).

Warning

This function is not pure, it mutates rng.

source

',4))]),e[56]||(e[56]=s("h2",{id:"parameters",tabindex:"-1"},[t("Parameters "),s("a",{class:"header-anchor",href:"#parameters","aria-label":'Permalink to "Parameters"'},"​")],-1)),s("details",x,[s("summary",null,[e[30]||(e[30]=s("a",{id:"LuxCore.initialparameters",href:"#LuxCore.initialparameters"},[s("span",{class:"jlbinding"},"LuxCore.initialparameters")],-1)),e[31]||(e[31]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[32]||(e[32]=a('
julia
initialparameters(rng::AbstractRNG, layer)

Generate the initial parameters of the layer l.

source

',3))]),s("details",C,[s("summary",null,[e[33]||(e[33]=s("a",{id:"LuxCore.parameterlength",href:"#LuxCore.parameterlength"},[s("span",{class:"jlbinding"},"LuxCore.parameterlength")],-1)),e[34]||(e[34]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[35]||(e[35]=a('
julia
parameterlength(layer)

Return the total number of parameters of the layer l.

source

',3))]),e[57]||(e[57]=s("h2",{id:"states",tabindex:"-1"},[t("States "),s("a",{class:"header-anchor",href:"#states","aria-label":'Permalink to "States"'},"​")],-1)),s("details",j,[s("summary",null,[e[36]||(e[36]=s("a",{id:"LuxCore.initialstates",href:"#LuxCore.initialstates"},[s("span",{class:"jlbinding"},"LuxCore.initialstates")],-1)),e[37]||(e[37]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[38]||(e[38]=a('
julia
initialstates(rng::AbstractRNG, layer)

Generate the initial states of the layer l.

source

',3))]),s("details",v,[s("summary",null,[e[39]||(e[39]=s("a",{id:"LuxCore.statelength",href:"#LuxCore.statelength"},[s("span",{class:"jlbinding"},"LuxCore.statelength")],-1)),e[40]||(e[40]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[41]||(e[41]=a('
julia
statelength(layer)

Return the total number of states of the layer l.

source

',3))]),s("details",E,[s("summary",null,[e[42]||(e[42]=s("a",{id:"LuxCore.testmode",href:"#LuxCore.testmode"},[s("span",{class:"jlbinding"},"LuxCore.testmode")],-1)),e[43]||(e[43]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[44]||(e[44]=a('
julia
testmode(st::NamedTuple)

Make all occurrences of training in state stVal(false).

source

',3))]),s("details",F,[s("summary",null,[e[45]||(e[45]=s("a",{id:"LuxCore.trainmode",href:"#LuxCore.trainmode"},[s("span",{class:"jlbinding"},"LuxCore.trainmode")],-1)),e[46]||(e[46]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[47]||(e[47]=a('
julia
trainmode(st::NamedTuple)

Make all occurrences of training in state stVal(true).

source

',3))]),s("details",A,[s("summary",null,[e[48]||(e[48]=s("a",{id:"LuxCore.update_state",href:"#LuxCore.update_state"},[s("span",{class:"jlbinding"},"LuxCore.update_state")],-1)),e[49]||(e[49]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[50]||(e[50]=a('
julia
update_state(st::NamedTuple, key::Symbol, value; exclude=Internal.isleaf)

Recursively update all occurrences of the key in the state st with the value. exclude is a function that is passed to Functors.fmap_with_path's exclude keyword.

Needs Functors.jl

This function requires Functors.jl to be loaded.

source

',4))]),e[58]||(e[58]=s("h2",{id:"Layer-size",tabindex:"-1"},[t("Layer size "),s("a",{class:"header-anchor",href:"#Layer-size","aria-label":'Permalink to "Layer size {#Layer-size}"'},"​")],-1)),s("details",B,[s("summary",null,[e[51]||(e[51]=s("a",{id:"LuxCore.outputsize",href:"#LuxCore.outputsize"},[s("span",{class:"jlbinding"},"LuxCore.outputsize")],-1)),e[52]||(e[52]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[53]||(e[53]=a('
julia
outputsize(layer, x, rng)

Return the output size of the layer.

The fallback implementation of this function assumes the inputs were batched, i.e., if any of the outputs are Arrays, with ndims(A) > 1, it will return size(A)[1:(end - 1)]. If this behavior is undesirable, provide a custom outputsize(layer, x, rng) implementation).

Fallback Implementation

The fallback implementation of this function is defined once Lux.jl is loaded.

Changes from Pre-1.0 Behavior

Previously it was possible to override this function by defining outputsize(layer). However, this can potentially introduce a bug that is hard to bypass. See this PR for more information.

source

',6))])])}const z=o(d,[["render",T]]);export{S as __pageData,z as default}; diff --git a/previews/PR1023/assets/api_Building_Blocks_LuxCore.md.CF0jvmvx.lean.js b/previews/PR1023/assets/api_Building_Blocks_LuxCore.md.CF0jvmvx.lean.js new file mode 100644 index 0000000000..2103fdcd2e --- /dev/null +++ b/previews/PR1023/assets/api_Building_Blocks_LuxCore.md.CF0jvmvx.lean.js @@ -0,0 +1 @@ +import{_ as o,c as n,a2 as a,j as s,a as t,G as l,B as r,o as p}from"./chunks/framework.DFwXuivk.js";const S=JSON.parse('{"title":"LuxCore","description":"","frontmatter":{},"headers":[],"relativePath":"api/Building_Blocks/LuxCore.md","filePath":"api/Building_Blocks/LuxCore.md","lastUpdated":null}'),d={name:"api/Building_Blocks/LuxCore.md"},c={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"},h={class:"jldocstring custom-block"},k={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},L={class:"jldocstring custom-block"},x={class:"jldocstring custom-block"},C={class:"jldocstring custom-block"},j={class:"jldocstring custom-block"},v={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},F={class:"jldocstring custom-block"},A={class:"jldocstring custom-block"},B={class:"jldocstring custom-block"};function T(w,e,D,P,R,N){const i=r("Badge");return p(),n("div",null,[e[54]||(e[54]=a('

LuxCore

LuxCore.jl defines the abstract layers for Lux. Allows users to be compatible with the entirely of Lux.jl without having such a heavy dependency. If you are depending on Lux.jl directly, you do not need to depend on LuxCore.jl (all the functionality is exported via Lux.jl).

Abstract Types

',3)),s("details",c,[s("summary",null,[e[0]||(e[0]=s("a",{id:"LuxCore.AbstractLuxLayer",href:"#LuxCore.AbstractLuxLayer"},[s("span",{class:"jlbinding"},"LuxCore.AbstractLuxLayer")],-1)),e[1]||(e[1]=t()),l(i,{type:"info",class:"jlObjectType jlType",text:"Type"})]),e[2]||(e[2]=a('
julia
abstract type AbstractLuxLayer

Abstract Type for all Lux Layers

Users implementing their custom layer, must implement

Optionally:

See also AbstractLuxContainerLayer

source

',8))]),s("details",u,[s("summary",null,[e[3]||(e[3]=s("a",{id:"LuxCore.AbstractLuxWrapperLayer",href:"#LuxCore.AbstractLuxWrapperLayer"},[s("span",{class:"jlbinding"},"LuxCore.AbstractLuxWrapperLayer")],-1)),e[4]||(e[4]=t()),l(i,{type:"info",class:"jlObjectType jlType",text:"Type"})]),e[5]||(e[5]=a('
julia
abstract type AbstractLuxWrapperLayer{layer} <: AbstractLuxLayer

See AbstractLuxContainerLayer for detailed documentation. This abstract type is very similar to AbstractLuxContainerLayer except that it allows for a single layer to be wrapped in a container.

Additionally, on calling initialparameters and initialstates, the parameters and states are not wrapped in a NamedTuple with the same name as the field.

As a convenience, we define the fallback call (::AbstractLuxWrapperLayer)(x, ps, st), which calls getfield(x, layer)(x, ps, st).

source

',5))]),s("details",h,[s("summary",null,[e[6]||(e[6]=s("a",{id:"LuxCore.AbstractLuxContainerLayer",href:"#LuxCore.AbstractLuxContainerLayer"},[s("span",{class:"jlbinding"},"LuxCore.AbstractLuxContainerLayer")],-1)),e[7]||(e[7]=t()),l(i,{type:"info",class:"jlObjectType jlType",text:"Type"})]),e[8]||(e[8]=a('
julia
abstract type AbstractLuxContainerLayer{layers} <: AbstractLuxLayer

Abstract Container Type for certain Lux Layers. layers is a tuple containing fieldnames for the layer, and constructs the parameters and states using those.

Users implementing their custom layer can extend the same functions as in AbstractLuxLayer.

Advanced Structure Manipulation

Advanced structure manipulation of these layers post construction is possible via Functors.fmap. For a more flexible interface, we recommend using Lux.Experimental.@layer_map.

fmap Support

fmap support needs to be explicitly enabled by loading Functors.jl and Setfield.jl.

Changes from Pre-1.0 Behavior

Previously if layers was a singleton tuple, initialparameters and initialstates would return the parameters and states for the single field layers. From v1.0.0 onwards, even for singleton tuples, the parameters/states are wrapped in a NamedTuple with the same name as the field. See AbstractLuxWrapperLayer to replicate the previous behavior of singleton tuples.

source

',7))]),e[55]||(e[55]=s("h2",{id:"general",tabindex:"-1"},[t("General "),s("a",{class:"header-anchor",href:"#general","aria-label":'Permalink to "General"'},"​")],-1)),s("details",k,[s("summary",null,[e[9]||(e[9]=s("a",{id:"LuxCore.apply",href:"#LuxCore.apply"},[s("span",{class:"jlbinding"},"LuxCore.apply")],-1)),e[10]||(e[10]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[11]||(e[11]=a('
julia
apply(model, x, ps, st)

In most cases this function simply calls model(x, ps, st). However, it is still recommended to call apply instead of model(x, ps, st) directly. Some of the reasons for this include:

  1. For certain types of inputs x, we might want to perform preprocessing before calling model. For eg, if x is an Array of ReverseDiff.TrackedReals this can cause significant regressions in model(x, ps, st) (since it won't hit any of the BLAS dispatches). In those cases, we would automatically convert x to a ReverseDiff.TrackedArray.

  2. Certain user defined inputs need to be applied to specific layers but we want the datatype of propagate through all the layers (even unsupported ones). In these cases, we can unpack the input in apply and pass it to the appropriate layer and then repack it before returning. See the Lux manual on Custom Input Types for a motivating example.

Tip

apply is integrated with DispatchDoctor.jl that allows automatic verification of type stability. By default this is "disable"d. For more information, see the documentation.

source

',5))]),s("details",g,[s("summary",null,[e[12]||(e[12]=s("a",{id:"LuxCore.stateless_apply",href:"#LuxCore.stateless_apply"},[s("span",{class:"jlbinding"},"LuxCore.stateless_apply")],-1)),e[13]||(e[13]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[14]||(e[14]=a('
julia
stateless_apply(model, x, ps)

Calls apply and only returns the first argument. This function requires that model has an empty state of NamedTuple(). Behavior of other kinds of models are undefined and it is the responsibility of the user to ensure that the model has an empty state.

source

',3))]),s("details",f,[s("summary",null,[e[15]||(e[15]=s("a",{id:"LuxCore.check_fmap_condition",href:"#LuxCore.check_fmap_condition"},[s("span",{class:"jlbinding"},"LuxCore.check_fmap_condition")],-1)),e[16]||(e[16]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[17]||(e[17]=a('
julia
check_fmap_condition(cond, tmatch::Union{Type, Nothing}, x) -> Bool

fmaps into the structure x and see if cond is satisfied for any of the leaf elements.

Arguments

Returns

A Boolean Value

source

',7))]),s("details",b,[s("summary",null,[e[18]||(e[18]=s("a",{id:"LuxCore.contains_lux_layer",href:"#LuxCore.contains_lux_layer"},[s("span",{class:"jlbinding"},"LuxCore.contains_lux_layer")],-1)),e[19]||(e[19]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[20]||(e[20]=a('
julia
contains_lux_layer(l) -> Bool

Check if the structure l is a Lux AbstractLuxLayer or a container of such a layer.

source

',3))]),s("details",y,[s("summary",null,[e[21]||(e[21]=s("a",{id:"LuxCore.display_name",href:"#LuxCore.display_name"},[s("span",{class:"jlbinding"},"LuxCore.display_name")],-1)),e[22]||(e[22]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[23]||(e[23]=a('
julia
display_name(layer::AbstractLuxLayer)

Printed Name of the layer. If the layer has a field name that is used, else the type name is used.

source

',3))]),s("details",m,[s("summary",null,[e[24]||(e[24]=s("a",{id:"LuxCore.replicate",href:"#LuxCore.replicate"},[s("span",{class:"jlbinding"},"LuxCore.replicate")],-1)),e[25]||(e[25]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[26]||(e[26]=a('
julia
replicate(rng::AbstractRNG)

Creates a copy of the rng state depending on its type.

source

',3))]),s("details",L,[s("summary",null,[e[27]||(e[27]=s("a",{id:"LuxCore.setup",href:"#LuxCore.setup"},[s("span",{class:"jlbinding"},"LuxCore.setup")],-1)),e[28]||(e[28]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[29]||(e[29]=a('
julia
setup(rng::AbstractRNG, layer)

Shorthand for getting the parameters and states of the layer l. Is equivalent to (initialparameters(rng, l), initialstates(rng, l)).

Warning

This function is not pure, it mutates rng.

source

',4))]),e[56]||(e[56]=s("h2",{id:"parameters",tabindex:"-1"},[t("Parameters "),s("a",{class:"header-anchor",href:"#parameters","aria-label":'Permalink to "Parameters"'},"​")],-1)),s("details",x,[s("summary",null,[e[30]||(e[30]=s("a",{id:"LuxCore.initialparameters",href:"#LuxCore.initialparameters"},[s("span",{class:"jlbinding"},"LuxCore.initialparameters")],-1)),e[31]||(e[31]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[32]||(e[32]=a('
julia
initialparameters(rng::AbstractRNG, layer)

Generate the initial parameters of the layer l.

source

',3))]),s("details",C,[s("summary",null,[e[33]||(e[33]=s("a",{id:"LuxCore.parameterlength",href:"#LuxCore.parameterlength"},[s("span",{class:"jlbinding"},"LuxCore.parameterlength")],-1)),e[34]||(e[34]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[35]||(e[35]=a('
julia
parameterlength(layer)

Return the total number of parameters of the layer l.

source

',3))]),e[57]||(e[57]=s("h2",{id:"states",tabindex:"-1"},[t("States "),s("a",{class:"header-anchor",href:"#states","aria-label":'Permalink to "States"'},"​")],-1)),s("details",j,[s("summary",null,[e[36]||(e[36]=s("a",{id:"LuxCore.initialstates",href:"#LuxCore.initialstates"},[s("span",{class:"jlbinding"},"LuxCore.initialstates")],-1)),e[37]||(e[37]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[38]||(e[38]=a('
julia
initialstates(rng::AbstractRNG, layer)

Generate the initial states of the layer l.

source

',3))]),s("details",v,[s("summary",null,[e[39]||(e[39]=s("a",{id:"LuxCore.statelength",href:"#LuxCore.statelength"},[s("span",{class:"jlbinding"},"LuxCore.statelength")],-1)),e[40]||(e[40]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[41]||(e[41]=a('
julia
statelength(layer)

Return the total number of states of the layer l.

source

',3))]),s("details",E,[s("summary",null,[e[42]||(e[42]=s("a",{id:"LuxCore.testmode",href:"#LuxCore.testmode"},[s("span",{class:"jlbinding"},"LuxCore.testmode")],-1)),e[43]||(e[43]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[44]||(e[44]=a('
julia
testmode(st::NamedTuple)

Make all occurrences of training in state stVal(false).

source

',3))]),s("details",F,[s("summary",null,[e[45]||(e[45]=s("a",{id:"LuxCore.trainmode",href:"#LuxCore.trainmode"},[s("span",{class:"jlbinding"},"LuxCore.trainmode")],-1)),e[46]||(e[46]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[47]||(e[47]=a('
julia
trainmode(st::NamedTuple)

Make all occurrences of training in state stVal(true).

source

',3))]),s("details",A,[s("summary",null,[e[48]||(e[48]=s("a",{id:"LuxCore.update_state",href:"#LuxCore.update_state"},[s("span",{class:"jlbinding"},"LuxCore.update_state")],-1)),e[49]||(e[49]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[50]||(e[50]=a('
julia
update_state(st::NamedTuple, key::Symbol, value; exclude=Internal.isleaf)

Recursively update all occurrences of the key in the state st with the value. exclude is a function that is passed to Functors.fmap_with_path's exclude keyword.

Needs Functors.jl

This function requires Functors.jl to be loaded.

source

',4))]),e[58]||(e[58]=s("h2",{id:"Layer-size",tabindex:"-1"},[t("Layer size "),s("a",{class:"header-anchor",href:"#Layer-size","aria-label":'Permalink to "Layer size {#Layer-size}"'},"​")],-1)),s("details",B,[s("summary",null,[e[51]||(e[51]=s("a",{id:"LuxCore.outputsize",href:"#LuxCore.outputsize"},[s("span",{class:"jlbinding"},"LuxCore.outputsize")],-1)),e[52]||(e[52]=t()),l(i,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[53]||(e[53]=a('
julia
outputsize(layer, x, rng)

Return the output size of the layer.

The fallback implementation of this function assumes the inputs were batched, i.e., if any of the outputs are Arrays, with ndims(A) > 1, it will return size(A)[1:(end - 1)]. If this behavior is undesirable, provide a custom outputsize(layer, x, rng) implementation).

Fallback Implementation

The fallback implementation of this function is defined once Lux.jl is loaded.

Changes from Pre-1.0 Behavior

Previously it was possible to override this function by defining outputsize(layer). However, this can potentially introduce a bug that is hard to bypass. See this PR for more information.

source

',6))])])}const z=o(d,[["render",T]]);export{S as __pageData,z as default}; diff --git a/previews/PR1023/assets/api_Building_Blocks_LuxLib.md.DEJmN7Bf.js b/previews/PR1023/assets/api_Building_Blocks_LuxLib.md.DEJmN7Bf.js new file mode 100644 index 0000000000..90493dfafe --- /dev/null +++ b/previews/PR1023/assets/api_Building_Blocks_LuxLib.md.DEJmN7Bf.js @@ -0,0 +1,10 @@ +import{_ as r,c as l,j as t,a as s,G as n,a2 as e,B as d,o}from"./chunks/framework.DFwXuivk.js";const st=JSON.parse('{"title":"LuxLib","description":"","frontmatter":{},"headers":[],"relativePath":"api/Building_Blocks/LuxLib.md","filePath":"api/Building_Blocks/LuxLib.md","lastUpdated":null}'),p={name:"api/Building_Blocks/LuxLib.md"},h={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"},Q={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},k={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},T={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},y={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},x={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.471ex"},xmlns:"http://www.w3.org/2000/svg",width:"25.07ex",height:"2.016ex",role:"img",focusable:"false",viewBox:"0 -683 11080.9 891","aria-hidden":"true"},L={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},E={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},v={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},w={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.281ex",height:"2.034ex",role:"img",focusable:"false",viewBox:"0 -705 566 899","aria-hidden":"true"},F={class:"jldocstring custom-block"},C={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},A={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},j={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},H={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.281ex",height:"2.034ex",role:"img",focusable:"false",viewBox:"0 -705 566 899","aria-hidden":"true"},D={class:"jldocstring custom-block"},M={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},B={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.471ex"},xmlns:"http://www.w3.org/2000/svg",width:"22.72ex",height:"2.016ex",role:"img",focusable:"false",viewBox:"0 -683 10042 891","aria-hidden":"true"},V={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},P={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},I={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},Z={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.281ex",height:"2.034ex",role:"img",focusable:"false",viewBox:"0 -705 566 899","aria-hidden":"true"},z={class:"jldocstring custom-block"},N={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},R={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.294ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 572 453","aria-hidden":"true"},O={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},S={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.76ex"},xmlns:"http://www.w3.org/2000/svg",width:"25.034ex",height:"6.063ex",role:"img",focusable:"false",viewBox:"0 -1460 11064.9 2680","aria-hidden":"true"},G={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},U={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},J={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},q={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.281ex",height:"2.034ex",role:"img",focusable:"false",viewBox:"0 -705 566 899","aria-hidden":"true"},X={class:"jldocstring custom-block"};function K(W,i,$,Y,_,tt){const a=d("Badge");return o(),l("div",null,[i[144]||(i[144]=t("h1",{id:"LuxLib-API",tabindex:"-1"},[s("LuxLib "),t("a",{class:"header-anchor",href:"#LuxLib-API","aria-label":'Permalink to "LuxLib {#LuxLib-API}"'},"​")],-1)),i[145]||(i[145]=t("p",null,"Backend for Lux.jl",-1)),i[146]||(i[146]=t("h2",{id:"Apply-Activation",tabindex:"-1"},[s("Apply Activation "),t("a",{class:"header-anchor",href:"#Apply-Activation","aria-label":'Permalink to "Apply Activation {#Apply-Activation}"'},"​")],-1)),t("details",h,[t("summary",null,[i[0]||(i[0]=t("a",{id:"LuxLib.API.fast_activation",href:"#LuxLib.API.fast_activation"},[t("span",{class:"jlbinding"},"LuxLib.API.fast_activation")],-1)),i[1]||(i[1]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[2]||(i[2]=e('
julia
fast_activation::F, x::AbstractArray) where {F}

Compute σ.(x) with the best possible implementation available. On CPUs we unroll the loop and use LoopVectorization.jl to vectorize the computation. On GPUs we use simply use broadcasting.

Note

This function doesn't replace σ with NNlib.fast_act(σ, ...), that needs to be done by the user if needed.

Arguments

Returns

source

',8))]),t("details",u,[t("summary",null,[i[3]||(i[3]=t("a",{id:"LuxLib.API.fast_activation!!",href:"#LuxLib.API.fast_activation!!"},[t("span",{class:"jlbinding"},"LuxLib.API.fast_activation!!")],-1)),i[4]||(i[4]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[5]||(i[5]=e('
julia
fast_activation!!::F, x::AbstractArray) where {F}

Compute σ.(x) with the best possible implementation available. If it is possible to rewrite x in-place, it does so. If x is an immutable array, it falls back to the generic implementation.

Note

This function doesn't replace σ with NNlib.fast_act(σ, ...), that needs to be done by the user if needed.

Load SLEEFPirates.jl to get faster activations

Certain activation functions are replaced with specialized implementations from SLEEFPirates.jl for FP32. This might lead to faster performance but can cause slight decrease in accuracy (in the floating point limit).

Arguments

Returns

source

',9))]),i[147]||(i[147]=t("h2",{id:"Batched-Operations",tabindex:"-1"},[s("Batched Operations "),t("a",{class:"header-anchor",href:"#Batched-Operations","aria-label":'Permalink to "Batched Operations {#Batched-Operations}"'},"​")],-1)),t("details",Q,[t("summary",null,[i[6]||(i[6]=t("a",{id:"LuxLib.API.batched_matmul",href:"#LuxLib.API.batched_matmul"},[t("span",{class:"jlbinding"},"LuxLib.API.batched_matmul")],-1)),i[7]||(i[7]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[8]||(i[8]=e('
julia
batched_matmul(x, y)

Computes the batched matrix multiplication of x and y. For more details see the NNlib documentation on NNlib.batched_mul. This function is mostly a wrapper around batched_mul but attempts to be faster on CPUs.

Load LoopVectorization.jl to get faster batched matrix multiplication

On CPUs loading LoopVectorization adds faster implementations of batched matrix multiplication.

source

',4))]),i[148]||(i[148]=t("h2",{id:"Bias-Activation",tabindex:"-1"},[s("Bias Activation "),t("a",{class:"header-anchor",href:"#Bias-Activation","aria-label":'Permalink to "Bias Activation {#Bias-Activation}"'},"​")],-1)),t("details",m,[t("summary",null,[i[9]||(i[9]=t("a",{id:"LuxLib.API.bias_activation",href:"#LuxLib.API.bias_activation"},[t("span",{class:"jlbinding"},"LuxLib.API.bias_activation")],-1)),i[10]||(i[10]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[11]||(i[11]=e('
julia
bias_activation(σ, x, bias)

Applies the activation function σ elementwise to the result of broadcasted addition of x and bias along the penultimate dimension. A vector x is treated as a matrix with a single last dimension.

Arguments

See also bias_activation!!, fast_activation.

source

',6))]),t("details",k,[t("summary",null,[i[12]||(i[12]=t("a",{id:"LuxLib.API.bias_activation!!",href:"#LuxLib.API.bias_activation!!"},[t("span",{class:"jlbinding"},"LuxLib.API.bias_activation!!")],-1)),i[13]||(i[13]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[14]||(i[14]=e('
julia
bias_activation!!(σ, x, bias)

Same as bias_activation but might update x in-place if possible. Users should not rely on x being mutated, it is recommended to use it like y = bias_activation!!(σ, x, bias). If x is updated in-place, y aliases x.

See also bias_activation, fast_activation!!.

source

',4))]),i[149]||(i[149]=t("h2",{id:"Convolutional-Layers",tabindex:"-1"},[s("Convolutional Layers "),t("a",{class:"header-anchor",href:"#Convolutional-Layers","aria-label":'Permalink to "Convolutional Layers {#Convolutional-Layers}"'},"​")],-1)),t("details",g,[t("summary",null,[i[15]||(i[15]=t("a",{id:"LuxLib.API.fused_conv_bias_activation",href:"#LuxLib.API.fused_conv_bias_activation"},[t("span",{class:"jlbinding"},"LuxLib.API.fused_conv_bias_activation")],-1)),i[16]||(i[16]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[17]||(i[17]=e(`
julia
fused_conv_bias_activation::F, weight::AbstractArray, x::AbstractArray,
+    b::Optional{<:AbstractVector}, cdims::ConvDims) where {F}

Computes σ.(conv(x, weight, cdims) .+ b) (b is not exactly broadcasted like this, rather it is reshaped and broadcasted to the penultimate dimension) with the best possible implementation available. This operation fuses operations into a single kernel if possible, and minimizes reallocations by reusing the output buffer for multiple operations.

Arguments

Notes on implementation

source

`,7))]),i[150]||(i[150]=t("h2",{id:"dropout",tabindex:"-1"},[s("Dropout "),t("a",{class:"header-anchor",href:"#dropout","aria-label":'Permalink to "Dropout"'},"​")],-1)),t("details",c,[t("summary",null,[i[18]||(i[18]=t("a",{id:"LuxLib.API.alpha_dropout",href:"#LuxLib.API.alpha_dropout"},[t("span",{class:"jlbinding"},"LuxLib.API.alpha_dropout")],-1)),i[19]||(i[19]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[20]||(i[20]=e('
julia
alpha_dropout(rng::AbstractRNG, x, p, training)\nalpha_dropout(rng::AbstractRNG, x, p, training, α, A, B)

Alpha Dropout: Dropout ensuring that the mean and variance of the output remains same as the input. For details see [1]. Use the second call signature to avoid recomputing the constants for a fixed dropout probability.

Arguments

Returns

References

[1] Klambauer, Günter, et al. "Self-normalizing neural networks." Advances in neural information processing systems 30 (2017).

source

',9))]),t("details",T,[t("summary",null,[i[21]||(i[21]=t("a",{id:"LuxLib.API.dropout",href:"#LuxLib.API.dropout"},[t("span",{class:"jlbinding"},"LuxLib.API.dropout")],-1)),i[22]||(i[22]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[23]||(i[23]=e(`
julia
dropout(rng::AbstractRNG, x, p, training, invp, dims)
+dropout(rng::AbstractRNG, x, mask, p, training, update_mask::Union{Val, StaticBool},
+    invp, dims)

Dropout: Simple Way to prevent Neural Networks for Overfitting. For details see [1].

Arguments

Returns

References

[1] Srivastava, Nitish, et al. "Dropout: a simple way to prevent neural networks from overfitting." The journal of machine learning research 15.1 (2014): 1929-1958.

source

`,9))]),i[151]||(i[151]=t("h2",{id:"Fully-Connected-Layers",tabindex:"-1"},[s("Fully Connected Layers "),t("a",{class:"header-anchor",href:"#Fully-Connected-Layers","aria-label":'Permalink to "Fully Connected Layers {#Fully-Connected-Layers}"'},"​")],-1)),t("details",b,[t("summary",null,[i[24]||(i[24]=t("a",{id:"LuxLib.API.fused_dense_bias_activation",href:"#LuxLib.API.fused_dense_bias_activation"},[t("span",{class:"jlbinding"},"LuxLib.API.fused_dense_bias_activation")],-1)),i[25]||(i[25]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[26]||(i[26]=e('
julia
fused_dense_bias_activation::F, weight::AbstractMatrix, x::AbstractMatrix,\n    b::Optional{<:AbstractVector}) where {F}

Compute σ.(weight * x .+ b) with the best possible implementation available. Currently this implementation attempts to minimize reallocations by reusing the output buffer for multiple operations.

Arguments

Notes on implementation

!!! tip "Load Octavian.jl

Loading `Octavian.jl` enables a polyalgorithm that uses different backends based on the\ninput sizes.

source

',9))]),i[152]||(i[152]=t("h2",{id:"normalization",tabindex:"-1"},[s("Normalization "),t("a",{class:"header-anchor",href:"#normalization","aria-label":'Permalink to "Normalization"'},"​")],-1)),t("details",f,[t("summary",null,[i[27]||(i[27]=t("a",{id:"LuxLib.API.batchnorm",href:"#LuxLib.API.batchnorm"},[t("span",{class:"jlbinding"},"LuxLib.API.batchnorm")],-1)),i[28]||(i[28]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[49]||(i[49]=e(`
julia
batchnorm(x, scale, bias, running_mean, running_var, training,
+    σ=identity, momentum = 0.1f0, epsilon = eps(eltype(x)) ^ (5 // 7))

Batch Normalization. For details see [1].

`,2)),t("p",null,[i[31]||(i[31]=s("Batch Normalization computes the mean and variance for each ")),t("mjx-container",y,[(o(),l("svg",x,i[29]||(i[29]=[e('',1)]))),i[30]||(i[30]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"D"),t("mn",null,"1")]),t("mo",null,"×"),t("mo",null,"."),t("mo",null,"."),t("mo",null,"."),t("mo",null,"×"),t("msub",null,[t("mi",null,"D"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"N"),t("mo",null,"−"),t("mn",null,"2")])]),t("mo",null,"×"),t("mn",null,"1"),t("mo",null,"×"),t("msub",null,[t("mi",null,"D"),t("mi",null,"N")])])],-1))]),i[32]||(i[32]=s(" input slice and normalises the input accordingly."))]),i[50]||(i[50]=t("p",null,[t("strong",null,"Arguments")],-1)),t("ul",null,[i[47]||(i[47]=t("li",null,[t("p",null,[t("code",null,"x"),s(": Input to be Normalized")])],-1)),t("li",null,[t("p",null,[i[35]||(i[35]=t("code",null,"scale",-1)),i[36]||(i[36]=s(": Scale factor (")),t("mjx-container",L,[(o(),l("svg",E,i[33]||(i[33]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),i[34]||(i[34]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"γ")])],-1))]),i[37]||(i[37]=s(") (can be ")),i[38]||(i[38]=t("code",null,"nothing",-1)),i[39]||(i[39]=s(")"))])]),t("li",null,[t("p",null,[i[42]||(i[42]=t("code",null,"bias",-1)),i[43]||(i[43]=s(": Bias factor (")),t("mjx-container",v,[(o(),l("svg",w,i[40]||(i[40]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FD",d:"M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z",style:{"stroke-width":"3"}})])])],-1)]))),i[41]||(i[41]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"β")])],-1))]),i[44]||(i[44]=s(") (can be ")),i[45]||(i[45]=t("code",null,"nothing",-1)),i[46]||(i[46]=s(")"))])]),i[48]||(i[48]=e("
  • running_mean: Running mean (can be nothing)

  • running_var: Running variance (can be nothing)

  • training: Set to Val(true) or True() if running in training mode. Can be set to nothing to automatically determine if the function is being called within an autodiff context

  • σ: Activation function (default: identity)

  • momentum: Momentum for updating running mean and variance (default: 0.1f0)

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

  • ",6))]),i[51]||(i[51]=t("p",null,[t("strong",null,"Returns")],-1)),i[52]||(i[52]=t("p",null,[s("Normalized Array of same size as "),t("code",null,"x"),s(". And a Named Tuple containing the updated running mean and variance.")],-1)),i[53]||(i[53]=t("p",null,[t("strong",null,"References")],-1)),i[54]||(i[54]=t("p",null,'[1] Ioffe, Sergey, and Christian Szegedy. "Batch normalization: Accelerating deep network training by reducing internal covariate shift." International conference on machine learning. PMLR, 2015.',-1)),i[55]||(i[55]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/lib/LuxLib/src/api/batchnorm.jl#L1",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",F,[t("summary",null,[i[56]||(i[56]=t("a",{id:"LuxLib.API.groupnorm",href:"#LuxLib.API.groupnorm"},[t("span",{class:"jlbinding"},"LuxLib.API.groupnorm")],-1)),i[57]||(i[57]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[74]||(i[74]=e(`
    julia
    groupnorm(x, scale, bias, groups::Int, σ::F=identity,
    +    epsilon::Real=eps(eltype(x)) ^ (5 // 7))

    Group Normalization. For details see [1].

    This op is similar to batch normalization, but statistics are shared across equally-sized groups of channels and not shared across batch dimension. Thus, group normalization does not depend on the batch composition and does not require maintaining internal state for storing statistics.

    Arguments

    `,4)),t("ul",null,[i[72]||(i[72]=t("li",null,[t("p",null,[t("code",null,"x"),s(": Input to be Normalized")])],-1)),t("li",null,[t("p",null,[i[60]||(i[60]=t("code",null,"scale",-1)),i[61]||(i[61]=s(": Scale factor (")),t("mjx-container",C,[(o(),l("svg",A,i[58]||(i[58]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),i[59]||(i[59]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"γ")])],-1))]),i[62]||(i[62]=s(") (can be ")),i[63]||(i[63]=t("code",null,"nothing",-1)),i[64]||(i[64]=s(")"))])]),t("li",null,[t("p",null,[i[67]||(i[67]=t("code",null,"bias",-1)),i[68]||(i[68]=s(": Bias factor (")),t("mjx-container",j,[(o(),l("svg",H,i[65]||(i[65]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FD",d:"M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z",style:{"stroke-width":"3"}})])])],-1)]))),i[66]||(i[66]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"β")])],-1))]),i[69]||(i[69]=s(") (can be ")),i[70]||(i[70]=t("code",null,"nothing",-1)),i[71]||(i[71]=s(")"))])]),i[73]||(i[73]=e("
  • groups: Number of groups

  • σ: Activation function (default: identity)

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

  • ",3))]),i[75]||(i[75]=t("p",null,[t("strong",null,"Returns")],-1)),i[76]||(i[76]=t("p",null,"The normalized array is returned.",-1)),i[77]||(i[77]=t("p",null,[t("strong",null,"References")],-1)),i[78]||(i[78]=t("p",null,'[1] Wu, Yuxin, and Kaiming He. "Group normalization." Proceedings of the European conference on computer vision (ECCV). 2018.',-1)),i[79]||(i[79]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/lib/LuxLib/src/api/groupnorm.jl#L1",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",D,[t("summary",null,[i[80]||(i[80]=t("a",{id:"LuxLib.API.instancenorm",href:"#LuxLib.API.instancenorm"},[t("span",{class:"jlbinding"},"LuxLib.API.instancenorm")],-1)),i[81]||(i[81]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[102]||(i[102]=e(`
    julia
    instancenorm(x, scale, bias, training, act, epsilon = eps(eltype(x)) ^ (5 // 7))
    +instancenorm(x, scale, bias, running_mean, running_var, training, act, momentum,
    +    epsilon = eps(eltype(x)) ^ (5 // 7))

    Instance Normalization. For details see [1].

    `,2)),t("p",null,[i[84]||(i[84]=s("Instance Normalization computes the mean and variance for each ")),t("mjx-container",M,[(o(),l("svg",B,i[82]||(i[82]=[e('',1)]))),i[83]||(i[83]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"D"),t("mn",null,"1")]),t("mo",null,"×"),t("mo",null,"."),t("mo",null,"."),t("mo",null,"."),t("mo",null,"×"),t("msub",null,[t("mi",null,"D"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"N"),t("mo",null,"−"),t("mn",null,"2")])]),t("mo",null,"×"),t("mn",null,"1"),t("mo",null,"×"),t("mn",null,"1")])],-1))]),i[85]||(i[85]=s(" input slice and normalises the input accordingly."))]),i[103]||(i[103]=t("p",null,[t("strong",null,"Arguments")],-1)),t("ul",null,[i[100]||(i[100]=t("li",null,[t("p",null,[t("code",null,"x"),s(": Input to be Normalized (must be atleast 3D)")])],-1)),t("li",null,[t("p",null,[i[88]||(i[88]=t("code",null,"scale",-1)),i[89]||(i[89]=s(": Scale factor (")),t("mjx-container",V,[(o(),l("svg",P,i[86]||(i[86]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),i[87]||(i[87]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"γ")])],-1))]),i[90]||(i[90]=s(") (can be ")),i[91]||(i[91]=t("code",null,"nothing",-1)),i[92]||(i[92]=s(")"))])]),t("li",null,[t("p",null,[i[95]||(i[95]=t("code",null,"bias",-1)),i[96]||(i[96]=s(": Bias factor (")),t("mjx-container",I,[(o(),l("svg",Z,i[93]||(i[93]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FD",d:"M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z",style:{"stroke-width":"3"}})])])],-1)]))),i[94]||(i[94]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"β")])],-1))]),i[97]||(i[97]=s(") (can be ")),i[98]||(i[98]=t("code",null,"nothing",-1)),i[99]||(i[99]=s(")"))])]),i[101]||(i[101]=e("
  • running_mean: Running mean (can be nothing)

  • running_var: Running variance (can be nothing)

  • training: Set to Val(true) or True() if running in training mode. Can be set to nothing to automatically determine if the function is being called within an autodiff context

  • σ: Activation function (default: identity)

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

  • momentum: Momentum for updating running mean and variance (default: 0.1f0)

  • ",6))]),i[104]||(i[104]=t("p",null,[t("strong",null,"Returns")],-1)),i[105]||(i[105]=t("p",null,[s("Normalized Array of same size as "),t("code",null,"x"),s(". And a Named Tuple containing the updated running mean and variance.")],-1)),i[106]||(i[106]=t("p",null,[t("strong",null,"References")],-1)),i[107]||(i[107]=t("p",null,'[1] Ulyanov, Dmitry, Andrea Vedaldi, and Victor Lempitsky. "Instance normalization: The missing ingredient for fast stylization." arXiv preprint arXiv:1607.08022 (2016).',-1)),i[108]||(i[108]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/lib/LuxLib/src/api/instancenorm.jl#L1",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",z,[t("summary",null,[i[109]||(i[109]=t("a",{id:"LuxLib.API.layernorm",href:"#LuxLib.API.layernorm"},[t("span",{class:"jlbinding"},"LuxLib.API.layernorm")],-1)),i[110]||(i[110]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[133]||(i[133]=e(`
    julia
    layernorm(x::AbstractArray{xT, N}, scale, bias, σ = identity, dims=1:(N - 1),
    +    epsilon = eps(eltype(x)) ^ (5 / 7)) where {xT, N}

    Layer Normalization. For details see [1].

    `,2)),t("p",null,[i[113]||(i[113]=s("Given an input array ")),t("mjx-container",N,[(o(),l("svg",R,i[111]||(i[111]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D465",d:"M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z",style:{"stroke-width":"3"}})])])],-1)]))),i[112]||(i[112]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"x")])],-1))]),i[114]||(i[114]=s(", this layer computes"))]),t("mjx-container",O,[(o(),l("svg",S,i[115]||(i[115]=[e('',1)]))),i[116]||(i[116]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("mi",null,"y"),t("mo",null,"="),t("mfrac",null,[t("mrow",null,[t("mi",null,"x"),t("mo",null,"−"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",{mathvariant:"double-struck"},"E")]),t("mo",{stretchy:"false"},"["),t("mi",null,"x"),t("mo",{stretchy:"false"},"]")]),t("msqrt",null,[t("mi",null,"V"),t("mi",null,"a"),t("mi",null,"r"),t("mo",{stretchy:"false"},"["),t("mi",null,"x"),t("mo",{stretchy:"false"},"]"),t("mo",null,"+"),t("mi",null,"ϵ")])]),t("mo",null,"∗"),t("mi",null,"γ"),t("mo",null,"+"),t("mi",null,"β")])],-1))]),i[134]||(i[134]=t("p",null,[s("and applies the activation function "),t("code",null,"σ"),s(" elementwise to "),t("code",null,"y"),s(".")],-1)),i[135]||(i[135]=t("p",null,[t("strong",null,"Arguments")],-1)),t("ul",null,[i[131]||(i[131]=t("li",null,[t("p",null,[t("code",null,"x"),s(": Input to be Normalized")])],-1)),t("li",null,[t("p",null,[i[119]||(i[119]=t("code",null,"scale",-1)),i[120]||(i[120]=s(": Scale factor (")),t("mjx-container",G,[(o(),l("svg",U,i[117]||(i[117]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),i[118]||(i[118]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"γ")])],-1))]),i[121]||(i[121]=s(") (can be ")),i[122]||(i[122]=t("code",null,"nothing",-1)),i[123]||(i[123]=s(")"))])]),t("li",null,[t("p",null,[i[126]||(i[126]=t("code",null,"bias",-1)),i[127]||(i[127]=s(": Bias factor (")),t("mjx-container",J,[(o(),l("svg",q,i[124]||(i[124]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FD",d:"M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z",style:{"stroke-width":"3"}})])])],-1)]))),i[125]||(i[125]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"β")])],-1))]),i[128]||(i[128]=s(") (can be ")),i[129]||(i[129]=t("code",null,"nothing",-1)),i[130]||(i[130]=s(")"))])]),i[132]||(i[132]=e("
  • σ: Activation function (default: identity)

  • dims: Dimensions along which the mean and std of x is computed. If nothing is passed, the dims are inferred based on the dimensions of scale and bias. For example, if x is N dimensional and scale and bias are M dimensional, then the dims will be 1:(N - M).

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

  • ",3))]),i[136]||(i[136]=t("p",null,[t("strong",null,"Returns")],-1)),i[137]||(i[137]=t("p",null,[s("Normalized Array of same size as "),t("code",null,"x"),s(".")],-1)),i[138]||(i[138]=t("p",null,[t("strong",null,"References")],-1)),i[139]||(i[139]=t("p",null,'[1] Ba, Jimmy Lei, Jamie Ryan Kiros, and Geoffrey E. Hinton. "Layer normalization." arXiv preprint arXiv:1607.06450 (2016).',-1)),i[140]||(i[140]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/lib/LuxLib/src/api/layernorm.jl#L1",target:"_blank",rel:"noreferrer"},"source")],-1))]),i[153]||(i[153]=t("h2",{id:"Helper-Functions",tabindex:"-1"},[s("Helper Functions "),t("a",{class:"header-anchor",href:"#Helper-Functions","aria-label":'Permalink to "Helper Functions {#Helper-Functions}"'},"​")],-1)),t("details",X,[t("summary",null,[i[141]||(i[141]=t("a",{id:"LuxLib.internal_operation_mode",href:"#LuxLib.internal_operation_mode"},[t("span",{class:"jlbinding"},"LuxLib.internal_operation_mode")],-1)),i[142]||(i[142]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[143]||(i[143]=e(`
    julia
    internal_operation_mode(xs::Tuple)
    +internal_operation_mode(x::AbstractArray)

    Returns the internal operation mode for the given array(s). This is useful to define custom implementations using different backends like simple Julia broadcasting, Kernel Abstractions, Loop Vectorization, etc.

    Currently supported modes are:

    source

    `,5))])])}const et=r(p,[["render",K]]);export{st as __pageData,et as default}; diff --git a/previews/PR1023/assets/api_Building_Blocks_LuxLib.md.DEJmN7Bf.lean.js b/previews/PR1023/assets/api_Building_Blocks_LuxLib.md.DEJmN7Bf.lean.js new file mode 100644 index 0000000000..90493dfafe --- /dev/null +++ b/previews/PR1023/assets/api_Building_Blocks_LuxLib.md.DEJmN7Bf.lean.js @@ -0,0 +1,10 @@ +import{_ as r,c as l,j as t,a as s,G as n,a2 as e,B as d,o}from"./chunks/framework.DFwXuivk.js";const st=JSON.parse('{"title":"LuxLib","description":"","frontmatter":{},"headers":[],"relativePath":"api/Building_Blocks/LuxLib.md","filePath":"api/Building_Blocks/LuxLib.md","lastUpdated":null}'),p={name:"api/Building_Blocks/LuxLib.md"},h={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"},Q={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},k={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},T={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},y={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},x={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.471ex"},xmlns:"http://www.w3.org/2000/svg",width:"25.07ex",height:"2.016ex",role:"img",focusable:"false",viewBox:"0 -683 11080.9 891","aria-hidden":"true"},L={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},E={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},v={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},w={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.281ex",height:"2.034ex",role:"img",focusable:"false",viewBox:"0 -705 566 899","aria-hidden":"true"},F={class:"jldocstring custom-block"},C={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},A={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},j={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},H={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.281ex",height:"2.034ex",role:"img",focusable:"false",viewBox:"0 -705 566 899","aria-hidden":"true"},D={class:"jldocstring custom-block"},M={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},B={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.471ex"},xmlns:"http://www.w3.org/2000/svg",width:"22.72ex",height:"2.016ex",role:"img",focusable:"false",viewBox:"0 -683 10042 891","aria-hidden":"true"},V={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},P={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},I={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},Z={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.281ex",height:"2.034ex",role:"img",focusable:"false",viewBox:"0 -705 566 899","aria-hidden":"true"},z={class:"jldocstring custom-block"},N={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},R={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.294ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 572 453","aria-hidden":"true"},O={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},S={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.76ex"},xmlns:"http://www.w3.org/2000/svg",width:"25.034ex",height:"6.063ex",role:"img",focusable:"false",viewBox:"0 -1460 11064.9 2680","aria-hidden":"true"},G={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},U={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},J={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},q={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.281ex",height:"2.034ex",role:"img",focusable:"false",viewBox:"0 -705 566 899","aria-hidden":"true"},X={class:"jldocstring custom-block"};function K(W,i,$,Y,_,tt){const a=d("Badge");return o(),l("div",null,[i[144]||(i[144]=t("h1",{id:"LuxLib-API",tabindex:"-1"},[s("LuxLib "),t("a",{class:"header-anchor",href:"#LuxLib-API","aria-label":'Permalink to "LuxLib {#LuxLib-API}"'},"​")],-1)),i[145]||(i[145]=t("p",null,"Backend for Lux.jl",-1)),i[146]||(i[146]=t("h2",{id:"Apply-Activation",tabindex:"-1"},[s("Apply Activation "),t("a",{class:"header-anchor",href:"#Apply-Activation","aria-label":'Permalink to "Apply Activation {#Apply-Activation}"'},"​")],-1)),t("details",h,[t("summary",null,[i[0]||(i[0]=t("a",{id:"LuxLib.API.fast_activation",href:"#LuxLib.API.fast_activation"},[t("span",{class:"jlbinding"},"LuxLib.API.fast_activation")],-1)),i[1]||(i[1]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[2]||(i[2]=e('
    julia
    fast_activation::F, x::AbstractArray) where {F}

    Compute σ.(x) with the best possible implementation available. On CPUs we unroll the loop and use LoopVectorization.jl to vectorize the computation. On GPUs we use simply use broadcasting.

    Note

    This function doesn't replace σ with NNlib.fast_act(σ, ...), that needs to be done by the user if needed.

    Arguments

    Returns

    source

    ',8))]),t("details",u,[t("summary",null,[i[3]||(i[3]=t("a",{id:"LuxLib.API.fast_activation!!",href:"#LuxLib.API.fast_activation!!"},[t("span",{class:"jlbinding"},"LuxLib.API.fast_activation!!")],-1)),i[4]||(i[4]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[5]||(i[5]=e('
    julia
    fast_activation!!::F, x::AbstractArray) where {F}

    Compute σ.(x) with the best possible implementation available. If it is possible to rewrite x in-place, it does so. If x is an immutable array, it falls back to the generic implementation.

    Note

    This function doesn't replace σ with NNlib.fast_act(σ, ...), that needs to be done by the user if needed.

    Load SLEEFPirates.jl to get faster activations

    Certain activation functions are replaced with specialized implementations from SLEEFPirates.jl for FP32. This might lead to faster performance but can cause slight decrease in accuracy (in the floating point limit).

    Arguments

    Returns

    source

    ',9))]),i[147]||(i[147]=t("h2",{id:"Batched-Operations",tabindex:"-1"},[s("Batched Operations "),t("a",{class:"header-anchor",href:"#Batched-Operations","aria-label":'Permalink to "Batched Operations {#Batched-Operations}"'},"​")],-1)),t("details",Q,[t("summary",null,[i[6]||(i[6]=t("a",{id:"LuxLib.API.batched_matmul",href:"#LuxLib.API.batched_matmul"},[t("span",{class:"jlbinding"},"LuxLib.API.batched_matmul")],-1)),i[7]||(i[7]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[8]||(i[8]=e('
    julia
    batched_matmul(x, y)

    Computes the batched matrix multiplication of x and y. For more details see the NNlib documentation on NNlib.batched_mul. This function is mostly a wrapper around batched_mul but attempts to be faster on CPUs.

    Load LoopVectorization.jl to get faster batched matrix multiplication

    On CPUs loading LoopVectorization adds faster implementations of batched matrix multiplication.

    source

    ',4))]),i[148]||(i[148]=t("h2",{id:"Bias-Activation",tabindex:"-1"},[s("Bias Activation "),t("a",{class:"header-anchor",href:"#Bias-Activation","aria-label":'Permalink to "Bias Activation {#Bias-Activation}"'},"​")],-1)),t("details",m,[t("summary",null,[i[9]||(i[9]=t("a",{id:"LuxLib.API.bias_activation",href:"#LuxLib.API.bias_activation"},[t("span",{class:"jlbinding"},"LuxLib.API.bias_activation")],-1)),i[10]||(i[10]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[11]||(i[11]=e('
    julia
    bias_activation(σ, x, bias)

    Applies the activation function σ elementwise to the result of broadcasted addition of x and bias along the penultimate dimension. A vector x is treated as a matrix with a single last dimension.

    Arguments

    See also bias_activation!!, fast_activation.

    source

    ',6))]),t("details",k,[t("summary",null,[i[12]||(i[12]=t("a",{id:"LuxLib.API.bias_activation!!",href:"#LuxLib.API.bias_activation!!"},[t("span",{class:"jlbinding"},"LuxLib.API.bias_activation!!")],-1)),i[13]||(i[13]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[14]||(i[14]=e('
    julia
    bias_activation!!(σ, x, bias)

    Same as bias_activation but might update x in-place if possible. Users should not rely on x being mutated, it is recommended to use it like y = bias_activation!!(σ, x, bias). If x is updated in-place, y aliases x.

    See also bias_activation, fast_activation!!.

    source

    ',4))]),i[149]||(i[149]=t("h2",{id:"Convolutional-Layers",tabindex:"-1"},[s("Convolutional Layers "),t("a",{class:"header-anchor",href:"#Convolutional-Layers","aria-label":'Permalink to "Convolutional Layers {#Convolutional-Layers}"'},"​")],-1)),t("details",g,[t("summary",null,[i[15]||(i[15]=t("a",{id:"LuxLib.API.fused_conv_bias_activation",href:"#LuxLib.API.fused_conv_bias_activation"},[t("span",{class:"jlbinding"},"LuxLib.API.fused_conv_bias_activation")],-1)),i[16]||(i[16]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[17]||(i[17]=e(`
    julia
    fused_conv_bias_activation::F, weight::AbstractArray, x::AbstractArray,
    +    b::Optional{<:AbstractVector}, cdims::ConvDims) where {F}

    Computes σ.(conv(x, weight, cdims) .+ b) (b is not exactly broadcasted like this, rather it is reshaped and broadcasted to the penultimate dimension) with the best possible implementation available. This operation fuses operations into a single kernel if possible, and minimizes reallocations by reusing the output buffer for multiple operations.

    Arguments

    Notes on implementation

    source

    `,7))]),i[150]||(i[150]=t("h2",{id:"dropout",tabindex:"-1"},[s("Dropout "),t("a",{class:"header-anchor",href:"#dropout","aria-label":'Permalink to "Dropout"'},"​")],-1)),t("details",c,[t("summary",null,[i[18]||(i[18]=t("a",{id:"LuxLib.API.alpha_dropout",href:"#LuxLib.API.alpha_dropout"},[t("span",{class:"jlbinding"},"LuxLib.API.alpha_dropout")],-1)),i[19]||(i[19]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[20]||(i[20]=e('
    julia
    alpha_dropout(rng::AbstractRNG, x, p, training)\nalpha_dropout(rng::AbstractRNG, x, p, training, α, A, B)

    Alpha Dropout: Dropout ensuring that the mean and variance of the output remains same as the input. For details see [1]. Use the second call signature to avoid recomputing the constants for a fixed dropout probability.

    Arguments

    Returns

    References

    [1] Klambauer, Günter, et al. "Self-normalizing neural networks." Advances in neural information processing systems 30 (2017).

    source

    ',9))]),t("details",T,[t("summary",null,[i[21]||(i[21]=t("a",{id:"LuxLib.API.dropout",href:"#LuxLib.API.dropout"},[t("span",{class:"jlbinding"},"LuxLib.API.dropout")],-1)),i[22]||(i[22]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[23]||(i[23]=e(`
    julia
    dropout(rng::AbstractRNG, x, p, training, invp, dims)
    +dropout(rng::AbstractRNG, x, mask, p, training, update_mask::Union{Val, StaticBool},
    +    invp, dims)

    Dropout: Simple Way to prevent Neural Networks for Overfitting. For details see [1].

    Arguments

    Returns

    References

    [1] Srivastava, Nitish, et al. "Dropout: a simple way to prevent neural networks from overfitting." The journal of machine learning research 15.1 (2014): 1929-1958.

    source

    `,9))]),i[151]||(i[151]=t("h2",{id:"Fully-Connected-Layers",tabindex:"-1"},[s("Fully Connected Layers "),t("a",{class:"header-anchor",href:"#Fully-Connected-Layers","aria-label":'Permalink to "Fully Connected Layers {#Fully-Connected-Layers}"'},"​")],-1)),t("details",b,[t("summary",null,[i[24]||(i[24]=t("a",{id:"LuxLib.API.fused_dense_bias_activation",href:"#LuxLib.API.fused_dense_bias_activation"},[t("span",{class:"jlbinding"},"LuxLib.API.fused_dense_bias_activation")],-1)),i[25]||(i[25]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[26]||(i[26]=e('
    julia
    fused_dense_bias_activation::F, weight::AbstractMatrix, x::AbstractMatrix,\n    b::Optional{<:AbstractVector}) where {F}

    Compute σ.(weight * x .+ b) with the best possible implementation available. Currently this implementation attempts to minimize reallocations by reusing the output buffer for multiple operations.

    Arguments

    Notes on implementation

    !!! tip "Load Octavian.jl

    Loading `Octavian.jl` enables a polyalgorithm that uses different backends based on the\ninput sizes.

    source

    ',9))]),i[152]||(i[152]=t("h2",{id:"normalization",tabindex:"-1"},[s("Normalization "),t("a",{class:"header-anchor",href:"#normalization","aria-label":'Permalink to "Normalization"'},"​")],-1)),t("details",f,[t("summary",null,[i[27]||(i[27]=t("a",{id:"LuxLib.API.batchnorm",href:"#LuxLib.API.batchnorm"},[t("span",{class:"jlbinding"},"LuxLib.API.batchnorm")],-1)),i[28]||(i[28]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[49]||(i[49]=e(`
    julia
    batchnorm(x, scale, bias, running_mean, running_var, training,
    +    σ=identity, momentum = 0.1f0, epsilon = eps(eltype(x)) ^ (5 // 7))

    Batch Normalization. For details see [1].

    `,2)),t("p",null,[i[31]||(i[31]=s("Batch Normalization computes the mean and variance for each ")),t("mjx-container",y,[(o(),l("svg",x,i[29]||(i[29]=[e('',1)]))),i[30]||(i[30]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"D"),t("mn",null,"1")]),t("mo",null,"×"),t("mo",null,"."),t("mo",null,"."),t("mo",null,"."),t("mo",null,"×"),t("msub",null,[t("mi",null,"D"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"N"),t("mo",null,"−"),t("mn",null,"2")])]),t("mo",null,"×"),t("mn",null,"1"),t("mo",null,"×"),t("msub",null,[t("mi",null,"D"),t("mi",null,"N")])])],-1))]),i[32]||(i[32]=s(" input slice and normalises the input accordingly."))]),i[50]||(i[50]=t("p",null,[t("strong",null,"Arguments")],-1)),t("ul",null,[i[47]||(i[47]=t("li",null,[t("p",null,[t("code",null,"x"),s(": Input to be Normalized")])],-1)),t("li",null,[t("p",null,[i[35]||(i[35]=t("code",null,"scale",-1)),i[36]||(i[36]=s(": Scale factor (")),t("mjx-container",L,[(o(),l("svg",E,i[33]||(i[33]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),i[34]||(i[34]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"γ")])],-1))]),i[37]||(i[37]=s(") (can be ")),i[38]||(i[38]=t("code",null,"nothing",-1)),i[39]||(i[39]=s(")"))])]),t("li",null,[t("p",null,[i[42]||(i[42]=t("code",null,"bias",-1)),i[43]||(i[43]=s(": Bias factor (")),t("mjx-container",v,[(o(),l("svg",w,i[40]||(i[40]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FD",d:"M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z",style:{"stroke-width":"3"}})])])],-1)]))),i[41]||(i[41]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"β")])],-1))]),i[44]||(i[44]=s(") (can be ")),i[45]||(i[45]=t("code",null,"nothing",-1)),i[46]||(i[46]=s(")"))])]),i[48]||(i[48]=e("
  • running_mean: Running mean (can be nothing)

  • running_var: Running variance (can be nothing)

  • training: Set to Val(true) or True() if running in training mode. Can be set to nothing to automatically determine if the function is being called within an autodiff context

  • σ: Activation function (default: identity)

  • momentum: Momentum for updating running mean and variance (default: 0.1f0)

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

  • ",6))]),i[51]||(i[51]=t("p",null,[t("strong",null,"Returns")],-1)),i[52]||(i[52]=t("p",null,[s("Normalized Array of same size as "),t("code",null,"x"),s(". And a Named Tuple containing the updated running mean and variance.")],-1)),i[53]||(i[53]=t("p",null,[t("strong",null,"References")],-1)),i[54]||(i[54]=t("p",null,'[1] Ioffe, Sergey, and Christian Szegedy. "Batch normalization: Accelerating deep network training by reducing internal covariate shift." International conference on machine learning. PMLR, 2015.',-1)),i[55]||(i[55]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/lib/LuxLib/src/api/batchnorm.jl#L1",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",F,[t("summary",null,[i[56]||(i[56]=t("a",{id:"LuxLib.API.groupnorm",href:"#LuxLib.API.groupnorm"},[t("span",{class:"jlbinding"},"LuxLib.API.groupnorm")],-1)),i[57]||(i[57]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[74]||(i[74]=e(`
    julia
    groupnorm(x, scale, bias, groups::Int, σ::F=identity,
    +    epsilon::Real=eps(eltype(x)) ^ (5 // 7))

    Group Normalization. For details see [1].

    This op is similar to batch normalization, but statistics are shared across equally-sized groups of channels and not shared across batch dimension. Thus, group normalization does not depend on the batch composition and does not require maintaining internal state for storing statistics.

    Arguments

    `,4)),t("ul",null,[i[72]||(i[72]=t("li",null,[t("p",null,[t("code",null,"x"),s(": Input to be Normalized")])],-1)),t("li",null,[t("p",null,[i[60]||(i[60]=t("code",null,"scale",-1)),i[61]||(i[61]=s(": Scale factor (")),t("mjx-container",C,[(o(),l("svg",A,i[58]||(i[58]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),i[59]||(i[59]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"γ")])],-1))]),i[62]||(i[62]=s(") (can be ")),i[63]||(i[63]=t("code",null,"nothing",-1)),i[64]||(i[64]=s(")"))])]),t("li",null,[t("p",null,[i[67]||(i[67]=t("code",null,"bias",-1)),i[68]||(i[68]=s(": Bias factor (")),t("mjx-container",j,[(o(),l("svg",H,i[65]||(i[65]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FD",d:"M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z",style:{"stroke-width":"3"}})])])],-1)]))),i[66]||(i[66]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"β")])],-1))]),i[69]||(i[69]=s(") (can be ")),i[70]||(i[70]=t("code",null,"nothing",-1)),i[71]||(i[71]=s(")"))])]),i[73]||(i[73]=e("
  • groups: Number of groups

  • σ: Activation function (default: identity)

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

  • ",3))]),i[75]||(i[75]=t("p",null,[t("strong",null,"Returns")],-1)),i[76]||(i[76]=t("p",null,"The normalized array is returned.",-1)),i[77]||(i[77]=t("p",null,[t("strong",null,"References")],-1)),i[78]||(i[78]=t("p",null,'[1] Wu, Yuxin, and Kaiming He. "Group normalization." Proceedings of the European conference on computer vision (ECCV). 2018.',-1)),i[79]||(i[79]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/lib/LuxLib/src/api/groupnorm.jl#L1",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",D,[t("summary",null,[i[80]||(i[80]=t("a",{id:"LuxLib.API.instancenorm",href:"#LuxLib.API.instancenorm"},[t("span",{class:"jlbinding"},"LuxLib.API.instancenorm")],-1)),i[81]||(i[81]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[102]||(i[102]=e(`
    julia
    instancenorm(x, scale, bias, training, act, epsilon = eps(eltype(x)) ^ (5 // 7))
    +instancenorm(x, scale, bias, running_mean, running_var, training, act, momentum,
    +    epsilon = eps(eltype(x)) ^ (5 // 7))

    Instance Normalization. For details see [1].

    `,2)),t("p",null,[i[84]||(i[84]=s("Instance Normalization computes the mean and variance for each ")),t("mjx-container",M,[(o(),l("svg",B,i[82]||(i[82]=[e('',1)]))),i[83]||(i[83]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"D"),t("mn",null,"1")]),t("mo",null,"×"),t("mo",null,"."),t("mo",null,"."),t("mo",null,"."),t("mo",null,"×"),t("msub",null,[t("mi",null,"D"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"N"),t("mo",null,"−"),t("mn",null,"2")])]),t("mo",null,"×"),t("mn",null,"1"),t("mo",null,"×"),t("mn",null,"1")])],-1))]),i[85]||(i[85]=s(" input slice and normalises the input accordingly."))]),i[103]||(i[103]=t("p",null,[t("strong",null,"Arguments")],-1)),t("ul",null,[i[100]||(i[100]=t("li",null,[t("p",null,[t("code",null,"x"),s(": Input to be Normalized (must be atleast 3D)")])],-1)),t("li",null,[t("p",null,[i[88]||(i[88]=t("code",null,"scale",-1)),i[89]||(i[89]=s(": Scale factor (")),t("mjx-container",V,[(o(),l("svg",P,i[86]||(i[86]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),i[87]||(i[87]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"γ")])],-1))]),i[90]||(i[90]=s(") (can be ")),i[91]||(i[91]=t("code",null,"nothing",-1)),i[92]||(i[92]=s(")"))])]),t("li",null,[t("p",null,[i[95]||(i[95]=t("code",null,"bias",-1)),i[96]||(i[96]=s(": Bias factor (")),t("mjx-container",I,[(o(),l("svg",Z,i[93]||(i[93]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FD",d:"M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z",style:{"stroke-width":"3"}})])])],-1)]))),i[94]||(i[94]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"β")])],-1))]),i[97]||(i[97]=s(") (can be ")),i[98]||(i[98]=t("code",null,"nothing",-1)),i[99]||(i[99]=s(")"))])]),i[101]||(i[101]=e("
  • running_mean: Running mean (can be nothing)

  • running_var: Running variance (can be nothing)

  • training: Set to Val(true) or True() if running in training mode. Can be set to nothing to automatically determine if the function is being called within an autodiff context

  • σ: Activation function (default: identity)

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

  • momentum: Momentum for updating running mean and variance (default: 0.1f0)

  • ",6))]),i[104]||(i[104]=t("p",null,[t("strong",null,"Returns")],-1)),i[105]||(i[105]=t("p",null,[s("Normalized Array of same size as "),t("code",null,"x"),s(". And a Named Tuple containing the updated running mean and variance.")],-1)),i[106]||(i[106]=t("p",null,[t("strong",null,"References")],-1)),i[107]||(i[107]=t("p",null,'[1] Ulyanov, Dmitry, Andrea Vedaldi, and Victor Lempitsky. "Instance normalization: The missing ingredient for fast stylization." arXiv preprint arXiv:1607.08022 (2016).',-1)),i[108]||(i[108]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/lib/LuxLib/src/api/instancenorm.jl#L1",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",z,[t("summary",null,[i[109]||(i[109]=t("a",{id:"LuxLib.API.layernorm",href:"#LuxLib.API.layernorm"},[t("span",{class:"jlbinding"},"LuxLib.API.layernorm")],-1)),i[110]||(i[110]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[133]||(i[133]=e(`
    julia
    layernorm(x::AbstractArray{xT, N}, scale, bias, σ = identity, dims=1:(N - 1),
    +    epsilon = eps(eltype(x)) ^ (5 / 7)) where {xT, N}

    Layer Normalization. For details see [1].

    `,2)),t("p",null,[i[113]||(i[113]=s("Given an input array ")),t("mjx-container",N,[(o(),l("svg",R,i[111]||(i[111]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D465",d:"M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z",style:{"stroke-width":"3"}})])])],-1)]))),i[112]||(i[112]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"x")])],-1))]),i[114]||(i[114]=s(", this layer computes"))]),t("mjx-container",O,[(o(),l("svg",S,i[115]||(i[115]=[e('',1)]))),i[116]||(i[116]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("mi",null,"y"),t("mo",null,"="),t("mfrac",null,[t("mrow",null,[t("mi",null,"x"),t("mo",null,"−"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",{mathvariant:"double-struck"},"E")]),t("mo",{stretchy:"false"},"["),t("mi",null,"x"),t("mo",{stretchy:"false"},"]")]),t("msqrt",null,[t("mi",null,"V"),t("mi",null,"a"),t("mi",null,"r"),t("mo",{stretchy:"false"},"["),t("mi",null,"x"),t("mo",{stretchy:"false"},"]"),t("mo",null,"+"),t("mi",null,"ϵ")])]),t("mo",null,"∗"),t("mi",null,"γ"),t("mo",null,"+"),t("mi",null,"β")])],-1))]),i[134]||(i[134]=t("p",null,[s("and applies the activation function "),t("code",null,"σ"),s(" elementwise to "),t("code",null,"y"),s(".")],-1)),i[135]||(i[135]=t("p",null,[t("strong",null,"Arguments")],-1)),t("ul",null,[i[131]||(i[131]=t("li",null,[t("p",null,[t("code",null,"x"),s(": Input to be Normalized")])],-1)),t("li",null,[t("p",null,[i[119]||(i[119]=t("code",null,"scale",-1)),i[120]||(i[120]=s(": Scale factor (")),t("mjx-container",G,[(o(),l("svg",U,i[117]||(i[117]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),i[118]||(i[118]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"γ")])],-1))]),i[121]||(i[121]=s(") (can be ")),i[122]||(i[122]=t("code",null,"nothing",-1)),i[123]||(i[123]=s(")"))])]),t("li",null,[t("p",null,[i[126]||(i[126]=t("code",null,"bias",-1)),i[127]||(i[127]=s(": Bias factor (")),t("mjx-container",J,[(o(),l("svg",q,i[124]||(i[124]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FD",d:"M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z",style:{"stroke-width":"3"}})])])],-1)]))),i[125]||(i[125]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"β")])],-1))]),i[128]||(i[128]=s(") (can be ")),i[129]||(i[129]=t("code",null,"nothing",-1)),i[130]||(i[130]=s(")"))])]),i[132]||(i[132]=e("
  • σ: Activation function (default: identity)

  • dims: Dimensions along which the mean and std of x is computed. If nothing is passed, the dims are inferred based on the dimensions of scale and bias. For example, if x is N dimensional and scale and bias are M dimensional, then the dims will be 1:(N - M).

  • epsilon: Value added to the denominator for numerical stability (default: eps(eltype(x)) ^ (5 / 7))

  • ",3))]),i[136]||(i[136]=t("p",null,[t("strong",null,"Returns")],-1)),i[137]||(i[137]=t("p",null,[s("Normalized Array of same size as "),t("code",null,"x"),s(".")],-1)),i[138]||(i[138]=t("p",null,[t("strong",null,"References")],-1)),i[139]||(i[139]=t("p",null,'[1] Ba, Jimmy Lei, Jamie Ryan Kiros, and Geoffrey E. Hinton. "Layer normalization." arXiv preprint arXiv:1607.06450 (2016).',-1)),i[140]||(i[140]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/lib/LuxLib/src/api/layernorm.jl#L1",target:"_blank",rel:"noreferrer"},"source")],-1))]),i[153]||(i[153]=t("h2",{id:"Helper-Functions",tabindex:"-1"},[s("Helper Functions "),t("a",{class:"header-anchor",href:"#Helper-Functions","aria-label":'Permalink to "Helper Functions {#Helper-Functions}"'},"​")],-1)),t("details",X,[t("summary",null,[i[141]||(i[141]=t("a",{id:"LuxLib.internal_operation_mode",href:"#LuxLib.internal_operation_mode"},[t("span",{class:"jlbinding"},"LuxLib.internal_operation_mode")],-1)),i[142]||(i[142]=s()),n(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[143]||(i[143]=e(`
    julia
    internal_operation_mode(xs::Tuple)
    +internal_operation_mode(x::AbstractArray)

    Returns the internal operation mode for the given array(s). This is useful to define custom implementations using different backends like simple Julia broadcasting, Kernel Abstractions, Loop Vectorization, etc.

    Currently supported modes are:

    source

    `,5))])])}const et=r(p,[["render",K]]);export{st as __pageData,et as default}; diff --git a/previews/PR1023/assets/api_Building_Blocks_WeightInitializers.md.YK6sT70z.js b/previews/PR1023/assets/api_Building_Blocks_WeightInitializers.md.YK6sT70z.js new file mode 100644 index 0000000000..53f79bf307 --- /dev/null +++ b/previews/PR1023/assets/api_Building_Blocks_WeightInitializers.md.YK6sT70z.js @@ -0,0 +1,52 @@ +import{_ as r,c as e,a2 as t,j as s,a,G as l,B as p,o as h}from"./chunks/framework.DFwXuivk.js";const Y=JSON.parse('{"title":"WeightInitializers","description":"","frontmatter":{},"headers":[],"relativePath":"api/Building_Blocks/WeightInitializers.md","filePath":"api/Building_Blocks/WeightInitializers.md","lastUpdated":null}'),k={name:"api/Building_Blocks/WeightInitializers.md"},d={class:"jldocstring custom-block"},o={class:"jldocstring custom-block"},g={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},E={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"6.612ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 2922.7 1000","aria-hidden":"true"},y={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"},F={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},C={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},A={class:"jldocstring custom-block"},z={class:"jldocstring custom-block"},j={class:"jldocstring custom-block"},D={class:"jldocstring custom-block"},v={class:"jldocstring custom-block"},x={class:"jldocstring custom-block"},B={class:"jldocstring custom-block"},I={class:"jldocstring custom-block"},L={class:"jldocstring custom-block"},T={class:"jldocstring custom-block"},W={class:"jldocstring custom-block"},R={class:"jldocstring custom-block"},w={class:"jldocstring custom-block"},Q={class:"jldocstring custom-block"},N={class:"jldocstring custom-block"},G={class:"jldocstring custom-block"},U={class:"jldocstring custom-block"},O={class:"jldocstring custom-block"},P={class:"jldocstring custom-block"},M={class:"jldocstring custom-block"},q={class:"jldocstring custom-block"},H={class:"jldocstring custom-block"};function V(S,i,X,Z,$,J){const n=p("Badge");return h(),e("div",null,[i[109]||(i[109]=t('

    WeightInitializers

    This package is a light dependency providing common weight initialization schemes for deep learning models.

    Supported RNG Types

    RNG Type / PackageReturned Array TypeUnsupported Functions
    Random.jlArray
    StableRNGs.jlArray
    CUDA.default_rng()CuArray
    GPUArrays.default_rng(CuArray)CuArray
    AMDGPU.rocrand_rng()ROCArray
    AMDGPU.gpuarrays_rng()ROCArray
    GPUArrays.default_rng(ROCArray)ROCArray
    Metal.gpuarrays_rng()MtlArrayorthogonal
    GPUArrays.default_rng(MtlArray)MtlArrayorthogonal
    oneAPI.gpuarrays_rng()oneArrayorthogonal, truncated_normal
    GPUArrays.default_rng(oneArray)oneArrayorthogonal, truncated_normal

    API Reference

    Main Functions

    ',6)),s("details",d,[s("summary",null,[i[0]||(i[0]=s("a",{id:"WeightInitializers.glorot_normal",href:"#WeightInitializers.glorot_normal"},[s("span",{class:"jlbinding"},"WeightInitializers.glorot_normal")],-1)),i[1]||(i[1]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[2]||(i[2]=t(`
    julia
    glorot_normal([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
    +    gain = 1) -> AbstractArray{T, length(size)}

    Return an AbstractArray{T} of the given size containing random numbers drawn from a normal distribution with standard deviation gain * sqrt(2 / (fan_in + fan_out)). This method is described in [1] and also known as Xavier initialization.

    References

    [1] Glorot, Xavier, and Yoshua Bengio. "Understanding the difficulty of training deep feedforward neural networks." Proceedings of the thirteenth international conference on artificial intelligence and statistics. 2010.

    source

    `,5))]),s("details",o,[s("summary",null,[i[3]||(i[3]=s("a",{id:"WeightInitializers.glorot_uniform",href:"#WeightInitializers.glorot_uniform"},[s("span",{class:"jlbinding"},"WeightInitializers.glorot_uniform")],-1)),i[4]||(i[4]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[15]||(i[15]=t(`
    julia
    glorot_uniform([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
    +    gain = 1) -> AbstractArray{T, length(size)}
    `,1)),s("p",null,[i[7]||(i[7]=a("Return an ")),i[8]||(i[8]=s("code",null,"AbstractArray{T}",-1)),i[9]||(i[9]=a(" of the given ")),i[10]||(i[10]=s("code",null,"size",-1)),i[11]||(i[11]=a(" containing random numbers drawn from a uniform distribution on the interval ")),s("mjx-container",g,[(h(),e("svg",E,i[5]||(i[5]=[t('',1)]))),i[6]||(i[6]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mo",{stretchy:"false"},"["),s("mo",null,"−"),s("mi",null,"x"),s("mo",null,","),s("mi",null,"x"),s("mo",{stretchy:"false"},"]")])],-1))]),i[12]||(i[12]=a(", where ")),i[13]||(i[13]=s("code",null,"x = gain * sqrt(6 / (fan_in + fan_out))",-1)),i[14]||(i[14]=a(". This method is described in [1] and also known as Xavier initialization."))]),i[16]||(i[16]=s("p",null,[s("strong",null,"References")],-1)),i[17]||(i[17]=s("p",null,[a('[1] Glorot, Xavier, and Yoshua Bengio. "Understanding the difficulty of training deep feedforward neural networks." '),s("em",null,"Proceedings of the thirteenth international conference on artificial intelligence and statistics"),a(". 2010.")],-1)),i[18]||(i[18]=s("p",null,[s("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/lib/WeightInitializers/src/initializers.jl#L13-L27",target:"_blank",rel:"noreferrer"},"source")],-1))]),s("details",y,[s("summary",null,[i[19]||(i[19]=s("a",{id:"WeightInitializers.identity_init",href:"#WeightInitializers.identity_init"},[s("span",{class:"jlbinding"},"WeightInitializers.identity_init")],-1)),i[20]||(i[20]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[21]||(i[21]=t(`
    julia
    identity_init([::AbstractRNG=Utils.default_rng()], [T=Float32], size...; gain::Number=1,
    +    shift::Union{Integer, Tuple{Integer, Integer}}=0) -> AbstractArray{T}

    Constructs an array that aims to provide an identity mapping when used as parameters in most layers of a neural network. The identity mapping is scaled by the gain parameter.

    Behavior

    Caveats

    Arguments

    Returns

    Examples

    julia
    julia> identity_init(Xoshiro(123), Float32, 5, 5)
    +5×5 Matrix{Float32}:
    + 1.0  1.0  1.0  1.0  1.0
    + 1.0  1.0  1.0  1.0  1.0
    + 1.0  1.0  1.0  1.0  1.0
    + 1.0  1.0  1.0  1.0  1.0
    + 1.0  1.0  1.0  1.0  1.0
    +
    +julia> identity_init(Xoshiro(123), Float32, 3, 3, 1, 1; gain=1.5)
    +3×3×1×1 Array{Float32, 4}:
    +[:, :, 1, 1] =
    + 0.0  0.0  0.0
    + 0.0  1.5  0.0
    + 0.0  0.0  0.0

    source

    `,13))]),s("details",c,[s("summary",null,[i[22]||(i[22]=s("a",{id:"WeightInitializers.kaiming_normal",href:"#WeightInitializers.kaiming_normal"},[s("span",{class:"jlbinding"},"WeightInitializers.kaiming_normal")],-1)),i[23]||(i[23]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[24]||(i[24]=t(`
    julia
    kaiming_normal([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
    +    gain =T(2)) -> AbstractArray{T, length(size)}

    Return an AbstractArray{T} of the given size containing random numbers taken from a normal distribution standard deviation gain / sqrt(fan_in)

    References

    [1] He, Kaiming, et al. "Delving deep into rectifiers: Surpassing human-level performance on imagenet classification." Proceedings of the IEEE international conference on computer vision. 2015.

    source

    `,5))]),s("details",u,[s("summary",null,[i[25]||(i[25]=s("a",{id:"WeightInitializers.kaiming_uniform",href:"#WeightInitializers.kaiming_uniform"},[s("span",{class:"jlbinding"},"WeightInitializers.kaiming_uniform")],-1)),i[26]||(i[26]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[27]||(i[27]=t(`
    julia
    kaiming_uniform([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
    +    gain =T(2)) -> AbstractArray{T, length(size)}

    Return an AbstractArray{T} of the given size containing random numbers drawn from a uniform distribution on the interval [-x, x], where x = gain * sqrt(3/fan_in).

    References

    [1] He, Kaiming, et al. "Delving deep into rectifiers: Surpassing human-level performance on imagenet classification." Proceedings of the IEEE international conference on computer vision. 2015.

    source

    `,5))]),s("details",F,[s("summary",null,[i[28]||(i[28]=s("a",{id:"WeightInitializers.sparse_init",href:"#WeightInitializers.sparse_init"},[s("span",{class:"jlbinding"},"WeightInitializers.sparse_init")],-1)),i[29]||(i[29]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[30]||(i[30]=t(`
    julia
    sparse_init([::AbstractRNG=Utils.default_rng()], [T=Float32], dims::Integer...;
    +    sparsity::Number, std::Number=0.01) -> AbstractArray{T}

    Creates a sparsely initialized weight matrix with a specified proportion of zeroed elements, using random numbers drawn from a normal distribution for the non-zero elements. This method was introduced in [1].

    Note

    The sparsity parameter controls the proportion of the matrix that will be zeroed. For example, a sparsity of 0.3 means that approximately 30% of the elements will be set to zero. The non-zero elements are distributed according to a normal distribution, scaled by the std parameter.

    Arguments

    Returns

    Examples

    julia
    julia> y = sparse_init(Xoshiro(123), Float32, 5, 5; sparsity=0.3, std=0.01);
    +
    +julia> y isa Matrix{Float32}
    +true
    +
    +julia> size(y) == (5, 5)
    +true

    References

    [1] Martens, J, "Deep learning via Hessian-free optimization" Proceedings of the 27th International Conference on International Conference on Machine Learning. 2010.

    source

    `,12))]),s("details",b,[s("summary",null,[i[31]||(i[31]=s("a",{id:"WeightInitializers.truncated_normal",href:"#WeightInitializers.truncated_normal"},[s("span",{class:"jlbinding"},"WeightInitializers.truncated_normal")],-1)),i[32]||(i[32]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[33]||(i[33]=t(`
    julia
    truncated_normal([::AbstractRNG=Utils.default_rng()], [T=Float32], size...; mean = 0,
    +    std = 1, lo = -2, hi = 2) -> AbstractArray{T, length(size)}

    Return an AbstractArray{T} of the given size where each element is drawn from a truncated normal distribution. The numbers are distributed like filter(x -> lo ≤ x ≤ hi, mean .+ std .* randn(100)).

    source

    `,3))]),s("details",f,[s("summary",null,[i[34]||(i[34]=s("a",{id:"WeightInitializers.orthogonal",href:"#WeightInitializers.orthogonal"},[s("span",{class:"jlbinding"},"WeightInitializers.orthogonal")],-1)),i[35]||(i[35]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[36]||(i[36]=t(`
    julia
    orthogonal([::AbstractRNG=Utils.default_rng()], [T=Float32], dims::Integer...;
    +    gain = 1)  -> AbstractArray{T, length(dims)}

    Return an AbstractArray{T} of the given dimensions (dims) which is a (semi) orthogonal matrix, as described in [1].

    The function constructs an orthogonal or semi-orthogonal matrix depending on the specified dimensions. For two dimensions, it returns a matrix where dims = (rows, cols). For more than two dimensions, it computes an orthogonal matrix of size prod(dims[1:(end - 1)]) by dims[end] before reshaping it to the original dimensions.

    Cannot construct a vector, i.e., length(dims) == 1 is forbidden.

    Arguments

    References

    [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

    source

    `,9))]),i[110]||(i[110]=s("h3",{id:"Other-Convenience-Functions",tabindex:"-1"},[a("Other Convenience Functions "),s("a",{class:"header-anchor",href:"#Other-Convenience-Functions","aria-label":'Permalink to "Other Convenience Functions {#Other-Convenience-Functions}"'},"​")],-1)),i[111]||(i[111]=s("div",{class:"warning custom-block"},[s("p",{class:"custom-block-title"},"Beware"),s("p",null,"Unlike the other functions these ones don't take a type argument.")],-1)),s("details",C,[s("summary",null,[i[37]||(i[37]=s("a",{id:"WeightInitializers.zeros16",href:"#WeightInitializers.zeros16"},[s("span",{class:"jlbinding"},"WeightInitializers.zeros16")],-1)),i[38]||(i[38]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[39]||(i[39]=t(`
    julia
    zeros16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float16, length(size)}

    Return an AbstractArray{Float16} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",m,[s("summary",null,[i[40]||(i[40]=s("a",{id:"WeightInitializers.ones16",href:"#WeightInitializers.ones16"},[s("span",{class:"jlbinding"},"WeightInitializers.ones16")],-1)),i[41]||(i[41]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[42]||(i[42]=t(`
    julia
    ones16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float16, length(size)}

    Return an AbstractArray{Float16} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",A,[s("summary",null,[i[43]||(i[43]=s("a",{id:"WeightInitializers.rand16",href:"#WeightInitializers.rand16"},[s("span",{class:"jlbinding"},"WeightInitializers.rand16")],-1)),i[44]||(i[44]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[45]||(i[45]=t(`
    julia
    rand16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float16, length(size)}

    Return an AbstractArray{Float16} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",z,[s("summary",null,[i[46]||(i[46]=s("a",{id:"WeightInitializers.randn16",href:"#WeightInitializers.randn16"},[s("span",{class:"jlbinding"},"WeightInitializers.randn16")],-1)),i[47]||(i[47]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[48]||(i[48]=t(`
    julia
    randn16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float16, length(size)}

    Return an AbstractArray{Float16} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))]),s("details",j,[s("summary",null,[i[49]||(i[49]=s("a",{id:"WeightInitializers.zeros32",href:"#WeightInitializers.zeros32"},[s("span",{class:"jlbinding"},"WeightInitializers.zeros32")],-1)),i[50]||(i[50]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[51]||(i[51]=t(`
    julia
    zeros32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float32, length(size)}

    Return an AbstractArray{Float32} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",D,[s("summary",null,[i[52]||(i[52]=s("a",{id:"WeightInitializers.ones32",href:"#WeightInitializers.ones32"},[s("span",{class:"jlbinding"},"WeightInitializers.ones32")],-1)),i[53]||(i[53]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[54]||(i[54]=t(`
    julia
    ones32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float32, length(size)}

    Return an AbstractArray{Float32} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",v,[s("summary",null,[i[55]||(i[55]=s("a",{id:"WeightInitializers.rand32",href:"#WeightInitializers.rand32"},[s("span",{class:"jlbinding"},"WeightInitializers.rand32")],-1)),i[56]||(i[56]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[57]||(i[57]=t(`
    julia
    rand32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float32, length(size)}

    Return an AbstractArray{Float32} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",x,[s("summary",null,[i[58]||(i[58]=s("a",{id:"WeightInitializers.randn32",href:"#WeightInitializers.randn32"},[s("span",{class:"jlbinding"},"WeightInitializers.randn32")],-1)),i[59]||(i[59]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[60]||(i[60]=t(`
    julia
    randn32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float32, length(size)}

    Return an AbstractArray{Float32} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))]),s("details",B,[s("summary",null,[i[61]||(i[61]=s("a",{id:"WeightInitializers.zeros64",href:"#WeightInitializers.zeros64"},[s("span",{class:"jlbinding"},"WeightInitializers.zeros64")],-1)),i[62]||(i[62]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[63]||(i[63]=t(`
    julia
    zeros64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float64, length(size)}

    Return an AbstractArray{Float64} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",I,[s("summary",null,[i[64]||(i[64]=s("a",{id:"WeightInitializers.ones64",href:"#WeightInitializers.ones64"},[s("span",{class:"jlbinding"},"WeightInitializers.ones64")],-1)),i[65]||(i[65]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[66]||(i[66]=t(`
    julia
    ones64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float64, length(size)}

    Return an AbstractArray{Float64} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",L,[s("summary",null,[i[67]||(i[67]=s("a",{id:"WeightInitializers.rand64",href:"#WeightInitializers.rand64"},[s("span",{class:"jlbinding"},"WeightInitializers.rand64")],-1)),i[68]||(i[68]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[69]||(i[69]=t(`
    julia
    rand64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float64, length(size)}

    Return an AbstractArray{Float64} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",T,[s("summary",null,[i[70]||(i[70]=s("a",{id:"WeightInitializers.randn64",href:"#WeightInitializers.randn64"},[s("span",{class:"jlbinding"},"WeightInitializers.randn64")],-1)),i[71]||(i[71]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[72]||(i[72]=t(`
    julia
    randn64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float64, length(size)}

    Return an AbstractArray{Float64} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))]),s("details",W,[s("summary",null,[i[73]||(i[73]=s("a",{id:"WeightInitializers.zerosC16",href:"#WeightInitializers.zerosC16"},[s("span",{class:"jlbinding"},"WeightInitializers.zerosC16")],-1)),i[74]||(i[74]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[75]||(i[75]=t(`
    julia
    zerosC16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF16, length(size)}

    Return an AbstractArray{ComplexF16} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",R,[s("summary",null,[i[76]||(i[76]=s("a",{id:"WeightInitializers.onesC16",href:"#WeightInitializers.onesC16"},[s("span",{class:"jlbinding"},"WeightInitializers.onesC16")],-1)),i[77]||(i[77]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[78]||(i[78]=t(`
    julia
    onesC16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF16, length(size)}

    Return an AbstractArray{ComplexF16} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",w,[s("summary",null,[i[79]||(i[79]=s("a",{id:"WeightInitializers.randC16",href:"#WeightInitializers.randC16"},[s("span",{class:"jlbinding"},"WeightInitializers.randC16")],-1)),i[80]||(i[80]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[81]||(i[81]=t(`
    julia
    randC16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF16, length(size)}

    Return an AbstractArray{ComplexF16} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",Q,[s("summary",null,[i[82]||(i[82]=s("a",{id:"WeightInitializers.randnC16",href:"#WeightInitializers.randnC16"},[s("span",{class:"jlbinding"},"WeightInitializers.randnC16")],-1)),i[83]||(i[83]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[84]||(i[84]=t(`
    julia
    randnC16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF16, length(size)}

    Return an AbstractArray{ComplexF16} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))]),s("details",N,[s("summary",null,[i[85]||(i[85]=s("a",{id:"WeightInitializers.zerosC32",href:"#WeightInitializers.zerosC32"},[s("span",{class:"jlbinding"},"WeightInitializers.zerosC32")],-1)),i[86]||(i[86]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[87]||(i[87]=t(`
    julia
    zerosC32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF32, length(size)}

    Return an AbstractArray{ComplexF32} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",G,[s("summary",null,[i[88]||(i[88]=s("a",{id:"WeightInitializers.onesC32",href:"#WeightInitializers.onesC32"},[s("span",{class:"jlbinding"},"WeightInitializers.onesC32")],-1)),i[89]||(i[89]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[90]||(i[90]=t(`
    julia
    onesC32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF32, length(size)}

    Return an AbstractArray{ComplexF32} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",U,[s("summary",null,[i[91]||(i[91]=s("a",{id:"WeightInitializers.randC32",href:"#WeightInitializers.randC32"},[s("span",{class:"jlbinding"},"WeightInitializers.randC32")],-1)),i[92]||(i[92]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[93]||(i[93]=t(`
    julia
    randC32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF32, length(size)}

    Return an AbstractArray{ComplexF32} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",O,[s("summary",null,[i[94]||(i[94]=s("a",{id:"WeightInitializers.randnC32",href:"#WeightInitializers.randnC32"},[s("span",{class:"jlbinding"},"WeightInitializers.randnC32")],-1)),i[95]||(i[95]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[96]||(i[96]=t(`
    julia
    randnC32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF32, length(size)}

    Return an AbstractArray{ComplexF32} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))]),s("details",P,[s("summary",null,[i[97]||(i[97]=s("a",{id:"WeightInitializers.zerosC64",href:"#WeightInitializers.zerosC64"},[s("span",{class:"jlbinding"},"WeightInitializers.zerosC64")],-1)),i[98]||(i[98]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[99]||(i[99]=t(`
    julia
    zerosC64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF64, length(size)}

    Return an AbstractArray{ComplexF64} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",M,[s("summary",null,[i[100]||(i[100]=s("a",{id:"WeightInitializers.onesC64",href:"#WeightInitializers.onesC64"},[s("span",{class:"jlbinding"},"WeightInitializers.onesC64")],-1)),i[101]||(i[101]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[102]||(i[102]=t(`
    julia
    onesC64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF64, length(size)}

    Return an AbstractArray{ComplexF64} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",q,[s("summary",null,[i[103]||(i[103]=s("a",{id:"WeightInitializers.randC64",href:"#WeightInitializers.randC64"},[s("span",{class:"jlbinding"},"WeightInitializers.randC64")],-1)),i[104]||(i[104]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[105]||(i[105]=t(`
    julia
    randC64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF64, length(size)}

    Return an AbstractArray{ComplexF64} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",H,[s("summary",null,[i[106]||(i[106]=s("a",{id:"WeightInitializers.randnC64",href:"#WeightInitializers.randnC64"},[s("span",{class:"jlbinding"},"WeightInitializers.randnC64")],-1)),i[107]||(i[107]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[108]||(i[108]=t(`
    julia
    randnC64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF64, length(size)}

    Return an AbstractArray{ComplexF64} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))])])}const _=r(k,[["render",V]]);export{Y as __pageData,_ as default}; diff --git a/previews/PR1023/assets/api_Building_Blocks_WeightInitializers.md.YK6sT70z.lean.js b/previews/PR1023/assets/api_Building_Blocks_WeightInitializers.md.YK6sT70z.lean.js new file mode 100644 index 0000000000..53f79bf307 --- /dev/null +++ b/previews/PR1023/assets/api_Building_Blocks_WeightInitializers.md.YK6sT70z.lean.js @@ -0,0 +1,52 @@ +import{_ as r,c as e,a2 as t,j as s,a,G as l,B as p,o as h}from"./chunks/framework.DFwXuivk.js";const Y=JSON.parse('{"title":"WeightInitializers","description":"","frontmatter":{},"headers":[],"relativePath":"api/Building_Blocks/WeightInitializers.md","filePath":"api/Building_Blocks/WeightInitializers.md","lastUpdated":null}'),k={name:"api/Building_Blocks/WeightInitializers.md"},d={class:"jldocstring custom-block"},o={class:"jldocstring custom-block"},g={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},E={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"6.612ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 2922.7 1000","aria-hidden":"true"},y={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"},F={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},C={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},A={class:"jldocstring custom-block"},z={class:"jldocstring custom-block"},j={class:"jldocstring custom-block"},D={class:"jldocstring custom-block"},v={class:"jldocstring custom-block"},x={class:"jldocstring custom-block"},B={class:"jldocstring custom-block"},I={class:"jldocstring custom-block"},L={class:"jldocstring custom-block"},T={class:"jldocstring custom-block"},W={class:"jldocstring custom-block"},R={class:"jldocstring custom-block"},w={class:"jldocstring custom-block"},Q={class:"jldocstring custom-block"},N={class:"jldocstring custom-block"},G={class:"jldocstring custom-block"},U={class:"jldocstring custom-block"},O={class:"jldocstring custom-block"},P={class:"jldocstring custom-block"},M={class:"jldocstring custom-block"},q={class:"jldocstring custom-block"},H={class:"jldocstring custom-block"};function V(S,i,X,Z,$,J){const n=p("Badge");return h(),e("div",null,[i[109]||(i[109]=t('

    WeightInitializers

    This package is a light dependency providing common weight initialization schemes for deep learning models.

    Supported RNG Types

    RNG Type / PackageReturned Array TypeUnsupported Functions
    Random.jlArray
    StableRNGs.jlArray
    CUDA.default_rng()CuArray
    GPUArrays.default_rng(CuArray)CuArray
    AMDGPU.rocrand_rng()ROCArray
    AMDGPU.gpuarrays_rng()ROCArray
    GPUArrays.default_rng(ROCArray)ROCArray
    Metal.gpuarrays_rng()MtlArrayorthogonal
    GPUArrays.default_rng(MtlArray)MtlArrayorthogonal
    oneAPI.gpuarrays_rng()oneArrayorthogonal, truncated_normal
    GPUArrays.default_rng(oneArray)oneArrayorthogonal, truncated_normal

    API Reference

    Main Functions

    ',6)),s("details",d,[s("summary",null,[i[0]||(i[0]=s("a",{id:"WeightInitializers.glorot_normal",href:"#WeightInitializers.glorot_normal"},[s("span",{class:"jlbinding"},"WeightInitializers.glorot_normal")],-1)),i[1]||(i[1]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[2]||(i[2]=t(`
    julia
    glorot_normal([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
    +    gain = 1) -> AbstractArray{T, length(size)}

    Return an AbstractArray{T} of the given size containing random numbers drawn from a normal distribution with standard deviation gain * sqrt(2 / (fan_in + fan_out)). This method is described in [1] and also known as Xavier initialization.

    References

    [1] Glorot, Xavier, and Yoshua Bengio. "Understanding the difficulty of training deep feedforward neural networks." Proceedings of the thirteenth international conference on artificial intelligence and statistics. 2010.

    source

    `,5))]),s("details",o,[s("summary",null,[i[3]||(i[3]=s("a",{id:"WeightInitializers.glorot_uniform",href:"#WeightInitializers.glorot_uniform"},[s("span",{class:"jlbinding"},"WeightInitializers.glorot_uniform")],-1)),i[4]||(i[4]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[15]||(i[15]=t(`
    julia
    glorot_uniform([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
    +    gain = 1) -> AbstractArray{T, length(size)}
    `,1)),s("p",null,[i[7]||(i[7]=a("Return an ")),i[8]||(i[8]=s("code",null,"AbstractArray{T}",-1)),i[9]||(i[9]=a(" of the given ")),i[10]||(i[10]=s("code",null,"size",-1)),i[11]||(i[11]=a(" containing random numbers drawn from a uniform distribution on the interval ")),s("mjx-container",g,[(h(),e("svg",E,i[5]||(i[5]=[t('',1)]))),i[6]||(i[6]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mo",{stretchy:"false"},"["),s("mo",null,"−"),s("mi",null,"x"),s("mo",null,","),s("mi",null,"x"),s("mo",{stretchy:"false"},"]")])],-1))]),i[12]||(i[12]=a(", where ")),i[13]||(i[13]=s("code",null,"x = gain * sqrt(6 / (fan_in + fan_out))",-1)),i[14]||(i[14]=a(". This method is described in [1] and also known as Xavier initialization."))]),i[16]||(i[16]=s("p",null,[s("strong",null,"References")],-1)),i[17]||(i[17]=s("p",null,[a('[1] Glorot, Xavier, and Yoshua Bengio. "Understanding the difficulty of training deep feedforward neural networks." '),s("em",null,"Proceedings of the thirteenth international conference on artificial intelligence and statistics"),a(". 2010.")],-1)),i[18]||(i[18]=s("p",null,[s("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/lib/WeightInitializers/src/initializers.jl#L13-L27",target:"_blank",rel:"noreferrer"},"source")],-1))]),s("details",y,[s("summary",null,[i[19]||(i[19]=s("a",{id:"WeightInitializers.identity_init",href:"#WeightInitializers.identity_init"},[s("span",{class:"jlbinding"},"WeightInitializers.identity_init")],-1)),i[20]||(i[20]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[21]||(i[21]=t(`
    julia
    identity_init([::AbstractRNG=Utils.default_rng()], [T=Float32], size...; gain::Number=1,
    +    shift::Union{Integer, Tuple{Integer, Integer}}=0) -> AbstractArray{T}

    Constructs an array that aims to provide an identity mapping when used as parameters in most layers of a neural network. The identity mapping is scaled by the gain parameter.

    Behavior

    Caveats

    Arguments

    Returns

    Examples

    julia
    julia> identity_init(Xoshiro(123), Float32, 5, 5)
    +5×5 Matrix{Float32}:
    + 1.0  1.0  1.0  1.0  1.0
    + 1.0  1.0  1.0  1.0  1.0
    + 1.0  1.0  1.0  1.0  1.0
    + 1.0  1.0  1.0  1.0  1.0
    + 1.0  1.0  1.0  1.0  1.0
    +
    +julia> identity_init(Xoshiro(123), Float32, 3, 3, 1, 1; gain=1.5)
    +3×3×1×1 Array{Float32, 4}:
    +[:, :, 1, 1] =
    + 0.0  0.0  0.0
    + 0.0  1.5  0.0
    + 0.0  0.0  0.0

    source

    `,13))]),s("details",c,[s("summary",null,[i[22]||(i[22]=s("a",{id:"WeightInitializers.kaiming_normal",href:"#WeightInitializers.kaiming_normal"},[s("span",{class:"jlbinding"},"WeightInitializers.kaiming_normal")],-1)),i[23]||(i[23]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[24]||(i[24]=t(`
    julia
    kaiming_normal([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
    +    gain =T(2)) -> AbstractArray{T, length(size)}

    Return an AbstractArray{T} of the given size containing random numbers taken from a normal distribution standard deviation gain / sqrt(fan_in)

    References

    [1] He, Kaiming, et al. "Delving deep into rectifiers: Surpassing human-level performance on imagenet classification." Proceedings of the IEEE international conference on computer vision. 2015.

    source

    `,5))]),s("details",u,[s("summary",null,[i[25]||(i[25]=s("a",{id:"WeightInitializers.kaiming_uniform",href:"#WeightInitializers.kaiming_uniform"},[s("span",{class:"jlbinding"},"WeightInitializers.kaiming_uniform")],-1)),i[26]||(i[26]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[27]||(i[27]=t(`
    julia
    kaiming_uniform([::AbstractRNG=Utils.default_rng()], [T=Float32], size...;
    +    gain =T(2)) -> AbstractArray{T, length(size)}

    Return an AbstractArray{T} of the given size containing random numbers drawn from a uniform distribution on the interval [-x, x], where x = gain * sqrt(3/fan_in).

    References

    [1] He, Kaiming, et al. "Delving deep into rectifiers: Surpassing human-level performance on imagenet classification." Proceedings of the IEEE international conference on computer vision. 2015.

    source

    `,5))]),s("details",F,[s("summary",null,[i[28]||(i[28]=s("a",{id:"WeightInitializers.sparse_init",href:"#WeightInitializers.sparse_init"},[s("span",{class:"jlbinding"},"WeightInitializers.sparse_init")],-1)),i[29]||(i[29]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[30]||(i[30]=t(`
    julia
    sparse_init([::AbstractRNG=Utils.default_rng()], [T=Float32], dims::Integer...;
    +    sparsity::Number, std::Number=0.01) -> AbstractArray{T}

    Creates a sparsely initialized weight matrix with a specified proportion of zeroed elements, using random numbers drawn from a normal distribution for the non-zero elements. This method was introduced in [1].

    Note

    The sparsity parameter controls the proportion of the matrix that will be zeroed. For example, a sparsity of 0.3 means that approximately 30% of the elements will be set to zero. The non-zero elements are distributed according to a normal distribution, scaled by the std parameter.

    Arguments

    Returns

    Examples

    julia
    julia> y = sparse_init(Xoshiro(123), Float32, 5, 5; sparsity=0.3, std=0.01);
    +
    +julia> y isa Matrix{Float32}
    +true
    +
    +julia> size(y) == (5, 5)
    +true

    References

    [1] Martens, J, "Deep learning via Hessian-free optimization" Proceedings of the 27th International Conference on International Conference on Machine Learning. 2010.

    source

    `,12))]),s("details",b,[s("summary",null,[i[31]||(i[31]=s("a",{id:"WeightInitializers.truncated_normal",href:"#WeightInitializers.truncated_normal"},[s("span",{class:"jlbinding"},"WeightInitializers.truncated_normal")],-1)),i[32]||(i[32]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[33]||(i[33]=t(`
    julia
    truncated_normal([::AbstractRNG=Utils.default_rng()], [T=Float32], size...; mean = 0,
    +    std = 1, lo = -2, hi = 2) -> AbstractArray{T, length(size)}

    Return an AbstractArray{T} of the given size where each element is drawn from a truncated normal distribution. The numbers are distributed like filter(x -> lo ≤ x ≤ hi, mean .+ std .* randn(100)).

    source

    `,3))]),s("details",f,[s("summary",null,[i[34]||(i[34]=s("a",{id:"WeightInitializers.orthogonal",href:"#WeightInitializers.orthogonal"},[s("span",{class:"jlbinding"},"WeightInitializers.orthogonal")],-1)),i[35]||(i[35]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[36]||(i[36]=t(`
    julia
    orthogonal([::AbstractRNG=Utils.default_rng()], [T=Float32], dims::Integer...;
    +    gain = 1)  -> AbstractArray{T, length(dims)}

    Return an AbstractArray{T} of the given dimensions (dims) which is a (semi) orthogonal matrix, as described in [1].

    The function constructs an orthogonal or semi-orthogonal matrix depending on the specified dimensions. For two dimensions, it returns a matrix where dims = (rows, cols). For more than two dimensions, it computes an orthogonal matrix of size prod(dims[1:(end - 1)]) by dims[end] before reshaping it to the original dimensions.

    Cannot construct a vector, i.e., length(dims) == 1 is forbidden.

    Arguments

    References

    [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

    source

    `,9))]),i[110]||(i[110]=s("h3",{id:"Other-Convenience-Functions",tabindex:"-1"},[a("Other Convenience Functions "),s("a",{class:"header-anchor",href:"#Other-Convenience-Functions","aria-label":'Permalink to "Other Convenience Functions {#Other-Convenience-Functions}"'},"​")],-1)),i[111]||(i[111]=s("div",{class:"warning custom-block"},[s("p",{class:"custom-block-title"},"Beware"),s("p",null,"Unlike the other functions these ones don't take a type argument.")],-1)),s("details",C,[s("summary",null,[i[37]||(i[37]=s("a",{id:"WeightInitializers.zeros16",href:"#WeightInitializers.zeros16"},[s("span",{class:"jlbinding"},"WeightInitializers.zeros16")],-1)),i[38]||(i[38]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[39]||(i[39]=t(`
    julia
    zeros16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float16, length(size)}

    Return an AbstractArray{Float16} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",m,[s("summary",null,[i[40]||(i[40]=s("a",{id:"WeightInitializers.ones16",href:"#WeightInitializers.ones16"},[s("span",{class:"jlbinding"},"WeightInitializers.ones16")],-1)),i[41]||(i[41]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[42]||(i[42]=t(`
    julia
    ones16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float16, length(size)}

    Return an AbstractArray{Float16} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",A,[s("summary",null,[i[43]||(i[43]=s("a",{id:"WeightInitializers.rand16",href:"#WeightInitializers.rand16"},[s("span",{class:"jlbinding"},"WeightInitializers.rand16")],-1)),i[44]||(i[44]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[45]||(i[45]=t(`
    julia
    rand16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float16, length(size)}

    Return an AbstractArray{Float16} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",z,[s("summary",null,[i[46]||(i[46]=s("a",{id:"WeightInitializers.randn16",href:"#WeightInitializers.randn16"},[s("span",{class:"jlbinding"},"WeightInitializers.randn16")],-1)),i[47]||(i[47]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[48]||(i[48]=t(`
    julia
    randn16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float16, length(size)}

    Return an AbstractArray{Float16} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))]),s("details",j,[s("summary",null,[i[49]||(i[49]=s("a",{id:"WeightInitializers.zeros32",href:"#WeightInitializers.zeros32"},[s("span",{class:"jlbinding"},"WeightInitializers.zeros32")],-1)),i[50]||(i[50]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[51]||(i[51]=t(`
    julia
    zeros32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float32, length(size)}

    Return an AbstractArray{Float32} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",D,[s("summary",null,[i[52]||(i[52]=s("a",{id:"WeightInitializers.ones32",href:"#WeightInitializers.ones32"},[s("span",{class:"jlbinding"},"WeightInitializers.ones32")],-1)),i[53]||(i[53]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[54]||(i[54]=t(`
    julia
    ones32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float32, length(size)}

    Return an AbstractArray{Float32} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",v,[s("summary",null,[i[55]||(i[55]=s("a",{id:"WeightInitializers.rand32",href:"#WeightInitializers.rand32"},[s("span",{class:"jlbinding"},"WeightInitializers.rand32")],-1)),i[56]||(i[56]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[57]||(i[57]=t(`
    julia
    rand32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float32, length(size)}

    Return an AbstractArray{Float32} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",x,[s("summary",null,[i[58]||(i[58]=s("a",{id:"WeightInitializers.randn32",href:"#WeightInitializers.randn32"},[s("span",{class:"jlbinding"},"WeightInitializers.randn32")],-1)),i[59]||(i[59]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[60]||(i[60]=t(`
    julia
    randn32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float32, length(size)}

    Return an AbstractArray{Float32} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))]),s("details",B,[s("summary",null,[i[61]||(i[61]=s("a",{id:"WeightInitializers.zeros64",href:"#WeightInitializers.zeros64"},[s("span",{class:"jlbinding"},"WeightInitializers.zeros64")],-1)),i[62]||(i[62]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[63]||(i[63]=t(`
    julia
    zeros64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float64, length(size)}

    Return an AbstractArray{Float64} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",I,[s("summary",null,[i[64]||(i[64]=s("a",{id:"WeightInitializers.ones64",href:"#WeightInitializers.ones64"},[s("span",{class:"jlbinding"},"WeightInitializers.ones64")],-1)),i[65]||(i[65]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[66]||(i[66]=t(`
    julia
    ones64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float64, length(size)}

    Return an AbstractArray{Float64} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",L,[s("summary",null,[i[67]||(i[67]=s("a",{id:"WeightInitializers.rand64",href:"#WeightInitializers.rand64"},[s("span",{class:"jlbinding"},"WeightInitializers.rand64")],-1)),i[68]||(i[68]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[69]||(i[69]=t(`
    julia
    rand64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float64, length(size)}

    Return an AbstractArray{Float64} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",T,[s("summary",null,[i[70]||(i[70]=s("a",{id:"WeightInitializers.randn64",href:"#WeightInitializers.randn64"},[s("span",{class:"jlbinding"},"WeightInitializers.randn64")],-1)),i[71]||(i[71]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[72]||(i[72]=t(`
    julia
    randn64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{Float64, length(size)}

    Return an AbstractArray{Float64} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))]),s("details",W,[s("summary",null,[i[73]||(i[73]=s("a",{id:"WeightInitializers.zerosC16",href:"#WeightInitializers.zerosC16"},[s("span",{class:"jlbinding"},"WeightInitializers.zerosC16")],-1)),i[74]||(i[74]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[75]||(i[75]=t(`
    julia
    zerosC16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF16, length(size)}

    Return an AbstractArray{ComplexF16} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",R,[s("summary",null,[i[76]||(i[76]=s("a",{id:"WeightInitializers.onesC16",href:"#WeightInitializers.onesC16"},[s("span",{class:"jlbinding"},"WeightInitializers.onesC16")],-1)),i[77]||(i[77]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[78]||(i[78]=t(`
    julia
    onesC16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF16, length(size)}

    Return an AbstractArray{ComplexF16} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",w,[s("summary",null,[i[79]||(i[79]=s("a",{id:"WeightInitializers.randC16",href:"#WeightInitializers.randC16"},[s("span",{class:"jlbinding"},"WeightInitializers.randC16")],-1)),i[80]||(i[80]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[81]||(i[81]=t(`
    julia
    randC16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF16, length(size)}

    Return an AbstractArray{ComplexF16} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",Q,[s("summary",null,[i[82]||(i[82]=s("a",{id:"WeightInitializers.randnC16",href:"#WeightInitializers.randnC16"},[s("span",{class:"jlbinding"},"WeightInitializers.randnC16")],-1)),i[83]||(i[83]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[84]||(i[84]=t(`
    julia
    randnC16([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF16, length(size)}

    Return an AbstractArray{ComplexF16} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))]),s("details",N,[s("summary",null,[i[85]||(i[85]=s("a",{id:"WeightInitializers.zerosC32",href:"#WeightInitializers.zerosC32"},[s("span",{class:"jlbinding"},"WeightInitializers.zerosC32")],-1)),i[86]||(i[86]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[87]||(i[87]=t(`
    julia
    zerosC32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF32, length(size)}

    Return an AbstractArray{ComplexF32} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",G,[s("summary",null,[i[88]||(i[88]=s("a",{id:"WeightInitializers.onesC32",href:"#WeightInitializers.onesC32"},[s("span",{class:"jlbinding"},"WeightInitializers.onesC32")],-1)),i[89]||(i[89]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[90]||(i[90]=t(`
    julia
    onesC32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF32, length(size)}

    Return an AbstractArray{ComplexF32} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",U,[s("summary",null,[i[91]||(i[91]=s("a",{id:"WeightInitializers.randC32",href:"#WeightInitializers.randC32"},[s("span",{class:"jlbinding"},"WeightInitializers.randC32")],-1)),i[92]||(i[92]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[93]||(i[93]=t(`
    julia
    randC32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF32, length(size)}

    Return an AbstractArray{ComplexF32} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",O,[s("summary",null,[i[94]||(i[94]=s("a",{id:"WeightInitializers.randnC32",href:"#WeightInitializers.randnC32"},[s("span",{class:"jlbinding"},"WeightInitializers.randnC32")],-1)),i[95]||(i[95]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[96]||(i[96]=t(`
    julia
    randnC32([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF32, length(size)}

    Return an AbstractArray{ComplexF32} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))]),s("details",P,[s("summary",null,[i[97]||(i[97]=s("a",{id:"WeightInitializers.zerosC64",href:"#WeightInitializers.zerosC64"},[s("span",{class:"jlbinding"},"WeightInitializers.zerosC64")],-1)),i[98]||(i[98]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[99]||(i[99]=t(`
    julia
    zerosC64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF64, length(size)}

    Return an AbstractArray{ComplexF64} of the given size containing an AbstractArray of zeros.

    source

    `,3))]),s("details",M,[s("summary",null,[i[100]||(i[100]=s("a",{id:"WeightInitializers.onesC64",href:"#WeightInitializers.onesC64"},[s("span",{class:"jlbinding"},"WeightInitializers.onesC64")],-1)),i[101]||(i[101]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[102]||(i[102]=t(`
    julia
    onesC64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF64, length(size)}

    Return an AbstractArray{ComplexF64} of the given size containing an AbstractArray of ones.

    source

    `,3))]),s("details",q,[s("summary",null,[i[103]||(i[103]=s("a",{id:"WeightInitializers.randC64",href:"#WeightInitializers.randC64"},[s("span",{class:"jlbinding"},"WeightInitializers.randC64")],-1)),i[104]||(i[104]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[105]||(i[105]=t(`
    julia
    randC64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF64, length(size)}

    Return an AbstractArray{ComplexF64} of the given size containing random numbers from a uniform distribution.

    source

    `,3))]),s("details",H,[s("summary",null,[i[106]||(i[106]=s("a",{id:"WeightInitializers.randnC64",href:"#WeightInitializers.randnC64"},[s("span",{class:"jlbinding"},"WeightInitializers.randnC64")],-1)),i[107]||(i[107]=a()),l(n,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[108]||(i[108]=t(`
    julia
    randnC64([::AbstractRNG=Utils.default_rng()], size...;
    +    kwargs...) -> AbstractArray{ComplexF64, length(size)}

    Return an AbstractArray{ComplexF64} of the given size containing random numbers from a standard normal distribution.

    source

    `,3))])])}const _=r(k,[["render",V]]);export{Y as __pageData,_ as default}; diff --git a/previews/PR1023/assets/api_Lux_autodiff.md.CpXbBbTG.js b/previews/PR1023/assets/api_Lux_autodiff.md.CpXbBbTG.js new file mode 100644 index 0000000000..84ffed5cb4 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_autodiff.md.CpXbBbTG.js @@ -0,0 +1 @@ +import{_ as d,c as i,j as t,a,G as l,a2 as s,B as r,o as n}from"./chunks/framework.DFwXuivk.js";const v=JSON.parse('{"title":"Automatic Differentiation Helpers","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/autodiff.md","filePath":"api/Lux/autodiff.md","lastUpdated":null}'),Q={name:"api/Lux/autodiff.md"},p={class:"jldocstring custom-block"},c={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},T={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-1.469ex"},xmlns:"http://www.w3.org/2000/svg",width:"6.812ex",height:"4.07ex",role:"img",focusable:"false",viewBox:"0 -1149.5 3010.7 1799","aria-hidden":"true"},m={class:"jldocstring custom-block"},u={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},h={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-1.469ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.126ex",height:"4.536ex",role:"img",focusable:"false",viewBox:"0 -1355.3 3591.5 2004.8","aria-hidden":"true"},g={class:"jldocstring custom-block"};function f(b,e,x,k,y,w){const o=r("Badge");return n(),i("div",null,[e[19]||(e[19]=t("h1",{id:"autodiff-lux-helpers",tabindex:"-1"},[a("Automatic Differentiation Helpers "),t("a",{class:"header-anchor",href:"#autodiff-lux-helpers","aria-label":'Permalink to "Automatic Differentiation Helpers {#autodiff-lux-helpers}"'},"​")],-1)),e[20]||(e[20]=t("h2",{id:"JVP-and-VJP-Wrappers",tabindex:"-1"},[a("JVP & VJP Wrappers "),t("a",{class:"header-anchor",href:"#JVP-and-VJP-Wrappers","aria-label":'Permalink to "JVP & VJP Wrappers {#JVP-and-VJP-Wrappers}"'},"​")],-1)),t("details",p,[t("summary",null,[e[0]||(e[0]=t("a",{id:"Lux.jacobian_vector_product",href:"#Lux.jacobian_vector_product"},[t("span",{class:"jlbinding"},"Lux.jacobian_vector_product")],-1)),e[1]||(e[1]=a()),l(o,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[6]||(e[6]=s('
    julia
    jacobian_vector_product(f, backend::AbstractADType, x, u)
    ',1)),t("p",null,[e[4]||(e[4]=a("Compute the Jacobian-Vector Product ")),t("mjx-container",c,[(n(),i("svg",T,e[2]||(e[2]=[s('',1)]))),e[3]||(e[3]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"("),t("mfrac",null,[t("mrow",null,[t("mi",null,"∂"),t("mi",null,"f")]),t("mrow",null,[t("mi",null,"∂"),t("mi",null,"x")])]),t("mo",{"data-mjx-texclass":"CLOSE"},")")]),t("mi",null,"u")])],-1))]),e[5]||(e[5]=a(". This is a wrapper around AD backends but allows us to compute gradients of jacobian-vector products efficiently using mixed-mode AD."))]),e[7]||(e[7]=s('

    Backends & AD Packages

    Supported BackendsPackages Needed
    AutoForwardDiff

    Warning

    Gradient wrt u in the reverse pass is always dropped.

    Arguments

    Returns

    source

    ',8))]),t("details",m,[t("summary",null,[e[8]||(e[8]=t("a",{id:"Lux.vector_jacobian_product",href:"#Lux.vector_jacobian_product"},[t("span",{class:"jlbinding"},"Lux.vector_jacobian_product")],-1)),e[9]||(e[9]=a()),l(o,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[14]||(e[14]=s('
    julia
    vector_jacobian_product(f, backend::AbstractADType, x, u)
    ',1)),t("p",null,[e[12]||(e[12]=a("Compute the Vector-Jacobian Product ")),t("mjx-container",u,[(n(),i("svg",h,e[10]||(e[10]=[s('',1)]))),e[11]||(e[11]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msup",null,[t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"("),t("mfrac",null,[t("mrow",null,[t("mi",null,"∂"),t("mi",null,"f")]),t("mrow",null,[t("mi",null,"∂"),t("mi",null,"x")])]),t("mo",{"data-mjx-texclass":"CLOSE"},")")]),t("mi",null,"T")]),t("mi",null,"u")])],-1))]),e[13]||(e[13]=a(". This is a wrapper around AD backends but allows us to compute gradients of vector-jacobian products efficiently using mixed-mode AD."))]),e[15]||(e[15]=s('

    Backends & AD Packages

    Supported BackendsPackages Needed
    AutoZygoteZygote.jl

    Warning

    Gradient wrt u in the reverse pass is always dropped.

    Arguments

    Returns

    source

    ',8))]),e[21]||(e[21]=t("h2",{id:"Batched-AD",tabindex:"-1"},[a("Batched AD "),t("a",{class:"header-anchor",href:"#Batched-AD","aria-label":'Permalink to "Batched AD {#Batched-AD}"'},"​")],-1)),t("details",g,[t("summary",null,[e[16]||(e[16]=t("a",{id:"Lux.batched_jacobian",href:"#Lux.batched_jacobian"},[t("span",{class:"jlbinding"},"Lux.batched_jacobian")],-1)),e[17]||(e[17]=a()),l(o,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[18]||(e[18]=s('
    julia
    batched_jacobian(f, backend::AbstractADType, x::AbstractArray)

    Computes the Jacobian of a function f with respect to a batch of inputs x. This expects the following properties for y = f(x):

    1. ndims(y) ≥ 2

    2. size(y, ndims(y)) == size(x, ndims(x))

    Backends & AD Packages

    Supported BackendsPackages Needed
    AutoForwardDiff
    AutoZygoteZygote.jl

    Arguments

    Returns

    Danger

    f(x) must not be inter-mixing the batch dimensions, else the result will be incorrect. For example, if f contains operations like batch normalization, then the result will be incorrect.

    source

    ',11))]),e[22]||(e[22]=t("h2",{id:"Nested-2nd-Order-AD",tabindex:"-1"},[a("Nested 2nd Order AD "),t("a",{class:"header-anchor",href:"#Nested-2nd-Order-AD","aria-label":'Permalink to "Nested 2nd Order AD {#Nested-2nd-Order-AD}"'},"​")],-1)),e[23]||(e[23]=t("p",null,[a("Consult the "),t("a",{href:"/previews/PR1023/manual/nested_autodiff#nested_autodiff"},"manual page on Nested AD"),a(" for information on nested automatic differentiation.")],-1))])}const L=d(Q,[["render",f]]);export{v as __pageData,L as default}; diff --git a/previews/PR1023/assets/api_Lux_autodiff.md.CpXbBbTG.lean.js b/previews/PR1023/assets/api_Lux_autodiff.md.CpXbBbTG.lean.js new file mode 100644 index 0000000000..84ffed5cb4 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_autodiff.md.CpXbBbTG.lean.js @@ -0,0 +1 @@ +import{_ as d,c as i,j as t,a,G as l,a2 as s,B as r,o as n}from"./chunks/framework.DFwXuivk.js";const v=JSON.parse('{"title":"Automatic Differentiation Helpers","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/autodiff.md","filePath":"api/Lux/autodiff.md","lastUpdated":null}'),Q={name:"api/Lux/autodiff.md"},p={class:"jldocstring custom-block"},c={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},T={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-1.469ex"},xmlns:"http://www.w3.org/2000/svg",width:"6.812ex",height:"4.07ex",role:"img",focusable:"false",viewBox:"0 -1149.5 3010.7 1799","aria-hidden":"true"},m={class:"jldocstring custom-block"},u={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},h={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-1.469ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.126ex",height:"4.536ex",role:"img",focusable:"false",viewBox:"0 -1355.3 3591.5 2004.8","aria-hidden":"true"},g={class:"jldocstring custom-block"};function f(b,e,x,k,y,w){const o=r("Badge");return n(),i("div",null,[e[19]||(e[19]=t("h1",{id:"autodiff-lux-helpers",tabindex:"-1"},[a("Automatic Differentiation Helpers "),t("a",{class:"header-anchor",href:"#autodiff-lux-helpers","aria-label":'Permalink to "Automatic Differentiation Helpers {#autodiff-lux-helpers}"'},"​")],-1)),e[20]||(e[20]=t("h2",{id:"JVP-and-VJP-Wrappers",tabindex:"-1"},[a("JVP & VJP Wrappers "),t("a",{class:"header-anchor",href:"#JVP-and-VJP-Wrappers","aria-label":'Permalink to "JVP & VJP Wrappers {#JVP-and-VJP-Wrappers}"'},"​")],-1)),t("details",p,[t("summary",null,[e[0]||(e[0]=t("a",{id:"Lux.jacobian_vector_product",href:"#Lux.jacobian_vector_product"},[t("span",{class:"jlbinding"},"Lux.jacobian_vector_product")],-1)),e[1]||(e[1]=a()),l(o,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[6]||(e[6]=s('
    julia
    jacobian_vector_product(f, backend::AbstractADType, x, u)
    ',1)),t("p",null,[e[4]||(e[4]=a("Compute the Jacobian-Vector Product ")),t("mjx-container",c,[(n(),i("svg",T,e[2]||(e[2]=[s('',1)]))),e[3]||(e[3]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"("),t("mfrac",null,[t("mrow",null,[t("mi",null,"∂"),t("mi",null,"f")]),t("mrow",null,[t("mi",null,"∂"),t("mi",null,"x")])]),t("mo",{"data-mjx-texclass":"CLOSE"},")")]),t("mi",null,"u")])],-1))]),e[5]||(e[5]=a(". This is a wrapper around AD backends but allows us to compute gradients of jacobian-vector products efficiently using mixed-mode AD."))]),e[7]||(e[7]=s('

    Backends & AD Packages

    Supported BackendsPackages Needed
    AutoForwardDiff

    Warning

    Gradient wrt u in the reverse pass is always dropped.

    Arguments

    Returns

    source

    ',8))]),t("details",m,[t("summary",null,[e[8]||(e[8]=t("a",{id:"Lux.vector_jacobian_product",href:"#Lux.vector_jacobian_product"},[t("span",{class:"jlbinding"},"Lux.vector_jacobian_product")],-1)),e[9]||(e[9]=a()),l(o,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[14]||(e[14]=s('
    julia
    vector_jacobian_product(f, backend::AbstractADType, x, u)
    ',1)),t("p",null,[e[12]||(e[12]=a("Compute the Vector-Jacobian Product ")),t("mjx-container",u,[(n(),i("svg",h,e[10]||(e[10]=[s('',1)]))),e[11]||(e[11]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msup",null,[t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"("),t("mfrac",null,[t("mrow",null,[t("mi",null,"∂"),t("mi",null,"f")]),t("mrow",null,[t("mi",null,"∂"),t("mi",null,"x")])]),t("mo",{"data-mjx-texclass":"CLOSE"},")")]),t("mi",null,"T")]),t("mi",null,"u")])],-1))]),e[13]||(e[13]=a(". This is a wrapper around AD backends but allows us to compute gradients of vector-jacobian products efficiently using mixed-mode AD."))]),e[15]||(e[15]=s('

    Backends & AD Packages

    Supported BackendsPackages Needed
    AutoZygoteZygote.jl

    Warning

    Gradient wrt u in the reverse pass is always dropped.

    Arguments

    Returns

    source

    ',8))]),e[21]||(e[21]=t("h2",{id:"Batched-AD",tabindex:"-1"},[a("Batched AD "),t("a",{class:"header-anchor",href:"#Batched-AD","aria-label":'Permalink to "Batched AD {#Batched-AD}"'},"​")],-1)),t("details",g,[t("summary",null,[e[16]||(e[16]=t("a",{id:"Lux.batched_jacobian",href:"#Lux.batched_jacobian"},[t("span",{class:"jlbinding"},"Lux.batched_jacobian")],-1)),e[17]||(e[17]=a()),l(o,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),e[18]||(e[18]=s('
    julia
    batched_jacobian(f, backend::AbstractADType, x::AbstractArray)

    Computes the Jacobian of a function f with respect to a batch of inputs x. This expects the following properties for y = f(x):

    1. ndims(y) ≥ 2

    2. size(y, ndims(y)) == size(x, ndims(x))

    Backends & AD Packages

    Supported BackendsPackages Needed
    AutoForwardDiff
    AutoZygoteZygote.jl

    Arguments

    Returns

    Danger

    f(x) must not be inter-mixing the batch dimensions, else the result will be incorrect. For example, if f contains operations like batch normalization, then the result will be incorrect.

    source

    ',11))]),e[22]||(e[22]=t("h2",{id:"Nested-2nd-Order-AD",tabindex:"-1"},[a("Nested 2nd Order AD "),t("a",{class:"header-anchor",href:"#Nested-2nd-Order-AD","aria-label":'Permalink to "Nested 2nd Order AD {#Nested-2nd-Order-AD}"'},"​")],-1)),e[23]||(e[23]=t("p",null,[a("Consult the "),t("a",{href:"/previews/PR1023/manual/nested_autodiff#nested_autodiff"},"manual page on Nested AD"),a(" for information on nested automatic differentiation.")],-1))])}const L=d(Q,[["render",f]]);export{v as __pageData,L as default}; diff --git a/previews/PR1023/assets/api_Lux_contrib.md.tcySUcib.js b/previews/PR1023/assets/api_Lux_contrib.md.tcySUcib.js new file mode 100644 index 0000000000..35e29c2668 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_contrib.md.tcySUcib.js @@ -0,0 +1,55 @@ +import{_ as h,c as l,a2 as e,j as i,a,G as n,B as p,o as k}from"./chunks/framework.DFwXuivk.js";const A=JSON.parse('{"title":"Experimental Features","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/contrib.md","filePath":"api/Lux/contrib.md","lastUpdated":null}'),r={name:"api/Lux/contrib.md"},d={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},o={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"};function F(m,s,C,f,b,D){const t=p("Badge");return k(),l("div",null,[s[21]||(s[21]=e('

    Experimental Features

    All features listed on this page are experimental which means:

    1. No SemVer Guarantees. We use code here to iterate fast. That said, historically we have never broken any code in this module and have always provided a deprecation period.

    2. Expect edge-cases and report them. It will help us move these features out of experimental sooner.

    3. None of the features are exported.

    Parameter Freezing

    ',4)),i("details",d,[i("summary",null,[s[0]||(s[0]=i("a",{id:"Lux.Experimental.FrozenLayer",href:"#Lux.Experimental.FrozenLayer"},[i("span",{class:"jlbinding"},"Lux.Experimental.FrozenLayer")],-1)),s[1]||(s[1]=a()),n(t,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[2]||(s[2]=e(`
    julia
    FrozenLayer(l::AbstractLuxLayer, which_params::Optional{Tuple})

    Freeze the parameters with name which_params of the layer l.

    Use Lux.Experimental.freeze instead

    It is always recommended to use the Lux.Experimental.freeze function instead of directly using the FrozenLayer constructor.

    No checks for which_params

    There are no checks for which_params. For example, if the original layer has parameters named (:weight, :bias), and which_params is set to (:myweight,) then none of the parameters are frozen and no error is thrown.

    Arguments

    Extended Help

    Parameters

    States

    Note on Internal Layer Implementation

    The inner layer should work with NamedTuple parameters. In order to support custom parameter types, users need to implement Lux.Utils.merge(::CustomParamType, ::NamedTuple) or extend Lux.Utils.named_tuple(::CustomParamType) to return a NamedTuple.

    Example

    julia
    julia> Lux.Experimental.FrozenLayer(Dense(2 => 2), (:weight,))
    +FrozenLayer(Dense(2 => 2), (:weight,))  # 2 parameters, plus 4 non-trainable

    See also Lux.Experimental.freeze, Lux.Experimental.unfreeze.

    source

    `,17))]),i("details",E,[i("summary",null,[s[3]||(s[3]=i("a",{id:"Lux.Experimental.freeze",href:"#Lux.Experimental.freeze"},[i("span",{class:"jlbinding"},"Lux.Experimental.freeze")],-1)),s[4]||(s[4]=a()),n(t,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[5]||(s[5]=e(`
    julia
    freeze(l::AbstractLuxLayer, which_params::Optional{Tuple} = nothing)

    Constructs a version of l with which_params frozen. If which_params is nothing, then all parameters are frozen.

    source

    julia
    freeze(l::AbstractLuxLayer, ps, st::NamedTuple,
    +    which_params::Optional{Tuple} = nothing)

    Construct a Lux.Experimental.FrozenLayer for l with the current parameters and states. If which_params is nothing, then all parameters are frozen.

    source

    `,6))]),i("details",o,[i("summary",null,[s[6]||(s[6]=i("a",{id:"Lux.Experimental.unfreeze",href:"#Lux.Experimental.unfreeze"},[i("span",{class:"jlbinding"},"Lux.Experimental.unfreeze")],-1)),s[7]||(s[7]=a()),n(t,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[8]||(s[8]=e('
    julia
    unfreeze(l::FrozenLayer)

    Unfreezes the layer l.

    source

    julia
    unfreeze(l::FrozenLayer, ps, st::NamedTuple)

    Unwraps a Lux.Experimental.FrozenLayer l with the current parameters and states.

    source

    ',6))]),s[22]||(s[22]=i("p",null,[a("For detailed usage example look at the "),i("a",{href:"/previews/PR1023/manual/freezing_model_parameters#freezing-model-parameters"},"manual page"),a(".")],-1)),s[23]||(s[23]=i("h2",{id:"Map-over-Layer",tabindex:"-1"},[a("Map over Layer "),i("a",{class:"header-anchor",href:"#Map-over-Layer","aria-label":'Permalink to "Map over Layer {#Map-over-Layer}"'},"​")],-1)),i("details",g,[i("summary",null,[s[9]||(s[9]=i("a",{id:"Lux.Experimental.layer_map",href:"#Lux.Experimental.layer_map"},[i("span",{class:"jlbinding"},"Lux.Experimental.layer_map")],-1)),s[10]||(s[10]=a()),n(t,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[11]||(s[11]=e(`
    julia
    layer_map(f, l::AbstractLuxLayer, ps, st::NamedTuple)

    Map the function f over the model l, with the parameters ps and states st. This is different from Functors.fmap since it zips the layers, parameters, and states and invokes the function on all of them together.

    KeyPath provided to the function

    The KeyPath depths on the structure of the parameters and states. This is of consequence exclusively for AbstractLuxWrapperLayer where the structure of the layer doesn't match the structure of the parameters and states. In the example, provided below, the KeyPath is (:chain, :dense_1) for the first layer (following the structure in ps) while accessing the same layer in the chain is done with ( :chain, :layers, :dense_1).

    Call Signature for f

    Extended Help

    Example

    julia
    julia> using Lux, Random
    +
    +julia> c = Parallel(
    +           +; chain=Chain(; dense_1=Dense(2 => 3), bn=BatchNorm(3), dense_2=Dense(3 => 5)),
    +           dense_3=Dense(5 => 1));
    +
    +julia> rng = Random.default_rng();
    +
    +julia> ps, st = Lux.setup(rng, c);
    +
    +julia> # Makes parameters of Dense Layers inside Chain zero
    +       function zero_dense_params(l, ps, st, name)
    +           if l isa Dense
    +               println("zeroing params of $name")
    +               ps = merge(ps, (; weight=zero.(ps.weight), bias=zero.(ps.bias)))
    +           end
    +           return l, ps, st
    +       end;
    +
    +julia> _, ps_new, _ = Lux.Experimental.layer_map(zero_dense_params, c, ps, st);
    +zeroing params of KeyPath(:chain, :dense_1)
    +zeroing params of KeyPath(:chain, :dense_2)
    +zeroing params of KeyPath(:dense_3,)
    +
    +julia> all(iszero, (ps_new.chain.dense_1.weight, ps_new.chain.dense_1.bias,
    +                    ps_new.chain.dense_2.weight, ps_new.chain.dense_2.bias,
    +                    ps_new.dense_3.weight, ps_new.dense_3.bias))
    +true

    source

    `,9))]),s[24]||(s[24]=i("h2",{id:"Debugging-Functionality",tabindex:"-1"},[a("Debugging Functionality "),i("a",{class:"header-anchor",href:"#Debugging-Functionality","aria-label":'Permalink to "Debugging Functionality {#Debugging-Functionality}"'},"​")],-1)),s[25]||(s[25]=i("p",null,"Model not working properly! Here are some functionalities to help you debug you Lux model.",-1)),i("details",y,[i("summary",null,[s[12]||(s[12]=i("a",{id:"Lux.Experimental.@debug_mode",href:"#Lux.Experimental.@debug_mode"},[i("span",{class:"jlbinding"},"Lux.Experimental.@debug_mode")],-1)),s[13]||(s[13]=a()),n(t,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),s[14]||(s[14]=e('
    julia
    @debug_mode layer kwargs...

    Recurses into the layer and replaces the inner most non Container Layers with a Lux.Experimental.DebugLayer.

    See Lux.Experimental.DebugLayer for details about the Keyword Arguments.

    source

    ',4))]),i("details",c,[i("summary",null,[s[15]||(s[15]=i("a",{id:"Lux.Experimental.DebugLayer",href:"#Lux.Experimental.DebugLayer"},[i("span",{class:"jlbinding"},"Lux.Experimental.DebugLayer")],-1)),s[16]||(s[16]=a()),n(t,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[17]||(s[17]=e(`
    julia
    DebugLayer(layer::AbstractLuxLayer;
    +    nan_check::Union{Symbol, StaticSymbol, Val}=static(:both),
    +    error_check::Union{StaticBool, Bool, Val{true}, Val{false}}=True(),
    +    location::KeyPath=KeyPath())

    A wrapper over Lux layers that adds checks for NaNs and errors. This is useful for debugging.

    Arguments

    Extended Help

    Keyword Arguments

    Input / Output

    Inputs and outputs are the same as the layer unless one of the nan_check or error_check criteria is met.

    If nan_check is enabled and NaNs are detected then a DomainError is thrown. If error_check is enabled, then any errors in the layer are thrown with useful information to track where the error originates.

    ChainRules Compatible Reverse Mode AD Tools

    nan_check for the backward mode only works with ChainRules Compatible Reverse Mode AD Tools currently.

    Disable After Debugging

    This layer is only meant to be used for debugging. If used for actual training or inference, will lead to extremely bad performance.

    See Lux.Experimental.@debug_mode to construct this layer.

    source

    `,14))]),s[26]||(s[26]=i("h2",{id:"Tied-Parameters",tabindex:"-1"},[a("Tied Parameters "),i("a",{class:"header-anchor",href:"#Tied-Parameters","aria-label":'Permalink to "Tied Parameters {#Tied-Parameters}"'},"​")],-1)),i("details",u,[i("summary",null,[s[18]||(s[18]=i("a",{id:"Lux.Experimental.share_parameters",href:"#Lux.Experimental.share_parameters"},[i("span",{class:"jlbinding"},"Lux.Experimental.share_parameters")],-1)),s[19]||(s[19]=a()),n(t,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[20]||(s[20]=e(`
    julia
    share_parameters(ps, sharing)
    +share_parameters(ps, sharing, new_parameters)

    Updates the parameters in ps with a common set of parameters new_parameters that are shared between each list in the nested list sharing. (That was kind of a mouthful, the example should make it clear).

    Arguments

    Returns

    Updated Parameters having the same structure as ps.

    Example

    julia
    julia> model = Chain(; d1=Dense(2 => 4, tanh),
    +           d3=Chain(; l1=Dense(4 => 2), l2=Dense(2 => 4)), d2=Dense(4 => 2))
    +Chain(
    +    d1 = Dense(2 => 4, tanh),           # 12 parameters
    +    d3 = Chain(
    +        l1 = Dense(4 => 2),             # 10 parameters
    +        l2 = Dense(2 => 4),             # 12 parameters
    +    ),
    +    d2 = Dense(4 => 2),                 # 10 parameters
    +)         # Total: 44 parameters,
    +          #        plus 0 states.
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), model);
    +
    +julia> # share parameters of (d1 and d3.l1) and (d3.l2 and d2)
    +       ps = Lux.Experimental.share_parameters(ps, (("d3.l2", "d1"), ("d2", "d3.l1")));
    +
    +julia> ps.d3.l2.weight === ps.d1.weight &&
    +           ps.d3.l2.bias === ps.d1.bias &&
    +           ps.d2.weight === ps.d3.l1.weight &&
    +           ps.d2.bias === ps.d3.l1.bias
    +true

    ComponentArrays

    ComponentArrays doesn't allow sharing parameters. Converting the returned parameters to a ComponentArray will silently cause the parameter sharing to be undone.

    source

    `,10))])])}const L=h(r,[["render",F]]);export{A as __pageData,L as default}; diff --git a/previews/PR1023/assets/api_Lux_contrib.md.tcySUcib.lean.js b/previews/PR1023/assets/api_Lux_contrib.md.tcySUcib.lean.js new file mode 100644 index 0000000000..35e29c2668 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_contrib.md.tcySUcib.lean.js @@ -0,0 +1,55 @@ +import{_ as h,c as l,a2 as e,j as i,a,G as n,B as p,o as k}from"./chunks/framework.DFwXuivk.js";const A=JSON.parse('{"title":"Experimental Features","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/contrib.md","filePath":"api/Lux/contrib.md","lastUpdated":null}'),r={name:"api/Lux/contrib.md"},d={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},o={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"};function F(m,s,C,f,b,D){const t=p("Badge");return k(),l("div",null,[s[21]||(s[21]=e('

    Experimental Features

    All features listed on this page are experimental which means:

    1. No SemVer Guarantees. We use code here to iterate fast. That said, historically we have never broken any code in this module and have always provided a deprecation period.

    2. Expect edge-cases and report them. It will help us move these features out of experimental sooner.

    3. None of the features are exported.

    Parameter Freezing

    ',4)),i("details",d,[i("summary",null,[s[0]||(s[0]=i("a",{id:"Lux.Experimental.FrozenLayer",href:"#Lux.Experimental.FrozenLayer"},[i("span",{class:"jlbinding"},"Lux.Experimental.FrozenLayer")],-1)),s[1]||(s[1]=a()),n(t,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[2]||(s[2]=e(`
    julia
    FrozenLayer(l::AbstractLuxLayer, which_params::Optional{Tuple})

    Freeze the parameters with name which_params of the layer l.

    Use Lux.Experimental.freeze instead

    It is always recommended to use the Lux.Experimental.freeze function instead of directly using the FrozenLayer constructor.

    No checks for which_params

    There are no checks for which_params. For example, if the original layer has parameters named (:weight, :bias), and which_params is set to (:myweight,) then none of the parameters are frozen and no error is thrown.

    Arguments

    Extended Help

    Parameters

    States

    Note on Internal Layer Implementation

    The inner layer should work with NamedTuple parameters. In order to support custom parameter types, users need to implement Lux.Utils.merge(::CustomParamType, ::NamedTuple) or extend Lux.Utils.named_tuple(::CustomParamType) to return a NamedTuple.

    Example

    julia
    julia> Lux.Experimental.FrozenLayer(Dense(2 => 2), (:weight,))
    +FrozenLayer(Dense(2 => 2), (:weight,))  # 2 parameters, plus 4 non-trainable

    See also Lux.Experimental.freeze, Lux.Experimental.unfreeze.

    source

    `,17))]),i("details",E,[i("summary",null,[s[3]||(s[3]=i("a",{id:"Lux.Experimental.freeze",href:"#Lux.Experimental.freeze"},[i("span",{class:"jlbinding"},"Lux.Experimental.freeze")],-1)),s[4]||(s[4]=a()),n(t,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[5]||(s[5]=e(`
    julia
    freeze(l::AbstractLuxLayer, which_params::Optional{Tuple} = nothing)

    Constructs a version of l with which_params frozen. If which_params is nothing, then all parameters are frozen.

    source

    julia
    freeze(l::AbstractLuxLayer, ps, st::NamedTuple,
    +    which_params::Optional{Tuple} = nothing)

    Construct a Lux.Experimental.FrozenLayer for l with the current parameters and states. If which_params is nothing, then all parameters are frozen.

    source

    `,6))]),i("details",o,[i("summary",null,[s[6]||(s[6]=i("a",{id:"Lux.Experimental.unfreeze",href:"#Lux.Experimental.unfreeze"},[i("span",{class:"jlbinding"},"Lux.Experimental.unfreeze")],-1)),s[7]||(s[7]=a()),n(t,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[8]||(s[8]=e('
    julia
    unfreeze(l::FrozenLayer)

    Unfreezes the layer l.

    source

    julia
    unfreeze(l::FrozenLayer, ps, st::NamedTuple)

    Unwraps a Lux.Experimental.FrozenLayer l with the current parameters and states.

    source

    ',6))]),s[22]||(s[22]=i("p",null,[a("For detailed usage example look at the "),i("a",{href:"/previews/PR1023/manual/freezing_model_parameters#freezing-model-parameters"},"manual page"),a(".")],-1)),s[23]||(s[23]=i("h2",{id:"Map-over-Layer",tabindex:"-1"},[a("Map over Layer "),i("a",{class:"header-anchor",href:"#Map-over-Layer","aria-label":'Permalink to "Map over Layer {#Map-over-Layer}"'},"​")],-1)),i("details",g,[i("summary",null,[s[9]||(s[9]=i("a",{id:"Lux.Experimental.layer_map",href:"#Lux.Experimental.layer_map"},[i("span",{class:"jlbinding"},"Lux.Experimental.layer_map")],-1)),s[10]||(s[10]=a()),n(t,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[11]||(s[11]=e(`
    julia
    layer_map(f, l::AbstractLuxLayer, ps, st::NamedTuple)

    Map the function f over the model l, with the parameters ps and states st. This is different from Functors.fmap since it zips the layers, parameters, and states and invokes the function on all of them together.

    KeyPath provided to the function

    The KeyPath depths on the structure of the parameters and states. This is of consequence exclusively for AbstractLuxWrapperLayer where the structure of the layer doesn't match the structure of the parameters and states. In the example, provided below, the KeyPath is (:chain, :dense_1) for the first layer (following the structure in ps) while accessing the same layer in the chain is done with ( :chain, :layers, :dense_1).

    Call Signature for f

    Extended Help

    Example

    julia
    julia> using Lux, Random
    +
    +julia> c = Parallel(
    +           +; chain=Chain(; dense_1=Dense(2 => 3), bn=BatchNorm(3), dense_2=Dense(3 => 5)),
    +           dense_3=Dense(5 => 1));
    +
    +julia> rng = Random.default_rng();
    +
    +julia> ps, st = Lux.setup(rng, c);
    +
    +julia> # Makes parameters of Dense Layers inside Chain zero
    +       function zero_dense_params(l, ps, st, name)
    +           if l isa Dense
    +               println("zeroing params of $name")
    +               ps = merge(ps, (; weight=zero.(ps.weight), bias=zero.(ps.bias)))
    +           end
    +           return l, ps, st
    +       end;
    +
    +julia> _, ps_new, _ = Lux.Experimental.layer_map(zero_dense_params, c, ps, st);
    +zeroing params of KeyPath(:chain, :dense_1)
    +zeroing params of KeyPath(:chain, :dense_2)
    +zeroing params of KeyPath(:dense_3,)
    +
    +julia> all(iszero, (ps_new.chain.dense_1.weight, ps_new.chain.dense_1.bias,
    +                    ps_new.chain.dense_2.weight, ps_new.chain.dense_2.bias,
    +                    ps_new.dense_3.weight, ps_new.dense_3.bias))
    +true

    source

    `,9))]),s[24]||(s[24]=i("h2",{id:"Debugging-Functionality",tabindex:"-1"},[a("Debugging Functionality "),i("a",{class:"header-anchor",href:"#Debugging-Functionality","aria-label":'Permalink to "Debugging Functionality {#Debugging-Functionality}"'},"​")],-1)),s[25]||(s[25]=i("p",null,"Model not working properly! Here are some functionalities to help you debug you Lux model.",-1)),i("details",y,[i("summary",null,[s[12]||(s[12]=i("a",{id:"Lux.Experimental.@debug_mode",href:"#Lux.Experimental.@debug_mode"},[i("span",{class:"jlbinding"},"Lux.Experimental.@debug_mode")],-1)),s[13]||(s[13]=a()),n(t,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),s[14]||(s[14]=e('
    julia
    @debug_mode layer kwargs...

    Recurses into the layer and replaces the inner most non Container Layers with a Lux.Experimental.DebugLayer.

    See Lux.Experimental.DebugLayer for details about the Keyword Arguments.

    source

    ',4))]),i("details",c,[i("summary",null,[s[15]||(s[15]=i("a",{id:"Lux.Experimental.DebugLayer",href:"#Lux.Experimental.DebugLayer"},[i("span",{class:"jlbinding"},"Lux.Experimental.DebugLayer")],-1)),s[16]||(s[16]=a()),n(t,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[17]||(s[17]=e(`
    julia
    DebugLayer(layer::AbstractLuxLayer;
    +    nan_check::Union{Symbol, StaticSymbol, Val}=static(:both),
    +    error_check::Union{StaticBool, Bool, Val{true}, Val{false}}=True(),
    +    location::KeyPath=KeyPath())

    A wrapper over Lux layers that adds checks for NaNs and errors. This is useful for debugging.

    Arguments

    Extended Help

    Keyword Arguments

    Input / Output

    Inputs and outputs are the same as the layer unless one of the nan_check or error_check criteria is met.

    If nan_check is enabled and NaNs are detected then a DomainError is thrown. If error_check is enabled, then any errors in the layer are thrown with useful information to track where the error originates.

    ChainRules Compatible Reverse Mode AD Tools

    nan_check for the backward mode only works with ChainRules Compatible Reverse Mode AD Tools currently.

    Disable After Debugging

    This layer is only meant to be used for debugging. If used for actual training or inference, will lead to extremely bad performance.

    See Lux.Experimental.@debug_mode to construct this layer.

    source

    `,14))]),s[26]||(s[26]=i("h2",{id:"Tied-Parameters",tabindex:"-1"},[a("Tied Parameters "),i("a",{class:"header-anchor",href:"#Tied-Parameters","aria-label":'Permalink to "Tied Parameters {#Tied-Parameters}"'},"​")],-1)),i("details",u,[i("summary",null,[s[18]||(s[18]=i("a",{id:"Lux.Experimental.share_parameters",href:"#Lux.Experimental.share_parameters"},[i("span",{class:"jlbinding"},"Lux.Experimental.share_parameters")],-1)),s[19]||(s[19]=a()),n(t,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[20]||(s[20]=e(`
    julia
    share_parameters(ps, sharing)
    +share_parameters(ps, sharing, new_parameters)

    Updates the parameters in ps with a common set of parameters new_parameters that are shared between each list in the nested list sharing. (That was kind of a mouthful, the example should make it clear).

    Arguments

    Returns

    Updated Parameters having the same structure as ps.

    Example

    julia
    julia> model = Chain(; d1=Dense(2 => 4, tanh),
    +           d3=Chain(; l1=Dense(4 => 2), l2=Dense(2 => 4)), d2=Dense(4 => 2))
    +Chain(
    +    d1 = Dense(2 => 4, tanh),           # 12 parameters
    +    d3 = Chain(
    +        l1 = Dense(4 => 2),             # 10 parameters
    +        l2 = Dense(2 => 4),             # 12 parameters
    +    ),
    +    d2 = Dense(4 => 2),                 # 10 parameters
    +)         # Total: 44 parameters,
    +          #        plus 0 states.
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), model);
    +
    +julia> # share parameters of (d1 and d3.l1) and (d3.l2 and d2)
    +       ps = Lux.Experimental.share_parameters(ps, (("d3.l2", "d1"), ("d2", "d3.l1")));
    +
    +julia> ps.d3.l2.weight === ps.d1.weight &&
    +           ps.d3.l2.bias === ps.d1.bias &&
    +           ps.d2.weight === ps.d3.l1.weight &&
    +           ps.d2.bias === ps.d3.l1.bias
    +true

    ComponentArrays

    ComponentArrays doesn't allow sharing parameters. Converting the returned parameters to a ComponentArray will silently cause the parameter sharing to be undone.

    source

    `,10))])])}const L=h(r,[["render",F]]);export{A as __pageData,L as default}; diff --git a/previews/PR1023/assets/api_Lux_distributed_utils.md.D1YsLAOX.js b/previews/PR1023/assets/api_Lux_distributed_utils.md.D1YsLAOX.js new file mode 100644 index 0000000000..39f3ab4f17 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_distributed_utils.md.D1YsLAOX.js @@ -0,0 +1,4 @@ +import{_ as n,c as d,a2 as e,j as s,a as t,G as l,B as r,o as p}from"./chunks/framework.DFwXuivk.js";const I=JSON.parse('{"title":"Distributed Utils","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/distributed_utils.md","filePath":"api/Lux/distributed_utils.md","lastUpdated":null}'),o={name:"api/Lux/distributed_utils.md"},k={class:"jldocstring custom-block"},h={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},C={class:"jldocstring custom-block"},L={class:"jldocstring custom-block"},j={class:"jldocstring custom-block"};function F(v,i,x,D,B,U){const a=r("Badge");return p(),d("div",null,[i[39]||(i[39]=e('

    Distributed Utils

    Note

    These functionalities are available via the Lux.DistributedUtils module.

    Backends

    ',3)),s("details",k,[s("summary",null,[i[0]||(i[0]=s("a",{id:"Lux.MPIBackend",href:"#Lux.MPIBackend"},[s("span",{class:"jlbinding"},"Lux.MPIBackend")],-1)),i[1]||(i[1]=t()),l(a,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[2]||(i[2]=e('
    julia
    MPIBackend(comm = nothing)

    Create an MPI backend for distributed training. Users should not use this function directly. Instead use DistributedUtils.get_distributed_backend(MPIBackend).

    source

    ',3))]),s("details",h,[s("summary",null,[i[3]||(i[3]=s("a",{id:"Lux.NCCLBackend",href:"#Lux.NCCLBackend"},[s("span",{class:"jlbinding"},"Lux.NCCLBackend")],-1)),i[4]||(i[4]=t()),l(a,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[5]||(i[5]=e('
    julia
    NCCLBackend(comm = nothing, mpi_backend = nothing)

    Create an NCCL backend for distributed training. Users should not use this function directly. Instead use DistributedUtils.get_distributed_backend(NCCLBackend).

    source

    ',3))]),i[40]||(i[40]=s("h2",{id:"initialization",tabindex:"-1"},[t("Initialization "),s("a",{class:"header-anchor",href:"#initialization","aria-label":'Permalink to "Initialization"'},"​")],-1)),s("details",u,[s("summary",null,[i[6]||(i[6]=s("a",{id:"Lux.DistributedUtils.initialize",href:"#Lux.DistributedUtils.initialize"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.initialize")],-1)),i[7]||(i[7]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[8]||(i[8]=e('
    julia
    initialize(backend::Type{<:AbstractLuxDistributedBackend}; kwargs...)

    Initialize the given backend. Users can supply cuda_devices and amdgpu_devices to initialize the backend with the given devices. These can be set to missing to prevent initialization of the given device type. If set to nothing, and the backend is functional we assign GPUs in a round-robin fashion. Finally, a list of integers can be supplied to initialize the backend with the given devices.

    Possible values for backend are:

    source

    ',5))]),s("details",c,[s("summary",null,[i[9]||(i[9]=s("a",{id:"Lux.DistributedUtils.initialized",href:"#Lux.DistributedUtils.initialized"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.initialized")],-1)),i[10]||(i[10]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[11]||(i[11]=e('
    julia
    initialized(backend::Type{<:AbstractLuxDistributedBackend})

    Check if the given backend is initialized.

    source

    ',3))]),s("details",b,[s("summary",null,[i[12]||(i[12]=s("a",{id:"Lux.DistributedUtils.get_distributed_backend",href:"#Lux.DistributedUtils.get_distributed_backend"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.get_distributed_backend")],-1)),i[13]||(i[13]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[14]||(i[14]=e('
    julia
    get_distributed_backend(backend::Type{<:AbstractLuxDistributedBackend})

    Get the distributed backend for the given backend type. Possible values are:

    Danger

    initialize(backend; kwargs...) must be called before calling this function.

    source

    ',5))]),i[41]||(i[41]=s("h2",{id:"Helper-Functions",tabindex:"-1"},[t("Helper Functions "),s("a",{class:"header-anchor",href:"#Helper-Functions","aria-label":'Permalink to "Helper Functions {#Helper-Functions}"'},"​")],-1)),s("details",g,[s("summary",null,[i[15]||(i[15]=s("a",{id:"Lux.DistributedUtils.local_rank",href:"#Lux.DistributedUtils.local_rank"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.local_rank")],-1)),i[16]||(i[16]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[17]||(i[17]=e('
    julia
    local_rank(backend::AbstractLuxDistributedBackend)

    Get the local rank for the given backend.

    source

    ',3))]),s("details",f,[s("summary",null,[i[18]||(i[18]=s("a",{id:"Lux.DistributedUtils.total_workers",href:"#Lux.DistributedUtils.total_workers"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.total_workers")],-1)),i[19]||(i[19]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[20]||(i[20]=e('
    julia
    total_workers(backend::AbstractLuxDistributedBackend)

    Get the total number of workers for the given backend.

    source

    ',3))]),i[42]||(i[42]=s("h2",{id:"Communication-Primitives",tabindex:"-1"},[t("Communication Primitives "),s("a",{class:"header-anchor",href:"#Communication-Primitives","aria-label":'Permalink to "Communication Primitives {#Communication-Primitives}"'},"​")],-1)),s("details",y,[s("summary",null,[i[21]||(i[21]=s("a",{id:"Lux.DistributedUtils.allreduce!",href:"#Lux.DistributedUtils.allreduce!"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.allreduce!")],-1)),i[22]||(i[22]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[23]||(i[23]=e(`
    julia
    allreduce!(backend::AbstractLuxDistributedBackend, sendrecvbuf, op)
    +allreduce!(backend::AbstractLuxDistributedBackend, sendbuf, recvbuf, op)

    Backend Agnostic API to perform an allreduce operation on the given buffer sendrecvbuf or sendbuf and store the result in recvbuf.

    op allows a special DistributedUtils.avg operation that averages the result across all workers.

    source

    `,4))]),s("details",m,[s("summary",null,[i[24]||(i[24]=s("a",{id:"Lux.DistributedUtils.bcast!",href:"#Lux.DistributedUtils.bcast!"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.bcast!")],-1)),i[25]||(i[25]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[26]||(i[26]=e(`
    julia
    bcast!(backend::AbstractLuxDistributedBackend, sendrecvbuf; root::Int=0)
    +bcast!(backend::AbstractLuxDistributedBackend, sendbuf, recvbuf; root::Int=0)

    Backend Agnostic API to broadcast the given buffer sendrecvbuf or sendbuf to all workers into recvbuf. The value at root will be broadcasted to all other workers.

    source

    `,3))]),s("details",E,[s("summary",null,[i[27]||(i[27]=s("a",{id:"Lux.DistributedUtils.reduce!",href:"#Lux.DistributedUtils.reduce!"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.reduce!")],-1)),i[28]||(i[28]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[29]||(i[29]=e(`
    julia
    reduce!(backend::AbstractLuxDistributedBackend, sendrecvbuf, op; root::Int=0)
    +reduce!(backend::AbstractLuxDistributedBackend, sendbuf, recvbuf, op; root::Int=0)

    Backend Agnostic API to perform a reduce operation on the given buffer sendrecvbuf or sendbuf and store the result in recvbuf.

    op allows a special DistributedUtils.avg operation that averages the result across all workers.

    source

    `,4))]),s("details",C,[s("summary",null,[i[30]||(i[30]=s("a",{id:"Lux.DistributedUtils.synchronize!!",href:"#Lux.DistributedUtils.synchronize!!"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.synchronize!!")],-1)),i[31]||(i[31]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[32]||(i[32]=e('
    julia
    synchronize!!(backend::AbstractLuxDistributedBackend, ps; root::Int=0)

    Synchronize the given structure ps using the given backend. The value at root will be broadcasted to all other workers.

    source

    ',3))]),i[43]||(i[43]=s("h2",{id:"Optimizers.jl-Integration",tabindex:"-1"},[t("Optimizers.jl Integration "),s("a",{class:"header-anchor",href:"#Optimizers.jl-Integration","aria-label":'Permalink to "Optimizers.jl Integration {#Optimizers.jl-Integration}"'},"​")],-1)),s("details",L,[s("summary",null,[i[33]||(i[33]=s("a",{id:"Lux.DistributedUtils.DistributedOptimizer",href:"#Lux.DistributedUtils.DistributedOptimizer"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.DistributedOptimizer")],-1)),i[34]||(i[34]=t()),l(a,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[35]||(i[35]=e('
    julia
    DistributedOptimizer(backend::AbstractLuxDistributedBacked, optimizer)

    Wrap the optimizer in a DistributedOptimizer. Before updating the parameters, this averages the gradients across the processes using Allreduce.

    Arguments

    source

    ',5))]),i[44]||(i[44]=s("h2",{id:"MLUtils.jl-Integration",tabindex:"-1"},[t("MLUtils.jl Integration "),s("a",{class:"header-anchor",href:"#MLUtils.jl-Integration","aria-label":'Permalink to "MLUtils.jl Integration {#MLUtils.jl-Integration}"'},"​")],-1)),s("details",j,[s("summary",null,[i[36]||(i[36]=s("a",{id:"Lux.DistributedUtils.DistributedDataContainer",href:"#Lux.DistributedUtils.DistributedDataContainer"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.DistributedDataContainer")],-1)),i[37]||(i[37]=t()),l(a,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[38]||(i[38]=e('
    julia
    DistributedDataContainer(backend::AbstractLuxDistributedBackend, data)

    data must be compatible with MLUtils interface. The returned container is compatible with MLUtils interface and is used to partition the dataset across the available processes.

    Load MLUtils.jl

    MLUtils.jl must be installed and loaded before using this.

    source

    ',4))])])}const P=n(o,[["render",F]]);export{I as __pageData,P as default}; diff --git a/previews/PR1023/assets/api_Lux_distributed_utils.md.D1YsLAOX.lean.js b/previews/PR1023/assets/api_Lux_distributed_utils.md.D1YsLAOX.lean.js new file mode 100644 index 0000000000..39f3ab4f17 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_distributed_utils.md.D1YsLAOX.lean.js @@ -0,0 +1,4 @@ +import{_ as n,c as d,a2 as e,j as s,a as t,G as l,B as r,o as p}from"./chunks/framework.DFwXuivk.js";const I=JSON.parse('{"title":"Distributed Utils","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/distributed_utils.md","filePath":"api/Lux/distributed_utils.md","lastUpdated":null}'),o={name:"api/Lux/distributed_utils.md"},k={class:"jldocstring custom-block"},h={class:"jldocstring custom-block"},u={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},C={class:"jldocstring custom-block"},L={class:"jldocstring custom-block"},j={class:"jldocstring custom-block"};function F(v,i,x,D,B,U){const a=r("Badge");return p(),d("div",null,[i[39]||(i[39]=e('

    Distributed Utils

    Note

    These functionalities are available via the Lux.DistributedUtils module.

    Backends

    ',3)),s("details",k,[s("summary",null,[i[0]||(i[0]=s("a",{id:"Lux.MPIBackend",href:"#Lux.MPIBackend"},[s("span",{class:"jlbinding"},"Lux.MPIBackend")],-1)),i[1]||(i[1]=t()),l(a,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[2]||(i[2]=e('
    julia
    MPIBackend(comm = nothing)

    Create an MPI backend for distributed training. Users should not use this function directly. Instead use DistributedUtils.get_distributed_backend(MPIBackend).

    source

    ',3))]),s("details",h,[s("summary",null,[i[3]||(i[3]=s("a",{id:"Lux.NCCLBackend",href:"#Lux.NCCLBackend"},[s("span",{class:"jlbinding"},"Lux.NCCLBackend")],-1)),i[4]||(i[4]=t()),l(a,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[5]||(i[5]=e('
    julia
    NCCLBackend(comm = nothing, mpi_backend = nothing)

    Create an NCCL backend for distributed training. Users should not use this function directly. Instead use DistributedUtils.get_distributed_backend(NCCLBackend).

    source

    ',3))]),i[40]||(i[40]=s("h2",{id:"initialization",tabindex:"-1"},[t("Initialization "),s("a",{class:"header-anchor",href:"#initialization","aria-label":'Permalink to "Initialization"'},"​")],-1)),s("details",u,[s("summary",null,[i[6]||(i[6]=s("a",{id:"Lux.DistributedUtils.initialize",href:"#Lux.DistributedUtils.initialize"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.initialize")],-1)),i[7]||(i[7]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[8]||(i[8]=e('
    julia
    initialize(backend::Type{<:AbstractLuxDistributedBackend}; kwargs...)

    Initialize the given backend. Users can supply cuda_devices and amdgpu_devices to initialize the backend with the given devices. These can be set to missing to prevent initialization of the given device type. If set to nothing, and the backend is functional we assign GPUs in a round-robin fashion. Finally, a list of integers can be supplied to initialize the backend with the given devices.

    Possible values for backend are:

    source

    ',5))]),s("details",c,[s("summary",null,[i[9]||(i[9]=s("a",{id:"Lux.DistributedUtils.initialized",href:"#Lux.DistributedUtils.initialized"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.initialized")],-1)),i[10]||(i[10]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[11]||(i[11]=e('
    julia
    initialized(backend::Type{<:AbstractLuxDistributedBackend})

    Check if the given backend is initialized.

    source

    ',3))]),s("details",b,[s("summary",null,[i[12]||(i[12]=s("a",{id:"Lux.DistributedUtils.get_distributed_backend",href:"#Lux.DistributedUtils.get_distributed_backend"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.get_distributed_backend")],-1)),i[13]||(i[13]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[14]||(i[14]=e('
    julia
    get_distributed_backend(backend::Type{<:AbstractLuxDistributedBackend})

    Get the distributed backend for the given backend type. Possible values are:

    Danger

    initialize(backend; kwargs...) must be called before calling this function.

    source

    ',5))]),i[41]||(i[41]=s("h2",{id:"Helper-Functions",tabindex:"-1"},[t("Helper Functions "),s("a",{class:"header-anchor",href:"#Helper-Functions","aria-label":'Permalink to "Helper Functions {#Helper-Functions}"'},"​")],-1)),s("details",g,[s("summary",null,[i[15]||(i[15]=s("a",{id:"Lux.DistributedUtils.local_rank",href:"#Lux.DistributedUtils.local_rank"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.local_rank")],-1)),i[16]||(i[16]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[17]||(i[17]=e('
    julia
    local_rank(backend::AbstractLuxDistributedBackend)

    Get the local rank for the given backend.

    source

    ',3))]),s("details",f,[s("summary",null,[i[18]||(i[18]=s("a",{id:"Lux.DistributedUtils.total_workers",href:"#Lux.DistributedUtils.total_workers"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.total_workers")],-1)),i[19]||(i[19]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[20]||(i[20]=e('
    julia
    total_workers(backend::AbstractLuxDistributedBackend)

    Get the total number of workers for the given backend.

    source

    ',3))]),i[42]||(i[42]=s("h2",{id:"Communication-Primitives",tabindex:"-1"},[t("Communication Primitives "),s("a",{class:"header-anchor",href:"#Communication-Primitives","aria-label":'Permalink to "Communication Primitives {#Communication-Primitives}"'},"​")],-1)),s("details",y,[s("summary",null,[i[21]||(i[21]=s("a",{id:"Lux.DistributedUtils.allreduce!",href:"#Lux.DistributedUtils.allreduce!"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.allreduce!")],-1)),i[22]||(i[22]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[23]||(i[23]=e(`
    julia
    allreduce!(backend::AbstractLuxDistributedBackend, sendrecvbuf, op)
    +allreduce!(backend::AbstractLuxDistributedBackend, sendbuf, recvbuf, op)

    Backend Agnostic API to perform an allreduce operation on the given buffer sendrecvbuf or sendbuf and store the result in recvbuf.

    op allows a special DistributedUtils.avg operation that averages the result across all workers.

    source

    `,4))]),s("details",m,[s("summary",null,[i[24]||(i[24]=s("a",{id:"Lux.DistributedUtils.bcast!",href:"#Lux.DistributedUtils.bcast!"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.bcast!")],-1)),i[25]||(i[25]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[26]||(i[26]=e(`
    julia
    bcast!(backend::AbstractLuxDistributedBackend, sendrecvbuf; root::Int=0)
    +bcast!(backend::AbstractLuxDistributedBackend, sendbuf, recvbuf; root::Int=0)

    Backend Agnostic API to broadcast the given buffer sendrecvbuf or sendbuf to all workers into recvbuf. The value at root will be broadcasted to all other workers.

    source

    `,3))]),s("details",E,[s("summary",null,[i[27]||(i[27]=s("a",{id:"Lux.DistributedUtils.reduce!",href:"#Lux.DistributedUtils.reduce!"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.reduce!")],-1)),i[28]||(i[28]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[29]||(i[29]=e(`
    julia
    reduce!(backend::AbstractLuxDistributedBackend, sendrecvbuf, op; root::Int=0)
    +reduce!(backend::AbstractLuxDistributedBackend, sendbuf, recvbuf, op; root::Int=0)

    Backend Agnostic API to perform a reduce operation on the given buffer sendrecvbuf or sendbuf and store the result in recvbuf.

    op allows a special DistributedUtils.avg operation that averages the result across all workers.

    source

    `,4))]),s("details",C,[s("summary",null,[i[30]||(i[30]=s("a",{id:"Lux.DistributedUtils.synchronize!!",href:"#Lux.DistributedUtils.synchronize!!"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.synchronize!!")],-1)),i[31]||(i[31]=t()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[32]||(i[32]=e('
    julia
    synchronize!!(backend::AbstractLuxDistributedBackend, ps; root::Int=0)

    Synchronize the given structure ps using the given backend. The value at root will be broadcasted to all other workers.

    source

    ',3))]),i[43]||(i[43]=s("h2",{id:"Optimizers.jl-Integration",tabindex:"-1"},[t("Optimizers.jl Integration "),s("a",{class:"header-anchor",href:"#Optimizers.jl-Integration","aria-label":'Permalink to "Optimizers.jl Integration {#Optimizers.jl-Integration}"'},"​")],-1)),s("details",L,[s("summary",null,[i[33]||(i[33]=s("a",{id:"Lux.DistributedUtils.DistributedOptimizer",href:"#Lux.DistributedUtils.DistributedOptimizer"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.DistributedOptimizer")],-1)),i[34]||(i[34]=t()),l(a,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[35]||(i[35]=e('
    julia
    DistributedOptimizer(backend::AbstractLuxDistributedBacked, optimizer)

    Wrap the optimizer in a DistributedOptimizer. Before updating the parameters, this averages the gradients across the processes using Allreduce.

    Arguments

    source

    ',5))]),i[44]||(i[44]=s("h2",{id:"MLUtils.jl-Integration",tabindex:"-1"},[t("MLUtils.jl Integration "),s("a",{class:"header-anchor",href:"#MLUtils.jl-Integration","aria-label":'Permalink to "MLUtils.jl Integration {#MLUtils.jl-Integration}"'},"​")],-1)),s("details",j,[s("summary",null,[i[36]||(i[36]=s("a",{id:"Lux.DistributedUtils.DistributedDataContainer",href:"#Lux.DistributedUtils.DistributedDataContainer"},[s("span",{class:"jlbinding"},"Lux.DistributedUtils.DistributedDataContainer")],-1)),i[37]||(i[37]=t()),l(a,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[38]||(i[38]=e('
    julia
    DistributedDataContainer(backend::AbstractLuxDistributedBackend, data)

    data must be compatible with MLUtils interface. The returned container is compatible with MLUtils interface and is used to partition the dataset across the available processes.

    Load MLUtils.jl

    MLUtils.jl must be installed and loaded before using this.

    source

    ',4))])])}const P=n(o,[["render",F]]);export{I as __pageData,P as default}; diff --git a/previews/PR1023/assets/api_Lux_interop.md.DzKzCHM4.js b/previews/PR1023/assets/api_Lux_interop.md.DzKzCHM4.js new file mode 100644 index 0000000000..6bd83fd777 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_interop.md.DzKzCHM4.js @@ -0,0 +1,32 @@ +import{_ as n,c as p,a2 as a,j as i,a as t,G as l,B as h,o as k}from"./chunks/framework.DFwXuivk.js";const A=JSON.parse('{"title":"Interoperability between Lux and other packages","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/interop.md","filePath":"api/Lux/interop.md","lastUpdated":null}'),r={name:"api/Lux/interop.md"},d={class:"jldocstring custom-block"},o={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"};function u(F,s,C,m,f,b){const e=h("Badge");return k(),p("div",null,[s[18]||(s[18]=a('

    Interoperability between Lux and other packages

    Switching from older frameworks

    Flux Models to Lux Models

    Flux.jl has been around in the Julia ecosystem for a long time and has a large userbase, hence we provide a way to convert Flux models to Lux models.

    Tip

    Accessing these functions require manually loading Flux, i.e., using Flux must be present somewhere in the code for these to be used.

    ',5)),i("details",d,[i("summary",null,[s[0]||(s[0]=i("a",{id:"Adapt.adapt-Tuple{FromFluxAdaptor, Any}",href:"#Adapt.adapt-Tuple{FromFluxAdaptor, Any}"},[i("span",{class:"jlbinding"},"Adapt.adapt")],-1)),s[1]||(s[1]=t()),l(e,{type:"info",class:"jlObjectType jlMethod",text:"Method"})]),s[2]||(s[2]=a('
    julia
    Adapt.adapt(from::FromFluxAdaptor, L)

    Adapt a Flux model L to Lux model. See FromFluxAdaptor for more details.

    source

    ',3))]),i("details",o,[i("summary",null,[s[3]||(s[3]=i("a",{id:"Lux.FromFluxAdaptor",href:"#Lux.FromFluxAdaptor"},[i("span",{class:"jlbinding"},"Lux.FromFluxAdaptor")],-1)),s[4]||(s[4]=t()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[5]||(s[5]=a(`
    julia
    FromFluxAdaptor(preserve_ps_st::Bool=false, force_preserve::Bool=false)

    Convert a Flux Model to Lux Model.

    active field

    This always ignores the active field of some of the Flux layers. This is almost never going to be supported.

    Keyword Arguments

    Example

    julia
    julia> import Flux
    +
    +julia> using Adapt, Lux, Random
    +
    +julia> m = Flux.Chain(Flux.Dense(2 => 3, relu), Flux.Dense(3 => 2));
    +
    +julia> m2 = adapt(FromFluxAdaptor(), m); # or FromFluxAdaptor()(m.layers)
    +
    +julia> x = randn(Float32, 2, 32);
    +
    +julia> ps, st = Lux.setup(Random.default_rng(), m2);
    +
    +julia> size(first(m2(x, ps, st)))
    +(2, 32)

    source

    `,8))]),i("details",E,[i("summary",null,[s[6]||(s[6]=i("a",{id:"Lux.FluxLayer",href:"#Lux.FluxLayer"},[i("span",{class:"jlbinding"},"Lux.FluxLayer")],-1)),s[7]||(s[7]=t()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[8]||(s[8]=a('
    julia
    FluxLayer(layer)

    Serves as a compatibility layer between Flux and Lux. This uses Optimisers.destructure API internally.

    Warning

    Lux was written to overcome the limitations of destructure + Flux. It is recommended to rewrite your layer in Lux instead of using this layer.

    Warning

    Introducing this Layer in your model will lead to type instabilities, given the way Optimisers.destructure works.

    Arguments

    Parameters

    source

    ',9))]),s[19]||(s[19]=a('

    Using a different backend for Lux

    Lux Models to Simple Chains

    SimpleChains.jl provides a way to train Small Neural Networks really fast on CPUs. See this blog post for more details. This section describes how to convert Lux models to SimpleChains models while preserving the layer interface.

    Tip

    Accessing these functions require manually loading SimpleChains, i.e., using SimpleChains must be present somewhere in the code for these to be used.

    ',4)),i("details",g,[i("summary",null,[s[9]||(s[9]=i("a",{id:"Adapt.adapt-Tuple{ToSimpleChainsAdaptor, AbstractLuxLayer}",href:"#Adapt.adapt-Tuple{ToSimpleChainsAdaptor, AbstractLuxLayer}"},[i("span",{class:"jlbinding"},"Adapt.adapt")],-1)),s[10]||(s[10]=t()),l(e,{type:"info",class:"jlObjectType jlMethod",text:"Method"})]),s[11]||(s[11]=a('
    julia
    Adapt.adapt(from::ToSimpleChainsAdaptor, L::AbstractLuxLayer)

    Adapt a Simple Chains model to Lux model. See ToSimpleChainsAdaptor for more details.

    source

    ',3))]),i("details",y,[i("summary",null,[s[12]||(s[12]=i("a",{id:"Lux.ToSimpleChainsAdaptor",href:"#Lux.ToSimpleChainsAdaptor"},[i("span",{class:"jlbinding"},"Lux.ToSimpleChainsAdaptor")],-1)),s[13]||(s[13]=t()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[14]||(s[14]=a(`
    julia
    ToSimpleChainsAdaptor(input_dims, convert_to_array::Bool=false)

    Adaptor for converting a Lux Model to SimpleChains. The returned model is still a Lux model, and satisfies the AbstractLuxLayer interfacem but all internal calculations are performed using SimpleChains.

    Warning

    There is no way to preserve trained parameters and states when converting to SimpleChains.jl.

    Warning

    Any kind of initialization function is not preserved when converting to SimpleChains.jl.

    Arguments

    Example

    julia
    julia> import SimpleChains
    +
    +julia> using Adapt, Lux, Random
    +
    +julia> lux_model = Chain(Conv((5, 5), 1 => 6, relu), MaxPool((2, 2)),
    +           Conv((5, 5), 6 => 16, relu), MaxPool((2, 2)), FlattenLayer(3),
    +           Chain(Dense(256 => 128, relu), Dense(128 => 84, relu), Dense(84 => 10)));
    +
    +julia> adaptor = ToSimpleChainsAdaptor((28, 28, 1));
    +
    +julia> simple_chains_model = adapt(adaptor, lux_model); # or adaptor(lux_model)
    +
    +julia> ps, st = Lux.setup(Random.default_rng(), simple_chains_model);
    +
    +julia> x = randn(Float32, 28, 28, 1, 1);
    +
    +julia> size(first(simple_chains_model(x, ps, st)))
    +(10, 1)

    source

    `,9))]),i("details",c,[i("summary",null,[s[15]||(s[15]=i("a",{id:"Lux.SimpleChainsLayer",href:"#Lux.SimpleChainsLayer"},[i("span",{class:"jlbinding"},"Lux.SimpleChainsLayer")],-1)),s[16]||(s[16]=t()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[17]||(s[17]=a(`
    julia
    SimpleChainsLayer(layer, to_array::Union{Bool, Val}=Val(false))
    +SimpleChainsLayer(layer, lux_layer, to_array)

    Wraps a SimpleChains layer into a Lux layer. All operations are performed using SimpleChains but the layer satisfies the AbstractLuxLayer interface.

    ToArray is a boolean flag that determines whether the output should be converted to a regular Array or not. Default is false.

    Arguments

    source

    `,6))])])}const L=n(r,[["render",u]]);export{A as __pageData,L as default}; diff --git a/previews/PR1023/assets/api_Lux_interop.md.DzKzCHM4.lean.js b/previews/PR1023/assets/api_Lux_interop.md.DzKzCHM4.lean.js new file mode 100644 index 0000000000..6bd83fd777 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_interop.md.DzKzCHM4.lean.js @@ -0,0 +1,32 @@ +import{_ as n,c as p,a2 as a,j as i,a as t,G as l,B as h,o as k}from"./chunks/framework.DFwXuivk.js";const A=JSON.parse('{"title":"Interoperability between Lux and other packages","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/interop.md","filePath":"api/Lux/interop.md","lastUpdated":null}'),r={name:"api/Lux/interop.md"},d={class:"jldocstring custom-block"},o={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"};function u(F,s,C,m,f,b){const e=h("Badge");return k(),p("div",null,[s[18]||(s[18]=a('

    Interoperability between Lux and other packages

    Switching from older frameworks

    Flux Models to Lux Models

    Flux.jl has been around in the Julia ecosystem for a long time and has a large userbase, hence we provide a way to convert Flux models to Lux models.

    Tip

    Accessing these functions require manually loading Flux, i.e., using Flux must be present somewhere in the code for these to be used.

    ',5)),i("details",d,[i("summary",null,[s[0]||(s[0]=i("a",{id:"Adapt.adapt-Tuple{FromFluxAdaptor, Any}",href:"#Adapt.adapt-Tuple{FromFluxAdaptor, Any}"},[i("span",{class:"jlbinding"},"Adapt.adapt")],-1)),s[1]||(s[1]=t()),l(e,{type:"info",class:"jlObjectType jlMethod",text:"Method"})]),s[2]||(s[2]=a('
    julia
    Adapt.adapt(from::FromFluxAdaptor, L)

    Adapt a Flux model L to Lux model. See FromFluxAdaptor for more details.

    source

    ',3))]),i("details",o,[i("summary",null,[s[3]||(s[3]=i("a",{id:"Lux.FromFluxAdaptor",href:"#Lux.FromFluxAdaptor"},[i("span",{class:"jlbinding"},"Lux.FromFluxAdaptor")],-1)),s[4]||(s[4]=t()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[5]||(s[5]=a(`
    julia
    FromFluxAdaptor(preserve_ps_st::Bool=false, force_preserve::Bool=false)

    Convert a Flux Model to Lux Model.

    active field

    This always ignores the active field of some of the Flux layers. This is almost never going to be supported.

    Keyword Arguments

    Example

    julia
    julia> import Flux
    +
    +julia> using Adapt, Lux, Random
    +
    +julia> m = Flux.Chain(Flux.Dense(2 => 3, relu), Flux.Dense(3 => 2));
    +
    +julia> m2 = adapt(FromFluxAdaptor(), m); # or FromFluxAdaptor()(m.layers)
    +
    +julia> x = randn(Float32, 2, 32);
    +
    +julia> ps, st = Lux.setup(Random.default_rng(), m2);
    +
    +julia> size(first(m2(x, ps, st)))
    +(2, 32)

    source

    `,8))]),i("details",E,[i("summary",null,[s[6]||(s[6]=i("a",{id:"Lux.FluxLayer",href:"#Lux.FluxLayer"},[i("span",{class:"jlbinding"},"Lux.FluxLayer")],-1)),s[7]||(s[7]=t()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[8]||(s[8]=a('
    julia
    FluxLayer(layer)

    Serves as a compatibility layer between Flux and Lux. This uses Optimisers.destructure API internally.

    Warning

    Lux was written to overcome the limitations of destructure + Flux. It is recommended to rewrite your layer in Lux instead of using this layer.

    Warning

    Introducing this Layer in your model will lead to type instabilities, given the way Optimisers.destructure works.

    Arguments

    Parameters

    source

    ',9))]),s[19]||(s[19]=a('

    Using a different backend for Lux

    Lux Models to Simple Chains

    SimpleChains.jl provides a way to train Small Neural Networks really fast on CPUs. See this blog post for more details. This section describes how to convert Lux models to SimpleChains models while preserving the layer interface.

    Tip

    Accessing these functions require manually loading SimpleChains, i.e., using SimpleChains must be present somewhere in the code for these to be used.

    ',4)),i("details",g,[i("summary",null,[s[9]||(s[9]=i("a",{id:"Adapt.adapt-Tuple{ToSimpleChainsAdaptor, AbstractLuxLayer}",href:"#Adapt.adapt-Tuple{ToSimpleChainsAdaptor, AbstractLuxLayer}"},[i("span",{class:"jlbinding"},"Adapt.adapt")],-1)),s[10]||(s[10]=t()),l(e,{type:"info",class:"jlObjectType jlMethod",text:"Method"})]),s[11]||(s[11]=a('
    julia
    Adapt.adapt(from::ToSimpleChainsAdaptor, L::AbstractLuxLayer)

    Adapt a Simple Chains model to Lux model. See ToSimpleChainsAdaptor for more details.

    source

    ',3))]),i("details",y,[i("summary",null,[s[12]||(s[12]=i("a",{id:"Lux.ToSimpleChainsAdaptor",href:"#Lux.ToSimpleChainsAdaptor"},[i("span",{class:"jlbinding"},"Lux.ToSimpleChainsAdaptor")],-1)),s[13]||(s[13]=t()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[14]||(s[14]=a(`
    julia
    ToSimpleChainsAdaptor(input_dims, convert_to_array::Bool=false)

    Adaptor for converting a Lux Model to SimpleChains. The returned model is still a Lux model, and satisfies the AbstractLuxLayer interfacem but all internal calculations are performed using SimpleChains.

    Warning

    There is no way to preserve trained parameters and states when converting to SimpleChains.jl.

    Warning

    Any kind of initialization function is not preserved when converting to SimpleChains.jl.

    Arguments

    Example

    julia
    julia> import SimpleChains
    +
    +julia> using Adapt, Lux, Random
    +
    +julia> lux_model = Chain(Conv((5, 5), 1 => 6, relu), MaxPool((2, 2)),
    +           Conv((5, 5), 6 => 16, relu), MaxPool((2, 2)), FlattenLayer(3),
    +           Chain(Dense(256 => 128, relu), Dense(128 => 84, relu), Dense(84 => 10)));
    +
    +julia> adaptor = ToSimpleChainsAdaptor((28, 28, 1));
    +
    +julia> simple_chains_model = adapt(adaptor, lux_model); # or adaptor(lux_model)
    +
    +julia> ps, st = Lux.setup(Random.default_rng(), simple_chains_model);
    +
    +julia> x = randn(Float32, 28, 28, 1, 1);
    +
    +julia> size(first(simple_chains_model(x, ps, st)))
    +(10, 1)

    source

    `,9))]),i("details",c,[i("summary",null,[s[15]||(s[15]=i("a",{id:"Lux.SimpleChainsLayer",href:"#Lux.SimpleChainsLayer"},[i("span",{class:"jlbinding"},"Lux.SimpleChainsLayer")],-1)),s[16]||(s[16]=t()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),s[17]||(s[17]=a(`
    julia
    SimpleChainsLayer(layer, to_array::Union{Bool, Val}=Val(false))
    +SimpleChainsLayer(layer, lux_layer, to_array)

    Wraps a SimpleChains layer into a Lux layer. All operations are performed using SimpleChains but the layer satisfies the AbstractLuxLayer interface.

    ToArray is a boolean flag that determines whether the output should be converted to a regular Array or not. Default is false.

    Arguments

    source

    `,6))])])}const L=n(r,[["render",u]]);export{A as __pageData,L as default}; diff --git a/previews/PR1023/assets/api_Lux_layers.md.DhFbD-A5.js b/previews/PR1023/assets/api_Lux_layers.md.DhFbD-A5.js new file mode 100644 index 0000000000..09ce5f38a2 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_layers.md.DhFbD-A5.js @@ -0,0 +1,149 @@ +import{_ as T,c as n,j as t,a as s,G as l,a2 as i,B as d,o as Q}from"./chunks/framework.DFwXuivk.js";const o2=JSON.parse('{"title":"Built-In Layers","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/layers.md","filePath":"api/Lux/layers.md","lastUpdated":null}'),o={name:"api/Lux/layers.md"},r={class:"jldocstring custom-block"},p={class:"jldocstring custom-block"},h={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},k={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},u={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},y={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.148ex"},xmlns:"http://www.w3.org/2000/svg",width:"45.995ex",height:"5.686ex",role:"img",focusable:"false",viewBox:"0 -1563.5 20329.9 2513","aria-hidden":"true"},E={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},L={class:"jldocstring custom-block"},x={class:"jldocstring custom-block"},w={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},H={class:"jldocstring custom-block"},C={class:"jldocstring custom-block"},F={class:"jldocstring custom-block"},D={class:"jldocstring custom-block"},M={class:"jldocstring custom-block"},v={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},Z={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.148ex"},xmlns:"http://www.w3.org/2000/svg",width:"45.995ex",height:"5.686ex",role:"img",focusable:"false",viewBox:"0 -1563.5 20329.9 2513","aria-hidden":"true"},j={class:"jldocstring custom-block"},A={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},B={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.148ex"},xmlns:"http://www.w3.org/2000/svg",width:"45.995ex",height:"5.686ex",role:"img",focusable:"false",viewBox:"0 -1563.5 20329.9 2513","aria-hidden":"true"},V={class:"jldocstring custom-block"},R={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},N={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.148ex"},xmlns:"http://www.w3.org/2000/svg",width:"45.995ex",height:"5.686ex",role:"img",focusable:"false",viewBox:"0 -1563.5 20329.9 2513","aria-hidden":"true"},O={class:"jldocstring custom-block"},z={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},P={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-5.146ex"},xmlns:"http://www.w3.org/2000/svg",width:"51.473ex",height:"11.422ex",role:"img",focusable:"false",viewBox:"0 -2774.4 22750.9 5048.7","aria-hidden":"true"},I={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},S={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},_={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},G={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},W={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},X={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"15.326ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 6774.2 1000","aria-hidden":"true"},U={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},q={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"16.435ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 7264.2 1000","aria-hidden":"true"},J={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},K={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"11.831ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 5229.2 1000","aria-hidden":"true"},$={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},Y={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"12.939ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 5719.2 1000","aria-hidden":"true"},t1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},a1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"12.939ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 5719.2 1000","aria-hidden":"true"},s1={class:"jldocstring custom-block"},i1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},e1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-8.146ex"},xmlns:"http://www.w3.org/2000/svg",width:"40.257ex",height:"17.424ex",role:"img",focusable:"false",viewBox:"0 -4100.7 17793.6 7701.4","aria-hidden":"true"},l1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},n1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},Q1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},T1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},d1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},o1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.018ex",height:"1.357ex",role:"img",focusable:"false",viewBox:"0 -442 1776.1 599.8","aria-hidden":"true"},r1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},p1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.667ex"},xmlns:"http://www.w3.org/2000/svg",width:"19.753ex",height:"2.364ex",role:"img",focusable:"false",viewBox:"0 -750 8730.9 1045","aria-hidden":"true"},h1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},m1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.667ex"},xmlns:"http://www.w3.org/2000/svg",width:"21.231ex",height:"2.364ex",role:"img",focusable:"false",viewBox:"0 -750 9384.3 1045","aria-hidden":"true"},g1={class:"jldocstring custom-block"},k1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},c1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.65ex"},xmlns:"http://www.w3.org/2000/svg",width:"67.61ex",height:"2.347ex",role:"img",focusable:"false",viewBox:"0 -750 29883.5 1037.2","aria-hidden":"true"},u1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},y1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},E1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},f1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},L1={class:"jldocstring custom-block"},x1={class:"jldocstring custom-block"},w1={class:"jldocstring custom-block"},b1={class:"jldocstring custom-block"},H1={class:"jldocstring custom-block"},C1={class:"jldocstring custom-block"},F1={class:"jldocstring custom-block"},D1={class:"jldocstring custom-block"},M1={class:"jldocstring custom-block"},v1={class:"jldocstring custom-block"},Z1={class:"jldocstring custom-block"},j1={class:"jldocstring custom-block"},A1={class:"jldocstring custom-block"},B1={class:"jldocstring custom-block"},V1={class:"jldocstring custom-block"},R1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},N1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.471ex"},xmlns:"http://www.w3.org/2000/svg",width:"23.059ex",height:"2.016ex",role:"img",focusable:"false",viewBox:"0 -683 10192.1 891","aria-hidden":"true"},O1={class:"jldocstring custom-block"},z1={class:"jldocstring custom-block"},P1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},I1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.471ex"},xmlns:"http://www.w3.org/2000/svg",width:"22.72ex",height:"2.016ex",role:"img",focusable:"false",viewBox:"0 -683 10042 891","aria-hidden":"true"},S1={class:"jldocstring custom-block"},_1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},G1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.294ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 572 453","aria-hidden":"true"},W1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},X1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.76ex"},xmlns:"http://www.w3.org/2000/svg",width:"25.034ex",height:"6.063ex",role:"img",focusable:"false",viewBox:"0 -1460 11064.9 2680","aria-hidden":"true"},U1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},q1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},J1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},K1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.281ex",height:"2.034ex",role:"img",focusable:"false",viewBox:"0 -705 566 899","aria-hidden":"true"},$1={class:"jldocstring custom-block"},Y1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},t2={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.172ex"},xmlns:"http://www.w3.org/2000/svg",width:"10.071ex",height:"4.704ex",role:"img",focusable:"false",viewBox:"0 -1119 4451.6 2079","aria-hidden":"true"},a2={class:"jldocstring custom-block"},s2={class:"jldocstring custom-block"};function i2(e2,a,l2,n2,Q2,T2){const e=d("Badge");return Q(),n("div",null,[a[269]||(a[269]=t("h1",{id:"Built-In-Layers",tabindex:"-1"},[s("Built-In Layers "),t("a",{class:"header-anchor",href:"#Built-In-Layers","aria-label":'Permalink to "Built-In Layers {#Built-In-Layers}"'},"​")],-1)),a[270]||(a[270]=t("h2",{id:"containers",tabindex:"-1"},[s("Containers "),t("a",{class:"header-anchor",href:"#containers","aria-label":'Permalink to "Containers"'},"​")],-1)),t("details",r,[t("summary",null,[a[0]||(a[0]=t("a",{id:"Lux.BranchLayer",href:"#Lux.BranchLayer"},[t("span",{class:"jlbinding"},"Lux.BranchLayer")],-1)),a[1]||(a[1]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[2]||(a[2]=i(`
    julia
    BranchLayer(layers...)
    +BranchLayer(; name=nothing, layers...)

    Takes an input x and passes it through all the layers and returns a tuple of the outputs.

    Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    Comparison with Parallel

    This is slightly different from Parallel(nothing, layers...)

    Example

    An easy way to replicate an input to an NTuple is to do

    julia
    julia> BranchLayer(NoOpLayer(), NoOpLayer(), NoOpLayer())
    +BranchLayer(
    +    layer_1 = NoOpLayer(),
    +    layer_2 = NoOpLayer(),
    +    layer_3 = NoOpLayer(),
    +)         # Total: 0 parameters,
    +          #        plus 0 states.

    source

    `,18))]),t("details",p,[t("summary",null,[a[3]||(a[3]=t("a",{id:"Lux.Chain",href:"#Lux.Chain"},[t("span",{class:"jlbinding"},"Lux.Chain")],-1)),a[4]||(a[4]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[5]||(a[5]=i(`
    julia
    Chain(layers...; name=nothing)
    +Chain(; layers..., name=nothing)

    Collects multiple layers / functions to be called in sequence on a given input.

    Arguments

    Extended Help

    Inputs

    Input x is passed sequentially to each layer, and must conform to the input requirements of the internal layers.

    Returns

    Parameters

    States

    Miscellaneous Properties

    Example

    julia
    julia> Chain(Dense(2, 3, relu), BatchNorm(3), Dense(3, 2))
    +Chain(
    +    layer_1 = Dense(2 => 3, relu),      # 9 parameters
    +    layer_2 = BatchNorm(3, affine=true, track_stats=true),  # 6 parameters, plus 7
    +    layer_3 = Dense(3 => 2),            # 8 parameters
    +)         # Total: 23 parameters,
    +          #        plus 7 states.
    +
    +julia> Chain(Dense(2, 3, relu), BatchNorm(3), Dense(3, 2); name="MyFancyChain")
    +MyFancyChain(
    +    layer_1 = Dense(2 => 3, relu),      # 9 parameters
    +    layer_2 = BatchNorm(3, affine=true, track_stats=true),  # 6 parameters, plus 7
    +    layer_3 = Dense(3 => 2),            # 8 parameters
    +)         # Total: 23 parameters,
    +          #        plus 7 states.

    source

    `,18))]),t("details",h,[t("summary",null,[a[6]||(a[6]=t("a",{id:"Lux.PairwiseFusion",href:"#Lux.PairwiseFusion"},[t("span",{class:"jlbinding"},"Lux.PairwiseFusion")],-1)),a[7]||(a[7]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[8]||(a[8]=i(`
    julia
    PairwiseFusion(connection, layers...; name=nothing)
    +PairwiseFusion(connection; name=nothing, layers...)
    +PairwiseFusion(; connection, layers..., name=nothing)
    x1 → layer1 → y1 ↘
    +                  connection → layer2 → y2 ↘
    +              x2 ↗                          connection → y3
    +                                        x3 ↗

    Arguments

    Extended Help

    Inputs

    Layer behaves differently based on input type:

    1. If the input x is a tuple of length N + 1, then the layers must be a tuple of length N. The computation is as follows
    julia
    y = x[1]
    +for i in 1:N
    +    y = connection(x[i + 1], layers[i](y))
    +end
    1. Any other kind of input
    julia
    y = x
    +for i in 1:N
    +    y = connection(x, layers[i](y))
    +end

    Returns

    Parameters

    States

    source

    `,18))]),t("details",m,[t("summary",null,[a[9]||(a[9]=t("a",{id:"Lux.Parallel",href:"#Lux.Parallel"},[t("span",{class:"jlbinding"},"Lux.Parallel")],-1)),a[10]||(a[10]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[11]||(a[11]=i(`
    julia
    Parallel(connection, layers...; name=nothing)
    +Parallel(connection; name=nothing, layers...)
    +Parallel(; connection, layers..., name=nothing)

    Create a layer which passes an input to each path in layers, before reducing the output with connection.

    Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    See also SkipConnection which is Parallel with one identity.

    Example

    julia
    julia> model = Parallel(nothing, Dense(2, 1), Dense(2, 1))
    +Parallel(
    +    layer_1 = Dense(2 => 1),            # 3 parameters
    +    layer_2 = Dense(2 => 1),            # 3 parameters
    +)         # Total: 6 parameters,
    +          #        plus 0 states.
    +
    +julia> using Random;
    +       rng = Random.seed!(123);
    +       ps, st = Lux.setup(rng, model);
    +       x1 = randn(rng, Float32, 2);
    +       x2 = randn(rng, Float32, 2);
    +
    +julia> size.(first(model((x1, x2), ps, st)))
    +((1,), (1,))

    source

    `,17))]),t("details",g,[t("summary",null,[a[12]||(a[12]=t("a",{id:"Lux.SkipConnection",href:"#Lux.SkipConnection"},[t("span",{class:"jlbinding"},"Lux.SkipConnection")],-1)),a[13]||(a[13]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[14]||(a[14]=i(`
    julia
    SkipConnection(layers, connection; name=nothing)
    +SkipConnection(; layers, connection, name=nothing)

    Create a skip connection which consists of a layer or Chain of consecutive layers and a shortcut connection linking the block's input to the output through a user-supplied 2-argument callable. The first argument to the callable will be propagated through the given layer while the second is the unchanged, "skipped" input.

    The simplest "ResNet"-type connection is just SkipConnection(layer, +).

    Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    See Parallel for a more general implementation.

    source

    `,16))]),t("details",k,[t("summary",null,[a[15]||(a[15]=t("a",{id:"Lux.RepeatedLayer",href:"#Lux.RepeatedLayer"},[t("span",{class:"jlbinding"},"Lux.RepeatedLayer")],-1)),a[16]||(a[16]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[17]||(a[17]=i(`
    julia
    RepeatedLayer(model; repeats::Val = Val(10), input_injection::Val = Val(false))

    Iteratively applies model for repeats number of times. The initial input is passed into the model repeatedly if input_injection = Val(true). This layer unrolls the computation, however, semantically this is same as:

    julia
    res = x
    +for i in 1:repeats
    +    res, st = model(res, ps, st)
    +end
    julia
    res = x
    +for i in 1:repeats
    +    res, st = model((res, x), ps, st)
    +end

    It is expected that repeats will be a reasonable number below 20, beyond that compile times for gradients might be unreasonably high.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    source

    `,21))]),a[271]||(a[271]=t("h2",{id:"Convolutional-Layers",tabindex:"-1"},[s("Convolutional Layers "),t("a",{class:"header-anchor",href:"#Convolutional-Layers","aria-label":'Permalink to "Convolutional Layers {#Convolutional-Layers}"'},"​")],-1)),t("details",c,[t("summary",null,[a[18]||(a[18]=t("a",{id:"Lux.Conv",href:"#Lux.Conv"},[t("span",{class:"jlbinding"},"Lux.Conv")],-1)),a[19]||(a[19]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[22]||(a[22]=i(`
    julia
    Conv(k::NTuple{N,Integer}, (in_chs => out_chs)::Pair{<:Integer,<:Integer},
    +     activation=identity; init_weight=nothing, init_bias=nothing, stride=1,
    +     pad=0, dilation=1, groups=1, use_bias=True(), cross_correlation=False())

    Standard convolutional layer.

    Conv 2D

    Image data should be stored in WHCN order (width, height, channels, batch). In other words, a 100 x 100 RGB image would be a 100 x 100 x 3 x 1 array, and a batch of 50 would be a 100 x 100 x 3 x 50 array. This has N = 2 spatial dimensions, and needs a kernel size like (5, 5), a 2-tuple of integers. To take convolutions along N feature dimensions, this layer expects as input an array with ndims(x) == N + 2, where size(x, N + 1) == in_chs is the number of input channels, and size(x, ndims(x)) is the number of observations in a batch.

    Warning

    Frameworks like Pytorch perform cross-correlation in their convolution layers. Pass cross_correlation=true to use cross-correlation instead.

    Arguments

    Extended Help

    Keyword Arguments

    Inputs

    Returns

    `,13)),t("mjx-container",u,[(Q(),n("svg",y,a[20]||(a[20]=[i('',1)]))),a[21]||(a[21]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("msub",null,[t("mi",null,"O"),t("mi",null,"i")]),t("mo",null,"="),t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"⌊"),t("mfrac",null,[t("mrow",null,[t("msub",null,[t("mi",null,"I"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mo",{stretchy:"false"},"("),t("mi",null,"i"),t("mo",null,"+"),t("mi",null,"N"),t("mo",{stretchy:"false"},")"),t("mi",{mathvariant:"normal"},"%"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),t("mi",null,"p"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|")])]),t("mo",null,"−"),t("msub",null,[t("mi",null,"d"),t("mi",null,"i")]),t("mo",null,"×"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"k"),t("mi",null,"i")]),t("mo",null,"−"),t("mn",null,"1"),t("mo",{stretchy:"false"},")")]),t("msub",null,[t("mi",null,"s"),t("mi",null,"i")])]),t("mo",null,"+"),t("mn",null,"1"),t("mo",{"data-mjx-texclass":"CLOSE"},"⌋")])])],-1))]),a[23]||(a[23]=i('

    Parameters

    source

    ',4))]),t("details",E,[t("summary",null,[a[24]||(a[24]=t("a",{id:"Lux.ConvTranspose",href:"#Lux.ConvTranspose"},[t("span",{class:"jlbinding"},"Lux.ConvTranspose")],-1)),a[25]||(a[25]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[26]||(a[26]=i(`
    julia
    ConvTranspose(k::NTuple{N,Integer}, (in_chs => out_chs)::Pair{<:Integer,<:Integer},
    +              activation=identity; init_weight=glorot_uniform, init_bias=zeros32,
    +              stride=1, pad=0, outpad=0, dilation=1, groups=1, use_bias=True(),
    +              cross_correlation=False())

    Standard convolutional transpose layer.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    source

    `,14))]),a[272]||(a[272]=t("h2",{id:"Dropout-Layers",tabindex:"-1"},[s("Dropout Layers "),t("a",{class:"header-anchor",href:"#Dropout-Layers","aria-label":'Permalink to "Dropout Layers {#Dropout-Layers}"'},"​")],-1)),t("details",f,[t("summary",null,[a[27]||(a[27]=t("a",{id:"Lux.AlphaDropout",href:"#Lux.AlphaDropout"},[t("span",{class:"jlbinding"},"Lux.AlphaDropout")],-1)),a[28]||(a[28]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[29]||(a[29]=i('
    julia
    AlphaDropout(p::Real)

    AlphaDropout layer.

    Arguments

    Inputs

    Returns

    States

    Call Lux.testmode to switch to test mode.

    See also Dropout, VariationalHiddenDropout

    source

    ',13))]),t("details",L,[t("summary",null,[a[30]||(a[30]=t("a",{id:"Lux.Dropout",href:"#Lux.Dropout"},[t("span",{class:"jlbinding"},"Lux.Dropout")],-1)),a[31]||(a[31]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[32]||(a[32]=i('
    julia
    Dropout(p; dims=:)

    Dropout layer.

    Arguments

    Keyword Arguments

    Inputs

    Returns

    States

    Call Lux.testmode to switch to test mode.

    See also AlphaDropout, VariationalHiddenDropout

    source

    ',15))]),t("details",x,[t("summary",null,[a[33]||(a[33]=t("a",{id:"Lux.VariationalHiddenDropout",href:"#Lux.VariationalHiddenDropout"},[t("span",{class:"jlbinding"},"Lux.VariationalHiddenDropout")],-1)),a[34]||(a[34]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[35]||(a[35]=i('
    julia
    VariationalHiddenDropout(p; dims=:)

    VariationalHiddenDropout layer. The only difference from Dropout is that the mask is retained until Lux.update_state(l, :update_mask, Val(true)) is called.

    Arguments

    Keyword Arguments

    Inputs

    Returns

    States

    Call Lux.testmode to switch to test mode.

    See also AlphaDropout, Dropout

    source

    ',15))]),a[273]||(a[273]=t("h2",{id:"Pooling-Layers",tabindex:"-1"},[s("Pooling Layers "),t("a",{class:"header-anchor",href:"#Pooling-Layers","aria-label":'Permalink to "Pooling Layers {#Pooling-Layers}"'},"​")],-1)),t("details",w,[t("summary",null,[a[36]||(a[36]=t("a",{id:"Lux.AdaptiveLPPool",href:"#Lux.AdaptiveLPPool"},[t("span",{class:"jlbinding"},"Lux.AdaptiveLPPool")],-1)),a[37]||(a[37]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[38]||(a[38]=i('
    julia
    AdaptiveLPPool(output_size; p=2)

    Adaptive LP Pooling layer. Calculates the necessary window size such that its output has size(y)[1:N] == output_size.

    Arguments

    GPU Support

    This layer is currently only supported on CPU.

    Inputs

    Returns

    source

    ',10))]),t("details",b,[t("summary",null,[a[39]||(a[39]=t("a",{id:"Lux.AdaptiveMaxPool",href:"#Lux.AdaptiveMaxPool"},[t("span",{class:"jlbinding"},"Lux.AdaptiveMaxPool")],-1)),a[40]||(a[40]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[41]||(a[41]=i('
    julia
    AdaptiveMaxPool(output_size)

    Adaptive Max Pooling layer. Calculates the necessary window size such that its output has size(y)[1:N] == output_size.

    Arguments

    Inputs

    Returns

    source

    ',9))]),t("details",H,[t("summary",null,[a[42]||(a[42]=t("a",{id:"Lux.AdaptiveMeanPool",href:"#Lux.AdaptiveMeanPool"},[t("span",{class:"jlbinding"},"Lux.AdaptiveMeanPool")],-1)),a[43]||(a[43]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[44]||(a[44]=i('
    julia
    AdaptiveMeanPool(output_size)

    Adaptive Mean Pooling layer. Calculates the necessary window size such that its output has size(y)[1:N] == output_size.

    Arguments

    Inputs

    Returns

    source

    ',9))]),t("details",C,[t("summary",null,[a[45]||(a[45]=t("a",{id:"Lux.GlobalLPPool",href:"#Lux.GlobalLPPool"},[t("span",{class:"jlbinding"},"Lux.GlobalLPPool")],-1)),a[46]||(a[46]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[47]||(a[47]=i('
    julia
    GlobalLPPool(; p=2)

    Global LP Pooling layer. Transforms (w, h, c, b)-shaped input into (1, 1, c, b)-shaped output, by performing mean pooling on the complete (w, h)-shaped feature maps.

    GPU Support

    This layer is currently only supported on CPU.

    Inputs

    Returns

    source

    ',8))]),t("details",F,[t("summary",null,[a[48]||(a[48]=t("a",{id:"Lux.GlobalMaxPool",href:"#Lux.GlobalMaxPool"},[t("span",{class:"jlbinding"},"Lux.GlobalMaxPool")],-1)),a[49]||(a[49]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[50]||(a[50]=i('
    julia
    GlobalMaxPool()

    Global Max Pooling layer. Transforms (w, h, c, b)-shaped input into (1, 1, c, b)-shaped output, by performing mean pooling on the complete (w, h)-shaped feature maps.

    Inputs

    Returns

    source

    ',7))]),t("details",D,[t("summary",null,[a[51]||(a[51]=t("a",{id:"Lux.GlobalMeanPool",href:"#Lux.GlobalMeanPool"},[t("span",{class:"jlbinding"},"Lux.GlobalMeanPool")],-1)),a[52]||(a[52]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[53]||(a[53]=i('
    julia
    GlobalMeanPool()

    Global Mean Pooling layer. Transforms (w, h, c, b)-shaped input into (1, 1, c, b)-shaped output, by performing mean pooling on the complete (w, h)-shaped feature maps.

    Inputs

    Returns

    source

    ',7))]),t("details",M,[t("summary",null,[a[54]||(a[54]=t("a",{id:"Lux.LPPool",href:"#Lux.LPPool"},[t("span",{class:"jlbinding"},"Lux.LPPool")],-1)),a[55]||(a[55]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[58]||(a[58]=i('
    julia
    LPPool(window; stride=window, pad=0, dilation=1, p=2)

    LP Pooling layer, which replaces all pixels in a block of size window with the reduction operation: lp.

    Arguments

    Keyword Arguments

    GPU Support

    This layer is currently only supported on CPU.

    Extended Help

    Inputs

    Returns

    ',12)),t("mjx-container",v,[(Q(),n("svg",Z,a[56]||(a[56]=[i('',1)]))),a[57]||(a[57]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("msub",null,[t("mi",null,"O"),t("mi",null,"i")]),t("mo",null,"="),t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"⌊"),t("mfrac",null,[t("mrow",null,[t("msub",null,[t("mi",null,"I"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mo",{stretchy:"false"},"("),t("mi",null,"i"),t("mo",null,"+"),t("mi",null,"N"),t("mo",{stretchy:"false"},")"),t("mi",{mathvariant:"normal"},"%"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),t("mi",null,"p"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|")])]),t("mo",null,"−"),t("msub",null,[t("mi",null,"d"),t("mi",null,"i")]),t("mo",null,"×"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"k"),t("mi",null,"i")]),t("mo",null,"−"),t("mn",null,"1"),t("mo",{stretchy:"false"},")")]),t("msub",null,[t("mi",null,"s"),t("mi",null,"i")])]),t("mo",null,"+"),t("mn",null,"1"),t("mo",{"data-mjx-texclass":"CLOSE"},"⌋")])])],-1))]),a[59]||(a[59]=t("ul",null,[t("li",null,[s("Empty "),t("code",null,"NamedTuple()")])],-1)),a[60]||(a[60]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/src/layers/pooling.jl#L188-L236",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",j,[t("summary",null,[a[61]||(a[61]=t("a",{id:"Lux.MaxPool",href:"#Lux.MaxPool"},[t("span",{class:"jlbinding"},"Lux.MaxPool")],-1)),a[62]||(a[62]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[65]||(a[65]=i('
    julia
    MaxPool(window; stride=window, pad=0, dilation=1)

    Max Pooling layer, which replaces all pixels in a block of size window with the reduction operation: max.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    ',11)),t("mjx-container",A,[(Q(),n("svg",B,a[63]||(a[63]=[i('',1)]))),a[64]||(a[64]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("msub",null,[t("mi",null,"O"),t("mi",null,"i")]),t("mo",null,"="),t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"⌊"),t("mfrac",null,[t("mrow",null,[t("msub",null,[t("mi",null,"I"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mo",{stretchy:"false"},"("),t("mi",null,"i"),t("mo",null,"+"),t("mi",null,"N"),t("mo",{stretchy:"false"},")"),t("mi",{mathvariant:"normal"},"%"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),t("mi",null,"p"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|")])]),t("mo",null,"−"),t("msub",null,[t("mi",null,"d"),t("mi",null,"i")]),t("mo",null,"×"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"k"),t("mi",null,"i")]),t("mo",null,"−"),t("mn",null,"1"),t("mo",{stretchy:"false"},")")]),t("msub",null,[t("mi",null,"s"),t("mi",null,"i")])]),t("mo",null,"+"),t("mn",null,"1"),t("mo",{"data-mjx-texclass":"CLOSE"},"⌋")])])],-1))]),a[66]||(a[66]=t("ul",null,[t("li",null,[s("Empty "),t("code",null,"NamedTuple()")])],-1)),a[67]||(a[67]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/src/layers/pooling.jl#L188-L232",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",V,[t("summary",null,[a[68]||(a[68]=t("a",{id:"Lux.MeanPool",href:"#Lux.MeanPool"},[t("span",{class:"jlbinding"},"Lux.MeanPool")],-1)),a[69]||(a[69]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[72]||(a[72]=i('
    julia
    MeanPool(window; stride=window, pad=0, dilation=1)

    Mean Pooling layer, which replaces all pixels in a block of size window with the reduction operation: mean.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    ',11)),t("mjx-container",R,[(Q(),n("svg",N,a[70]||(a[70]=[i('',1)]))),a[71]||(a[71]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("msub",null,[t("mi",null,"O"),t("mi",null,"i")]),t("mo",null,"="),t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"⌊"),t("mfrac",null,[t("mrow",null,[t("msub",null,[t("mi",null,"I"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mo",{stretchy:"false"},"("),t("mi",null,"i"),t("mo",null,"+"),t("mi",null,"N"),t("mo",{stretchy:"false"},")"),t("mi",{mathvariant:"normal"},"%"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),t("mi",null,"p"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|")])]),t("mo",null,"−"),t("msub",null,[t("mi",null,"d"),t("mi",null,"i")]),t("mo",null,"×"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"k"),t("mi",null,"i")]),t("mo",null,"−"),t("mn",null,"1"),t("mo",{stretchy:"false"},")")]),t("msub",null,[t("mi",null,"s"),t("mi",null,"i")])]),t("mo",null,"+"),t("mn",null,"1"),t("mo",{"data-mjx-texclass":"CLOSE"},"⌋")])])],-1))]),a[73]||(a[73]=t("ul",null,[t("li",null,[s("Empty "),t("code",null,"NamedTuple()")])],-1)),a[74]||(a[74]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/src/layers/pooling.jl#L188-L232",target:"_blank",rel:"noreferrer"},"source")],-1))]),a[274]||(a[274]=t("h2",{id:"Recurrent-Layers",tabindex:"-1"},[s("Recurrent Layers "),t("a",{class:"header-anchor",href:"#Recurrent-Layers","aria-label":'Permalink to "Recurrent Layers {#Recurrent-Layers}"'},"​")],-1)),t("details",O,[t("summary",null,[a[75]||(a[75]=t("a",{id:"Lux.GRUCell",href:"#Lux.GRUCell"},[t("span",{class:"jlbinding"},"Lux.GRUCell")],-1)),a[76]||(a[76]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[120]||(a[120]=i(`
    julia
    GRUCell((in_dims, out_dims)::Pair{<:Int,<:Int}; use_bias=true, train_state::Bool=false,
    +        init_weight=nothing, init_bias=nothing, init_state=zeros32)

    Gated Recurrent Unit (GRU) Cell

    `,2)),t("mjx-container",z,[(Q(),n("svg",P,a[77]||(a[77]=[i('',1)]))),a[78]||(a[78]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("mtable",{displaystyle:"true",columnalign:"right left",columnspacing:"0em",rowspacing:"3pt"},[t("mtr",null,[t("mtd",null,[t("mi",null,"r")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"σ"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"r")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"r")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"r")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"r")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("mi",null,"z")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"σ"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"z")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"z")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"z")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"z")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("mi",null,"n")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"tanh"),t("mo",{"data-mjx-texclass":"NONE"},"⁡"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"n")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"n")])]),t("mo",null,"+"),t("mi",null,"r"),t("mo",null,"⋅"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"n")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"n")])]),t("mo",{stretchy:"false"},")"),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mo",{stretchy:"false"},"("),t("mn",null,"1"),t("mo",null,"−"),t("mi",null,"z"),t("mo",{stretchy:"false"},")"),t("mo",null,"⋅"),t("mi",null,"n"),t("mo",null,"+"),t("mi",null,"z"),t("mo",null,"⋅"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])])])])])])],-1))]),a[121]||(a[121]=i("

    Arguments

    Inputs

    Returns

    ",5)),t("ul",null,[t("li",null,[a[87]||(a[87]=t("p",null,"Tuple containing",-1)),t("ul",null,[t("li",null,[t("p",null,[a[81]||(a[81]=s("Output ")),t("mjx-container",I,[(Q(),n("svg",S,a[79]||(a[79]=[i('',1)]))),a[80]||(a[80]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))]),a[82]||(a[82]=s(" of shape ")),a[83]||(a[83]=t("code",null,"(out_dims, batch_size)",-1))])]),t("li",null,[t("p",null,[a[86]||(a[86]=s("Tuple containing new hidden state ")),t("mjx-container",_,[(Q(),n("svg",G,a[84]||(a[84]=[i('',1)]))),a[85]||(a[85]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))])])])])]),a[88]||(a[88]=t("li",null,[t("p",null,"Updated model state")],-1))]),a[122]||(a[122]=t("p",null,[t("strong",null,"Parameters")],-1)),t("ul",null,[t("li",null,[t("p",null,[a[91]||(a[91]=t("code",null,"weight_ih",-1)),a[92]||(a[92]=s(": Concatenated Weights to map from input space ")),t("mjx-container",W,[(Q(),n("svg",X,a[89]||(a[89]=[i('',1)]))),a[90]||(a[90]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"r")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"z")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"n")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[93]||(a[93]=s("."))])]),t("li",null,[t("p",null,[a[96]||(a[96]=t("code",null,"weight_hh",-1)),a[97]||(a[97]=s(": Concatenated Weights to map from hidden space ")),t("mjx-container",U,[(Q(),n("svg",q,a[94]||(a[94]=[i('',1)]))),a[95]||(a[95]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"r")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"z")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"n")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[98]||(a[98]=s("."))])]),t("li",null,[t("p",null,[a[101]||(a[101]=t("code",null,"bias_ih",-1)),a[102]||(a[102]=s(": Concatenated Bias vector for the input space ")),t("mjx-container",J,[(Q(),n("svg",K,a[99]||(a[99]=[i('',1)]))),a[100]||(a[100]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"r")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"z")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"n")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[103]||(a[103]=s(" (not present if ")),a[104]||(a[104]=t("code",null,"use_bias=false",-1)),a[105]||(a[105]=s(")."))])]),t("li",null,[t("p",null,[a[108]||(a[108]=t("code",null,"bias_hh",-1)),a[109]||(a[109]=s(": Concatenated Bias vector for the hidden space ")),t("mjx-container",$,[(Q(),n("svg",Y,a[106]||(a[106]=[i('',1)]))),a[107]||(a[107]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"r")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"z")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"n")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[110]||(a[110]=s(" (not present if ")),a[111]||(a[111]=t("code",null,"use_bias=false",-1)),a[112]||(a[112]=s(")."))])]),t("li",null,[t("p",null,[a[115]||(a[115]=t("code",null,"hidden_state",-1)),a[116]||(a[116]=s(": Initial hidden state vector (not present if ")),a[117]||(a[117]=t("code",null,"train_state=false",-1)),a[118]||(a[118]=s(") ")),t("mjx-container",t1,[(Q(),n("svg",a1,a[113]||(a[113]=[i('',1)]))),a[114]||(a[114]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"r")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"z")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"n")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[119]||(a[119]=s("."))])])]),a[123]||(a[123]=t("p",null,[t("strong",null,"States")],-1)),a[124]||(a[124]=t("ul",null,[t("li",null,[t("code",null,"rng"),s(": Controls the randomness (if any) in the initial state generation")])],-1)),a[125]||(a[125]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/src/layers/recurrent.jl#L488",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",s1,[t("summary",null,[a[126]||(a[126]=t("a",{id:"Lux.LSTMCell",href:"#Lux.LSTMCell"},[t("span",{class:"jlbinding"},"Lux.LSTMCell")],-1)),a[127]||(a[127]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[153]||(a[153]=i(`
    julia
    LSTMCell(in_dims => out_dims; use_bias::Bool=true, train_state::Bool=false,
    +         train_memory::Bool=false, init_weight=nothing, init_bias=nothing,
    +         init_state=zeros32, init_memory=zeros32)

    Long Short-Term (LSTM) Cell

    `,2)),t("mjx-container",i1,[(Q(),n("svg",e1,a[128]||(a[128]=[i('',1)]))),a[129]||(a[129]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("mtable",{displaystyle:"true",columnalign:"right left",columnspacing:"0em",rowspacing:"3pt"},[t("mtr",null,[t("mtd",null,[t("mi",null,"i")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"σ"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"i")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"i")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("mi",null,"f")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"σ"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"f")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"f")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"f")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("mi",null,"g")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"t"),t("mi",null,"a"),t("mi",null,"n"),t("mi",null,"h"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"g")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"g")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"g")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("mi",null,"o")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"σ"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"o")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"o")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"o")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("msub",null,[t("mi",null,"c"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"f"),t("mo",null,"⋅"),t("msub",null,[t("mi",null,"c"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("mi",null,"i"),t("mo",null,"⋅"),t("mi",null,"g")])]),t("mtr",null,[t("mtd",null,[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"o"),t("mo",null,"⋅"),t("mi",null,"t"),t("mi",null,"a"),t("mi",null,"n"),t("mi",null,"h"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"c"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])]),t("mo",{stretchy:"false"},")")])])])])],-1))]),a[154]||(a[154]=i("

    Arguments

    Inputs

    Returns

    ",5)),t("ul",null,[t("li",null,[a[141]||(a[141]=t("p",null,"Tuple Containing",-1)),t("ul",null,[t("li",null,[t("p",null,[a[132]||(a[132]=s("Output ")),t("mjx-container",l1,[(Q(),n("svg",n1,a[130]||(a[130]=[i('',1)]))),a[131]||(a[131]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))]),a[133]||(a[133]=s(" of shape ")),a[134]||(a[134]=t("code",null,"(out_dims, batch_size)",-1))])]),t("li",null,[t("p",null,[a[139]||(a[139]=s("Tuple containing new hidden state ")),t("mjx-container",Q1,[(Q(),n("svg",T1,a[135]||(a[135]=[i('',1)]))),a[136]||(a[136]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))]),a[140]||(a[140]=s(" and new memory ")),t("mjx-container",d1,[(Q(),n("svg",o1,a[137]||(a[137]=[i('',1)]))),a[138]||(a[138]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"c"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))])])])])]),a[142]||(a[142]=t("li",null,[t("p",null,"Updated model state")],-1))]),a[155]||(a[155]=t("p",null,[t("strong",null,"Parameters")],-1)),t("ul",null,[t("li",null,[t("p",null,[a[145]||(a[145]=t("code",null,"weight_ih",-1)),a[146]||(a[146]=s(": Concatenated Weights to map from input space ")),t("mjx-container",r1,[(Q(),n("svg",p1,a[143]||(a[143]=[i('',1)]))),a[144]||(a[144]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"i")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"f")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"g")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"o")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[147]||(a[147]=s("."))])]),t("li",null,[t("p",null,[a[150]||(a[150]=t("code",null,"weight_hh",-1)),a[151]||(a[151]=s(": Concatenated Weights to map from hidden space ")),t("mjx-container",h1,[(Q(),n("svg",m1,a[148]||(a[148]=[i('',1)]))),a[149]||(a[149]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"i")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"f")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"g")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"o")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))])])]),a[152]||(a[152]=i("
  • bias_ih: Bias vector for the input-hidden connection (not present if use_bias=false)

  • bias_hh: Concatenated Bias vector for the hidden-hidden connection (not present if use_bias=false)

  • hidden_state: Initial hidden state vector (not present if train_state=false)

  • memory: Initial memory vector (not present if train_memory=false)

  • ",4))]),a[156]||(a[156]=t("p",null,[t("strong",null,"States")],-1)),a[157]||(a[157]=t("ul",null,[t("li",null,[t("code",null,"rng"),s(": Controls the randomness (if any) in the initial state generation")])],-1)),a[158]||(a[158]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/src/layers/recurrent.jl#L309",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",g1,[t("summary",null,[a[159]||(a[159]=t("a",{id:"Lux.RNNCell",href:"#Lux.RNNCell"},[t("span",{class:"jlbinding"},"Lux.RNNCell")],-1)),a[160]||(a[160]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[173]||(a[173]=i(`
    julia
    RNNCell(in_dims => out_dims, activation=tanh; use_bias=True(), train_state=False(),
    +    init_bias=nothing, init_weight=nothing, init_state=zeros32)

    An Elman RNNCell cell with activation (typically set to tanh or relu).

    `,2)),t("p",null,[t("mjx-container",k1,[(Q(),n("svg",c1,a[161]||(a[161]=[i('',1)]))),a[162]||(a[162]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])]),t("mo",null,"="),t("mi",null,"a"),t("mi",null,"c"),t("mi",null,"t"),t("mi",null,"i"),t("mi",null,"v"),t("mi",null,"a"),t("mi",null,"t"),t("mi",null,"i"),t("mi",null,"o"),t("mi",null,"n"),t("mo",{stretchy:"false"},"("),t("mi",null,"w"),t("mi",null,"e"),t("mi",null,"i"),t("mi",null,"g"),t("mi",null,"h"),t("msub",null,[t("mi",null,"t"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"h")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("mi",null,"b"),t("mi",null,"i"),t("mi",null,"a"),t("msub",null,[t("mi",null,"s"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"h")])]),t("mo",null,"+"),t("mi",null,"w"),t("mi",null,"e"),t("mi",null,"i"),t("mi",null,"g"),t("mi",null,"h"),t("msub",null,[t("mi",null,"t"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"h")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("mi",null,"b"),t("mi",null,"i"),t("mi",null,"a"),t("msub",null,[t("mi",null,"s"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"h")])]),t("mo",{stretchy:"false"},")")])],-1))])]),a[174]||(a[174]=i("

    Arguments

    Inputs

    Returns

    ",5)),t("ul",null,[t("li",null,[a[171]||(a[171]=t("p",null,"Tuple containing",-1)),t("ul",null,[t("li",null,[t("p",null,[a[165]||(a[165]=s("Output ")),t("mjx-container",u1,[(Q(),n("svg",y1,a[163]||(a[163]=[i('',1)]))),a[164]||(a[164]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))]),a[166]||(a[166]=s(" of shape ")),a[167]||(a[167]=t("code",null,"(out_dims, batch_size)",-1))])]),t("li",null,[t("p",null,[a[170]||(a[170]=s("Tuple containing new hidden state ")),t("mjx-container",E1,[(Q(),n("svg",f1,a[168]||(a[168]=[i('',1)]))),a[169]||(a[169]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))])])])])]),a[172]||(a[172]=t("li",null,[t("p",null,"Updated model state")],-1))]),a[175]||(a[175]=i('

    Parameters

    States

    source

    ',5))]),t("details",L1,[t("summary",null,[a[176]||(a[176]=t("a",{id:"Lux.Recurrence",href:"#Lux.Recurrence"},[t("span",{class:"jlbinding"},"Lux.Recurrence")],-1)),a[177]||(a[177]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[178]||(a[178]=i(`
    julia
    Recurrence(cell;
    +    ordering::AbstractTimeSeriesDataBatchOrdering=BatchLastIndex(),
    +    return_sequence::Bool=false)

    Wraps a recurrent cell (like RNNCell, LSTMCell, GRUCell) to automatically operate over a sequence of inputs.

    Relation to Flux.Recur

    This is completely distinct from Flux.Recur. It doesn't make the cell stateful, rather allows operating on an entire sequence of inputs at once. See StatefulRecurrentCell for functionality similar to Flux.Recur.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Tip

    Frameworks like Tensorflow have special implementation of StackedRNNCells to handle sequentially composed RNN Cells. In Lux, one can simple stack multiple Recurrence blocks in a Chain to achieve the same.

    Chain(
    +    Recurrence(RNNCell(inputsize => latentsize); return_sequence=true),
    +    Recurrence(RNNCell(latentsize => latentsize); return_sequence=true),
    +    :
    +    x -> stack(x; dims=2)
    +)

    For some discussion on this topic, see https://github.com/LuxDL/Lux.jl/issues/472.

    source

    `,14))]),t("details",x1,[t("summary",null,[a[179]||(a[179]=t("a",{id:"Lux.StatefulRecurrentCell",href:"#Lux.StatefulRecurrentCell"},[t("span",{class:"jlbinding"},"Lux.StatefulRecurrentCell")],-1)),a[180]||(a[180]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[181]||(a[181]=i('
    julia
    StatefulRecurrentCell(cell)

    Wraps a recurrent cell (like RNNCell, LSTMCell, GRUCell) and makes it stateful.

    To avoid undefined behavior, once the processing of a single sequence of data is complete, update the state with Lux.update_state(st, :carry, nothing).

    Arguments

    Inputs

    Returns

    States

    source

    ',12))]),t("details",w1,[t("summary",null,[a[182]||(a[182]=t("a",{id:"Lux.BidirectionalRNN",href:"#Lux.BidirectionalRNN"},[t("span",{class:"jlbinding"},"Lux.BidirectionalRNN")],-1)),a[183]||(a[183]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[184]||(a[184]=i(`
    julia
    BidirectionalRNN(cell::AbstractRecurrentCell,
    +    backward_cell::Union{AbstractRecurrentCell, Nothing}=nothing;
    +    merge_mode::Union{Function, Nothing}=vcat,
    +    ordering::AbstractTimeSeriesDataBatchOrdering=BatchLastIndex())

    Bidirectional RNN wrapper.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    source

    `,16))]),a[275]||(a[275]=t("h2",{id:"Linear-Layers",tabindex:"-1"},[s("Linear Layers "),t("a",{class:"header-anchor",href:"#Linear-Layers","aria-label":'Permalink to "Linear Layers {#Linear-Layers}"'},"​")],-1)),t("details",b1,[t("summary",null,[a[185]||(a[185]=t("a",{id:"Lux.Bilinear",href:"#Lux.Bilinear"},[t("span",{class:"jlbinding"},"Lux.Bilinear")],-1)),a[186]||(a[186]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[187]||(a[187]=i(`
    julia
    Bilinear((in1_dims, in2_dims) => out, activation=identity; init_weight=nothing,
    +         init_bias=nothing, use_bias=True())
    +Bilinear(in12_dims => out, activation=identity; init_weight=nothing,
    +         init_bias=nothing, use_bias=True())

    Create a fully connected layer between two inputs and an output, and otherwise similar to Dense. Its output, given vectors x & y, is another vector z with, for all i in 1:out:

    z[i] = activation(x' * W[i, :, :] * y + bias[i])

    If x and y are matrices, then each column of the output z = B(x, y) is of this form, with B the Bilinear layer.

    Arguments

    Keyword Arguments

    Input

    Returns

    Parameters

    source

    `,15))]),t("details",H1,[t("summary",null,[a[188]||(a[188]=t("a",{id:"Lux.Dense",href:"#Lux.Dense"},[t("span",{class:"jlbinding"},"Lux.Dense")],-1)),a[189]||(a[189]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[190]||(a[190]=i(`
    julia
    Dense(in_dims => out_dims, activation=identity; init_weight=nothing,
    +      init_bias=nothing, use_bias=True())

    Create a traditional fully connected layer, whose forward pass is given by: y = activation.(weight * x .+ bias)

    Arguments

    Keyword Arguments

    Input

    Returns

    Parameters

    source

    `,13))]),t("details",C1,[t("summary",null,[a[191]||(a[191]=t("a",{id:"Lux.Embedding",href:"#Lux.Embedding"},[t("span",{class:"jlbinding"},"Lux.Embedding")],-1)),a[192]||(a[192]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[193]||(a[193]=i('
    julia
    Embedding(in_dims => out_dims; init_weight=rand32)

    A lookup table that stores embeddings of dimension out_dims for a vocabulary of size in_dims. When the vocabulary is multi-dimensional, the input is expected to be a tuple of Cartesian indices.

    This layer is often used to store word embeddings and retrieve them using indices.

    Arguments

    Keyword Arguments

    Input

    Returns

    source

    ',12))]),t("details",F1,[t("summary",null,[a[194]||(a[194]=t("a",{id:"Lux.Scale",href:"#Lux.Scale"},[t("span",{class:"jlbinding"},"Lux.Scale")],-1)),a[195]||(a[195]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[196]||(a[196]=i('
    julia
    Scale(dims, activation=identity; init_weight=ones32, init_bias=zeros32, use_bias=True())

    Create a Sparsely Connected Layer with a very specific structure (only Diagonal Elements are non-zero). The forward pass is given by: y = activation.(weight .* x .+ bias)

    Arguments

    Keyword Arguments

    Input

    Returns

    Parameters

    source

    ',13))]),a[276]||(a[276]=t("h2",{id:"Misc.-Helper-Layers",tabindex:"-1"},[s("Misc. Helper Layers "),t("a",{class:"header-anchor",href:"#Misc.-Helper-Layers","aria-label":'Permalink to "Misc. Helper Layers {#Misc.-Helper-Layers}"'},"​")],-1)),t("details",D1,[t("summary",null,[a[197]||(a[197]=t("a",{id:"Lux.FlattenLayer",href:"#Lux.FlattenLayer"},[t("span",{class:"jlbinding"},"Lux.FlattenLayer")],-1)),a[198]||(a[198]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[199]||(a[199]=i(`
    julia
    FlattenLayer(; N = nothing)

    Flattens the passed array into a matrix.

    Keyword Arguments

    Inputs

    Returns

    Example

    julia
    julia> model = FlattenLayer()
    +FlattenLayer{Nothing}(nothing)
    +
    +julia> rng = Random.default_rng();
    +       Random.seed!(rng, 0);
    +       ps, st = Lux.setup(rng, model);
    +       x = randn(rng, Float32, (2, 2, 2, 2));
    +
    +julia> y, st_new = model(x, ps, st);
    +       size(y)
    +(8, 2)

    source

    `,11))]),t("details",M1,[t("summary",null,[a[200]||(a[200]=t("a",{id:"Lux.Maxout",href:"#Lux.Maxout"},[t("span",{class:"jlbinding"},"Lux.Maxout")],-1)),a[201]||(a[201]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[202]||(a[202]=i(`
    julia
    Maxout(layers...)
    +Maxout(; layers...)
    +Maxout(f::Function, n_alts::Int)

    This contains a number of internal layers, each of which receives the same input. Its output is the elementwise maximum of the the internal layers' outputs.

    Maxout over linear dense layers satisfies the universal approximation theorem. See [1].

    See also Parallel to reduce with other operators.

    Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    References

    [1] Goodfellow, Warde-Farley, Mirza, Courville & Bengio "Maxout Networks" https://arxiv.org/abs/1302.4389

    source

    `,18))]),t("details",v1,[t("summary",null,[a[203]||(a[203]=t("a",{id:"Lux.NoOpLayer",href:"#Lux.NoOpLayer"},[t("span",{class:"jlbinding"},"Lux.NoOpLayer")],-1)),a[204]||(a[204]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[205]||(a[205]=i(`
    julia
    NoOpLayer()

    As the name suggests does nothing but allows pretty printing of layers. Whatever input is passed is returned.

    Example

    julia
    julia> model = NoOpLayer()
    +NoOpLayer()
    +
    +julia> rng = Random.default_rng();
    +       Random.seed!(rng, 0);
    +       ps, st = Lux.setup(rng, model);
    +       x = 1
    +1
    +
    +julia> y, st_new = model(x, ps, st)
    +(1, NamedTuple())

    source

    `,5))]),t("details",Z1,[t("summary",null,[a[206]||(a[206]=t("a",{id:"Lux.ReshapeLayer",href:"#Lux.ReshapeLayer"},[t("span",{class:"jlbinding"},"Lux.ReshapeLayer")],-1)),a[207]||(a[207]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[208]||(a[208]=i(`
    julia
    ReshapeLayer(dims)

    Reshapes the passed array to have a size of (dims..., :)

    Arguments

    Inputs

    Returns

    Example

    julia
    julia> model = ReshapeLayer((2, 2))
    +ReshapeLayer(output_dims = (2, 2, :))
    +
    +julia> rng = Random.default_rng();
    +       Random.seed!(rng, 0);
    +       ps, st = Lux.setup(rng, model);
    +       x = randn(rng, Float32, (4, 1, 3));
    +
    +julia> y, st_new = model(x, ps, st);
    +       size(y)
    +(2, 2, 3)

    source

    `,11))]),t("details",j1,[t("summary",null,[a[209]||(a[209]=t("a",{id:"Lux.SelectDim",href:"#Lux.SelectDim"},[t("span",{class:"jlbinding"},"Lux.SelectDim")],-1)),a[210]||(a[210]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[211]||(a[211]=i('
    julia
    SelectDim(dim, i)

    Return a view of all the data of the input x where the index for dimension dim equals i. Equivalent to view(x,:,:,...,i,:,:,...) where i is in position d.

    Arguments

    Inputs

    Returns

    source

    ',9))]),t("details",A1,[t("summary",null,[a[212]||(a[212]=t("a",{id:"Lux.WrappedFunction",href:"#Lux.WrappedFunction"},[t("span",{class:"jlbinding"},"Lux.WrappedFunction")],-1)),a[213]||(a[213]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[214]||(a[214]=i('
    julia
    WrappedFunction(f)

    Wraps a stateless and parameter less function. Might be used when a function is added to Chain. For example, Chain(x -> relu.(x)) would not work and the right thing to do would be Chain((x, ps, st) -> (relu.(x), st)). An easier thing to do would be Chain(WrappedFunction(Base.Fix1(broadcast, relu)))

    Arguments

    Inputs

    Returns

    source

    ',9))]),t("details",B1,[t("summary",null,[a[215]||(a[215]=t("a",{id:"Lux.ReverseSequence",href:"#Lux.ReverseSequence"},[t("span",{class:"jlbinding"},"Lux.ReverseSequence")],-1)),a[216]||(a[216]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[217]||(a[217]=i(`
    julia
    ReverseSequence(dim = nothing)

    Reverse the specified dimension dims of the passed array

    Arguments

    Inputs

    Returns

    Example

    julia
    julia> model = ReverseSequence()
    +ReverseSequence{Nothing}(nothing)
    +
    +julia> rng = Random.default_rng();
    +       Random.seed!(rng, 0);
    +       ps, st = Lux.setup(rng, model);
    +       x = [1.0, 2.0, 3.0];
    +
    +julia> y, st_new = model(x, ps, st)
    +([3.0, 2.0, 1.0], NamedTuple())

    source

    `,11))]),a[277]||(a[277]=t("h2",{id:"Normalization-Layers",tabindex:"-1"},[s("Normalization Layers "),t("a",{class:"header-anchor",href:"#Normalization-Layers","aria-label":'Permalink to "Normalization Layers {#Normalization-Layers}"'},"​")],-1)),t("details",V1,[t("summary",null,[a[218]||(a[218]=t("a",{id:"Lux.BatchNorm",href:"#Lux.BatchNorm"},[t("span",{class:"jlbinding"},"Lux.BatchNorm")],-1)),a[219]||(a[219]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[225]||(a[225]=i(`
    julia
    BatchNorm(chs::Integer, activation=identity; init_bias=zeros32, init_scale=ones32,
    +          affine=True(), track_stats=True(), epsilon=1f-5, momentum=0.1f0)

    Batch Normalization layer.

    `,2)),t("p",null,[a[222]||(a[222]=t("code",null,"BatchNorm",-1)),a[223]||(a[223]=s(" computes the mean and variance for each ")),t("mjx-container",R1,[(Q(),n("svg",N1,a[220]||(a[220]=[i('',1)]))),a[221]||(a[221]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"D"),t("mn",null,"1")]),t("mi",null,"×"),t("mo",null,"."),t("mo",null,"."),t("mo",null,"."),t("mi",null,"×"),t("msub",null,[t("mi",null,"D"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"N"),t("mo",null,"−"),t("mn",null,"2")])]),t("mi",null,"×"),t("mn",null,"1"),t("mi",null,"×"),t("msub",null,[t("mi",null,"D"),t("mi",null,"N")])])],-1))]),a[224]||(a[224]=s(" input slice and normalises the input accordingly."))]),a[226]||(a[226]=i(`

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    Use Lux.testmode during inference.

    Example

    julia
    julia> Chain(Dense(784 => 64), BatchNorm(64, relu), Dense(64 => 10), BatchNorm(10))
    +Chain(
    +    layer_1 = Dense(784 => 64),         # 50_240 parameters
    +    layer_2 = BatchNorm(64, relu, affine=true, track_stats=true),  # 128 parameters, plus 129
    +    layer_3 = Dense(64 => 10),          # 650 parameters
    +    layer_4 = BatchNorm(10, affine=true, track_stats=true),  # 20 parameters, plus 21
    +)         # Total: 51_038 parameters,
    +          #        plus 150 states.

    Warning

    Passing a batch size of 1, during training will result in an error.

    See also BatchNorm, InstanceNorm, LayerNorm, WeightNorm

    source

    `,19))]),t("details",O1,[t("summary",null,[a[227]||(a[227]=t("a",{id:"Lux.GroupNorm",href:"#Lux.GroupNorm"},[t("span",{class:"jlbinding"},"Lux.GroupNorm")],-1)),a[228]||(a[228]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[229]||(a[229]=i(`
    julia
    GroupNorm(chs::Integer, groups::Integer, activation=identity; init_bias=zeros32,
    +          init_scale=ones32, affine=true, epsilon=1f-5)

    Group Normalization layer.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    Use Lux.testmode during inference.

    Example

    julia
    julia> Chain(Dense(784 => 64), GroupNorm(64, 4, relu), Dense(64 => 10), GroupNorm(10, 5))
    +Chain(
    +    layer_1 = Dense(784 => 64),         # 50_240 parameters
    +    layer_2 = GroupNorm(64, 4, relu, affine=true),  # 128 parameters
    +    layer_3 = Dense(64 => 10),          # 650 parameters
    +    layer_4 = GroupNorm(10, 5, affine=true),  # 20 parameters
    +)         # Total: 51_038 parameters,
    +          #        plus 0 states.

    See also GroupNorm, InstanceNorm, LayerNorm, WeightNorm

    source

    `,20))]),t("details",z1,[t("summary",null,[a[230]||(a[230]=t("a",{id:"Lux.InstanceNorm",href:"#Lux.InstanceNorm"},[t("span",{class:"jlbinding"},"Lux.InstanceNorm")],-1)),a[231]||(a[231]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[236]||(a[236]=i(`
    julia
    InstanceNorm(chs::Integer, activation=identity; init_bias=zeros32, init_scale=ones32,
    +             affine=False(), track_stats=False(), epsilon=1f-5, momentum=0.1f0)

    Instance Normalization. For details see [1].

    `,2)),t("p",null,[a[234]||(a[234]=s("Instance Normalization computes the mean and variance for each ")),t("mjx-container",P1,[(Q(),n("svg",I1,a[232]||(a[232]=[i('',1)]))),a[233]||(a[233]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"D"),t("mn",null,"1")]),t("mo",null,"×"),t("mo",null,"."),t("mo",null,"."),t("mo",null,"."),t("mo",null,"×"),t("msub",null,[t("mi",null,"D"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"N"),t("mo",null,"−"),t("mn",null,"2")])]),t("mo",null,"×"),t("mn",null,"1"),t("mo",null,"×"),t("mn",null,"1")])],-1))]),a[235]||(a[235]=s("` input slice and normalises the input accordingly."))]),a[237]||(a[237]=i(`

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    Use Lux.testmode during inference.

    Example

    julia
    julia> Chain(Dense(784 => 64), InstanceNorm(64, relu; affine=true), Dense(64 => 10),
    +           InstanceNorm(10, relu; affine=true))
    +Chain(
    +    layer_1 = Dense(784 => 64),         # 50_240 parameters
    +    layer_2 = InstanceNorm(64, relu, affine=true, track_stats=false),  # 128 parameters, plus 1
    +    layer_3 = Dense(64 => 10),          # 650 parameters
    +    layer_4 = InstanceNorm(10, relu, affine=true, track_stats=false),  # 20 parameters, plus 1
    +)         # Total: 51_038 parameters,
    +          #        plus 2 states.

    References

    [1] Ulyanov, Dmitry, Andrea Vedaldi, and Victor Lempitsky. "Instance normalization: The missing ingredient for fast stylization." arXiv preprint arXiv:1607.08022 (2016).

    See also BatchNorm, GroupNorm, LayerNorm, WeightNorm

    source

    `,20))]),t("details",S1,[t("summary",null,[a[238]||(a[238]=t("a",{id:"Lux.LayerNorm",href:"#Lux.LayerNorm"},[t("span",{class:"jlbinding"},"Lux.LayerNorm")],-1)),a[239]||(a[239]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[255]||(a[255]=i(`
    julia
    LayerNorm(shape::NTuple{N, Int}, activation=identity; epsilon=1f-5, dims=Colon(),
    +          affine=true, init_bias=zeros32, init_scale=ones32)

    Computes mean and standard deviation over the whole input array, and uses these to normalize the whole array. Optionally applies an elementwise affine transformation afterwards.

    `,2)),t("p",null,[a[242]||(a[242]=s("Given an input array ")),t("mjx-container",_1,[(Q(),n("svg",G1,a[240]||(a[240]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D465",d:"M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z",style:{"stroke-width":"3"}})])])],-1)]))),a[241]||(a[241]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"x")])],-1))]),a[243]||(a[243]=s(", this layer computes"))]),t("mjx-container",W1,[(Q(),n("svg",X1,a[244]||(a[244]=[i('',1)]))),a[245]||(a[245]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("mi",null,"y"),t("mo",null,"="),t("mfrac",null,[t("mrow",null,[t("mi",null,"x"),t("mo",null,"−"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",{mathvariant:"double-struck"},"E")]),t("mo",{stretchy:"false"},"["),t("mi",null,"x"),t("mo",{stretchy:"false"},"]")]),t("msqrt",null,[t("mi",null,"V"),t("mi",null,"a"),t("mi",null,"r"),t("mo",{stretchy:"false"},"["),t("mi",null,"x"),t("mo",{stretchy:"false"},"]"),t("mo",null,"+"),t("mi",null,"ϵ")])]),t("mo",null,"∗"),t("mi",null,"γ"),t("mo",null,"+"),t("mi",null,"β")])],-1))]),t("p",null,[a[250]||(a[250]=s("where ")),t("mjx-container",U1,[(Q(),n("svg",q1,a[246]||(a[246]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),a[247]||(a[247]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"γ")])],-1))]),a[251]||(a[251]=s(" & ")),t("mjx-container",J1,[(Q(),n("svg",K1,a[248]||(a[248]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FD",d:"M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z",style:{"stroke-width":"3"}})])])],-1)]))),a[249]||(a[249]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"β")])],-1))]),a[252]||(a[252]=s(" are trainable parameters if ")),a[253]||(a[253]=t("code",null,"affine=true",-1)),a[254]||(a[254]=s("."))]),a[256]||(a[256]=i('

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    source

    ',12))]),t("details",$1,[t("summary",null,[a[257]||(a[257]=t("a",{id:"Lux.WeightNorm",href:"#Lux.WeightNorm"},[t("span",{class:"jlbinding"},"Lux.WeightNorm")],-1)),a[258]||(a[258]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[261]||(a[261]=i(`
    julia
    WeightNorm(layer::AbstractLuxLayer, which_params::NTuple{N, Symbol},
    +           dims::Union{Tuple, Nothing}=nothing)

    Applies weight normalization to a parameter in the given layer.

    `,2)),t("mjx-container",Y1,[(Q(),n("svg",t2,a[259]||(a[259]=[i('',1)]))),a[260]||(a[260]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("mi",null,"w"),t("mo",null,"="),t("mi",null,"g"),t("mfrac",null,[t("mi",null,"v"),t("mrow",null,[t("mo",{"data-mjx-texclass":"ORD"},"∥"),t("mi",null,"v"),t("mo",{"data-mjx-texclass":"ORD"},"∥")])])])],-1))]),a[262]||(a[262]=i('

    Weight normalization is a reparameterization that decouples the magnitude of a weight tensor from its direction. This updates the parameters in which_params (e.g. weight) using two parameters: one specifying the magnitude (e.g. weight_g) and one specifying the direction (e.g. weight_v).

    Arguments

    Inputs

    Returns

    Parameters

    States

    source

    ',12))]),a[278]||(a[278]=t("h2",{id:"upsampling",tabindex:"-1"},[s("Upsampling "),t("a",{class:"header-anchor",href:"#upsampling","aria-label":'Permalink to "Upsampling"'},"​")],-1)),t("details",a2,[t("summary",null,[a[263]||(a[263]=t("a",{id:"Lux.PixelShuffle",href:"#Lux.PixelShuffle"},[t("span",{class:"jlbinding"},"Lux.PixelShuffle")],-1)),a[264]||(a[264]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[265]||(a[265]=i('
    julia
    PixelShuffle(r::Int)

    Pixel shuffling layer with upscale factor r. Usually used for generating higher resolution images while upscaling them.

    See NNlib.pixel_shuffle for more details.

    Arguments

    Inputs

    Returns

    source

    ',10))]),t("details",s2,[t("summary",null,[a[266]||(a[266]=t("a",{id:"Lux.Upsample",href:"#Lux.Upsample"},[t("span",{class:"jlbinding"},"Lux.Upsample")],-1)),a[267]||(a[267]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[268]||(a[268]=i(`
    julia
    Upsample(mode = :nearest; [scale, size, align_corners=false])
    +Upsample(scale, mode = :nearest)

    Upsampling Layer.

    Layer Construction

    Option 1

    Exactly one of two keywords must be specified:

    Option 2

    Currently supported upsampling modes and corresponding NNlib's methods are:

    Extended Help

    Other Keyword Arguments

    Inputs

    Returns

    source

    `,19))])])}const r2=T(o,[["render",i2]]);export{o2 as __pageData,r2 as default}; diff --git a/previews/PR1023/assets/api_Lux_layers.md.DhFbD-A5.lean.js b/previews/PR1023/assets/api_Lux_layers.md.DhFbD-A5.lean.js new file mode 100644 index 0000000000..09ce5f38a2 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_layers.md.DhFbD-A5.lean.js @@ -0,0 +1,149 @@ +import{_ as T,c as n,j as t,a as s,G as l,a2 as i,B as d,o as Q}from"./chunks/framework.DFwXuivk.js";const o2=JSON.parse('{"title":"Built-In Layers","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/layers.md","filePath":"api/Lux/layers.md","lastUpdated":null}'),o={name:"api/Lux/layers.md"},r={class:"jldocstring custom-block"},p={class:"jldocstring custom-block"},h={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},k={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},u={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},y={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.148ex"},xmlns:"http://www.w3.org/2000/svg",width:"45.995ex",height:"5.686ex",role:"img",focusable:"false",viewBox:"0 -1563.5 20329.9 2513","aria-hidden":"true"},E={class:"jldocstring custom-block"},f={class:"jldocstring custom-block"},L={class:"jldocstring custom-block"},x={class:"jldocstring custom-block"},w={class:"jldocstring custom-block"},b={class:"jldocstring custom-block"},H={class:"jldocstring custom-block"},C={class:"jldocstring custom-block"},F={class:"jldocstring custom-block"},D={class:"jldocstring custom-block"},M={class:"jldocstring custom-block"},v={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},Z={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.148ex"},xmlns:"http://www.w3.org/2000/svg",width:"45.995ex",height:"5.686ex",role:"img",focusable:"false",viewBox:"0 -1563.5 20329.9 2513","aria-hidden":"true"},j={class:"jldocstring custom-block"},A={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},B={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.148ex"},xmlns:"http://www.w3.org/2000/svg",width:"45.995ex",height:"5.686ex",role:"img",focusable:"false",viewBox:"0 -1563.5 20329.9 2513","aria-hidden":"true"},V={class:"jldocstring custom-block"},R={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},N={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.148ex"},xmlns:"http://www.w3.org/2000/svg",width:"45.995ex",height:"5.686ex",role:"img",focusable:"false",viewBox:"0 -1563.5 20329.9 2513","aria-hidden":"true"},O={class:"jldocstring custom-block"},z={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},P={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-5.146ex"},xmlns:"http://www.w3.org/2000/svg",width:"51.473ex",height:"11.422ex",role:"img",focusable:"false",viewBox:"0 -2774.4 22750.9 5048.7","aria-hidden":"true"},I={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},S={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},_={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},G={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},W={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},X={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"15.326ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 6774.2 1000","aria-hidden":"true"},U={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},q={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"16.435ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 7264.2 1000","aria-hidden":"true"},J={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},K={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"11.831ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 5229.2 1000","aria-hidden":"true"},$={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},Y={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"12.939ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 5719.2 1000","aria-hidden":"true"},t1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},a1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"12.939ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 5719.2 1000","aria-hidden":"true"},s1={class:"jldocstring custom-block"},i1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},e1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-8.146ex"},xmlns:"http://www.w3.org/2000/svg",width:"40.257ex",height:"17.424ex",role:"img",focusable:"false",viewBox:"0 -4100.7 17793.6 7701.4","aria-hidden":"true"},l1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},n1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},Q1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},T1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},d1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},o1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.018ex",height:"1.357ex",role:"img",focusable:"false",viewBox:"0 -442 1776.1 599.8","aria-hidden":"true"},r1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},p1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.667ex"},xmlns:"http://www.w3.org/2000/svg",width:"19.753ex",height:"2.364ex",role:"img",focusable:"false",viewBox:"0 -750 8730.9 1045","aria-hidden":"true"},h1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},m1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.667ex"},xmlns:"http://www.w3.org/2000/svg",width:"21.231ex",height:"2.364ex",role:"img",focusable:"false",viewBox:"0 -750 9384.3 1045","aria-hidden":"true"},g1={class:"jldocstring custom-block"},k1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},c1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.65ex"},xmlns:"http://www.w3.org/2000/svg",width:"67.61ex",height:"2.347ex",role:"img",focusable:"false",viewBox:"0 -750 29883.5 1037.2","aria-hidden":"true"},u1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},y1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},E1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},f1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"4.342ex",height:"1.927ex",role:"img",focusable:"false",viewBox:"0 -694 1919.1 851.8","aria-hidden":"true"},L1={class:"jldocstring custom-block"},x1={class:"jldocstring custom-block"},w1={class:"jldocstring custom-block"},b1={class:"jldocstring custom-block"},H1={class:"jldocstring custom-block"},C1={class:"jldocstring custom-block"},F1={class:"jldocstring custom-block"},D1={class:"jldocstring custom-block"},M1={class:"jldocstring custom-block"},v1={class:"jldocstring custom-block"},Z1={class:"jldocstring custom-block"},j1={class:"jldocstring custom-block"},A1={class:"jldocstring custom-block"},B1={class:"jldocstring custom-block"},V1={class:"jldocstring custom-block"},R1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},N1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.471ex"},xmlns:"http://www.w3.org/2000/svg",width:"23.059ex",height:"2.016ex",role:"img",focusable:"false",viewBox:"0 -683 10192.1 891","aria-hidden":"true"},O1={class:"jldocstring custom-block"},z1={class:"jldocstring custom-block"},P1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},I1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.471ex"},xmlns:"http://www.w3.org/2000/svg",width:"22.72ex",height:"2.016ex",role:"img",focusable:"false",viewBox:"0 -683 10042 891","aria-hidden":"true"},S1={class:"jldocstring custom-block"},_1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},G1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.294ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 572 453","aria-hidden":"true"},W1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},X1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.76ex"},xmlns:"http://www.w3.org/2000/svg",width:"25.034ex",height:"6.063ex",role:"img",focusable:"false",viewBox:"0 -1460 11064.9 2680","aria-hidden":"true"},U1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},q1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},J1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},K1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.281ex",height:"2.034ex",role:"img",focusable:"false",viewBox:"0 -705 566 899","aria-hidden":"true"},$1={class:"jldocstring custom-block"},Y1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},t2={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.172ex"},xmlns:"http://www.w3.org/2000/svg",width:"10.071ex",height:"4.704ex",role:"img",focusable:"false",viewBox:"0 -1119 4451.6 2079","aria-hidden":"true"},a2={class:"jldocstring custom-block"},s2={class:"jldocstring custom-block"};function i2(e2,a,l2,n2,Q2,T2){const e=d("Badge");return Q(),n("div",null,[a[269]||(a[269]=t("h1",{id:"Built-In-Layers",tabindex:"-1"},[s("Built-In Layers "),t("a",{class:"header-anchor",href:"#Built-In-Layers","aria-label":'Permalink to "Built-In Layers {#Built-In-Layers}"'},"​")],-1)),a[270]||(a[270]=t("h2",{id:"containers",tabindex:"-1"},[s("Containers "),t("a",{class:"header-anchor",href:"#containers","aria-label":'Permalink to "Containers"'},"​")],-1)),t("details",r,[t("summary",null,[a[0]||(a[0]=t("a",{id:"Lux.BranchLayer",href:"#Lux.BranchLayer"},[t("span",{class:"jlbinding"},"Lux.BranchLayer")],-1)),a[1]||(a[1]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[2]||(a[2]=i(`
    julia
    BranchLayer(layers...)
    +BranchLayer(; name=nothing, layers...)

    Takes an input x and passes it through all the layers and returns a tuple of the outputs.

    Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    Comparison with Parallel

    This is slightly different from Parallel(nothing, layers...)

    Example

    An easy way to replicate an input to an NTuple is to do

    julia
    julia> BranchLayer(NoOpLayer(), NoOpLayer(), NoOpLayer())
    +BranchLayer(
    +    layer_1 = NoOpLayer(),
    +    layer_2 = NoOpLayer(),
    +    layer_3 = NoOpLayer(),
    +)         # Total: 0 parameters,
    +          #        plus 0 states.

    source

    `,18))]),t("details",p,[t("summary",null,[a[3]||(a[3]=t("a",{id:"Lux.Chain",href:"#Lux.Chain"},[t("span",{class:"jlbinding"},"Lux.Chain")],-1)),a[4]||(a[4]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[5]||(a[5]=i(`
    julia
    Chain(layers...; name=nothing)
    +Chain(; layers..., name=nothing)

    Collects multiple layers / functions to be called in sequence on a given input.

    Arguments

    Extended Help

    Inputs

    Input x is passed sequentially to each layer, and must conform to the input requirements of the internal layers.

    Returns

    Parameters

    States

    Miscellaneous Properties

    Example

    julia
    julia> Chain(Dense(2, 3, relu), BatchNorm(3), Dense(3, 2))
    +Chain(
    +    layer_1 = Dense(2 => 3, relu),      # 9 parameters
    +    layer_2 = BatchNorm(3, affine=true, track_stats=true),  # 6 parameters, plus 7
    +    layer_3 = Dense(3 => 2),            # 8 parameters
    +)         # Total: 23 parameters,
    +          #        plus 7 states.
    +
    +julia> Chain(Dense(2, 3, relu), BatchNorm(3), Dense(3, 2); name="MyFancyChain")
    +MyFancyChain(
    +    layer_1 = Dense(2 => 3, relu),      # 9 parameters
    +    layer_2 = BatchNorm(3, affine=true, track_stats=true),  # 6 parameters, plus 7
    +    layer_3 = Dense(3 => 2),            # 8 parameters
    +)         # Total: 23 parameters,
    +          #        plus 7 states.

    source

    `,18))]),t("details",h,[t("summary",null,[a[6]||(a[6]=t("a",{id:"Lux.PairwiseFusion",href:"#Lux.PairwiseFusion"},[t("span",{class:"jlbinding"},"Lux.PairwiseFusion")],-1)),a[7]||(a[7]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[8]||(a[8]=i(`
    julia
    PairwiseFusion(connection, layers...; name=nothing)
    +PairwiseFusion(connection; name=nothing, layers...)
    +PairwiseFusion(; connection, layers..., name=nothing)
    x1 → layer1 → y1 ↘
    +                  connection → layer2 → y2 ↘
    +              x2 ↗                          connection → y3
    +                                        x3 ↗

    Arguments

    Extended Help

    Inputs

    Layer behaves differently based on input type:

    1. If the input x is a tuple of length N + 1, then the layers must be a tuple of length N. The computation is as follows
    julia
    y = x[1]
    +for i in 1:N
    +    y = connection(x[i + 1], layers[i](y))
    +end
    1. Any other kind of input
    julia
    y = x
    +for i in 1:N
    +    y = connection(x, layers[i](y))
    +end

    Returns

    Parameters

    States

    source

    `,18))]),t("details",m,[t("summary",null,[a[9]||(a[9]=t("a",{id:"Lux.Parallel",href:"#Lux.Parallel"},[t("span",{class:"jlbinding"},"Lux.Parallel")],-1)),a[10]||(a[10]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[11]||(a[11]=i(`
    julia
    Parallel(connection, layers...; name=nothing)
    +Parallel(connection; name=nothing, layers...)
    +Parallel(; connection, layers..., name=nothing)

    Create a layer which passes an input to each path in layers, before reducing the output with connection.

    Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    See also SkipConnection which is Parallel with one identity.

    Example

    julia
    julia> model = Parallel(nothing, Dense(2, 1), Dense(2, 1))
    +Parallel(
    +    layer_1 = Dense(2 => 1),            # 3 parameters
    +    layer_2 = Dense(2 => 1),            # 3 parameters
    +)         # Total: 6 parameters,
    +          #        plus 0 states.
    +
    +julia> using Random;
    +       rng = Random.seed!(123);
    +       ps, st = Lux.setup(rng, model);
    +       x1 = randn(rng, Float32, 2);
    +       x2 = randn(rng, Float32, 2);
    +
    +julia> size.(first(model((x1, x2), ps, st)))
    +((1,), (1,))

    source

    `,17))]),t("details",g,[t("summary",null,[a[12]||(a[12]=t("a",{id:"Lux.SkipConnection",href:"#Lux.SkipConnection"},[t("span",{class:"jlbinding"},"Lux.SkipConnection")],-1)),a[13]||(a[13]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[14]||(a[14]=i(`
    julia
    SkipConnection(layers, connection; name=nothing)
    +SkipConnection(; layers, connection, name=nothing)

    Create a skip connection which consists of a layer or Chain of consecutive layers and a shortcut connection linking the block's input to the output through a user-supplied 2-argument callable. The first argument to the callable will be propagated through the given layer while the second is the unchanged, "skipped" input.

    The simplest "ResNet"-type connection is just SkipConnection(layer, +).

    Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    See Parallel for a more general implementation.

    source

    `,16))]),t("details",k,[t("summary",null,[a[15]||(a[15]=t("a",{id:"Lux.RepeatedLayer",href:"#Lux.RepeatedLayer"},[t("span",{class:"jlbinding"},"Lux.RepeatedLayer")],-1)),a[16]||(a[16]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[17]||(a[17]=i(`
    julia
    RepeatedLayer(model; repeats::Val = Val(10), input_injection::Val = Val(false))

    Iteratively applies model for repeats number of times. The initial input is passed into the model repeatedly if input_injection = Val(true). This layer unrolls the computation, however, semantically this is same as:

    julia
    res = x
    +for i in 1:repeats
    +    res, st = model(res, ps, st)
    +end
    julia
    res = x
    +for i in 1:repeats
    +    res, st = model((res, x), ps, st)
    +end

    It is expected that repeats will be a reasonable number below 20, beyond that compile times for gradients might be unreasonably high.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    source

    `,21))]),a[271]||(a[271]=t("h2",{id:"Convolutional-Layers",tabindex:"-1"},[s("Convolutional Layers "),t("a",{class:"header-anchor",href:"#Convolutional-Layers","aria-label":'Permalink to "Convolutional Layers {#Convolutional-Layers}"'},"​")],-1)),t("details",c,[t("summary",null,[a[18]||(a[18]=t("a",{id:"Lux.Conv",href:"#Lux.Conv"},[t("span",{class:"jlbinding"},"Lux.Conv")],-1)),a[19]||(a[19]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[22]||(a[22]=i(`
    julia
    Conv(k::NTuple{N,Integer}, (in_chs => out_chs)::Pair{<:Integer,<:Integer},
    +     activation=identity; init_weight=nothing, init_bias=nothing, stride=1,
    +     pad=0, dilation=1, groups=1, use_bias=True(), cross_correlation=False())

    Standard convolutional layer.

    Conv 2D

    Image data should be stored in WHCN order (width, height, channels, batch). In other words, a 100 x 100 RGB image would be a 100 x 100 x 3 x 1 array, and a batch of 50 would be a 100 x 100 x 3 x 50 array. This has N = 2 spatial dimensions, and needs a kernel size like (5, 5), a 2-tuple of integers. To take convolutions along N feature dimensions, this layer expects as input an array with ndims(x) == N + 2, where size(x, N + 1) == in_chs is the number of input channels, and size(x, ndims(x)) is the number of observations in a batch.

    Warning

    Frameworks like Pytorch perform cross-correlation in their convolution layers. Pass cross_correlation=true to use cross-correlation instead.

    Arguments

    Extended Help

    Keyword Arguments

    Inputs

    Returns

    `,13)),t("mjx-container",u,[(Q(),n("svg",y,a[20]||(a[20]=[i('',1)]))),a[21]||(a[21]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("msub",null,[t("mi",null,"O"),t("mi",null,"i")]),t("mo",null,"="),t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"⌊"),t("mfrac",null,[t("mrow",null,[t("msub",null,[t("mi",null,"I"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mo",{stretchy:"false"},"("),t("mi",null,"i"),t("mo",null,"+"),t("mi",null,"N"),t("mo",{stretchy:"false"},")"),t("mi",{mathvariant:"normal"},"%"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),t("mi",null,"p"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|")])]),t("mo",null,"−"),t("msub",null,[t("mi",null,"d"),t("mi",null,"i")]),t("mo",null,"×"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"k"),t("mi",null,"i")]),t("mo",null,"−"),t("mn",null,"1"),t("mo",{stretchy:"false"},")")]),t("msub",null,[t("mi",null,"s"),t("mi",null,"i")])]),t("mo",null,"+"),t("mn",null,"1"),t("mo",{"data-mjx-texclass":"CLOSE"},"⌋")])])],-1))]),a[23]||(a[23]=i('

    Parameters

    source

    ',4))]),t("details",E,[t("summary",null,[a[24]||(a[24]=t("a",{id:"Lux.ConvTranspose",href:"#Lux.ConvTranspose"},[t("span",{class:"jlbinding"},"Lux.ConvTranspose")],-1)),a[25]||(a[25]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[26]||(a[26]=i(`
    julia
    ConvTranspose(k::NTuple{N,Integer}, (in_chs => out_chs)::Pair{<:Integer,<:Integer},
    +              activation=identity; init_weight=glorot_uniform, init_bias=zeros32,
    +              stride=1, pad=0, outpad=0, dilation=1, groups=1, use_bias=True(),
    +              cross_correlation=False())

    Standard convolutional transpose layer.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    source

    `,14))]),a[272]||(a[272]=t("h2",{id:"Dropout-Layers",tabindex:"-1"},[s("Dropout Layers "),t("a",{class:"header-anchor",href:"#Dropout-Layers","aria-label":'Permalink to "Dropout Layers {#Dropout-Layers}"'},"​")],-1)),t("details",f,[t("summary",null,[a[27]||(a[27]=t("a",{id:"Lux.AlphaDropout",href:"#Lux.AlphaDropout"},[t("span",{class:"jlbinding"},"Lux.AlphaDropout")],-1)),a[28]||(a[28]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[29]||(a[29]=i('
    julia
    AlphaDropout(p::Real)

    AlphaDropout layer.

    Arguments

    Inputs

    Returns

    States

    Call Lux.testmode to switch to test mode.

    See also Dropout, VariationalHiddenDropout

    source

    ',13))]),t("details",L,[t("summary",null,[a[30]||(a[30]=t("a",{id:"Lux.Dropout",href:"#Lux.Dropout"},[t("span",{class:"jlbinding"},"Lux.Dropout")],-1)),a[31]||(a[31]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[32]||(a[32]=i('
    julia
    Dropout(p; dims=:)

    Dropout layer.

    Arguments

    Keyword Arguments

    Inputs

    Returns

    States

    Call Lux.testmode to switch to test mode.

    See also AlphaDropout, VariationalHiddenDropout

    source

    ',15))]),t("details",x,[t("summary",null,[a[33]||(a[33]=t("a",{id:"Lux.VariationalHiddenDropout",href:"#Lux.VariationalHiddenDropout"},[t("span",{class:"jlbinding"},"Lux.VariationalHiddenDropout")],-1)),a[34]||(a[34]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[35]||(a[35]=i('
    julia
    VariationalHiddenDropout(p; dims=:)

    VariationalHiddenDropout layer. The only difference from Dropout is that the mask is retained until Lux.update_state(l, :update_mask, Val(true)) is called.

    Arguments

    Keyword Arguments

    Inputs

    Returns

    States

    Call Lux.testmode to switch to test mode.

    See also AlphaDropout, Dropout

    source

    ',15))]),a[273]||(a[273]=t("h2",{id:"Pooling-Layers",tabindex:"-1"},[s("Pooling Layers "),t("a",{class:"header-anchor",href:"#Pooling-Layers","aria-label":'Permalink to "Pooling Layers {#Pooling-Layers}"'},"​")],-1)),t("details",w,[t("summary",null,[a[36]||(a[36]=t("a",{id:"Lux.AdaptiveLPPool",href:"#Lux.AdaptiveLPPool"},[t("span",{class:"jlbinding"},"Lux.AdaptiveLPPool")],-1)),a[37]||(a[37]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[38]||(a[38]=i('
    julia
    AdaptiveLPPool(output_size; p=2)

    Adaptive LP Pooling layer. Calculates the necessary window size such that its output has size(y)[1:N] == output_size.

    Arguments

    GPU Support

    This layer is currently only supported on CPU.

    Inputs

    Returns

    source

    ',10))]),t("details",b,[t("summary",null,[a[39]||(a[39]=t("a",{id:"Lux.AdaptiveMaxPool",href:"#Lux.AdaptiveMaxPool"},[t("span",{class:"jlbinding"},"Lux.AdaptiveMaxPool")],-1)),a[40]||(a[40]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[41]||(a[41]=i('
    julia
    AdaptiveMaxPool(output_size)

    Adaptive Max Pooling layer. Calculates the necessary window size such that its output has size(y)[1:N] == output_size.

    Arguments

    Inputs

    Returns

    source

    ',9))]),t("details",H,[t("summary",null,[a[42]||(a[42]=t("a",{id:"Lux.AdaptiveMeanPool",href:"#Lux.AdaptiveMeanPool"},[t("span",{class:"jlbinding"},"Lux.AdaptiveMeanPool")],-1)),a[43]||(a[43]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[44]||(a[44]=i('
    julia
    AdaptiveMeanPool(output_size)

    Adaptive Mean Pooling layer. Calculates the necessary window size such that its output has size(y)[1:N] == output_size.

    Arguments

    Inputs

    Returns

    source

    ',9))]),t("details",C,[t("summary",null,[a[45]||(a[45]=t("a",{id:"Lux.GlobalLPPool",href:"#Lux.GlobalLPPool"},[t("span",{class:"jlbinding"},"Lux.GlobalLPPool")],-1)),a[46]||(a[46]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[47]||(a[47]=i('
    julia
    GlobalLPPool(; p=2)

    Global LP Pooling layer. Transforms (w, h, c, b)-shaped input into (1, 1, c, b)-shaped output, by performing mean pooling on the complete (w, h)-shaped feature maps.

    GPU Support

    This layer is currently only supported on CPU.

    Inputs

    Returns

    source

    ',8))]),t("details",F,[t("summary",null,[a[48]||(a[48]=t("a",{id:"Lux.GlobalMaxPool",href:"#Lux.GlobalMaxPool"},[t("span",{class:"jlbinding"},"Lux.GlobalMaxPool")],-1)),a[49]||(a[49]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[50]||(a[50]=i('
    julia
    GlobalMaxPool()

    Global Max Pooling layer. Transforms (w, h, c, b)-shaped input into (1, 1, c, b)-shaped output, by performing mean pooling on the complete (w, h)-shaped feature maps.

    Inputs

    Returns

    source

    ',7))]),t("details",D,[t("summary",null,[a[51]||(a[51]=t("a",{id:"Lux.GlobalMeanPool",href:"#Lux.GlobalMeanPool"},[t("span",{class:"jlbinding"},"Lux.GlobalMeanPool")],-1)),a[52]||(a[52]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[53]||(a[53]=i('
    julia
    GlobalMeanPool()

    Global Mean Pooling layer. Transforms (w, h, c, b)-shaped input into (1, 1, c, b)-shaped output, by performing mean pooling on the complete (w, h)-shaped feature maps.

    Inputs

    Returns

    source

    ',7))]),t("details",M,[t("summary",null,[a[54]||(a[54]=t("a",{id:"Lux.LPPool",href:"#Lux.LPPool"},[t("span",{class:"jlbinding"},"Lux.LPPool")],-1)),a[55]||(a[55]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[58]||(a[58]=i('
    julia
    LPPool(window; stride=window, pad=0, dilation=1, p=2)

    LP Pooling layer, which replaces all pixels in a block of size window with the reduction operation: lp.

    Arguments

    Keyword Arguments

    GPU Support

    This layer is currently only supported on CPU.

    Extended Help

    Inputs

    Returns

    ',12)),t("mjx-container",v,[(Q(),n("svg",Z,a[56]||(a[56]=[i('',1)]))),a[57]||(a[57]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("msub",null,[t("mi",null,"O"),t("mi",null,"i")]),t("mo",null,"="),t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"⌊"),t("mfrac",null,[t("mrow",null,[t("msub",null,[t("mi",null,"I"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mo",{stretchy:"false"},"("),t("mi",null,"i"),t("mo",null,"+"),t("mi",null,"N"),t("mo",{stretchy:"false"},")"),t("mi",{mathvariant:"normal"},"%"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),t("mi",null,"p"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|")])]),t("mo",null,"−"),t("msub",null,[t("mi",null,"d"),t("mi",null,"i")]),t("mo",null,"×"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"k"),t("mi",null,"i")]),t("mo",null,"−"),t("mn",null,"1"),t("mo",{stretchy:"false"},")")]),t("msub",null,[t("mi",null,"s"),t("mi",null,"i")])]),t("mo",null,"+"),t("mn",null,"1"),t("mo",{"data-mjx-texclass":"CLOSE"},"⌋")])])],-1))]),a[59]||(a[59]=t("ul",null,[t("li",null,[s("Empty "),t("code",null,"NamedTuple()")])],-1)),a[60]||(a[60]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/src/layers/pooling.jl#L188-L236",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",j,[t("summary",null,[a[61]||(a[61]=t("a",{id:"Lux.MaxPool",href:"#Lux.MaxPool"},[t("span",{class:"jlbinding"},"Lux.MaxPool")],-1)),a[62]||(a[62]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[65]||(a[65]=i('
    julia
    MaxPool(window; stride=window, pad=0, dilation=1)

    Max Pooling layer, which replaces all pixels in a block of size window with the reduction operation: max.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    ',11)),t("mjx-container",A,[(Q(),n("svg",B,a[63]||(a[63]=[i('',1)]))),a[64]||(a[64]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("msub",null,[t("mi",null,"O"),t("mi",null,"i")]),t("mo",null,"="),t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"⌊"),t("mfrac",null,[t("mrow",null,[t("msub",null,[t("mi",null,"I"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mo",{stretchy:"false"},"("),t("mi",null,"i"),t("mo",null,"+"),t("mi",null,"N"),t("mo",{stretchy:"false"},")"),t("mi",{mathvariant:"normal"},"%"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),t("mi",null,"p"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|")])]),t("mo",null,"−"),t("msub",null,[t("mi",null,"d"),t("mi",null,"i")]),t("mo",null,"×"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"k"),t("mi",null,"i")]),t("mo",null,"−"),t("mn",null,"1"),t("mo",{stretchy:"false"},")")]),t("msub",null,[t("mi",null,"s"),t("mi",null,"i")])]),t("mo",null,"+"),t("mn",null,"1"),t("mo",{"data-mjx-texclass":"CLOSE"},"⌋")])])],-1))]),a[66]||(a[66]=t("ul",null,[t("li",null,[s("Empty "),t("code",null,"NamedTuple()")])],-1)),a[67]||(a[67]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/src/layers/pooling.jl#L188-L232",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",V,[t("summary",null,[a[68]||(a[68]=t("a",{id:"Lux.MeanPool",href:"#Lux.MeanPool"},[t("span",{class:"jlbinding"},"Lux.MeanPool")],-1)),a[69]||(a[69]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[72]||(a[72]=i('
    julia
    MeanPool(window; stride=window, pad=0, dilation=1)

    Mean Pooling layer, which replaces all pixels in a block of size window with the reduction operation: mean.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    ',11)),t("mjx-container",R,[(Q(),n("svg",N,a[70]||(a[70]=[i('',1)]))),a[71]||(a[71]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("msub",null,[t("mi",null,"O"),t("mi",null,"i")]),t("mo",null,"="),t("mrow",{"data-mjx-texclass":"INNER"},[t("mo",{"data-mjx-texclass":"OPEN"},"⌊"),t("mfrac",null,[t("mrow",null,[t("msub",null,[t("mi",null,"I"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mi",null,"i")]),t("mo",null,"+"),t("msub",null,[t("mi",null,"p"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mo",{stretchy:"false"},"("),t("mi",null,"i"),t("mo",null,"+"),t("mi",null,"N"),t("mo",{stretchy:"false"},")"),t("mi",{mathvariant:"normal"},"%"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),t("mi",null,"p"),t("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|")])]),t("mo",null,"−"),t("msub",null,[t("mi",null,"d"),t("mi",null,"i")]),t("mo",null,"×"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"k"),t("mi",null,"i")]),t("mo",null,"−"),t("mn",null,"1"),t("mo",{stretchy:"false"},")")]),t("msub",null,[t("mi",null,"s"),t("mi",null,"i")])]),t("mo",null,"+"),t("mn",null,"1"),t("mo",{"data-mjx-texclass":"CLOSE"},"⌋")])])],-1))]),a[73]||(a[73]=t("ul",null,[t("li",null,[s("Empty "),t("code",null,"NamedTuple()")])],-1)),a[74]||(a[74]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/src/layers/pooling.jl#L188-L232",target:"_blank",rel:"noreferrer"},"source")],-1))]),a[274]||(a[274]=t("h2",{id:"Recurrent-Layers",tabindex:"-1"},[s("Recurrent Layers "),t("a",{class:"header-anchor",href:"#Recurrent-Layers","aria-label":'Permalink to "Recurrent Layers {#Recurrent-Layers}"'},"​")],-1)),t("details",O,[t("summary",null,[a[75]||(a[75]=t("a",{id:"Lux.GRUCell",href:"#Lux.GRUCell"},[t("span",{class:"jlbinding"},"Lux.GRUCell")],-1)),a[76]||(a[76]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[120]||(a[120]=i(`
    julia
    GRUCell((in_dims, out_dims)::Pair{<:Int,<:Int}; use_bias=true, train_state::Bool=false,
    +        init_weight=nothing, init_bias=nothing, init_state=zeros32)

    Gated Recurrent Unit (GRU) Cell

    `,2)),t("mjx-container",z,[(Q(),n("svg",P,a[77]||(a[77]=[i('',1)]))),a[78]||(a[78]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("mtable",{displaystyle:"true",columnalign:"right left",columnspacing:"0em",rowspacing:"3pt"},[t("mtr",null,[t("mtd",null,[t("mi",null,"r")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"σ"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"r")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"r")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"r")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"r")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("mi",null,"z")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"σ"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"z")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"z")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"z")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"z")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("mi",null,"n")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"tanh"),t("mo",{"data-mjx-texclass":"NONE"},"⁡"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"n")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"n")])]),t("mo",null,"+"),t("mi",null,"r"),t("mo",null,"⋅"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"n")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"n")])]),t("mo",{stretchy:"false"},")"),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mo",{stretchy:"false"},"("),t("mn",null,"1"),t("mo",null,"−"),t("mi",null,"z"),t("mo",{stretchy:"false"},")"),t("mo",null,"⋅"),t("mi",null,"n"),t("mo",null,"+"),t("mi",null,"z"),t("mo",null,"⋅"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])])])])])])],-1))]),a[121]||(a[121]=i("

    Arguments

    Inputs

    Returns

    ",5)),t("ul",null,[t("li",null,[a[87]||(a[87]=t("p",null,"Tuple containing",-1)),t("ul",null,[t("li",null,[t("p",null,[a[81]||(a[81]=s("Output ")),t("mjx-container",I,[(Q(),n("svg",S,a[79]||(a[79]=[i('',1)]))),a[80]||(a[80]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))]),a[82]||(a[82]=s(" of shape ")),a[83]||(a[83]=t("code",null,"(out_dims, batch_size)",-1))])]),t("li",null,[t("p",null,[a[86]||(a[86]=s("Tuple containing new hidden state ")),t("mjx-container",_,[(Q(),n("svg",G,a[84]||(a[84]=[i('',1)]))),a[85]||(a[85]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))])])])])]),a[88]||(a[88]=t("li",null,[t("p",null,"Updated model state")],-1))]),a[122]||(a[122]=t("p",null,[t("strong",null,"Parameters")],-1)),t("ul",null,[t("li",null,[t("p",null,[a[91]||(a[91]=t("code",null,"weight_ih",-1)),a[92]||(a[92]=s(": Concatenated Weights to map from input space ")),t("mjx-container",W,[(Q(),n("svg",X,a[89]||(a[89]=[i('',1)]))),a[90]||(a[90]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"r")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"z")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"n")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[93]||(a[93]=s("."))])]),t("li",null,[t("p",null,[a[96]||(a[96]=t("code",null,"weight_hh",-1)),a[97]||(a[97]=s(": Concatenated Weights to map from hidden space ")),t("mjx-container",U,[(Q(),n("svg",q,a[94]||(a[94]=[i('',1)]))),a[95]||(a[95]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"r")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"z")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"n")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[98]||(a[98]=s("."))])]),t("li",null,[t("p",null,[a[101]||(a[101]=t("code",null,"bias_ih",-1)),a[102]||(a[102]=s(": Concatenated Bias vector for the input space ")),t("mjx-container",J,[(Q(),n("svg",K,a[99]||(a[99]=[i('',1)]))),a[100]||(a[100]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"r")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"z")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"n")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[103]||(a[103]=s(" (not present if ")),a[104]||(a[104]=t("code",null,"use_bias=false",-1)),a[105]||(a[105]=s(")."))])]),t("li",null,[t("p",null,[a[108]||(a[108]=t("code",null,"bias_hh",-1)),a[109]||(a[109]=s(": Concatenated Bias vector for the hidden space ")),t("mjx-container",$,[(Q(),n("svg",Y,a[106]||(a[106]=[i('',1)]))),a[107]||(a[107]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"r")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"z")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"n")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[110]||(a[110]=s(" (not present if ")),a[111]||(a[111]=t("code",null,"use_bias=false",-1)),a[112]||(a[112]=s(")."))])]),t("li",null,[t("p",null,[a[115]||(a[115]=t("code",null,"hidden_state",-1)),a[116]||(a[116]=s(": Initial hidden state vector (not present if ")),a[117]||(a[117]=t("code",null,"train_state=false",-1)),a[118]||(a[118]=s(") ")),t("mjx-container",t1,[(Q(),n("svg",a1,a[113]||(a[113]=[i('',1)]))),a[114]||(a[114]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"r")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"z")])]),t("mo",null,","),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"n")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[119]||(a[119]=s("."))])])]),a[123]||(a[123]=t("p",null,[t("strong",null,"States")],-1)),a[124]||(a[124]=t("ul",null,[t("li",null,[t("code",null,"rng"),s(": Controls the randomness (if any) in the initial state generation")])],-1)),a[125]||(a[125]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/src/layers/recurrent.jl#L488",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",s1,[t("summary",null,[a[126]||(a[126]=t("a",{id:"Lux.LSTMCell",href:"#Lux.LSTMCell"},[t("span",{class:"jlbinding"},"Lux.LSTMCell")],-1)),a[127]||(a[127]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[153]||(a[153]=i(`
    julia
    LSTMCell(in_dims => out_dims; use_bias::Bool=true, train_state::Bool=false,
    +         train_memory::Bool=false, init_weight=nothing, init_bias=nothing,
    +         init_state=zeros32, init_memory=zeros32)

    Long Short-Term (LSTM) Cell

    `,2)),t("mjx-container",i1,[(Q(),n("svg",e1,a[128]||(a[128]=[i('',1)]))),a[129]||(a[129]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("mtable",{displaystyle:"true",columnalign:"right left",columnspacing:"0em",rowspacing:"3pt"},[t("mtr",null,[t("mtd",null,[t("mi",null,"i")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"σ"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"i")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"i")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("mi",null,"f")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"σ"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"f")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"f")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"f")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("mi",null,"g")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"t"),t("mi",null,"a"),t("mi",null,"n"),t("mi",null,"h"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"g")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"g")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"g")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("mi",null,"o")]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"σ"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"o")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"o")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("msub",null,[t("mi",null,"b"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"o")])]),t("mo",{stretchy:"false"},")")])]),t("mtr",null,[t("mtd",null,[t("msub",null,[t("mi",null,"c"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"f"),t("mo",null,"⋅"),t("msub",null,[t("mi",null,"c"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("mi",null,"i"),t("mo",null,"⋅"),t("mi",null,"g")])]),t("mtr",null,[t("mtd",null,[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])]),t("mtd",null,[t("mi"),t("mo",null,"="),t("mi",null,"o"),t("mo",null,"⋅"),t("mi",null,"t"),t("mi",null,"a"),t("mi",null,"n"),t("mi",null,"h"),t("mo",{stretchy:"false"},"("),t("msub",null,[t("mi",null,"c"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])]),t("mo",{stretchy:"false"},")")])])])])],-1))]),a[154]||(a[154]=i("

    Arguments

    Inputs

    Returns

    ",5)),t("ul",null,[t("li",null,[a[141]||(a[141]=t("p",null,"Tuple Containing",-1)),t("ul",null,[t("li",null,[t("p",null,[a[132]||(a[132]=s("Output ")),t("mjx-container",l1,[(Q(),n("svg",n1,a[130]||(a[130]=[i('',1)]))),a[131]||(a[131]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))]),a[133]||(a[133]=s(" of shape ")),a[134]||(a[134]=t("code",null,"(out_dims, batch_size)",-1))])]),t("li",null,[t("p",null,[a[139]||(a[139]=s("Tuple containing new hidden state ")),t("mjx-container",Q1,[(Q(),n("svg",T1,a[135]||(a[135]=[i('',1)]))),a[136]||(a[136]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))]),a[140]||(a[140]=s(" and new memory ")),t("mjx-container",d1,[(Q(),n("svg",o1,a[137]||(a[137]=[i('',1)]))),a[138]||(a[138]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"c"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))])])])])]),a[142]||(a[142]=t("li",null,[t("p",null,"Updated model state")],-1))]),a[155]||(a[155]=t("p",null,[t("strong",null,"Parameters")],-1)),t("ul",null,[t("li",null,[t("p",null,[a[145]||(a[145]=t("code",null,"weight_ih",-1)),a[146]||(a[146]=s(": Concatenated Weights to map from input space ")),t("mjx-container",r1,[(Q(),n("svg",p1,a[143]||(a[143]=[i('',1)]))),a[144]||(a[144]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"i")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"f")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"g")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"o")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[147]||(a[147]=s("."))])]),t("li",null,[t("p",null,[a[150]||(a[150]=t("code",null,"weight_hh",-1)),a[151]||(a[151]=s(": Concatenated Weights to map from hidden space ")),t("mjx-container",h1,[(Q(),n("svg",m1,a[148]||(a[148]=[i('',1)]))),a[149]||(a[149]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mo",{fence:"false",stretchy:"false"},"{"),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"i")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"f")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"g")])]),t("mo",null,","),t("msub",null,[t("mi",null,"W"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"o")])]),t("mo",{fence:"false",stretchy:"false"},"}")])],-1))])])]),a[152]||(a[152]=i("
  • bias_ih: Bias vector for the input-hidden connection (not present if use_bias=false)

  • bias_hh: Concatenated Bias vector for the hidden-hidden connection (not present if use_bias=false)

  • hidden_state: Initial hidden state vector (not present if train_state=false)

  • memory: Initial memory vector (not present if train_memory=false)

  • ",4))]),a[156]||(a[156]=t("p",null,[t("strong",null,"States")],-1)),a[157]||(a[157]=t("ul",null,[t("li",null,[t("code",null,"rng"),s(": Controls the randomness (if any) in the initial state generation")])],-1)),a[158]||(a[158]=t("p",null,[t("a",{href:"https://github.com/LuxDL/Lux.jl/blob/2ffa2f745c551ad2880316402fff5c9ff367ea40/src/layers/recurrent.jl#L309",target:"_blank",rel:"noreferrer"},"source")],-1))]),t("details",g1,[t("summary",null,[a[159]||(a[159]=t("a",{id:"Lux.RNNCell",href:"#Lux.RNNCell"},[t("span",{class:"jlbinding"},"Lux.RNNCell")],-1)),a[160]||(a[160]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[173]||(a[173]=i(`
    julia
    RNNCell(in_dims => out_dims, activation=tanh; use_bias=True(), train_state=False(),
    +    init_bias=nothing, init_weight=nothing, init_state=zeros32)

    An Elman RNNCell cell with activation (typically set to tanh or relu).

    `,2)),t("p",null,[t("mjx-container",k1,[(Q(),n("svg",c1,a[161]||(a[161]=[i('',1)]))),a[162]||(a[162]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])]),t("mo",null,"="),t("mi",null,"a"),t("mi",null,"c"),t("mi",null,"t"),t("mi",null,"i"),t("mi",null,"v"),t("mi",null,"a"),t("mi",null,"t"),t("mi",null,"i"),t("mi",null,"o"),t("mi",null,"n"),t("mo",{stretchy:"false"},"("),t("mi",null,"w"),t("mi",null,"e"),t("mi",null,"i"),t("mi",null,"g"),t("mi",null,"h"),t("msub",null,[t("mi",null,"t"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"h")])]),t("mo",null,"×"),t("mi",null,"x"),t("mo",null,"+"),t("mi",null,"b"),t("mi",null,"i"),t("mi",null,"a"),t("msub",null,[t("mi",null,"s"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"i"),t("mi",null,"h")])]),t("mo",null,"+"),t("mi",null,"w"),t("mi",null,"e"),t("mi",null,"i"),t("mi",null,"g"),t("mi",null,"h"),t("msub",null,[t("mi",null,"t"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"h")])]),t("mo",null,"×"),t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"p"),t("mi",null,"r"),t("mi",null,"e"),t("mi",null,"v")])]),t("mo",null,"+"),t("mi",null,"b"),t("mi",null,"i"),t("mi",null,"a"),t("msub",null,[t("mi",null,"s"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"h"),t("mi",null,"h")])]),t("mo",{stretchy:"false"},")")])],-1))])]),a[174]||(a[174]=i("

    Arguments

    Inputs

    Returns

    ",5)),t("ul",null,[t("li",null,[a[171]||(a[171]=t("p",null,"Tuple containing",-1)),t("ul",null,[t("li",null,[t("p",null,[a[165]||(a[165]=s("Output ")),t("mjx-container",u1,[(Q(),n("svg",y1,a[163]||(a[163]=[i('',1)]))),a[164]||(a[164]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))]),a[166]||(a[166]=s(" of shape ")),a[167]||(a[167]=t("code",null,"(out_dims, batch_size)",-1))])]),t("li",null,[t("p",null,[a[170]||(a[170]=s("Tuple containing new hidden state ")),t("mjx-container",E1,[(Q(),n("svg",f1,a[168]||(a[168]=[i('',1)]))),a[169]||(a[169]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"h"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"n"),t("mi",null,"e"),t("mi",null,"w")])])])],-1))])])])])]),a[172]||(a[172]=t("li",null,[t("p",null,"Updated model state")],-1))]),a[175]||(a[175]=i('

    Parameters

    States

    source

    ',5))]),t("details",L1,[t("summary",null,[a[176]||(a[176]=t("a",{id:"Lux.Recurrence",href:"#Lux.Recurrence"},[t("span",{class:"jlbinding"},"Lux.Recurrence")],-1)),a[177]||(a[177]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[178]||(a[178]=i(`
    julia
    Recurrence(cell;
    +    ordering::AbstractTimeSeriesDataBatchOrdering=BatchLastIndex(),
    +    return_sequence::Bool=false)

    Wraps a recurrent cell (like RNNCell, LSTMCell, GRUCell) to automatically operate over a sequence of inputs.

    Relation to Flux.Recur

    This is completely distinct from Flux.Recur. It doesn't make the cell stateful, rather allows operating on an entire sequence of inputs at once. See StatefulRecurrentCell for functionality similar to Flux.Recur.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Tip

    Frameworks like Tensorflow have special implementation of StackedRNNCells to handle sequentially composed RNN Cells. In Lux, one can simple stack multiple Recurrence blocks in a Chain to achieve the same.

    Chain(
    +    Recurrence(RNNCell(inputsize => latentsize); return_sequence=true),
    +    Recurrence(RNNCell(latentsize => latentsize); return_sequence=true),
    +    :
    +    x -> stack(x; dims=2)
    +)

    For some discussion on this topic, see https://github.com/LuxDL/Lux.jl/issues/472.

    source

    `,14))]),t("details",x1,[t("summary",null,[a[179]||(a[179]=t("a",{id:"Lux.StatefulRecurrentCell",href:"#Lux.StatefulRecurrentCell"},[t("span",{class:"jlbinding"},"Lux.StatefulRecurrentCell")],-1)),a[180]||(a[180]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[181]||(a[181]=i('
    julia
    StatefulRecurrentCell(cell)

    Wraps a recurrent cell (like RNNCell, LSTMCell, GRUCell) and makes it stateful.

    To avoid undefined behavior, once the processing of a single sequence of data is complete, update the state with Lux.update_state(st, :carry, nothing).

    Arguments

    Inputs

    Returns

    States

    source

    ',12))]),t("details",w1,[t("summary",null,[a[182]||(a[182]=t("a",{id:"Lux.BidirectionalRNN",href:"#Lux.BidirectionalRNN"},[t("span",{class:"jlbinding"},"Lux.BidirectionalRNN")],-1)),a[183]||(a[183]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[184]||(a[184]=i(`
    julia
    BidirectionalRNN(cell::AbstractRecurrentCell,
    +    backward_cell::Union{AbstractRecurrentCell, Nothing}=nothing;
    +    merge_mode::Union{Function, Nothing}=vcat,
    +    ordering::AbstractTimeSeriesDataBatchOrdering=BatchLastIndex())

    Bidirectional RNN wrapper.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    source

    `,16))]),a[275]||(a[275]=t("h2",{id:"Linear-Layers",tabindex:"-1"},[s("Linear Layers "),t("a",{class:"header-anchor",href:"#Linear-Layers","aria-label":'Permalink to "Linear Layers {#Linear-Layers}"'},"​")],-1)),t("details",b1,[t("summary",null,[a[185]||(a[185]=t("a",{id:"Lux.Bilinear",href:"#Lux.Bilinear"},[t("span",{class:"jlbinding"},"Lux.Bilinear")],-1)),a[186]||(a[186]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[187]||(a[187]=i(`
    julia
    Bilinear((in1_dims, in2_dims) => out, activation=identity; init_weight=nothing,
    +         init_bias=nothing, use_bias=True())
    +Bilinear(in12_dims => out, activation=identity; init_weight=nothing,
    +         init_bias=nothing, use_bias=True())

    Create a fully connected layer between two inputs and an output, and otherwise similar to Dense. Its output, given vectors x & y, is another vector z with, for all i in 1:out:

    z[i] = activation(x' * W[i, :, :] * y + bias[i])

    If x and y are matrices, then each column of the output z = B(x, y) is of this form, with B the Bilinear layer.

    Arguments

    Keyword Arguments

    Input

    Returns

    Parameters

    source

    `,15))]),t("details",H1,[t("summary",null,[a[188]||(a[188]=t("a",{id:"Lux.Dense",href:"#Lux.Dense"},[t("span",{class:"jlbinding"},"Lux.Dense")],-1)),a[189]||(a[189]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[190]||(a[190]=i(`
    julia
    Dense(in_dims => out_dims, activation=identity; init_weight=nothing,
    +      init_bias=nothing, use_bias=True())

    Create a traditional fully connected layer, whose forward pass is given by: y = activation.(weight * x .+ bias)

    Arguments

    Keyword Arguments

    Input

    Returns

    Parameters

    source

    `,13))]),t("details",C1,[t("summary",null,[a[191]||(a[191]=t("a",{id:"Lux.Embedding",href:"#Lux.Embedding"},[t("span",{class:"jlbinding"},"Lux.Embedding")],-1)),a[192]||(a[192]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[193]||(a[193]=i('
    julia
    Embedding(in_dims => out_dims; init_weight=rand32)

    A lookup table that stores embeddings of dimension out_dims for a vocabulary of size in_dims. When the vocabulary is multi-dimensional, the input is expected to be a tuple of Cartesian indices.

    This layer is often used to store word embeddings and retrieve them using indices.

    Arguments

    Keyword Arguments

    Input

    Returns

    source

    ',12))]),t("details",F1,[t("summary",null,[a[194]||(a[194]=t("a",{id:"Lux.Scale",href:"#Lux.Scale"},[t("span",{class:"jlbinding"},"Lux.Scale")],-1)),a[195]||(a[195]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[196]||(a[196]=i('
    julia
    Scale(dims, activation=identity; init_weight=ones32, init_bias=zeros32, use_bias=True())

    Create a Sparsely Connected Layer with a very specific structure (only Diagonal Elements are non-zero). The forward pass is given by: y = activation.(weight .* x .+ bias)

    Arguments

    Keyword Arguments

    Input

    Returns

    Parameters

    source

    ',13))]),a[276]||(a[276]=t("h2",{id:"Misc.-Helper-Layers",tabindex:"-1"},[s("Misc. Helper Layers "),t("a",{class:"header-anchor",href:"#Misc.-Helper-Layers","aria-label":'Permalink to "Misc. Helper Layers {#Misc.-Helper-Layers}"'},"​")],-1)),t("details",D1,[t("summary",null,[a[197]||(a[197]=t("a",{id:"Lux.FlattenLayer",href:"#Lux.FlattenLayer"},[t("span",{class:"jlbinding"},"Lux.FlattenLayer")],-1)),a[198]||(a[198]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[199]||(a[199]=i(`
    julia
    FlattenLayer(; N = nothing)

    Flattens the passed array into a matrix.

    Keyword Arguments

    Inputs

    Returns

    Example

    julia
    julia> model = FlattenLayer()
    +FlattenLayer{Nothing}(nothing)
    +
    +julia> rng = Random.default_rng();
    +       Random.seed!(rng, 0);
    +       ps, st = Lux.setup(rng, model);
    +       x = randn(rng, Float32, (2, 2, 2, 2));
    +
    +julia> y, st_new = model(x, ps, st);
    +       size(y)
    +(8, 2)

    source

    `,11))]),t("details",M1,[t("summary",null,[a[200]||(a[200]=t("a",{id:"Lux.Maxout",href:"#Lux.Maxout"},[t("span",{class:"jlbinding"},"Lux.Maxout")],-1)),a[201]||(a[201]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[202]||(a[202]=i(`
    julia
    Maxout(layers...)
    +Maxout(; layers...)
    +Maxout(f::Function, n_alts::Int)

    This contains a number of internal layers, each of which receives the same input. Its output is the elementwise maximum of the the internal layers' outputs.

    Maxout over linear dense layers satisfies the universal approximation theorem. See [1].

    See also Parallel to reduce with other operators.

    Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    References

    [1] Goodfellow, Warde-Farley, Mirza, Courville & Bengio "Maxout Networks" https://arxiv.org/abs/1302.4389

    source

    `,18))]),t("details",v1,[t("summary",null,[a[203]||(a[203]=t("a",{id:"Lux.NoOpLayer",href:"#Lux.NoOpLayer"},[t("span",{class:"jlbinding"},"Lux.NoOpLayer")],-1)),a[204]||(a[204]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[205]||(a[205]=i(`
    julia
    NoOpLayer()

    As the name suggests does nothing but allows pretty printing of layers. Whatever input is passed is returned.

    Example

    julia
    julia> model = NoOpLayer()
    +NoOpLayer()
    +
    +julia> rng = Random.default_rng();
    +       Random.seed!(rng, 0);
    +       ps, st = Lux.setup(rng, model);
    +       x = 1
    +1
    +
    +julia> y, st_new = model(x, ps, st)
    +(1, NamedTuple())

    source

    `,5))]),t("details",Z1,[t("summary",null,[a[206]||(a[206]=t("a",{id:"Lux.ReshapeLayer",href:"#Lux.ReshapeLayer"},[t("span",{class:"jlbinding"},"Lux.ReshapeLayer")],-1)),a[207]||(a[207]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[208]||(a[208]=i(`
    julia
    ReshapeLayer(dims)

    Reshapes the passed array to have a size of (dims..., :)

    Arguments

    Inputs

    Returns

    Example

    julia
    julia> model = ReshapeLayer((2, 2))
    +ReshapeLayer(output_dims = (2, 2, :))
    +
    +julia> rng = Random.default_rng();
    +       Random.seed!(rng, 0);
    +       ps, st = Lux.setup(rng, model);
    +       x = randn(rng, Float32, (4, 1, 3));
    +
    +julia> y, st_new = model(x, ps, st);
    +       size(y)
    +(2, 2, 3)

    source

    `,11))]),t("details",j1,[t("summary",null,[a[209]||(a[209]=t("a",{id:"Lux.SelectDim",href:"#Lux.SelectDim"},[t("span",{class:"jlbinding"},"Lux.SelectDim")],-1)),a[210]||(a[210]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[211]||(a[211]=i('
    julia
    SelectDim(dim, i)

    Return a view of all the data of the input x where the index for dimension dim equals i. Equivalent to view(x,:,:,...,i,:,:,...) where i is in position d.

    Arguments

    Inputs

    Returns

    source

    ',9))]),t("details",A1,[t("summary",null,[a[212]||(a[212]=t("a",{id:"Lux.WrappedFunction",href:"#Lux.WrappedFunction"},[t("span",{class:"jlbinding"},"Lux.WrappedFunction")],-1)),a[213]||(a[213]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[214]||(a[214]=i('
    julia
    WrappedFunction(f)

    Wraps a stateless and parameter less function. Might be used when a function is added to Chain. For example, Chain(x -> relu.(x)) would not work and the right thing to do would be Chain((x, ps, st) -> (relu.(x), st)). An easier thing to do would be Chain(WrappedFunction(Base.Fix1(broadcast, relu)))

    Arguments

    Inputs

    Returns

    source

    ',9))]),t("details",B1,[t("summary",null,[a[215]||(a[215]=t("a",{id:"Lux.ReverseSequence",href:"#Lux.ReverseSequence"},[t("span",{class:"jlbinding"},"Lux.ReverseSequence")],-1)),a[216]||(a[216]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[217]||(a[217]=i(`
    julia
    ReverseSequence(dim = nothing)

    Reverse the specified dimension dims of the passed array

    Arguments

    Inputs

    Returns

    Example

    julia
    julia> model = ReverseSequence()
    +ReverseSequence{Nothing}(nothing)
    +
    +julia> rng = Random.default_rng();
    +       Random.seed!(rng, 0);
    +       ps, st = Lux.setup(rng, model);
    +       x = [1.0, 2.0, 3.0];
    +
    +julia> y, st_new = model(x, ps, st)
    +([3.0, 2.0, 1.0], NamedTuple())

    source

    `,11))]),a[277]||(a[277]=t("h2",{id:"Normalization-Layers",tabindex:"-1"},[s("Normalization Layers "),t("a",{class:"header-anchor",href:"#Normalization-Layers","aria-label":'Permalink to "Normalization Layers {#Normalization-Layers}"'},"​")],-1)),t("details",V1,[t("summary",null,[a[218]||(a[218]=t("a",{id:"Lux.BatchNorm",href:"#Lux.BatchNorm"},[t("span",{class:"jlbinding"},"Lux.BatchNorm")],-1)),a[219]||(a[219]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[225]||(a[225]=i(`
    julia
    BatchNorm(chs::Integer, activation=identity; init_bias=zeros32, init_scale=ones32,
    +          affine=True(), track_stats=True(), epsilon=1f-5, momentum=0.1f0)

    Batch Normalization layer.

    `,2)),t("p",null,[a[222]||(a[222]=t("code",null,"BatchNorm",-1)),a[223]||(a[223]=s(" computes the mean and variance for each ")),t("mjx-container",R1,[(Q(),n("svg",N1,a[220]||(a[220]=[i('',1)]))),a[221]||(a[221]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"D"),t("mn",null,"1")]),t("mi",null,"×"),t("mo",null,"."),t("mo",null,"."),t("mo",null,"."),t("mi",null,"×"),t("msub",null,[t("mi",null,"D"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"N"),t("mo",null,"−"),t("mn",null,"2")])]),t("mi",null,"×"),t("mn",null,"1"),t("mi",null,"×"),t("msub",null,[t("mi",null,"D"),t("mi",null,"N")])])],-1))]),a[224]||(a[224]=s(" input slice and normalises the input accordingly."))]),a[226]||(a[226]=i(`

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    Use Lux.testmode during inference.

    Example

    julia
    julia> Chain(Dense(784 => 64), BatchNorm(64, relu), Dense(64 => 10), BatchNorm(10))
    +Chain(
    +    layer_1 = Dense(784 => 64),         # 50_240 parameters
    +    layer_2 = BatchNorm(64, relu, affine=true, track_stats=true),  # 128 parameters, plus 129
    +    layer_3 = Dense(64 => 10),          # 650 parameters
    +    layer_4 = BatchNorm(10, affine=true, track_stats=true),  # 20 parameters, plus 21
    +)         # Total: 51_038 parameters,
    +          #        plus 150 states.

    Warning

    Passing a batch size of 1, during training will result in an error.

    See also BatchNorm, InstanceNorm, LayerNorm, WeightNorm

    source

    `,19))]),t("details",O1,[t("summary",null,[a[227]||(a[227]=t("a",{id:"Lux.GroupNorm",href:"#Lux.GroupNorm"},[t("span",{class:"jlbinding"},"Lux.GroupNorm")],-1)),a[228]||(a[228]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[229]||(a[229]=i(`
    julia
    GroupNorm(chs::Integer, groups::Integer, activation=identity; init_bias=zeros32,
    +          init_scale=ones32, affine=true, epsilon=1f-5)

    Group Normalization layer.

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    Use Lux.testmode during inference.

    Example

    julia
    julia> Chain(Dense(784 => 64), GroupNorm(64, 4, relu), Dense(64 => 10), GroupNorm(10, 5))
    +Chain(
    +    layer_1 = Dense(784 => 64),         # 50_240 parameters
    +    layer_2 = GroupNorm(64, 4, relu, affine=true),  # 128 parameters
    +    layer_3 = Dense(64 => 10),          # 650 parameters
    +    layer_4 = GroupNorm(10, 5, affine=true),  # 20 parameters
    +)         # Total: 51_038 parameters,
    +          #        plus 0 states.

    See also GroupNorm, InstanceNorm, LayerNorm, WeightNorm

    source

    `,20))]),t("details",z1,[t("summary",null,[a[230]||(a[230]=t("a",{id:"Lux.InstanceNorm",href:"#Lux.InstanceNorm"},[t("span",{class:"jlbinding"},"Lux.InstanceNorm")],-1)),a[231]||(a[231]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[236]||(a[236]=i(`
    julia
    InstanceNorm(chs::Integer, activation=identity; init_bias=zeros32, init_scale=ones32,
    +             affine=False(), track_stats=False(), epsilon=1f-5, momentum=0.1f0)

    Instance Normalization. For details see [1].

    `,2)),t("p",null,[a[234]||(a[234]=s("Instance Normalization computes the mean and variance for each ")),t("mjx-container",P1,[(Q(),n("svg",I1,a[232]||(a[232]=[i('',1)]))),a[233]||(a[233]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("msub",null,[t("mi",null,"D"),t("mn",null,"1")]),t("mo",null,"×"),t("mo",null,"."),t("mo",null,"."),t("mo",null,"."),t("mo",null,"×"),t("msub",null,[t("mi",null,"D"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",null,"N"),t("mo",null,"−"),t("mn",null,"2")])]),t("mo",null,"×"),t("mn",null,"1"),t("mo",null,"×"),t("mn",null,"1")])],-1))]),a[235]||(a[235]=s("` input slice and normalises the input accordingly."))]),a[237]||(a[237]=i(`

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    States

    Use Lux.testmode during inference.

    Example

    julia
    julia> Chain(Dense(784 => 64), InstanceNorm(64, relu; affine=true), Dense(64 => 10),
    +           InstanceNorm(10, relu; affine=true))
    +Chain(
    +    layer_1 = Dense(784 => 64),         # 50_240 parameters
    +    layer_2 = InstanceNorm(64, relu, affine=true, track_stats=false),  # 128 parameters, plus 1
    +    layer_3 = Dense(64 => 10),          # 650 parameters
    +    layer_4 = InstanceNorm(10, relu, affine=true, track_stats=false),  # 20 parameters, plus 1
    +)         # Total: 51_038 parameters,
    +          #        plus 2 states.

    References

    [1] Ulyanov, Dmitry, Andrea Vedaldi, and Victor Lempitsky. "Instance normalization: The missing ingredient for fast stylization." arXiv preprint arXiv:1607.08022 (2016).

    See also BatchNorm, GroupNorm, LayerNorm, WeightNorm

    source

    `,20))]),t("details",S1,[t("summary",null,[a[238]||(a[238]=t("a",{id:"Lux.LayerNorm",href:"#Lux.LayerNorm"},[t("span",{class:"jlbinding"},"Lux.LayerNorm")],-1)),a[239]||(a[239]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[255]||(a[255]=i(`
    julia
    LayerNorm(shape::NTuple{N, Int}, activation=identity; epsilon=1f-5, dims=Colon(),
    +          affine=true, init_bias=zeros32, init_scale=ones32)

    Computes mean and standard deviation over the whole input array, and uses these to normalize the whole array. Optionally applies an elementwise affine transformation afterwards.

    `,2)),t("p",null,[a[242]||(a[242]=s("Given an input array ")),t("mjx-container",_1,[(Q(),n("svg",G1,a[240]||(a[240]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D465",d:"M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z",style:{"stroke-width":"3"}})])])],-1)]))),a[241]||(a[241]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"x")])],-1))]),a[243]||(a[243]=s(", this layer computes"))]),t("mjx-container",W1,[(Q(),n("svg",X1,a[244]||(a[244]=[i('',1)]))),a[245]||(a[245]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("mi",null,"y"),t("mo",null,"="),t("mfrac",null,[t("mrow",null,[t("mi",null,"x"),t("mo",null,"−"),t("mrow",{"data-mjx-texclass":"ORD"},[t("mi",{mathvariant:"double-struck"},"E")]),t("mo",{stretchy:"false"},"["),t("mi",null,"x"),t("mo",{stretchy:"false"},"]")]),t("msqrt",null,[t("mi",null,"V"),t("mi",null,"a"),t("mi",null,"r"),t("mo",{stretchy:"false"},"["),t("mi",null,"x"),t("mo",{stretchy:"false"},"]"),t("mo",null,"+"),t("mi",null,"ϵ")])]),t("mo",null,"∗"),t("mi",null,"γ"),t("mo",null,"+"),t("mi",null,"β")])],-1))]),t("p",null,[a[250]||(a[250]=s("where ")),t("mjx-container",U1,[(Q(),n("svg",q1,a[246]||(a[246]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),a[247]||(a[247]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"γ")])],-1))]),a[251]||(a[251]=s(" & ")),t("mjx-container",J1,[(Q(),n("svg",K1,a[248]||(a[248]=[t("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[t("g",{"data-mml-node":"math"},[t("g",{"data-mml-node":"mi"},[t("path",{"data-c":"1D6FD",d:"M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z",style:{"stroke-width":"3"}})])])],-1)]))),a[249]||(a[249]=t("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[t("mi",null,"β")])],-1))]),a[252]||(a[252]=s(" are trainable parameters if ")),a[253]||(a[253]=t("code",null,"affine=true",-1)),a[254]||(a[254]=s("."))]),a[256]||(a[256]=i('

    Arguments

    Keyword Arguments

    Extended Help

    Inputs

    Returns

    Parameters

    source

    ',12))]),t("details",$1,[t("summary",null,[a[257]||(a[257]=t("a",{id:"Lux.WeightNorm",href:"#Lux.WeightNorm"},[t("span",{class:"jlbinding"},"Lux.WeightNorm")],-1)),a[258]||(a[258]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[261]||(a[261]=i(`
    julia
    WeightNorm(layer::AbstractLuxLayer, which_params::NTuple{N, Symbol},
    +           dims::Union{Tuple, Nothing}=nothing)

    Applies weight normalization to a parameter in the given layer.

    `,2)),t("mjx-container",Y1,[(Q(),n("svg",t2,a[259]||(a[259]=[i('',1)]))),a[260]||(a[260]=t("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[t("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[t("mi",null,"w"),t("mo",null,"="),t("mi",null,"g"),t("mfrac",null,[t("mi",null,"v"),t("mrow",null,[t("mo",{"data-mjx-texclass":"ORD"},"∥"),t("mi",null,"v"),t("mo",{"data-mjx-texclass":"ORD"},"∥")])])])],-1))]),a[262]||(a[262]=i('

    Weight normalization is a reparameterization that decouples the magnitude of a weight tensor from its direction. This updates the parameters in which_params (e.g. weight) using two parameters: one specifying the magnitude (e.g. weight_g) and one specifying the direction (e.g. weight_v).

    Arguments

    Inputs

    Returns

    Parameters

    States

    source

    ',12))]),a[278]||(a[278]=t("h2",{id:"upsampling",tabindex:"-1"},[s("Upsampling "),t("a",{class:"header-anchor",href:"#upsampling","aria-label":'Permalink to "Upsampling"'},"​")],-1)),t("details",a2,[t("summary",null,[a[263]||(a[263]=t("a",{id:"Lux.PixelShuffle",href:"#Lux.PixelShuffle"},[t("span",{class:"jlbinding"},"Lux.PixelShuffle")],-1)),a[264]||(a[264]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[265]||(a[265]=i('
    julia
    PixelShuffle(r::Int)

    Pixel shuffling layer with upscale factor r. Usually used for generating higher resolution images while upscaling them.

    See NNlib.pixel_shuffle for more details.

    Arguments

    Inputs

    Returns

    source

    ',10))]),t("details",s2,[t("summary",null,[a[266]||(a[266]=t("a",{id:"Lux.Upsample",href:"#Lux.Upsample"},[t("span",{class:"jlbinding"},"Lux.Upsample")],-1)),a[267]||(a[267]=s()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),a[268]||(a[268]=i(`
    julia
    Upsample(mode = :nearest; [scale, size, align_corners=false])
    +Upsample(scale, mode = :nearest)

    Upsampling Layer.

    Layer Construction

    Option 1

    Exactly one of two keywords must be specified:

    Option 2

    Currently supported upsampling modes and corresponding NNlib's methods are:

    Extended Help

    Other Keyword Arguments

    Inputs

    Returns

    source

    `,19))])])}const r2=T(o,[["render",i2]]);export{o2 as __pageData,r2 as default}; diff --git a/previews/PR1023/assets/api_Lux_utilities.md.tnFESE9C.js b/previews/PR1023/assets/api_Lux_utilities.md.tnFESE9C.js new file mode 100644 index 0000000000..0246cab848 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_utilities.md.tnFESE9C.js @@ -0,0 +1,314 @@ +import{_ as p,c as n,j as s,a,G as l,a2 as t,B as r,o as h}from"./chunks/framework.DFwXuivk.js";const C2=JSON.parse('{"title":"Utilities","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/utilities.md","filePath":"api/Lux/utilities.md","lastUpdated":null}'),d={name:"api/Lux/utilities.md"},k={class:"jldocstring custom-block"},o={class:"jldocstring custom-block"},T={class:"jldocstring custom-block"},Q={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},c={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},u={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"46.681ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 20633.1 1199","aria-hidden":"true"},F={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},x={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"25.631ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 11329 1199","aria-hidden":"true"},f={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},C={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.161ex",role:"img",focusable:"false",viewBox:"0 -750 490 955","aria-hidden":"true"},L={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},b={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"6.664ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 2945.4 1000","aria-hidden":"true"},w={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},H={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.161ex",role:"img",focusable:"false",viewBox:"0 -750 490 955","aria-hidden":"true"},v={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},j={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"23.718ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 10483.3 1000","aria-hidden":"true"},D={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},B={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.448ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 640 453","aria-hidden":"true"},M={class:"jldocstring custom-block"},V={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},A={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.296ex",role:"img",focusable:"false",viewBox:"0 -810 490 1015","aria-hidden":"true"},Z={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},O={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"5.377ex",height:"1.995ex",role:"img",focusable:"false",viewBox:"0 -666 2376.6 882","aria-hidden":"true"},R={class:"jldocstring custom-block"},S={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},N={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.296ex",role:"img",focusable:"false",viewBox:"0 -810 490 1015","aria-hidden":"true"},P={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},z={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-1.469ex"},xmlns:"http://www.w3.org/2000/svg",width:"23.184ex",height:"4.07ex",role:"img",focusable:"false",viewBox:"0 -1149.5 10247.1 1799","aria-hidden":"true"},I={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},q={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"0.919ex",height:"1ex",role:"img",focusable:"false",viewBox:"0 -431 406 442","aria-hidden":"true"},G={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},X={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.161ex",role:"img",focusable:"false",viewBox:"0 -750 490 955","aria-hidden":"true"},J={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},U={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"6.664ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 2945.4 1000","aria-hidden":"true"},W={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},K={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.161ex",role:"img",focusable:"false",viewBox:"0 -750 490 955","aria-hidden":"true"},Y={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},$={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"34.539ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 15266.3 1000","aria-hidden":"true"},_={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},s1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.448ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 640 453","aria-hidden":"true"},i1={class:"jldocstring custom-block"},a1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},t1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.308ex"},xmlns:"http://www.w3.org/2000/svg",width:"28.659ex",height:"5.747ex",role:"img",focusable:"false",viewBox:"0 -1520 12667.4 2540","aria-hidden":"true"},e1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},l1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.448ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 640 453","aria-hidden":"true"},n1={class:"jldocstring custom-block"},h1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},p1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.296ex",role:"img",focusable:"false",viewBox:"0 -810 490 1015","aria-hidden":"true"},r1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},d1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},k1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},o1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"5.377ex",height:"1.995ex",role:"img",focusable:"false",viewBox:"0 -666 2376.6 882","aria-hidden":"true"},T1={class:"jldocstring custom-block"},Q1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},g1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"20.065ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 8868.8 1199","aria-hidden":"true"},m1={class:"jldocstring custom-block"},y1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},E1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.148ex"},xmlns:"http://www.w3.org/2000/svg",width:"40.607ex",height:"5.428ex",role:"img",focusable:"false",viewBox:"0 -1449.5 17948.3 2399","aria-hidden":"true"},c1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},u1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.023ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.005ex",height:"1.645ex",role:"img",focusable:"false",viewBox:"0 -717 444 727","aria-hidden":"true"},F1={class:"jldocstring custom-block"},x1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},f1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.296ex",role:"img",focusable:"false",viewBox:"0 -810 490 1015","aria-hidden":"true"},C1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},L1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"1.464ex",role:"img",focusable:"false",viewBox:"0 -442 490 647","aria-hidden":"true"},b1={class:"jldocstring custom-block"},w1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},H1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"12.333ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 5451.1 1199","aria-hidden":"true"},v1={class:"jldocstring custom-block"},j1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},D1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-1.469ex"},xmlns:"http://www.w3.org/2000/svg",width:"14.515ex",height:"4.07ex",role:"img",focusable:"false",viewBox:"0 -1149.5 6415.7 1799","aria-hidden":"true"},B1={class:"jldocstring custom-block"},M1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},V1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-1.469ex"},xmlns:"http://www.w3.org/2000/svg",width:"32.253ex",height:"4.07ex",role:"img",focusable:"false",viewBox:"0 -1149.5 14255.9 1799","aria-hidden":"true"},A1={class:"jldocstring custom-block"},Z1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},O1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.296ex",role:"img",focusable:"false",viewBox:"0 -810 490 1015","aria-hidden":"true"},R1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},S1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"1.464ex",role:"img",focusable:"false",viewBox:"0 -442 490 647","aria-hidden":"true"},N1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},P1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"18.723ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 8275.6 1199","aria-hidden":"true"},z1={class:"jldocstring custom-block"},I1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},q1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"40.607ex",height:"2.791ex",role:"img",focusable:"false",viewBox:"0 -883.9 17948.2 1233.4","aria-hidden":"true"},G1={class:"jldocstring custom-block"},X1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},J1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"21.053ex",height:"2.791ex",role:"img",focusable:"false",viewBox:"0 -883.9 9305.3 1233.4","aria-hidden":"true"},U1={class:"jldocstring custom-block"},W1={class:"jldocstring custom-block"},K1={class:"jldocstring custom-block"},Y1={class:"jldocstring custom-block"},$1={class:"jldocstring custom-block"},_1={class:"jldocstring custom-block"},s2={class:"jldocstring custom-block"},i2={class:"jldocstring custom-block"},a2={class:"jldocstring custom-block"},t2={class:"jldocstring custom-block"},e2={class:"jldocstring custom-block"},l2={class:"jldocstring custom-block"},n2={class:"jldocstring custom-block"},h2={class:"jldocstring custom-block"},p2={class:"jldocstring custom-block"},r2={class:"jldocstring custom-block"},d2={class:"jldocstring custom-block"},k2={class:"jldocstring custom-block"},o2={class:"jldocstring custom-block"},T2={class:"jldocstring custom-block"},Q2={class:"jldocstring custom-block"},g2={class:"jldocstring custom-block"},m2={class:"jldocstring custom-block"};function y2(E2,i,c2,u2,F2,x2){const e=r("Badge");return h(),n("div",null,[i[286]||(i[286]=s("h1",{id:"utilities",tabindex:"-1"},[a("Utilities "),s("a",{class:"header-anchor",href:"#utilities","aria-label":'Permalink to "Utilities"'},"​")],-1)),i[287]||(i[287]=s("h2",{id:"Training-API",tabindex:"-1"},[a("Training API "),s("a",{class:"header-anchor",href:"#Training-API","aria-label":'Permalink to "Training API {#Training-API}"'},"​")],-1)),i[288]||(i[288]=s("p",null,[a("Helper Functions making it easier to train "),s("code",null,"Lux.jl"),a(" models.")],-1)),i[289]||(i[289]=s("p",null,"Training is meant to be simple and provide extremely basic functionality. We provide basic building blocks which can be seamlessly composed to create complex training pipelines.",-1)),s("details",k,[s("summary",null,[i[0]||(i[0]=s("a",{id:"Lux.Training.TrainState",href:"#Lux.Training.TrainState"},[s("span",{class:"jlbinding"},"Lux.Training.TrainState")],-1)),i[1]||(i[1]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[2]||(i[2]=t('
    julia
    TrainState

    Training State containing:

    Internal fields:

    Warning

    Constructing this object directly shouldn't be considered a stable API. Use the version with the Optimisers API.

    source

    ',7))]),s("details",o,[s("summary",null,[i[3]||(i[3]=s("a",{id:"Lux.Training.compute_gradients",href:"#Lux.Training.compute_gradients"},[s("span",{class:"jlbinding"},"Lux.Training.compute_gradients")],-1)),i[4]||(i[4]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[5]||(i[5]=t(`
    julia
    compute_gradients(ad::AbstractADType, objective_function::Function, data,
    +    ts::TrainState)

    Compute the gradients of the objective function wrt parameters stored in ts.

    Backends & AD Packages

    Supported BackendsPackages Needed
    AutoZygoteZygote.jl
    AutoReverseDiff(; compile)ReverseDiff.jl
    AutoTrackerTracker.jl
    AutoEnzymeEnzyme.jl

    Arguments

    Return

    A 4-Tuple containing:

    Known Limitations

    Aliased Gradients

    grads returned by this function might be aliased by the implementation of the gradient backend. For example, if you cache the grads from step i, the new gradients returned in step i + 1 might be aliased by the old gradients. If you want to prevent this, simply use copy(grads) or deepcopy(grads) to make a copy of the gradients.

    source

    `,13))]),s("details",T,[s("summary",null,[i[6]||(i[6]=s("a",{id:"Lux.Training.apply_gradients",href:"#Lux.Training.apply_gradients"},[s("span",{class:"jlbinding"},"Lux.Training.apply_gradients")],-1)),i[7]||(i[7]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[8]||(i[8]=t('
    julia
    apply_gradients(ts::TrainState, grads)

    Update the parameters stored in ts using the gradients grads.

    Arguments

    Returns

    Updated TrainState object.

    source

    ',7))]),s("details",Q,[s("summary",null,[i[9]||(i[9]=s("a",{id:"Lux.Training.apply_gradients!",href:"#Lux.Training.apply_gradients!"},[s("span",{class:"jlbinding"},"Lux.Training.apply_gradients!")],-1)),i[10]||(i[10]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[11]||(i[11]=t('
    julia
    apply_gradients!(ts::TrainState, grads)

    Update the parameters stored in ts using the gradients grads. This is an inplace version of apply_gradients.

    Arguments

    Returns

    Updated TrainState object.

    source

    ',7))]),s("details",g,[s("summary",null,[i[12]||(i[12]=s("a",{id:"Lux.Training.single_train_step",href:"#Lux.Training.single_train_step"},[s("span",{class:"jlbinding"},"Lux.Training.single_train_step")],-1)),i[13]||(i[13]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[14]||(i[14]=t('
    julia
    single_train_step(backend, obj_fn::F, data, ts::TrainState)

    Perform a single training step. Computes the gradients using compute_gradients and updates the parameters using apply_gradients. All backends supported via compute_gradients are supported here.

    In most cases you should use single_train_step! instead of this function.

    Return

    Returned values are the same as compute_gradients.

    source

    ',6))]),s("details",m,[s("summary",null,[i[15]||(i[15]=s("a",{id:"Lux.Training.single_train_step!",href:"#Lux.Training.single_train_step!"},[s("span",{class:"jlbinding"},"Lux.Training.single_train_step!")],-1)),i[16]||(i[16]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[17]||(i[17]=t('
    julia
    single_train_step!(backend, obj_fn::F, data, ts::TrainState)

    Perform a single training step. Computes the gradients using compute_gradients and updates the parameters using apply_gradients!. All backends supported via compute_gradients are supported here.

    Return

    Returned values are the same as compute_gradients. Note that despite the !, only the parameters in ts are updated inplace. Users should be using the returned ts object for further training steps, else there is no caching and performance will be suboptimal (and absolutely terrible for backends like AutoReactant).

    source

    ',5))]),i[290]||(i[290]=t('

    Loss Functions

    Loss Functions Objects take 2 forms of inputs:

    1. and y where is the predicted output and y is the target output.

    2. model, ps, st, (x, y) where model is the model, ps are the parameters, st are the states and (x, y) are the input and target pair. Then it returns the loss, updated states, and an empty named tuple. This makes them compatible with the Training API.

    Warning

    When using ChainRules.jl compatible AD (like Zygote), we only compute the gradients wrt the inputs and drop any gradients wrt the targets.

    ',4)),s("details",y,[s("summary",null,[i[18]||(i[18]=s("a",{id:"Lux.GenericLossFunction",href:"#Lux.GenericLossFunction"},[s("span",{class:"jlbinding"},"Lux.GenericLossFunction")],-1)),i[19]||(i[19]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[20]||(i[20]=t(`
    julia
    GenericLossFunction(loss_fn; agg = mean)

    Takes any function loss_fn that maps 2 number inputs to a single number output. Additionally, array inputs are efficiently broadcasted and aggregated using agg.

    julia
    julia> mseloss = GenericLossFunction((ŷ, y) -> abs2(ŷ - y));
    +
    +julia> y_model = [1.1, 1.9, 3.1];
    +
    +julia> mseloss(y_model, 1:3)  0.01
    +true

    Special Note

    This function takes any of the LossFunctions.jl public functions into the Lux Losses API with efficient aggregation.

    source

    `,6))]),s("details",E,[s("summary",null,[i[21]||(i[21]=s("a",{id:"Lux.BinaryCrossEntropyLoss",href:"#Lux.BinaryCrossEntropyLoss"},[s("span",{class:"jlbinding"},"Lux.BinaryCrossEntropyLoss")],-1)),i[22]||(i[22]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[51]||(i[51]=t(`
    julia
    BinaryCrossEntropyLoss(; agg = mean, epsilon = nothing,
    +    label_smoothing::Union{Nothing, Real}=nothing,
    +    logits::Union{Bool, Val}=Val(false))

    Binary Cross Entropy Loss with optional label smoothing and fused logit computation.

    Returns the binary cross entropy loss computed as:

    `,4)),s("mjx-container",c,[(h(),n("svg",u,i[23]||(i[23]=[t('',1)]))),i[24]||(i[24]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mo",null,"∗"),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"+"),s("mi",null,"ϵ"),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mo",null,"−"),s("mo",{stretchy:"false"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mo",{stretchy:"false"},")"),s("mo",null,"∗"),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"+"),s("mi",null,"ϵ"),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[52]||(i[52]=s("ul",null,[s("li",null,[a("If "),s("code",null,"logits"),a(" is "),s("code",null,"true"),a(" or "),s("code",null,"Val(true)"),a(":")])],-1)),s("mjx-container",F,[(h(),n("svg",x,i[25]||(i[25]=[t('',1)]))),i[26]||(i[26]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",{stretchy:"false"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mo",{stretchy:"false"},")"),s("mo",null,"∗"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"−"),s("mi",null,"l"),s("mi",null,"o"),s("mi",null,"g"),s("mi",null,"σ"),s("mo",{stretchy:"false"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",{stretchy:"false"},")"),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),s("p",null,[i[33]||(i[33]=a("The value of ")),s("mjx-container",f,[(h(),n("svg",C,i[27]||(i[27]=[t('',1)]))),i[28]||(i[28]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])])])],-1))]),i[34]||(i[34]=a(" is computed using label smoothing. If ")),i[35]||(i[35]=s("code",null,"label_smoothing",-1)),i[36]||(i[36]=a(" is ")),i[37]||(i[37]=s("code",null,"nothing",-1)),i[38]||(i[38]=a(", then no label smoothing is applied. If ")),i[39]||(i[39]=s("code",null,"label_smoothing",-1)),i[40]||(i[40]=a(" is a real number ")),s("mjx-container",L,[(h(),n("svg",b,i[29]||(i[29]=[t('',1)]))),i[30]||(i[30]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mo",null,"∈"),s("mo",{stretchy:"false"},"["),s("mn",null,"0"),s("mo",null,","),s("mn",null,"1"),s("mo",{stretchy:"false"},"]")])],-1))]),i[41]||(i[41]=a(", then the value of ")),s("mjx-container",w,[(h(),n("svg",H,i[31]||(i[31]=[t('',1)]))),i[32]||(i[32]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])])])],-1))]),i[42]||(i[42]=a(" is:"))]),s("mjx-container",v,[(h(),n("svg",j,i[43]||(i[43]=[t('',1)]))),i[44]||(i[44]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mo",null,"="),s("mo",{stretchy:"false"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mi",null,"α"),s("mo",{stretchy:"false"},")"),s("mo",null,"∗"),s("mi",null,"y"),s("mo",null,"+"),s("mi",null,"α"),s("mo",null,"∗"),s("mn",null,"0.5")])],-1))]),s("p",null,[i[47]||(i[47]=a("where ")),s("mjx-container",D,[(h(),n("svg",B,i[45]||(i[45]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D6FC",d:"M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z",style:{"stroke-width":"3"}})])])],-1)]))),i[46]||(i[46]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"α")])],-1))]),i[48]||(i[48]=a(" is the value of ")),i[49]||(i[49]=s("code",null,"label_smoothing",-1)),i[50]||(i[50]=a("."))]),i[53]||(i[53]=t(`

    Extended Help

    Example

    julia
    julia> bce = BinaryCrossEntropyLoss();
    +
    +julia> y_bin = Bool[1, 0, 1];
    +
    +julia> y_model = Float32[2, -1, pi]
    +3-element Vector{Float32}:
    +  2.0
    + -1.0
    +  3.1415927
    +
    +julia> logitbce = BinaryCrossEntropyLoss(; logits=Val(true));
    +
    +julia> logitbce(y_model, y_bin)  0.160832f0
    +true
    +
    +julia> bce(sigmoid.(y_model), y_bin)  0.16083185f0
    +true
    +
    +julia> bce_ls = BinaryCrossEntropyLoss(label_smoothing=0.1);
    +
    +julia> bce_ls(sigmoid.(y_model), y_bin) > bce(sigmoid.(y_model), y_bin)
    +true
    +
    +julia> logitbce_ls = BinaryCrossEntropyLoss(label_smoothing=0.1, logits=Val(true));
    +
    +julia> logitbce_ls(y_model, y_bin) > logitbce(y_model, y_bin)
    +true

    source

    `,4))]),s("details",M,[s("summary",null,[i[54]||(i[54]=s("a",{id:"Lux.BinaryFocalLoss",href:"#Lux.BinaryFocalLoss"},[s("span",{class:"jlbinding"},"Lux.BinaryFocalLoss")],-1)),i[55]||(i[55]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[66]||(i[66]=t('
    julia
    BinaryFocalLoss(; gamma = 2, agg = mean, epsilon = nothing)
    ',1)),s("p",null,[i[58]||(i[58]=a("Return the binary focal loss [1]. The model input, ")),s("mjx-container",V,[(h(),n("svg",A,i[56]||(i[56]=[t('',1)]))),i[57]||(i[57]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])])])],-1))]),i[59]||(i[59]=a(", is expected to be normalized (i.e. softmax output)."))]),s("p",null,[i[62]||(i[62]=a("For ")),s("mjx-container",Z,[(h(),n("svg",O,i[60]||(i[60]=[t('',1)]))),i[61]||(i[61]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"γ"),s("mo",null,"="),s("mn",null,"0")])],-1))]),i[63]||(i[63]=a(" this is equivalent to ")),i[64]||(i[64]=s("a",{href:"/previews/PR1023/api/Lux/utilities#Lux.BinaryCrossEntropyLoss"},[s("code",null,"BinaryCrossEntropyLoss")],-1)),i[65]||(i[65]=a("."))]),i[67]||(i[67]=t(`

    Example

    julia
    julia> y = [0  1  0
    +            1  0  1];
    +
    +julia> ŷ = [0.268941  0.5  0.268941
    +            0.731059  0.5  0.731059];
    +
    +julia> BinaryFocalLoss()(ŷ, y)  0.0728675615927385
    +true
    +
    +julia> BinaryFocalLoss(gamma=0)(ŷ, y)  BinaryCrossEntropyLoss()(ŷ, y)
    +true

    References

    [1] Lin, Tsung-Yi, et al. "Focal loss for dense object detection." Proceedings of the IEEE international conference on computer vision. 2017.

    source

    `,5))]),s("details",R,[s("summary",null,[i[68]||(i[68]=s("a",{id:"Lux.CrossEntropyLoss",href:"#Lux.CrossEntropyLoss"},[s("span",{class:"jlbinding"},"Lux.CrossEntropyLoss")],-1)),i[69]||(i[69]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[111]||(i[111]=t(`
    julia
    CrossEntropyLoss(; agg=mean, epsilon=nothing, dims=1,
    +    label_smoothing::Union{Nothing, Real}=nothing)
    `,1)),s("p",null,[i[72]||(i[72]=a("Return the cross entropy loss which is used in multi-class classification tasks. The input, ")),s("mjx-container",S,[(h(),n("svg",N,i[70]||(i[70]=[t('',1)]))),i[71]||(i[71]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])])])],-1))]),i[73]||(i[73]=a(", is expected to be normalized (i.e. ")),i[74]||(i[74]=s("code",null,"softmax",-1)),i[75]||(i[75]=a(" output) if ")),i[76]||(i[76]=s("code",null,"logits",-1)),i[77]||(i[77]=a(" is ")),i[78]||(i[78]=s("code",null,"false",-1)),i[79]||(i[79]=a(" or ")),i[80]||(i[80]=s("code",null,"Val(false)",-1)),i[81]||(i[81]=a("."))]),i[112]||(i[112]=s("p",null,"The loss is calculated as:",-1)),s("mjx-container",P,[(h(),n("svg",z,i[82]||(i[82]=[t('',1)]))),i[83]||(i[83]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",null,"−"),s("mo",{"data-mjx-texclass":"OP"},"∑"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mo",{stretchy:"false"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"+"),s("mi",null,"ϵ"),s("mo",{stretchy:"false"},")"),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),s("p",null,[i[92]||(i[92]=a("where ")),s("mjx-container",I,[(h(),n("svg",q,i[84]||(i[84]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D716",d:"M227 -11Q149 -11 95 41T40 174Q40 262 87 322Q121 367 173 396T287 430Q289 431 329 431H367Q382 426 382 411Q382 385 341 385H325H312Q191 385 154 277L150 265H327Q340 256 340 246Q340 228 320 219H138V217Q128 187 128 143Q128 77 160 52T231 26Q258 26 284 36T326 57T343 68Q350 68 354 58T358 39Q358 36 357 35Q354 31 337 21T289 0T227 -11Z",style:{"stroke-width":"3"}})])])],-1)]))),i[85]||(i[85]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"ϵ")])],-1))]),i[93]||(i[93]=a(" is added for numerical stability. The value of ")),s("mjx-container",G,[(h(),n("svg",X,i[86]||(i[86]=[t('',1)]))),i[87]||(i[87]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])])])],-1))]),i[94]||(i[94]=a(" is computed using label smoothing. If ")),i[95]||(i[95]=s("code",null,"label_smoothing",-1)),i[96]||(i[96]=a(" is ")),i[97]||(i[97]=s("code",null,"nothing",-1)),i[98]||(i[98]=a(", then no label smoothing is applied. If ")),i[99]||(i[99]=s("code",null,"label_smoothing",-1)),i[100]||(i[100]=a(" is a real number ")),s("mjx-container",J,[(h(),n("svg",U,i[88]||(i[88]=[t('',1)]))),i[89]||(i[89]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mo",null,"∈"),s("mo",{stretchy:"false"},"["),s("mn",null,"0"),s("mo",null,","),s("mn",null,"1"),s("mo",{stretchy:"false"},"]")])],-1))]),i[101]||(i[101]=a(", then the value of ")),s("mjx-container",W,[(h(),n("svg",K,i[90]||(i[90]=[t('',1)]))),i[91]||(i[91]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])])])],-1))]),i[102]||(i[102]=a(" is calculated as:"))]),s("mjx-container",Y,[(h(),n("svg",$,i[103]||(i[103]=[t('',1)]))),i[104]||(i[104]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mo",null,"="),s("mo",{stretchy:"false"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mi",null,"α"),s("mo",{stretchy:"false"},")"),s("mo",null,"∗"),s("mi",null,"y"),s("mo",null,"+"),s("mi",null,"α"),s("mo",null,"∗"),s("mtext",null,"size along dim")])],-1))]),s("p",null,[i[107]||(i[107]=a("where ")),s("mjx-container",_,[(h(),n("svg",s1,i[105]||(i[105]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D6FC",d:"M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z",style:{"stroke-width":"3"}})])])],-1)]))),i[106]||(i[106]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"α")])],-1))]),i[108]||(i[108]=a(" is the value of ")),i[109]||(i[109]=s("code",null,"label_smoothing",-1)),i[110]||(i[110]=a("."))]),i[113]||(i[113]=t(`

    Extended Help

    Example

    julia
    julia> y = [1  0  0  0  1
    +            0  1  0  1  0
    +            0  0  1  0  0]
    +3×5 Matrix{Int64}:
    + 1  0  0  0  1
    + 0  1  0  1  0
    + 0  0  1  0  0
    +
    +julia> y_model = softmax(reshape(-7:7, 3, 5) .* 1f0)
    +3×5 Matrix{Float32}:
    + 0.0900306  0.0900306  0.0900306  0.0900306  0.0900306
    + 0.244728   0.244728   0.244728   0.244728   0.244728
    + 0.665241   0.665241   0.665241   0.665241   0.665241
    +
    +julia> CrossEntropyLoss()(y_model, y)  1.6076053f0
    +true
    +
    +julia> 5 * 1.6076053f0 CrossEntropyLoss(; agg=sum)(y_model, y)
    +true
    +
    +julia> CrossEntropyLoss(label_smoothing=0.15)(y_model, y)  1.5776052f0
    +true

    source

    `,4))]),s("details",i1,[s("summary",null,[i[114]||(i[114]=s("a",{id:"Lux.DiceCoeffLoss",href:"#Lux.DiceCoeffLoss"},[s("span",{class:"jlbinding"},"Lux.DiceCoeffLoss")],-1)),i[115]||(i[115]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[124]||(i[124]=t('
    julia
    DiceCoeffLoss(; smooth = true, agg = mean)

    Return the Dice Coefficient loss [1] which is used in segmentation tasks. The dice coefficient is similar to the F1_score. Loss calculated as:

    ',2)),s("mjx-container",a1,[(h(),n("svg",t1,i[116]||(i[116]=[t('',1)]))),i[117]||(i[117]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mi",null,"a"),s("mi",null,"g"),s("mi",null,"g"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mfrac",null,[s("mrow",null,[s("mn",null,"2"),s("mo",{"data-mjx-texclass":"OP"},"∑"),s("mi",null,"y"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"+"),s("mi",null,"α")]),s("mrow",null,[s("mo",{"data-mjx-texclass":"OP"},"∑"),s("msup",null,[s("mi",null,"y"),s("mn",null,"2")]),s("mo",null,"+"),s("mo",{"data-mjx-texclass":"OP"},"∑"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mn",null,"2")]),s("mo",null,"+"),s("mi",null,"α")])]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),s("p",null,[i[120]||(i[120]=a("where ")),s("mjx-container",e1,[(h(),n("svg",l1,i[118]||(i[118]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D6FC",d:"M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z",style:{"stroke-width":"3"}})])])],-1)]))),i[119]||(i[119]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"α")])],-1))]),i[121]||(i[121]=a(" is the smoothing factor (")),i[122]||(i[122]=s("code",null,"smooth",-1)),i[123]||(i[123]=a(")."))]),i[125]||(i[125]=t(`

    Example

    julia
    julia> y_pred = [1.1, 2.1, 3.1];
    +
    +julia> DiceCoeffLoss()(y_pred, 1:3)   0.000992391663909964
    +true
    +
    +julia> 1 - DiceCoeffLoss()(y_pred, 1:3)   0.99900760833609
    +true
    +
    +julia> DiceCoeffLoss()(reshape(y_pred, 3, 1), reshape(1:3, 3, 1))  0.000992391663909964
    +true

    References

    [1] Milletari, Fausto, Nassir Navab, and Seyed-Ahmad Ahmadi. "V-net: Fully convolutional neural networks for volumetric medical image segmentation." 2016 fourth international conference on 3D vision (3DV). Ieee, 2016.

    source

    `,5))]),s("details",n1,[s("summary",null,[i[126]||(i[126]=s("a",{id:"Lux.FocalLoss",href:"#Lux.FocalLoss"},[s("span",{class:"jlbinding"},"Lux.FocalLoss")],-1)),i[127]||(i[127]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[143]||(i[143]=t('
    julia
    FocalLoss(; gamma = 2, dims = 1, agg = mean, epsilon = nothing)
    ',1)),s("p",null,[i[130]||(i[130]=a("Return the focal loss [1] which can be used in classification tasks with highly imbalanced classes. It down-weights well-classified examples and focuses on hard examples. The input, ")),s("mjx-container",h1,[(h(),n("svg",p1,i[128]||(i[128]=[t('',1)]))),i[129]||(i[129]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])])])],-1))]),i[131]||(i[131]=a(", is expected to be normalized (i.e. ")),i[132]||(i[132]=s("code",null,"softmax",-1)),i[133]||(i[133]=a(" output)."))]),s("p",null,[i[138]||(i[138]=a("The modulating factor ")),s("mjx-container",r1,[(h(),n("svg",d1,i[134]||(i[134]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),i[135]||(i[135]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"γ")])],-1))]),i[139]||(i[139]=a(", controls the down-weighting strength. For ")),s("mjx-container",k1,[(h(),n("svg",o1,i[136]||(i[136]=[t('',1)]))),i[137]||(i[137]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"γ"),s("mo",null,"="),s("mn",null,"0")])],-1))]),i[140]||(i[140]=a(" this is equivalent to ")),i[141]||(i[141]=s("a",{href:"/previews/PR1023/api/Lux/utilities#Lux.CrossEntropyLoss"},[s("code",null,"CrossEntropyLoss")],-1)),i[142]||(i[142]=a("."))]),i[144]||(i[144]=t(`

    Example

    julia
    julia> y = [1  0  0  0  1
    +            0  1  0  1  0
    +            0  0  1  0  0]
    +3×5 Matrix{Int64}:
    + 1  0  0  0  1
    + 0  1  0  1  0
    + 0  0  1  0  0
    +
    +julia> ŷ = softmax(reshape(-7:7, 3, 5) .* 1f0)
    +3×5 Matrix{Float32}:
    + 0.0900306  0.0900306  0.0900306  0.0900306  0.0900306
    + 0.244728   0.244728   0.244728   0.244728   0.244728
    + 0.665241   0.665241   0.665241   0.665241   0.665241
    +
    +julia> FocalLoss()(ŷ, y)  1.1277556f0
    +true

    References

    [1] Lin, Tsung-Yi, et al. "Focal loss for dense object detection." Proceedings of the IEEE international conference on computer vision. 2017.

    source

    `,5))]),s("details",T1,[s("summary",null,[i[145]||(i[145]=s("a",{id:"Lux.HingeLoss",href:"#Lux.HingeLoss"},[s("span",{class:"jlbinding"},"Lux.HingeLoss")],-1)),i[146]||(i[146]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[149]||(i[149]=t('
    julia
    HingeLoss(; agg = mean)

    Return the hinge loss loss given the prediction and true labels y (containing 1 or -1); calculated as:

    ',2)),s("mjx-container",Q1,[(h(),n("svg",g1,i[147]||(i[147]=[t('',1)]))),i[148]||(i[148]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",{"data-mjx-texclass":"OP",movablelimits:"true"},"max"),s("mo",{stretchy:"false"},"("),s("mn",null,"0"),s("mo",null,","),s("mn",null,"1"),s("mo",null,"−"),s("mi",null,"y"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",{stretchy:"false"},")"),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[150]||(i[150]=t(`

    Usually used with classifiers like Support Vector Machines.

    Example

    julia
    julia> loss = HingeLoss();
    +
    +julia> y_true = [1, -1, 1, 1];
    +
    +julia> y_pred = [0.1, 0.3, 1, 1.5];
    +
    +julia> loss(y_pred, y_true)  0.55
    +true

    source

    `,4))]),s("details",m1,[s("summary",null,[i[151]||(i[151]=s("a",{id:"Lux.HuberLoss",href:"#Lux.HuberLoss"},[s("span",{class:"jlbinding"},"Lux.HuberLoss")],-1)),i[152]||(i[152]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[161]||(i[161]=t('
    julia
    HuberLoss(; delta = 1, agg = mean)

    Returns the Huber loss, calculated as:

    ',2)),s("mjx-container",y1,[(h(),n("svg",E1,i[153]||(i[153]=[t('',1)]))),i[154]||(i[154]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mi",null,"L"),s("mo",null,"="),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"{"),s("mtable",{columnalign:"left left",columnspacing:"1em",rowspacing:".2em"},[s("mtr",null,[s("mtd",null,[s("mn",null,"0.5"),s("mo",null,"∗"),s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mi",null,"y"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("msup",null,[s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mn",null,"2")])]),s("mtd",null,[s("mtext",null,"if "),s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mi",null,"y"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mo",null,"≤"),s("mi",null,"δ")])]),s("mtr",null,[s("mtd",null,[s("mi",null,"δ"),s("mo",null,"∗"),s("mo",{stretchy:"false"},"("),s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mi",null,"y"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mo",null,"−"),s("mn",null,"0.5"),s("mo",null,"∗"),s("mi",null,"δ"),s("mo",{stretchy:"false"},")")]),s("mtd",null,[s("mtext",null,"otherwise")])])]),s("mo",{"data-mjx-texclass":"CLOSE",fence:"true",stretchy:"true",symmetric:"true"})])])],-1))]),s("p",null,[i[157]||(i[157]=a("where ")),s("mjx-container",c1,[(h(),n("svg",u1,i[155]||(i[155]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D6FF",d:"M195 609Q195 656 227 686T302 717Q319 716 351 709T407 697T433 690Q451 682 451 662Q451 644 438 628T403 612Q382 612 348 641T288 671T249 657T235 628Q235 584 334 463Q401 379 401 292Q401 169 340 80T205 -10H198Q127 -10 83 36T36 153Q36 286 151 382Q191 413 252 434Q252 435 245 449T230 481T214 521T201 566T195 609ZM112 130Q112 83 136 55T204 27Q233 27 256 51T291 111T309 178T316 232Q316 267 309 298T295 344T269 400L259 396Q215 381 183 342T137 256T118 179T112 130Z",style:{"stroke-width":"3"}})])])],-1)]))),i[156]||(i[156]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"δ")])],-1))]),i[158]||(i[158]=a(" is the ")),i[159]||(i[159]=s("code",null,"delta",-1)),i[160]||(i[160]=a(" parameter."))]),i[162]||(i[162]=t(`

    Example

    julia
    julia> y_model = [1.1, 2.1, 3.1];
    +
    +julia> HuberLoss()(y_model, 1:3)  0.005000000000000009
    +true
    +
    +julia> HuberLoss(delta=0.05)(y_model, 1:3)  0.003750000000000005
    +true

    source

    `,3))]),s("details",F1,[s("summary",null,[i[163]||(i[163]=s("a",{id:"Lux.KLDivergenceLoss",href:"#Lux.KLDivergenceLoss"},[s("span",{class:"jlbinding"},"Lux.KLDivergenceLoss")],-1)),i[164]||(i[164]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[172]||(i[172]=t('
    julia
    KLDivergenceLoss(; dims = 1, agg = mean, epsilon = nothing, label_smoothing = nothing)
    ',1)),s("p",null,[i[169]||(i[169]=a("Return the Kullback-Leibler Divergence loss between the predicted distribution ")),s("mjx-container",x1,[(h(),n("svg",f1,i[165]||(i[165]=[t('',1)]))),i[166]||(i[166]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])])])],-1))]),i[170]||(i[170]=a(" and the true distribution ")),s("mjx-container",C1,[(h(),n("svg",L1,i[167]||(i[167]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D466",d:"M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z",style:{"stroke-width":"3"}})])])],-1)]))),i[168]||(i[168]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"y")])],-1))]),i[171]||(i[171]=a(":"))]),i[173]||(i[173]=t(`

    The KL divergence is a measure of how much one probability distribution is different from the other. It is always non-negative, and zero only when both the distributions are equal.

    For epsilon and label_smoothing, see CrossEntropyLoss.

    Example

    julia
    julia> p1 = [1 0; 0 1]
    +2×2 Matrix{Int64}:
    + 1  0
    + 0  1
    +
    +julia> p2 = fill(0.5, 2, 2)
    +2×2 Matrix{Float64}:
    + 0.5  0.5
    + 0.5  0.5
    +
    +julia> KLDivergenceLoss()(p2, p1)  log(2)
    +true
    +
    +julia> KLDivergenceLoss(; agg=sum)(p2, p1)  2 * log(2)
    +true
    +
    +julia> KLDivergenceLoss(; epsilon=0)(p2, p2)
    +0.0
    +
    +julia> KLDivergenceLoss(; epsilon=0)(p1, p2)
    +Inf

    source

    `,5))]),s("details",b1,[s("summary",null,[i[174]||(i[174]=s("a",{id:"Lux.MAELoss",href:"#Lux.MAELoss"},[s("span",{class:"jlbinding"},"Lux.MAELoss")],-1)),i[175]||(i[175]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[178]||(i[178]=t('
    julia
    MAELoss(; agg = mean)

    Returns the loss corresponding to mean absolute error:

    ',2)),s("mjx-container",w1,[(h(),n("svg",H1,i[176]||(i[176]=[t('',1)]))),i[177]||(i[177]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"|"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"−"),s("mi",null,"y"),s("mo",{"data-mjx-texclass":"CLOSE"},"|")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[179]||(i[179]=t(`

    Example

    julia
    julia> loss = MAELoss();
    +
    +julia> y_model = [1.1, 1.9, 3.1];
    +
    +julia> loss(y_model, 1:3)  0.1
    +true

    source

    `,3))]),s("details",v1,[s("summary",null,[i[180]||(i[180]=s("a",{id:"Lux.MSELoss",href:"#Lux.MSELoss"},[s("span",{class:"jlbinding"},"Lux.MSELoss")],-1)),i[181]||(i[181]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[184]||(i[184]=t('
    julia
    MSELoss(; agg = mean)

    Returns the loss corresponding to mean squared error:

    ',2)),s("mjx-container",j1,[(h(),n("svg",D1,i[182]||(i[182]=[t('',1)]))),i[183]||(i[183]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("msup",null,[s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"−"),s("mi",null,"y"),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mn",null,"2")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[185]||(i[185]=t(`

    Example

    julia
    julia> loss = MSELoss();
    +
    +julia> y_model = [1.1, 1.9, 3.1];
    +
    +julia> loss(y_model, 1:3)  0.01
    +true

    source

    `,3))]),s("details",B1,[s("summary",null,[i[186]||(i[186]=s("a",{id:"Lux.MSLELoss",href:"#Lux.MSLELoss"},[s("span",{class:"jlbinding"},"Lux.MSLELoss")],-1)),i[187]||(i[187]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[190]||(i[190]=t('
    julia
    MSLELoss(; agg = mean, epsilon = nothing)

    Returns the loss corresponding to mean squared logarithmic error:

    ',2)),s("mjx-container",M1,[(h(),n("svg",V1,i[188]||(i[188]=[t('',1)]))),i[189]||(i[189]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("msup",null,[s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"+"),s("mi",null,"ϵ"),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mo",null,"−"),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mi",null,"y"),s("mo",null,"+"),s("mi",null,"ϵ"),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mn",null,"2")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[191]||(i[191]=t(`

    epsilon is added to both y and to prevent taking the logarithm of zero. If epsilon is nothing, then we set it to eps(<type of y and ŷ>).

    Example

    julia
    julia> loss = MSLELoss();
    +
    +julia> loss(Float32[1.1, 2.2, 3.3], 1:3)  0.009084041f0
    +true
    +
    +julia> loss(Float32[0.9, 1.8, 2.7], 1:3)  0.011100831f0
    +true

    source

    `,4))]),s("details",A1,[s("summary",null,[i[192]||(i[192]=s("a",{id:"Lux.PoissonLoss",href:"#Lux.PoissonLoss"},[s("span",{class:"jlbinding"},"Lux.PoissonLoss")],-1)),i[193]||(i[193]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[203]||(i[203]=t('
    julia
    PoissonLoss(; agg = mean, epsilon = nothing)
    ',1)),s("p",null,[i[198]||(i[198]=a("Return how much the predicted distribution ")),s("mjx-container",Z1,[(h(),n("svg",O1,i[194]||(i[194]=[t('',1)]))),i[195]||(i[195]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])])])],-1))]),i[199]||(i[199]=a(" diverges from the expected Poisson distribution ")),s("mjx-container",R1,[(h(),n("svg",S1,i[196]||(i[196]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D466",d:"M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z",style:{"stroke-width":"3"}})])])],-1)]))),i[197]||(i[197]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"y")])],-1))]),i[200]||(i[200]=a(", calculated as:"))]),s("mjx-container",N1,[(h(),n("svg",P1,i[201]||(i[201]=[t('',1)]))),i[202]||(i[202]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"−"),s("mi",null,"y"),s("mo",null,"∗"),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mo",{stretchy:"false"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",{stretchy:"false"},")"),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[204]||(i[204]=t(`

    Example

    julia
    julia> y_model = [1, 3, 3];  # data should only take integral values
    +
    +julia> PoissonLoss()(y_model, 1:3)  0.502312852219817
    +true

    source

    `,3))]),s("details",z1,[s("summary",null,[i[205]||(i[205]=s("a",{id:"Lux.SiameseContrastiveLoss",href:"#Lux.SiameseContrastiveLoss"},[s("span",{class:"jlbinding"},"Lux.SiameseContrastiveLoss")],-1)),i[206]||(i[206]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[209]||(i[209]=t('
    julia
    SiameseContrastiveLoss(; margin = true, agg = mean)

    Return the contrastive loss [1] which can be useful for training Siamese Networks. It is given by:

    ',2)),s("mjx-container",I1,[(h(),n("svg",q1,i[207]||(i[207]=[t('',1)]))),i[208]||(i[208]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",{stretchy:"false"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mi",null,"y"),s("mo",{stretchy:"false"},")"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mn",null,"2")]),s("mo",null,"+"),s("mi",null,"y"),s("mo",null,"∗"),s("mo",{"data-mjx-texclass":"OP",movablelimits:"true"},"max"),s("mo",{stretchy:"false"},"("),s("mn",null,"0"),s("mo",null,","),s("mtext",null,"margin"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("msup",null,[s("mo",{stretchy:"false"},")"),s("mn",null,"2")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[210]||(i[210]=t(`

    Specify margin to set the baseline for distance at which pairs are dissimilar.

    Example

    julia
    julia>= [0.5, 1.5, 2.5];
    +
    +julia> SiameseContrastiveLoss()(ŷ, 1:3)  -4.833333333333333
    +true
    +
    +julia> SiameseContrastiveLoss(margin=2)(ŷ, 1:3)  -4.0
    +true

    References

    [1] Hadsell, Raia, Sumit Chopra, and Yann LeCun. "Dimensionality reduction by learning an invariant mapping." 2006 IEEE computer society conference on computer vision and pattern recognition (CVPR'06). Vol. 2. IEEE, 2006.

    source

    `,6))]),s("details",G1,[s("summary",null,[i[211]||(i[211]=s("a",{id:"Lux.SquaredHingeLoss",href:"#Lux.SquaredHingeLoss"},[s("span",{class:"jlbinding"},"Lux.SquaredHingeLoss")],-1)),i[212]||(i[212]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[215]||(i[215]=t('
    julia
    SquaredHingeLoss(; agg = mean)

    Return the squared hinge loss loss given the prediction and true labels y (containing 1 or -1); calculated as:

    ',2)),s("mjx-container",X1,[(h(),n("svg",J1,i[213]||(i[213]=[t('',1)]))),i[214]||(i[214]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",{"data-mjx-texclass":"OP",movablelimits:"true"},"max"),s("mo",{stretchy:"false"},"("),s("mn",null,"0"),s("mo",null,","),s("mn",null,"1"),s("mo",null,"−"),s("mi",null,"y"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("msup",null,[s("mo",{stretchy:"false"},")"),s("mn",null,"2")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[216]||(i[216]=t(`

    Usually used with classifiers like Support Vector Machines.

    Example

    julia
    julia> loss = SquaredHingeLoss();
    +
    +julia> y_true = [1, -1, 1, 1];
    +
    +julia> y_pred = [0.1, 0.3, 1, 1.5];
    +
    +julia> loss(y_pred, y_true)  0.625
    +true

    source

    `,4))]),i[291]||(i[291]=s("h2",{id:"LuxOps-Module",tabindex:"-1"},[a("LuxOps Module "),s("a",{class:"header-anchor",href:"#LuxOps-Module","aria-label":'Permalink to "LuxOps Module {#LuxOps-Module}"'},"​")],-1)),s("details",U1,[s("summary",null,[i[217]||(i[217]=s("a",{id:"Lux.LuxOps",href:"#Lux.LuxOps"},[s("span",{class:"jlbinding"},"Lux.LuxOps")],-1)),i[218]||(i[218]=a()),l(e,{type:"info",class:"jlObjectType jlModule",text:"Module"})]),i[219]||(i[219]=t('
    julia
    LuxOps

    This module is a part of Lux.jl. It contains operations that are useful in DL context. Additionally certain operations here alias Base functions to behave more sensibly with GPUArrays.

    source

    ',3))]),s("details",W1,[s("summary",null,[i[220]||(i[220]=s("a",{id:"Lux.LuxOps.eachslice",href:"#Lux.LuxOps.eachslice"},[s("span",{class:"jlbinding"},"Lux.LuxOps.eachslice")],-1)),i[221]||(i[221]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[222]||(i[222]=t('
    julia
    eachslice(x, dims::Val)

    Same as Base.eachslice but doesn't produce a SubArray for the slices if x is a GPUArray.

    Additional dispatches for RNN helpers are also provided for TimeLastIndex and BatchLastIndex.

    source

    ',4))]),s("details",K1,[s("summary",null,[i[223]||(i[223]=s("a",{id:"Lux.LuxOps.foldl_init",href:"#Lux.LuxOps.foldl_init"},[s("span",{class:"jlbinding"},"Lux.LuxOps.foldl_init")],-1)),i[224]||(i[224]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[225]||(i[225]=t(`
    julia
    foldl_init(op, x)
    +foldl_init(op, x, init)

    Exactly same as foldl(op, x; init) in the forward pass. But, gives gradients wrt init in the backward pass.

    source

    `,3))]),s("details",Y1,[s("summary",null,[i[226]||(i[226]=s("a",{id:"Lux.LuxOps.getproperty",href:"#Lux.LuxOps.getproperty"},[s("span",{class:"jlbinding"},"Lux.LuxOps.getproperty")],-1)),i[227]||(i[227]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[228]||(i[228]=t(`
    julia
    getproperty(x, ::Val{v})
    +getproperty(x, ::StaticSymbol{v})

    Similar to Base.getproperty but requires a Val (or Static.StaticSymbol). Additionally, if v is not present in x, then nothing is returned.

    source

    `,3))]),s("details",$1,[s("summary",null,[i[229]||(i[229]=s("a",{id:"Lux.LuxOps.xlogx",href:"#Lux.LuxOps.xlogx"},[s("span",{class:"jlbinding"},"Lux.LuxOps.xlogx")],-1)),i[230]||(i[230]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[231]||(i[231]=t('
    julia
    xlogx(x::Number)

    Return x * log(x) for x ≥ 0, handling x == 0 by taking the limit from above, to get zero.

    source

    ',3))]),s("details",_1,[s("summary",null,[i[232]||(i[232]=s("a",{id:"Lux.LuxOps.xlogy",href:"#Lux.LuxOps.xlogy"},[s("span",{class:"jlbinding"},"Lux.LuxOps.xlogy")],-1)),i[233]||(i[233]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[234]||(i[234]=t('
    julia
    xlogy(x::Number, y::Number)

    Return x * log(y) for y > 0, and zero when x == 0.

    source

    ',3))]),s("details",s2,[s("summary",null,[i[235]||(i[235]=s("a",{id:"Lux.LuxOps.istraining",href:"#Lux.LuxOps.istraining"},[s("span",{class:"jlbinding"},"Lux.LuxOps.istraining")],-1)),i[236]||(i[236]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[237]||(i[237]=t(`
    julia
    istraining(::Val{training})
    +istraining(::StaticBool)
    +istraining(::Bool)
    +istraining(st::NamedTuple)

    Returns true if training is true or if st contains a training field with value true. Else returns false.

    source

    `,3))]),s("details",i2,[s("summary",null,[i[238]||(i[238]=s("a",{id:"Lux.LuxOps.multigate",href:"#Lux.LuxOps.multigate"},[s("span",{class:"jlbinding"},"Lux.LuxOps.multigate")],-1)),i[239]||(i[239]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[240]||(i[240]=t('
    julia
    multigate(x::AbstractArray, ::Val{N})

    Split up x into N equally sized chunks (along dimension 1).

    source

    ',3))]),i[292]||(i[292]=s("h2",{id:"Recursive-Operations",tabindex:"-1"},[a("Recursive Operations "),s("a",{class:"header-anchor",href:"#Recursive-Operations","aria-label":'Permalink to "Recursive Operations {#Recursive-Operations}"'},"​")],-1)),s("details",a2,[s("summary",null,[i[241]||(i[241]=s("a",{id:"Lux.recursive_map",href:"#Lux.recursive_map"},[s("span",{class:"jlbinding"},"Lux.recursive_map")],-1)),i[242]||(i[242]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[243]||(i[243]=t('
    julia
    recursive_map(f, x, args...)

    Similar to fmap(f, args...) but with restricted support for the notion of "leaf" types. However, this allows for more efficient and type stable implementations of recursive operations.

    How this works?

    For the following types it directly defines recursion rules:

    1. AbstractArray: If eltype is isbitstype, then f is applied to the array, else we recurse on the array.

    2. Tuple/NamedTuple: We recurse on the values.

    3. Number/Val/Nothing: We directly apply f.

    4. For all other types, we recurse on the fields using Functors.fmap.

    Note

    In most cases, users should gravitate towards Functors.fmap if it is being used outside of hot loops. Even for other cases, it is always recommended to verify the correctness of this implementation for specific usecases.

    source

    ',7))]),s("details",t2,[s("summary",null,[i[244]||(i[244]=s("a",{id:"Lux.recursive_add!!",href:"#Lux.recursive_add!!"},[s("span",{class:"jlbinding"},"Lux.recursive_add!!")],-1)),i[245]||(i[245]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[246]||(i[246]=t('
    julia
    recursive_add!!(x, y)

    Recursively add the leaves of two nested structures x and y. In Functor language, this is equivalent to doing fmap(+, x, y), but this implementation uses type stable code for common cases.

    Any leaves of x that are arrays and allow in-place addition will be modified in place.

    source

    ',4))]),s("details",e2,[s("summary",null,[i[247]||(i[247]=s("a",{id:"Lux.recursive_copyto!",href:"#Lux.recursive_copyto!"},[s("span",{class:"jlbinding"},"Lux.recursive_copyto!")],-1)),i[248]||(i[248]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[249]||(i[249]=t('
    julia
    recursive_copyto!(x, y)

    Recursively copy the leaves of two nested structures x and y. In Functor language, this is equivalent to doing fmap(copyto!, x, y), but this implementation uses type stable code for common cases. Note that any immutable leaf will lead to an error.

    source

    ',3))]),s("details",l2,[s("summary",null,[i[250]||(i[250]=s("a",{id:"Lux.recursive_eltype",href:"#Lux.recursive_eltype"},[s("span",{class:"jlbinding"},"Lux.recursive_eltype")],-1)),i[251]||(i[251]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[252]||(i[252]=t('
    julia
    recursive_eltype(x, unwrap_ad_types = Val(false))

    Recursively determine the element type of a nested structure x. This is equivalent to doing fmap(Lux.Utils.eltype, x), but this implementation uses type stable code for common cases.

    For ambiguous inputs like nothing and Val types we return Bool as the eltype.

    If unwrap_ad_types is set to Val(true) then for tracing and operator overloading based ADs (ForwardDiff, ReverseDiff, Tracker), this function will return the eltype of the unwrapped value.

    source

    ',5))]),s("details",n2,[s("summary",null,[i[253]||(i[253]=s("a",{id:"Lux.recursive_make_zero",href:"#Lux.recursive_make_zero"},[s("span",{class:"jlbinding"},"Lux.recursive_make_zero")],-1)),i[254]||(i[254]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[255]||(i[255]=t('
    julia
    recursive_make_zero(x)

    Recursively create a zero value for a nested structure x. This is equivalent to doing fmap(zero, x), but this implementation uses type stable code for common cases.

    See also Lux.recursive_make_zero!!.

    source

    ',4))]),s("details",h2,[s("summary",null,[i[256]||(i[256]=s("a",{id:"Lux.recursive_make_zero!!",href:"#Lux.recursive_make_zero!!"},[s("span",{class:"jlbinding"},"Lux.recursive_make_zero!!")],-1)),i[257]||(i[257]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[258]||(i[258]=t('
    julia
    recursive_make_zero!!(x)

    Recursively create a zero value for a nested structure x. Leaves that can be mutated with in-place zeroing will be modified in place.

    See also Lux.recursive_make_zero for fully out-of-place version.

    source

    ',4))]),i[293]||(i[293]=s("h2",{id:"Updating-Floating-Point-Precision",tabindex:"-1"},[a("Updating Floating Point Precision "),s("a",{class:"header-anchor",href:"#Updating-Floating-Point-Precision","aria-label":'Permalink to "Updating Floating Point Precision {#Updating-Floating-Point-Precision}"'},"​")],-1)),i[294]||(i[294]=s("p",null,"By default, Lux uses Float32 for all parameters and states. To update the precision simply pass the parameters / states / arrays into one of the following functions.",-1)),s("details",p2,[s("summary",null,[i[259]||(i[259]=s("a",{id:"Lux.f16",href:"#Lux.f16"},[s("span",{class:"jlbinding"},"Lux.f16")],-1)),i[260]||(i[260]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[261]||(i[261]=t('
    julia
    f16(m)

    Converts the eltype of m floating point values to Float16. Recurses into structs marked with Functors.@functor.

    source

    ',3))]),s("details",r2,[s("summary",null,[i[262]||(i[262]=s("a",{id:"Lux.f32",href:"#Lux.f32"},[s("span",{class:"jlbinding"},"Lux.f32")],-1)),i[263]||(i[263]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[264]||(i[264]=t('
    julia
    f32(m)

    Converts the eltype of m floating point values to Float32. Recurses into structs marked with Functors.@functor.

    source

    ',3))]),s("details",d2,[s("summary",null,[i[265]||(i[265]=s("a",{id:"Lux.f64",href:"#Lux.f64"},[s("span",{class:"jlbinding"},"Lux.f64")],-1)),i[266]||(i[266]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[267]||(i[267]=t('
    julia
    f64(m)

    Converts the eltype of m floating point values to Float64. Recurses into structs marked with Functors.@functor.

    source

    ',3))]),i[295]||(i[295]=s("h2",{id:"Element-Type-Matching",tabindex:"-1"},[a("Element Type Matching "),s("a",{class:"header-anchor",href:"#Element-Type-Matching","aria-label":'Permalink to "Element Type Matching {#Element-Type-Matching}"'},"​")],-1)),s("details",k2,[s("summary",null,[i[268]||(i[268]=s("a",{id:"Lux.match_eltype",href:"#Lux.match_eltype"},[s("span",{class:"jlbinding"},"Lux.match_eltype")],-1)),i[269]||(i[269]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[270]||(i[270]=t('
    julia
    match_eltype(layer, ps, st, args...)

    Helper function to "maybe" (see below) match the element type of args... with the element type of the layer's parameters and states. This is useful for debugging purposes, to track down accidental type-promotions inside Lux layers.

    Extended Help

    Controlling the Behavior via Preferences

    Behavior of this function is controlled via the eltype_mismatch_handling preference. The following options are supported:

    Warning

    We print the warning for type-mismatch only once.

    Element Type Conversions

    For "convert" only the following conversions are done:

    Element Type of parameters/statesElement Type of args...Converted to
    Float64IntegerFloat64
    Float32Float64Float32
    Float32IntegerFloat32
    Float16Float64Float16
    Float16Float32Float16
    Float16IntegerFloat16

    source

    ',11))]),i[296]||(i[296]=s("h2",{id:"Stateful-Layer",tabindex:"-1"},[a("Stateful Layer "),s("a",{class:"header-anchor",href:"#Stateful-Layer","aria-label":'Permalink to "Stateful Layer {#Stateful-Layer}"'},"​")],-1)),s("details",o2,[s("summary",null,[i[271]||(i[271]=s("a",{id:"Lux.StatefulLuxLayer",href:"#Lux.StatefulLuxLayer"},[s("span",{class:"jlbinding"},"Lux.StatefulLuxLayer")],-1)),i[272]||(i[272]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[273]||(i[273]=t('
    julia
    StatefulLuxLayer{FT}(model, ps, st)

    Warning

    This is not a Lux.AbstractLuxLayer

    A convenience wrapper over Lux layers which stores the parameters and states internally. This is meant to be used in internal implementation of layers.

    Usecases

    Static Parameters

    Arguments

    Inputs

    Outputs

    source

    ',14))]),i[297]||(i[297]=s("h2",{id:"Compact-Layer",tabindex:"-1"},[a("Compact Layer "),s("a",{class:"header-anchor",href:"#Compact-Layer","aria-label":'Permalink to "Compact Layer {#Compact-Layer}"'},"​")],-1)),s("details",T2,[s("summary",null,[i[274]||(i[274]=s("a",{id:"Lux.@compact",href:"#Lux.@compact"},[s("span",{class:"jlbinding"},"Lux.@compact")],-1)),i[275]||(i[275]=a()),l(e,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),i[276]||(i[276]=t(`
    julia
    @compact(kw...) do x
    +    ...
    +    @return y # optional (but recommended for best performance)
    +end
    +@compact(kw...) do x, p
    +    ...
    +    @return y # optional (but recommended for best performance)
    +end
    +@compact(forward::Function; name=nothing, dispatch=nothing, parameters...)

    Creates a layer by specifying some parameters, in the form of keywords, and (usually as a do block) a function for the forward pass. You may think of @compact as a specialized let block creating local variables that are trainable in Lux. Declared variable names may be used within the body of the forward function. Note that unlike typical Lux models, the forward function doesn't need to explicitly manage states.

    Defining the version with p allows you to access the parameters in the forward pass. This is useful when using it with SciML tools which require passing in the parameters explicitly.

    Reserved Kwargs:

    1. name: The name of the layer.

    2. dispatch: The constructed layer has the type Lux.CompactLuxLayer{dispatch} which can be used for custom dispatches.

    Tip

    Check the Lux tutorials for more examples of using @compact.

    If you are passing in kwargs by splatting them, they will be passed as is to the function body. This means if your splatted kwargs contain a lux layer that won't be registered in the CompactLuxLayer.

    Special Syntax

    Extended Help

    Examples

    Here is a linear model:

    julia
    julia> using Lux, Random
    +
    +julia> r = @compact(w=ones(3)) do x
    +           @return w .* x
    +       end
    +@compact(
    +    w = 3-element Vector{Float64},
    +) do x
    +    return w .* x
    +end       # Total: 3 parameters,
    +          #        plus 0 states.
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), r);
    +
    +julia> r([1, 2, 3], ps, st)  # x is set to [1, 1, 1].
    +([1.0, 2.0, 3.0], NamedTuple())

    Here is a linear model with bias and activation:

    julia
    julia> d_in = 5
    +5
    +
    +julia> d_out = 3
    +3
    +
    +julia> d = @compact(W=ones(d_out, d_in), b=zeros(d_out), act=relu) do x
    +           y = W * x
    +           @return act.(y .+ b)
    +       end
    +@compact(
    +    W = 3×5 Matrix{Float64},
    +    b = 3-element Vector{Float64},
    +    act = relu,
    +) do x
    +    y = W * x
    +    return act.(y .+ b)
    +end       # Total: 18 parameters,
    +          #        plus 1 states.
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), d);
    +
    +julia> d(ones(5, 2), ps, st)[1] # 3×2 Matrix as output.
    +3×2 Matrix{Float64}:
    + 5.0  5.0
    + 5.0  5.0
    + 5.0  5.0
    +
    +julia> ps_dense = (; weight=ps.W, bias=ps.b);
    +
    +julia> first(d([1, 2, 3, 4, 5], ps, st)) 
    +       first(Dense(d_in => d_out, relu)([1, 2, 3, 4, 5], ps_dense, NamedTuple())) # Equivalent to a dense layer
    +true

    Finally, here is a simple MLP. We can train this model just like any Lux model:

    julia
    julia> n_in = 1;
    +
    +julia> n_out = 1;
    +
    +julia> nlayers = 3;
    +
    +julia> model = @compact(w1=Dense(n_in, 128),
    +           w2=[Dense(128, 128) for i in 1:nlayers], w3=Dense(128, n_out), act=relu) do x
    +           embed = act.(w1(x))
    +           for w in w2
    +               embed = act.(w(embed))
    +           end
    +           out = w3(embed)
    +           @return out
    +       end
    +@compact(
    +    w1 = Dense(1 => 128),               # 256 parameters
    +    w2 = NamedTuple(
    +        1 = Dense(128 => 128),          # 16_512 parameters
    +        2 = Dense(128 => 128),          # 16_512 parameters
    +        3 = Dense(128 => 128),          # 16_512 parameters
    +    ),
    +    w3 = Dense(128 => 1),               # 129 parameters
    +    act = relu,
    +) do x
    +    embed = act.(w1(x))
    +    for w = w2
    +        embed = act.(w(embed))
    +    end
    +    out = w3(embed)
    +    return out
    +end       # Total: 49_921 parameters,
    +          #        plus 1 states.
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), model);
    +
    +julia> size(first(model(randn(n_in, 32), ps, st)))  # 1×32 Matrix as output.
    +(1, 32)
    +
    +julia> using Optimisers, Zygote
    +
    +julia> x_data = collect(-2.0f0:0.1f0:2.0f0)';
    +
    +julia> y_data = 2 .* x_data .- x_data .^ 3;
    +
    +julia> optim = Optimisers.setup(Adam(), ps);
    +
    +julia> loss_initial = sum(abs2, first(model(x_data, ps, st)) .- y_data);
    +
    +julia> for epoch in 1:1000
    +           loss, gs = Zygote.withgradient(
    +               ps -> sum(abs2, first(model(x_data, ps, st)) .- y_data), ps)
    +           Optimisers.update!(optim, ps, gs[1])
    +       end;
    +
    +julia> loss_final = sum(abs2, first(model(x_data, ps, st)) .- y_data);
    +
    +julia> loss_initial > loss_final
    +true

    You may also specify a name for the model, which will be used instead of the default printout, which gives a verbatim representation of the code used to construct the model:

    julia
    julia> model = @compact(w=rand(3), name="Linear(3 => 1)") do x
    +           @return sum(w .* x)
    +       end
    +Linear(3 => 1)      # 3 parameters

    This can be useful when using @compact to hierarchically construct complex models to be used inside a Chain.

    Type Stability

    If your input function f is type-stable but the generated model is not type stable, it should be treated as a bug. We will appreciate issues if you find such cases.

    Parameter Count

    Array Parameter don't print the number of parameters on the side. However, they do account for the total number of parameters printed at the bottom.

    source

    `,23))]),s("details",Q2,[s("summary",null,[i[277]||(i[277]=s("a",{id:"Lux.@init_fn",href:"#Lux.@init_fn"},[s("span",{class:"jlbinding"},"Lux.@init_fn")],-1)),i[278]||(i[278]=a()),l(e,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),i[279]||(i[279]=t(`
    julia
    @init_fn(fn, kind::Symbol = :parameter)

    Create an initializer function for a parameter or state to be used for in a Compact Lux Layer created using @compact.

    Arguments

    Examples

    julia
    julia> using Lux, Random
    +
    +julia> r = @compact(w=@init_fn(rng->randn32(rng, 3, 2)),
    +           b=@init_fn(rng->randn32(rng, 3), :state)) do x
    +           @return w * x .+ b
    +       end;
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), r);
    +
    +julia> size(ps.w)
    +(3, 2)
    +
    +julia> size(st.b)
    +(3,)
    +
    +julia> size(r([1, 2], ps, st)[1])
    +(3,)

    source

    `,7))]),s("details",g2,[s("summary",null,[i[280]||(i[280]=s("a",{id:"Lux.@non_trainable",href:"#Lux.@non_trainable"},[s("span",{class:"jlbinding"},"Lux.@non_trainable")],-1)),i[281]||(i[281]=a()),l(e,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),i[282]||(i[282]=t(`
    julia
    @non_trainable(x)

    Mark a value as non-trainable. This bypasses the regular checks and places the value into the state of the layer.

    Arguments

    Examples

    julia
    julia> using Lux, Random
    +
    +julia> r = @compact(w=ones(3), w_fixed=@non_trainable(rand(3))) do x
    +           @return sum(w .* x .+ w_fixed)
    +       end;
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), r);
    +
    +julia> size(ps.w)
    +(3,)
    +
    +julia> size(st.w_fixed)
    +(3,)
    +
    +julia> res, st_ = r([1, 2, 3], ps, st);
    +
    +julia> st_.w_fixed == st.w_fixed
    +true
    +
    +julia> res isa Number
    +true

    source

    `,7))]),i[298]||(i[298]=s("h2",{id:"miscellaneous",tabindex:"-1"},[a("Miscellaneous "),s("a",{class:"header-anchor",href:"#miscellaneous","aria-label":'Permalink to "Miscellaneous"'},"​")],-1)),s("details",m2,[s("summary",null,[i[283]||(i[283]=s("a",{id:"Lux.set_dispatch_doctor_preferences!",href:"#Lux.set_dispatch_doctor_preferences!"},[s("span",{class:"jlbinding"},"Lux.set_dispatch_doctor_preferences!")],-1)),i[284]||(i[284]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[285]||(i[285]=t(`
    julia
    set_dispatch_doctor_preferences!(mode::String)
    +set_dispatch_doctor_preferences!(; luxcore::String="disable", luxlib::String="disable")

    Set the dispatch doctor preference for LuxCore and LuxLib packages.

    mode can be "disable", "warn", or "error". For details on the different modes, see the DispatchDoctor.jl documentation.

    If the preferences are already set, then no action is taken. Otherwise the preference is set. For changes to take effect, the Julia session must be restarted.

    source

    `,5))])])}const L2=p(d,[["render",y2]]);export{C2 as __pageData,L2 as default}; diff --git a/previews/PR1023/assets/api_Lux_utilities.md.tnFESE9C.lean.js b/previews/PR1023/assets/api_Lux_utilities.md.tnFESE9C.lean.js new file mode 100644 index 0000000000..0246cab848 --- /dev/null +++ b/previews/PR1023/assets/api_Lux_utilities.md.tnFESE9C.lean.js @@ -0,0 +1,314 @@ +import{_ as p,c as n,j as s,a,G as l,a2 as t,B as r,o as h}from"./chunks/framework.DFwXuivk.js";const C2=JSON.parse('{"title":"Utilities","description":"","frontmatter":{},"headers":[],"relativePath":"api/Lux/utilities.md","filePath":"api/Lux/utilities.md","lastUpdated":null}'),d={name:"api/Lux/utilities.md"},k={class:"jldocstring custom-block"},o={class:"jldocstring custom-block"},T={class:"jldocstring custom-block"},Q={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},m={class:"jldocstring custom-block"},y={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"},c={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},u={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"46.681ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 20633.1 1199","aria-hidden":"true"},F={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},x={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"25.631ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 11329 1199","aria-hidden":"true"},f={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},C={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.161ex",role:"img",focusable:"false",viewBox:"0 -750 490 955","aria-hidden":"true"},L={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},b={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"6.664ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 2945.4 1000","aria-hidden":"true"},w={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},H={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.161ex",role:"img",focusable:"false",viewBox:"0 -750 490 955","aria-hidden":"true"},v={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},j={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"23.718ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 10483.3 1000","aria-hidden":"true"},D={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},B={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.448ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 640 453","aria-hidden":"true"},M={class:"jldocstring custom-block"},V={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},A={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.296ex",role:"img",focusable:"false",viewBox:"0 -810 490 1015","aria-hidden":"true"},Z={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},O={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"5.377ex",height:"1.995ex",role:"img",focusable:"false",viewBox:"0 -666 2376.6 882","aria-hidden":"true"},R={class:"jldocstring custom-block"},S={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},N={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.296ex",role:"img",focusable:"false",viewBox:"0 -810 490 1015","aria-hidden":"true"},P={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},z={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-1.469ex"},xmlns:"http://www.w3.org/2000/svg",width:"23.184ex",height:"4.07ex",role:"img",focusable:"false",viewBox:"0 -1149.5 10247.1 1799","aria-hidden":"true"},I={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},q={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"0.919ex",height:"1ex",role:"img",focusable:"false",viewBox:"0 -431 406 442","aria-hidden":"true"},G={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},X={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.161ex",role:"img",focusable:"false",viewBox:"0 -750 490 955","aria-hidden":"true"},J={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},U={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"6.664ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 2945.4 1000","aria-hidden":"true"},W={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},K={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.161ex",role:"img",focusable:"false",viewBox:"0 -750 490 955","aria-hidden":"true"},Y={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},$={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"34.539ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 15266.3 1000","aria-hidden":"true"},_={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},s1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.448ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 640 453","aria-hidden":"true"},i1={class:"jldocstring custom-block"},a1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},t1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.308ex"},xmlns:"http://www.w3.org/2000/svg",width:"28.659ex",height:"5.747ex",role:"img",focusable:"false",viewBox:"0 -1520 12667.4 2540","aria-hidden":"true"},e1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},l1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.448ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 640 453","aria-hidden":"true"},n1={class:"jldocstring custom-block"},h1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},p1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.296ex",role:"img",focusable:"false",viewBox:"0 -810 490 1015","aria-hidden":"true"},r1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},d1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.229ex",height:"1.486ex",role:"img",focusable:"false",viewBox:"0 -441 543 657","aria-hidden":"true"},k1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},o1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.489ex"},xmlns:"http://www.w3.org/2000/svg",width:"5.377ex",height:"1.995ex",role:"img",focusable:"false",viewBox:"0 -666 2376.6 882","aria-hidden":"true"},T1={class:"jldocstring custom-block"},Q1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},g1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"20.065ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 8868.8 1199","aria-hidden":"true"},m1={class:"jldocstring custom-block"},y1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},E1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.148ex"},xmlns:"http://www.w3.org/2000/svg",width:"40.607ex",height:"5.428ex",role:"img",focusable:"false",viewBox:"0 -1449.5 17948.3 2399","aria-hidden":"true"},c1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},u1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.023ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.005ex",height:"1.645ex",role:"img",focusable:"false",viewBox:"0 -717 444 727","aria-hidden":"true"},F1={class:"jldocstring custom-block"},x1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},f1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.296ex",role:"img",focusable:"false",viewBox:"0 -810 490 1015","aria-hidden":"true"},C1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},L1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"1.464ex",role:"img",focusable:"false",viewBox:"0 -442 490 647","aria-hidden":"true"},b1={class:"jldocstring custom-block"},w1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},H1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"12.333ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 5451.1 1199","aria-hidden":"true"},v1={class:"jldocstring custom-block"},j1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},D1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-1.469ex"},xmlns:"http://www.w3.org/2000/svg",width:"14.515ex",height:"4.07ex",role:"img",focusable:"false",viewBox:"0 -1149.5 6415.7 1799","aria-hidden":"true"},B1={class:"jldocstring custom-block"},M1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},V1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-1.469ex"},xmlns:"http://www.w3.org/2000/svg",width:"32.253ex",height:"4.07ex",role:"img",focusable:"false",viewBox:"0 -1149.5 14255.9 1799","aria-hidden":"true"},A1={class:"jldocstring custom-block"},Z1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},O1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"2.296ex",role:"img",focusable:"false",viewBox:"0 -810 490 1015","aria-hidden":"true"},R1={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},S1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.109ex",height:"1.464ex",role:"img",focusable:"false",viewBox:"0 -442 490 647","aria-hidden":"true"},N1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},P1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"18.723ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 8275.6 1199","aria-hidden":"true"},z1={class:"jldocstring custom-block"},I1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},q1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"40.607ex",height:"2.791ex",role:"img",focusable:"false",viewBox:"0 -883.9 17948.2 1233.4","aria-hidden":"true"},G1={class:"jldocstring custom-block"},X1={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},J1={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"21.053ex",height:"2.791ex",role:"img",focusable:"false",viewBox:"0 -883.9 9305.3 1233.4","aria-hidden":"true"},U1={class:"jldocstring custom-block"},W1={class:"jldocstring custom-block"},K1={class:"jldocstring custom-block"},Y1={class:"jldocstring custom-block"},$1={class:"jldocstring custom-block"},_1={class:"jldocstring custom-block"},s2={class:"jldocstring custom-block"},i2={class:"jldocstring custom-block"},a2={class:"jldocstring custom-block"},t2={class:"jldocstring custom-block"},e2={class:"jldocstring custom-block"},l2={class:"jldocstring custom-block"},n2={class:"jldocstring custom-block"},h2={class:"jldocstring custom-block"},p2={class:"jldocstring custom-block"},r2={class:"jldocstring custom-block"},d2={class:"jldocstring custom-block"},k2={class:"jldocstring custom-block"},o2={class:"jldocstring custom-block"},T2={class:"jldocstring custom-block"},Q2={class:"jldocstring custom-block"},g2={class:"jldocstring custom-block"},m2={class:"jldocstring custom-block"};function y2(E2,i,c2,u2,F2,x2){const e=r("Badge");return h(),n("div",null,[i[286]||(i[286]=s("h1",{id:"utilities",tabindex:"-1"},[a("Utilities "),s("a",{class:"header-anchor",href:"#utilities","aria-label":'Permalink to "Utilities"'},"​")],-1)),i[287]||(i[287]=s("h2",{id:"Training-API",tabindex:"-1"},[a("Training API "),s("a",{class:"header-anchor",href:"#Training-API","aria-label":'Permalink to "Training API {#Training-API}"'},"​")],-1)),i[288]||(i[288]=s("p",null,[a("Helper Functions making it easier to train "),s("code",null,"Lux.jl"),a(" models.")],-1)),i[289]||(i[289]=s("p",null,"Training is meant to be simple and provide extremely basic functionality. We provide basic building blocks which can be seamlessly composed to create complex training pipelines.",-1)),s("details",k,[s("summary",null,[i[0]||(i[0]=s("a",{id:"Lux.Training.TrainState",href:"#Lux.Training.TrainState"},[s("span",{class:"jlbinding"},"Lux.Training.TrainState")],-1)),i[1]||(i[1]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[2]||(i[2]=t('
    julia
    TrainState

    Training State containing:

    Internal fields:

    Warning

    Constructing this object directly shouldn't be considered a stable API. Use the version with the Optimisers API.

    source

    ',7))]),s("details",o,[s("summary",null,[i[3]||(i[3]=s("a",{id:"Lux.Training.compute_gradients",href:"#Lux.Training.compute_gradients"},[s("span",{class:"jlbinding"},"Lux.Training.compute_gradients")],-1)),i[4]||(i[4]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[5]||(i[5]=t(`
    julia
    compute_gradients(ad::AbstractADType, objective_function::Function, data,
    +    ts::TrainState)

    Compute the gradients of the objective function wrt parameters stored in ts.

    Backends & AD Packages

    Supported BackendsPackages Needed
    AutoZygoteZygote.jl
    AutoReverseDiff(; compile)ReverseDiff.jl
    AutoTrackerTracker.jl
    AutoEnzymeEnzyme.jl

    Arguments

    Return

    A 4-Tuple containing:

    Known Limitations

    Aliased Gradients

    grads returned by this function might be aliased by the implementation of the gradient backend. For example, if you cache the grads from step i, the new gradients returned in step i + 1 might be aliased by the old gradients. If you want to prevent this, simply use copy(grads) or deepcopy(grads) to make a copy of the gradients.

    source

    `,13))]),s("details",T,[s("summary",null,[i[6]||(i[6]=s("a",{id:"Lux.Training.apply_gradients",href:"#Lux.Training.apply_gradients"},[s("span",{class:"jlbinding"},"Lux.Training.apply_gradients")],-1)),i[7]||(i[7]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[8]||(i[8]=t('
    julia
    apply_gradients(ts::TrainState, grads)

    Update the parameters stored in ts using the gradients grads.

    Arguments

    Returns

    Updated TrainState object.

    source

    ',7))]),s("details",Q,[s("summary",null,[i[9]||(i[9]=s("a",{id:"Lux.Training.apply_gradients!",href:"#Lux.Training.apply_gradients!"},[s("span",{class:"jlbinding"},"Lux.Training.apply_gradients!")],-1)),i[10]||(i[10]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[11]||(i[11]=t('
    julia
    apply_gradients!(ts::TrainState, grads)

    Update the parameters stored in ts using the gradients grads. This is an inplace version of apply_gradients.

    Arguments

    Returns

    Updated TrainState object.

    source

    ',7))]),s("details",g,[s("summary",null,[i[12]||(i[12]=s("a",{id:"Lux.Training.single_train_step",href:"#Lux.Training.single_train_step"},[s("span",{class:"jlbinding"},"Lux.Training.single_train_step")],-1)),i[13]||(i[13]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[14]||(i[14]=t('
    julia
    single_train_step(backend, obj_fn::F, data, ts::TrainState)

    Perform a single training step. Computes the gradients using compute_gradients and updates the parameters using apply_gradients. All backends supported via compute_gradients are supported here.

    In most cases you should use single_train_step! instead of this function.

    Return

    Returned values are the same as compute_gradients.

    source

    ',6))]),s("details",m,[s("summary",null,[i[15]||(i[15]=s("a",{id:"Lux.Training.single_train_step!",href:"#Lux.Training.single_train_step!"},[s("span",{class:"jlbinding"},"Lux.Training.single_train_step!")],-1)),i[16]||(i[16]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[17]||(i[17]=t('
    julia
    single_train_step!(backend, obj_fn::F, data, ts::TrainState)

    Perform a single training step. Computes the gradients using compute_gradients and updates the parameters using apply_gradients!. All backends supported via compute_gradients are supported here.

    Return

    Returned values are the same as compute_gradients. Note that despite the !, only the parameters in ts are updated inplace. Users should be using the returned ts object for further training steps, else there is no caching and performance will be suboptimal (and absolutely terrible for backends like AutoReactant).

    source

    ',5))]),i[290]||(i[290]=t('

    Loss Functions

    Loss Functions Objects take 2 forms of inputs:

    1. and y where is the predicted output and y is the target output.

    2. model, ps, st, (x, y) where model is the model, ps are the parameters, st are the states and (x, y) are the input and target pair. Then it returns the loss, updated states, and an empty named tuple. This makes them compatible with the Training API.

    Warning

    When using ChainRules.jl compatible AD (like Zygote), we only compute the gradients wrt the inputs and drop any gradients wrt the targets.

    ',4)),s("details",y,[s("summary",null,[i[18]||(i[18]=s("a",{id:"Lux.GenericLossFunction",href:"#Lux.GenericLossFunction"},[s("span",{class:"jlbinding"},"Lux.GenericLossFunction")],-1)),i[19]||(i[19]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[20]||(i[20]=t(`
    julia
    GenericLossFunction(loss_fn; agg = mean)

    Takes any function loss_fn that maps 2 number inputs to a single number output. Additionally, array inputs are efficiently broadcasted and aggregated using agg.

    julia
    julia> mseloss = GenericLossFunction((ŷ, y) -> abs2(ŷ - y));
    +
    +julia> y_model = [1.1, 1.9, 3.1];
    +
    +julia> mseloss(y_model, 1:3)  0.01
    +true

    Special Note

    This function takes any of the LossFunctions.jl public functions into the Lux Losses API with efficient aggregation.

    source

    `,6))]),s("details",E,[s("summary",null,[i[21]||(i[21]=s("a",{id:"Lux.BinaryCrossEntropyLoss",href:"#Lux.BinaryCrossEntropyLoss"},[s("span",{class:"jlbinding"},"Lux.BinaryCrossEntropyLoss")],-1)),i[22]||(i[22]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[51]||(i[51]=t(`
    julia
    BinaryCrossEntropyLoss(; agg = mean, epsilon = nothing,
    +    label_smoothing::Union{Nothing, Real}=nothing,
    +    logits::Union{Bool, Val}=Val(false))

    Binary Cross Entropy Loss with optional label smoothing and fused logit computation.

    Returns the binary cross entropy loss computed as:

    `,4)),s("mjx-container",c,[(h(),n("svg",u,i[23]||(i[23]=[t('',1)]))),i[24]||(i[24]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mo",null,"∗"),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"+"),s("mi",null,"ϵ"),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mo",null,"−"),s("mo",{stretchy:"false"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mo",{stretchy:"false"},")"),s("mo",null,"∗"),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"+"),s("mi",null,"ϵ"),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[52]||(i[52]=s("ul",null,[s("li",null,[a("If "),s("code",null,"logits"),a(" is "),s("code",null,"true"),a(" or "),s("code",null,"Val(true)"),a(":")])],-1)),s("mjx-container",F,[(h(),n("svg",x,i[25]||(i[25]=[t('',1)]))),i[26]||(i[26]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",{stretchy:"false"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mo",{stretchy:"false"},")"),s("mo",null,"∗"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"−"),s("mi",null,"l"),s("mi",null,"o"),s("mi",null,"g"),s("mi",null,"σ"),s("mo",{stretchy:"false"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",{stretchy:"false"},")"),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),s("p",null,[i[33]||(i[33]=a("The value of ")),s("mjx-container",f,[(h(),n("svg",C,i[27]||(i[27]=[t('',1)]))),i[28]||(i[28]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])])])],-1))]),i[34]||(i[34]=a(" is computed using label smoothing. If ")),i[35]||(i[35]=s("code",null,"label_smoothing",-1)),i[36]||(i[36]=a(" is ")),i[37]||(i[37]=s("code",null,"nothing",-1)),i[38]||(i[38]=a(", then no label smoothing is applied. If ")),i[39]||(i[39]=s("code",null,"label_smoothing",-1)),i[40]||(i[40]=a(" is a real number ")),s("mjx-container",L,[(h(),n("svg",b,i[29]||(i[29]=[t('',1)]))),i[30]||(i[30]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mo",null,"∈"),s("mo",{stretchy:"false"},"["),s("mn",null,"0"),s("mo",null,","),s("mn",null,"1"),s("mo",{stretchy:"false"},"]")])],-1))]),i[41]||(i[41]=a(", then the value of ")),s("mjx-container",w,[(h(),n("svg",H,i[31]||(i[31]=[t('',1)]))),i[32]||(i[32]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])])])],-1))]),i[42]||(i[42]=a(" is:"))]),s("mjx-container",v,[(h(),n("svg",j,i[43]||(i[43]=[t('',1)]))),i[44]||(i[44]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mo",null,"="),s("mo",{stretchy:"false"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mi",null,"α"),s("mo",{stretchy:"false"},")"),s("mo",null,"∗"),s("mi",null,"y"),s("mo",null,"+"),s("mi",null,"α"),s("mo",null,"∗"),s("mn",null,"0.5")])],-1))]),s("p",null,[i[47]||(i[47]=a("where ")),s("mjx-container",D,[(h(),n("svg",B,i[45]||(i[45]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D6FC",d:"M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z",style:{"stroke-width":"3"}})])])],-1)]))),i[46]||(i[46]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"α")])],-1))]),i[48]||(i[48]=a(" is the value of ")),i[49]||(i[49]=s("code",null,"label_smoothing",-1)),i[50]||(i[50]=a("."))]),i[53]||(i[53]=t(`

    Extended Help

    Example

    julia
    julia> bce = BinaryCrossEntropyLoss();
    +
    +julia> y_bin = Bool[1, 0, 1];
    +
    +julia> y_model = Float32[2, -1, pi]
    +3-element Vector{Float32}:
    +  2.0
    + -1.0
    +  3.1415927
    +
    +julia> logitbce = BinaryCrossEntropyLoss(; logits=Val(true));
    +
    +julia> logitbce(y_model, y_bin)  0.160832f0
    +true
    +
    +julia> bce(sigmoid.(y_model), y_bin)  0.16083185f0
    +true
    +
    +julia> bce_ls = BinaryCrossEntropyLoss(label_smoothing=0.1);
    +
    +julia> bce_ls(sigmoid.(y_model), y_bin) > bce(sigmoid.(y_model), y_bin)
    +true
    +
    +julia> logitbce_ls = BinaryCrossEntropyLoss(label_smoothing=0.1, logits=Val(true));
    +
    +julia> logitbce_ls(y_model, y_bin) > logitbce(y_model, y_bin)
    +true

    source

    `,4))]),s("details",M,[s("summary",null,[i[54]||(i[54]=s("a",{id:"Lux.BinaryFocalLoss",href:"#Lux.BinaryFocalLoss"},[s("span",{class:"jlbinding"},"Lux.BinaryFocalLoss")],-1)),i[55]||(i[55]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[66]||(i[66]=t('
    julia
    BinaryFocalLoss(; gamma = 2, agg = mean, epsilon = nothing)
    ',1)),s("p",null,[i[58]||(i[58]=a("Return the binary focal loss [1]. The model input, ")),s("mjx-container",V,[(h(),n("svg",A,i[56]||(i[56]=[t('',1)]))),i[57]||(i[57]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])])])],-1))]),i[59]||(i[59]=a(", is expected to be normalized (i.e. softmax output)."))]),s("p",null,[i[62]||(i[62]=a("For ")),s("mjx-container",Z,[(h(),n("svg",O,i[60]||(i[60]=[t('',1)]))),i[61]||(i[61]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"γ"),s("mo",null,"="),s("mn",null,"0")])],-1))]),i[63]||(i[63]=a(" this is equivalent to ")),i[64]||(i[64]=s("a",{href:"/previews/PR1023/api/Lux/utilities#Lux.BinaryCrossEntropyLoss"},[s("code",null,"BinaryCrossEntropyLoss")],-1)),i[65]||(i[65]=a("."))]),i[67]||(i[67]=t(`

    Example

    julia
    julia> y = [0  1  0
    +            1  0  1];
    +
    +julia> ŷ = [0.268941  0.5  0.268941
    +            0.731059  0.5  0.731059];
    +
    +julia> BinaryFocalLoss()(ŷ, y)  0.0728675615927385
    +true
    +
    +julia> BinaryFocalLoss(gamma=0)(ŷ, y)  BinaryCrossEntropyLoss()(ŷ, y)
    +true

    References

    [1] Lin, Tsung-Yi, et al. "Focal loss for dense object detection." Proceedings of the IEEE international conference on computer vision. 2017.

    source

    `,5))]),s("details",R,[s("summary",null,[i[68]||(i[68]=s("a",{id:"Lux.CrossEntropyLoss",href:"#Lux.CrossEntropyLoss"},[s("span",{class:"jlbinding"},"Lux.CrossEntropyLoss")],-1)),i[69]||(i[69]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[111]||(i[111]=t(`
    julia
    CrossEntropyLoss(; agg=mean, epsilon=nothing, dims=1,
    +    label_smoothing::Union{Nothing, Real}=nothing)
    `,1)),s("p",null,[i[72]||(i[72]=a("Return the cross entropy loss which is used in multi-class classification tasks. The input, ")),s("mjx-container",S,[(h(),n("svg",N,i[70]||(i[70]=[t('',1)]))),i[71]||(i[71]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])])])],-1))]),i[73]||(i[73]=a(", is expected to be normalized (i.e. ")),i[74]||(i[74]=s("code",null,"softmax",-1)),i[75]||(i[75]=a(" output) if ")),i[76]||(i[76]=s("code",null,"logits",-1)),i[77]||(i[77]=a(" is ")),i[78]||(i[78]=s("code",null,"false",-1)),i[79]||(i[79]=a(" or ")),i[80]||(i[80]=s("code",null,"Val(false)",-1)),i[81]||(i[81]=a("."))]),i[112]||(i[112]=s("p",null,"The loss is calculated as:",-1)),s("mjx-container",P,[(h(),n("svg",z,i[82]||(i[82]=[t('',1)]))),i[83]||(i[83]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",null,"−"),s("mo",{"data-mjx-texclass":"OP"},"∑"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mo",{stretchy:"false"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"+"),s("mi",null,"ϵ"),s("mo",{stretchy:"false"},")"),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),s("p",null,[i[92]||(i[92]=a("where ")),s("mjx-container",I,[(h(),n("svg",q,i[84]||(i[84]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D716",d:"M227 -11Q149 -11 95 41T40 174Q40 262 87 322Q121 367 173 396T287 430Q289 431 329 431H367Q382 426 382 411Q382 385 341 385H325H312Q191 385 154 277L150 265H327Q340 256 340 246Q340 228 320 219H138V217Q128 187 128 143Q128 77 160 52T231 26Q258 26 284 36T326 57T343 68Q350 68 354 58T358 39Q358 36 357 35Q354 31 337 21T289 0T227 -11Z",style:{"stroke-width":"3"}})])])],-1)]))),i[85]||(i[85]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"ϵ")])],-1))]),i[93]||(i[93]=a(" is added for numerical stability. The value of ")),s("mjx-container",G,[(h(),n("svg",X,i[86]||(i[86]=[t('',1)]))),i[87]||(i[87]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])])])],-1))]),i[94]||(i[94]=a(" is computed using label smoothing. If ")),i[95]||(i[95]=s("code",null,"label_smoothing",-1)),i[96]||(i[96]=a(" is ")),i[97]||(i[97]=s("code",null,"nothing",-1)),i[98]||(i[98]=a(", then no label smoothing is applied. If ")),i[99]||(i[99]=s("code",null,"label_smoothing",-1)),i[100]||(i[100]=a(" is a real number ")),s("mjx-container",J,[(h(),n("svg",U,i[88]||(i[88]=[t('',1)]))),i[89]||(i[89]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mo",null,"∈"),s("mo",{stretchy:"false"},"["),s("mn",null,"0"),s("mo",null,","),s("mn",null,"1"),s("mo",{stretchy:"false"},"]")])],-1))]),i[101]||(i[101]=a(", then the value of ")),s("mjx-container",W,[(h(),n("svg",K,i[90]||(i[90]=[t('',1)]))),i[91]||(i[91]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])])])],-1))]),i[102]||(i[102]=a(" is calculated as:"))]),s("mjx-container",Y,[(h(),n("svg",$,i[103]||(i[103]=[t('',1)]))),i[104]||(i[104]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"~")])]),s("mo",null,"="),s("mo",{stretchy:"false"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mi",null,"α"),s("mo",{stretchy:"false"},")"),s("mo",null,"∗"),s("mi",null,"y"),s("mo",null,"+"),s("mi",null,"α"),s("mo",null,"∗"),s("mtext",null,"size along dim")])],-1))]),s("p",null,[i[107]||(i[107]=a("where ")),s("mjx-container",_,[(h(),n("svg",s1,i[105]||(i[105]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D6FC",d:"M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z",style:{"stroke-width":"3"}})])])],-1)]))),i[106]||(i[106]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"α")])],-1))]),i[108]||(i[108]=a(" is the value of ")),i[109]||(i[109]=s("code",null,"label_smoothing",-1)),i[110]||(i[110]=a("."))]),i[113]||(i[113]=t(`

    Extended Help

    Example

    julia
    julia> y = [1  0  0  0  1
    +            0  1  0  1  0
    +            0  0  1  0  0]
    +3×5 Matrix{Int64}:
    + 1  0  0  0  1
    + 0  1  0  1  0
    + 0  0  1  0  0
    +
    +julia> y_model = softmax(reshape(-7:7, 3, 5) .* 1f0)
    +3×5 Matrix{Float32}:
    + 0.0900306  0.0900306  0.0900306  0.0900306  0.0900306
    + 0.244728   0.244728   0.244728   0.244728   0.244728
    + 0.665241   0.665241   0.665241   0.665241   0.665241
    +
    +julia> CrossEntropyLoss()(y_model, y)  1.6076053f0
    +true
    +
    +julia> 5 * 1.6076053f0 CrossEntropyLoss(; agg=sum)(y_model, y)
    +true
    +
    +julia> CrossEntropyLoss(label_smoothing=0.15)(y_model, y)  1.5776052f0
    +true

    source

    `,4))]),s("details",i1,[s("summary",null,[i[114]||(i[114]=s("a",{id:"Lux.DiceCoeffLoss",href:"#Lux.DiceCoeffLoss"},[s("span",{class:"jlbinding"},"Lux.DiceCoeffLoss")],-1)),i[115]||(i[115]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[124]||(i[124]=t('
    julia
    DiceCoeffLoss(; smooth = true, agg = mean)

    Return the Dice Coefficient loss [1] which is used in segmentation tasks. The dice coefficient is similar to the F1_score. Loss calculated as:

    ',2)),s("mjx-container",a1,[(h(),n("svg",t1,i[116]||(i[116]=[t('',1)]))),i[117]||(i[117]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mi",null,"a"),s("mi",null,"g"),s("mi",null,"g"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mfrac",null,[s("mrow",null,[s("mn",null,"2"),s("mo",{"data-mjx-texclass":"OP"},"∑"),s("mi",null,"y"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"+"),s("mi",null,"α")]),s("mrow",null,[s("mo",{"data-mjx-texclass":"OP"},"∑"),s("msup",null,[s("mi",null,"y"),s("mn",null,"2")]),s("mo",null,"+"),s("mo",{"data-mjx-texclass":"OP"},"∑"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mn",null,"2")]),s("mo",null,"+"),s("mi",null,"α")])]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),s("p",null,[i[120]||(i[120]=a("where ")),s("mjx-container",e1,[(h(),n("svg",l1,i[118]||(i[118]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D6FC",d:"M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z",style:{"stroke-width":"3"}})])])],-1)]))),i[119]||(i[119]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"α")])],-1))]),i[121]||(i[121]=a(" is the smoothing factor (")),i[122]||(i[122]=s("code",null,"smooth",-1)),i[123]||(i[123]=a(")."))]),i[125]||(i[125]=t(`

    Example

    julia
    julia> y_pred = [1.1, 2.1, 3.1];
    +
    +julia> DiceCoeffLoss()(y_pred, 1:3)   0.000992391663909964
    +true
    +
    +julia> 1 - DiceCoeffLoss()(y_pred, 1:3)   0.99900760833609
    +true
    +
    +julia> DiceCoeffLoss()(reshape(y_pred, 3, 1), reshape(1:3, 3, 1))  0.000992391663909964
    +true

    References

    [1] Milletari, Fausto, Nassir Navab, and Seyed-Ahmad Ahmadi. "V-net: Fully convolutional neural networks for volumetric medical image segmentation." 2016 fourth international conference on 3D vision (3DV). Ieee, 2016.

    source

    `,5))]),s("details",n1,[s("summary",null,[i[126]||(i[126]=s("a",{id:"Lux.FocalLoss",href:"#Lux.FocalLoss"},[s("span",{class:"jlbinding"},"Lux.FocalLoss")],-1)),i[127]||(i[127]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[143]||(i[143]=t('
    julia
    FocalLoss(; gamma = 2, dims = 1, agg = mean, epsilon = nothing)
    ',1)),s("p",null,[i[130]||(i[130]=a("Return the focal loss [1] which can be used in classification tasks with highly imbalanced classes. It down-weights well-classified examples and focuses on hard examples. The input, ")),s("mjx-container",h1,[(h(),n("svg",p1,i[128]||(i[128]=[t('',1)]))),i[129]||(i[129]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])])])],-1))]),i[131]||(i[131]=a(", is expected to be normalized (i.e. ")),i[132]||(i[132]=s("code",null,"softmax",-1)),i[133]||(i[133]=a(" output)."))]),s("p",null,[i[138]||(i[138]=a("The modulating factor ")),s("mjx-container",r1,[(h(),n("svg",d1,i[134]||(i[134]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D6FE",d:"M31 249Q11 249 11 258Q11 275 26 304T66 365T129 418T206 441Q233 441 239 440Q287 429 318 386T371 255Q385 195 385 170Q385 166 386 166L398 193Q418 244 443 300T486 391T508 430Q510 431 524 431H537Q543 425 543 422Q543 418 522 378T463 251T391 71Q385 55 378 6T357 -100Q341 -165 330 -190T303 -216Q286 -216 286 -188Q286 -138 340 32L346 51L347 69Q348 79 348 100Q348 257 291 317Q251 355 196 355Q148 355 108 329T51 260Q49 251 47 251Q45 249 31 249Z",style:{"stroke-width":"3"}})])])],-1)]))),i[135]||(i[135]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"γ")])],-1))]),i[139]||(i[139]=a(", controls the down-weighting strength. For ")),s("mjx-container",k1,[(h(),n("svg",o1,i[136]||(i[136]=[t('',1)]))),i[137]||(i[137]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"γ"),s("mo",null,"="),s("mn",null,"0")])],-1))]),i[140]||(i[140]=a(" this is equivalent to ")),i[141]||(i[141]=s("a",{href:"/previews/PR1023/api/Lux/utilities#Lux.CrossEntropyLoss"},[s("code",null,"CrossEntropyLoss")],-1)),i[142]||(i[142]=a("."))]),i[144]||(i[144]=t(`

    Example

    julia
    julia> y = [1  0  0  0  1
    +            0  1  0  1  0
    +            0  0  1  0  0]
    +3×5 Matrix{Int64}:
    + 1  0  0  0  1
    + 0  1  0  1  0
    + 0  0  1  0  0
    +
    +julia> ŷ = softmax(reshape(-7:7, 3, 5) .* 1f0)
    +3×5 Matrix{Float32}:
    + 0.0900306  0.0900306  0.0900306  0.0900306  0.0900306
    + 0.244728   0.244728   0.244728   0.244728   0.244728
    + 0.665241   0.665241   0.665241   0.665241   0.665241
    +
    +julia> FocalLoss()(ŷ, y)  1.1277556f0
    +true

    References

    [1] Lin, Tsung-Yi, et al. "Focal loss for dense object detection." Proceedings of the IEEE international conference on computer vision. 2017.

    source

    `,5))]),s("details",T1,[s("summary",null,[i[145]||(i[145]=s("a",{id:"Lux.HingeLoss",href:"#Lux.HingeLoss"},[s("span",{class:"jlbinding"},"Lux.HingeLoss")],-1)),i[146]||(i[146]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[149]||(i[149]=t('
    julia
    HingeLoss(; agg = mean)

    Return the hinge loss loss given the prediction and true labels y (containing 1 or -1); calculated as:

    ',2)),s("mjx-container",Q1,[(h(),n("svg",g1,i[147]||(i[147]=[t('',1)]))),i[148]||(i[148]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",{"data-mjx-texclass":"OP",movablelimits:"true"},"max"),s("mo",{stretchy:"false"},"("),s("mn",null,"0"),s("mo",null,","),s("mn",null,"1"),s("mo",null,"−"),s("mi",null,"y"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",{stretchy:"false"},")"),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[150]||(i[150]=t(`

    Usually used with classifiers like Support Vector Machines.

    Example

    julia
    julia> loss = HingeLoss();
    +
    +julia> y_true = [1, -1, 1, 1];
    +
    +julia> y_pred = [0.1, 0.3, 1, 1.5];
    +
    +julia> loss(y_pred, y_true)  0.55
    +true

    source

    `,4))]),s("details",m1,[s("summary",null,[i[151]||(i[151]=s("a",{id:"Lux.HuberLoss",href:"#Lux.HuberLoss"},[s("span",{class:"jlbinding"},"Lux.HuberLoss")],-1)),i[152]||(i[152]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[161]||(i[161]=t('
    julia
    HuberLoss(; delta = 1, agg = mean)

    Returns the Huber loss, calculated as:

    ',2)),s("mjx-container",y1,[(h(),n("svg",E1,i[153]||(i[153]=[t('',1)]))),i[154]||(i[154]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mi",null,"L"),s("mo",null,"="),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"{"),s("mtable",{columnalign:"left left",columnspacing:"1em",rowspacing:".2em"},[s("mtr",null,[s("mtd",null,[s("mn",null,"0.5"),s("mo",null,"∗"),s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mi",null,"y"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("msup",null,[s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mn",null,"2")])]),s("mtd",null,[s("mtext",null,"if "),s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mi",null,"y"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mo",null,"≤"),s("mi",null,"δ")])]),s("mtr",null,[s("mtd",null,[s("mi",null,"δ"),s("mo",null,"∗"),s("mo",{stretchy:"false"},"("),s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mi",null,"y"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),s("mo",null,"−"),s("mn",null,"0.5"),s("mo",null,"∗"),s("mi",null,"δ"),s("mo",{stretchy:"false"},")")]),s("mtd",null,[s("mtext",null,"otherwise")])])]),s("mo",{"data-mjx-texclass":"CLOSE",fence:"true",stretchy:"true",symmetric:"true"})])])],-1))]),s("p",null,[i[157]||(i[157]=a("where ")),s("mjx-container",c1,[(h(),n("svg",u1,i[155]||(i[155]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D6FF",d:"M195 609Q195 656 227 686T302 717Q319 716 351 709T407 697T433 690Q451 682 451 662Q451 644 438 628T403 612Q382 612 348 641T288 671T249 657T235 628Q235 584 334 463Q401 379 401 292Q401 169 340 80T205 -10H198Q127 -10 83 36T36 153Q36 286 151 382Q191 413 252 434Q252 435 245 449T230 481T214 521T201 566T195 609ZM112 130Q112 83 136 55T204 27Q233 27 256 51T291 111T309 178T316 232Q316 267 309 298T295 344T269 400L259 396Q215 381 183 342T137 256T118 179T112 130Z",style:{"stroke-width":"3"}})])])],-1)]))),i[156]||(i[156]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"δ")])],-1))]),i[158]||(i[158]=a(" is the ")),i[159]||(i[159]=s("code",null,"delta",-1)),i[160]||(i[160]=a(" parameter."))]),i[162]||(i[162]=t(`

    Example

    julia
    julia> y_model = [1.1, 2.1, 3.1];
    +
    +julia> HuberLoss()(y_model, 1:3)  0.005000000000000009
    +true
    +
    +julia> HuberLoss(delta=0.05)(y_model, 1:3)  0.003750000000000005
    +true

    source

    `,3))]),s("details",F1,[s("summary",null,[i[163]||(i[163]=s("a",{id:"Lux.KLDivergenceLoss",href:"#Lux.KLDivergenceLoss"},[s("span",{class:"jlbinding"},"Lux.KLDivergenceLoss")],-1)),i[164]||(i[164]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[172]||(i[172]=t('
    julia
    KLDivergenceLoss(; dims = 1, agg = mean, epsilon = nothing, label_smoothing = nothing)
    ',1)),s("p",null,[i[169]||(i[169]=a("Return the Kullback-Leibler Divergence loss between the predicted distribution ")),s("mjx-container",x1,[(h(),n("svg",f1,i[165]||(i[165]=[t('',1)]))),i[166]||(i[166]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])])])],-1))]),i[170]||(i[170]=a(" and the true distribution ")),s("mjx-container",C1,[(h(),n("svg",L1,i[167]||(i[167]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D466",d:"M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z",style:{"stroke-width":"3"}})])])],-1)]))),i[168]||(i[168]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"y")])],-1))]),i[171]||(i[171]=a(":"))]),i[173]||(i[173]=t(`

    The KL divergence is a measure of how much one probability distribution is different from the other. It is always non-negative, and zero only when both the distributions are equal.

    For epsilon and label_smoothing, see CrossEntropyLoss.

    Example

    julia
    julia> p1 = [1 0; 0 1]
    +2×2 Matrix{Int64}:
    + 1  0
    + 0  1
    +
    +julia> p2 = fill(0.5, 2, 2)
    +2×2 Matrix{Float64}:
    + 0.5  0.5
    + 0.5  0.5
    +
    +julia> KLDivergenceLoss()(p2, p1)  log(2)
    +true
    +
    +julia> KLDivergenceLoss(; agg=sum)(p2, p1)  2 * log(2)
    +true
    +
    +julia> KLDivergenceLoss(; epsilon=0)(p2, p2)
    +0.0
    +
    +julia> KLDivergenceLoss(; epsilon=0)(p1, p2)
    +Inf

    source

    `,5))]),s("details",b1,[s("summary",null,[i[174]||(i[174]=s("a",{id:"Lux.MAELoss",href:"#Lux.MAELoss"},[s("span",{class:"jlbinding"},"Lux.MAELoss")],-1)),i[175]||(i[175]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[178]||(i[178]=t('
    julia
    MAELoss(; agg = mean)

    Returns the loss corresponding to mean absolute error:

    ',2)),s("mjx-container",w1,[(h(),n("svg",H1,i[176]||(i[176]=[t('',1)]))),i[177]||(i[177]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"|"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"−"),s("mi",null,"y"),s("mo",{"data-mjx-texclass":"CLOSE"},"|")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[179]||(i[179]=t(`

    Example

    julia
    julia> loss = MAELoss();
    +
    +julia> y_model = [1.1, 1.9, 3.1];
    +
    +julia> loss(y_model, 1:3)  0.1
    +true

    source

    `,3))]),s("details",v1,[s("summary",null,[i[180]||(i[180]=s("a",{id:"Lux.MSELoss",href:"#Lux.MSELoss"},[s("span",{class:"jlbinding"},"Lux.MSELoss")],-1)),i[181]||(i[181]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[184]||(i[184]=t('
    julia
    MSELoss(; agg = mean)

    Returns the loss corresponding to mean squared error:

    ',2)),s("mjx-container",j1,[(h(),n("svg",D1,i[182]||(i[182]=[t('',1)]))),i[183]||(i[183]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("msup",null,[s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"−"),s("mi",null,"y"),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mn",null,"2")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[185]||(i[185]=t(`

    Example

    julia
    julia> loss = MSELoss();
    +
    +julia> y_model = [1.1, 1.9, 3.1];
    +
    +julia> loss(y_model, 1:3)  0.01
    +true

    source

    `,3))]),s("details",B1,[s("summary",null,[i[186]||(i[186]=s("a",{id:"Lux.MSLELoss",href:"#Lux.MSLELoss"},[s("span",{class:"jlbinding"},"Lux.MSLELoss")],-1)),i[187]||(i[187]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[190]||(i[190]=t('
    julia
    MSLELoss(; agg = mean, epsilon = nothing)

    Returns the loss corresponding to mean squared logarithmic error:

    ',2)),s("mjx-container",M1,[(h(),n("svg",V1,i[188]||(i[188]=[t('',1)]))),i[189]||(i[189]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("msup",null,[s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"+"),s("mi",null,"ϵ"),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mo",null,"−"),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mi",null,"y"),s("mo",null,"+"),s("mi",null,"ϵ"),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")]),s("mn",null,"2")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[191]||(i[191]=t(`

    epsilon is added to both y and to prevent taking the logarithm of zero. If epsilon is nothing, then we set it to eps(<type of y and ŷ>).

    Example

    julia
    julia> loss = MSLELoss();
    +
    +julia> loss(Float32[1.1, 2.2, 3.3], 1:3)  0.009084041f0
    +true
    +
    +julia> loss(Float32[0.9, 1.8, 2.7], 1:3)  0.011100831f0
    +true

    source

    `,4))]),s("details",A1,[s("summary",null,[i[192]||(i[192]=s("a",{id:"Lux.PoissonLoss",href:"#Lux.PoissonLoss"},[s("span",{class:"jlbinding"},"Lux.PoissonLoss")],-1)),i[193]||(i[193]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[203]||(i[203]=t('
    julia
    PoissonLoss(; agg = mean, epsilon = nothing)
    ',1)),s("p",null,[i[198]||(i[198]=a("Return how much the predicted distribution ")),s("mjx-container",Z1,[(h(),n("svg",O1,i[194]||(i[194]=[t('',1)]))),i[195]||(i[195]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])])])],-1))]),i[199]||(i[199]=a(" diverges from the expected Poisson distribution ")),s("mjx-container",R1,[(h(),n("svg",S1,i[196]||(i[196]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D466",d:"M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z",style:{"stroke-width":"3"}})])])],-1)]))),i[197]||(i[197]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"y")])],-1))]),i[200]||(i[200]=a(", calculated as:"))]),s("mjx-container",N1,[(h(),n("svg",P1,i[201]||(i[201]=[t('',1)]))),i[202]||(i[202]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",null,"−"),s("mi",null,"y"),s("mo",null,"∗"),s("mi",null,"log"),s("mo",{"data-mjx-texclass":"NONE"},"⁡"),s("mo",{stretchy:"false"},"("),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mo",{stretchy:"false"},")"),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[204]||(i[204]=t(`

    Example

    julia
    julia> y_model = [1, 3, 3];  # data should only take integral values
    +
    +julia> PoissonLoss()(y_model, 1:3)  0.502312852219817
    +true

    source

    `,3))]),s("details",z1,[s("summary",null,[i[205]||(i[205]=s("a",{id:"Lux.SiameseContrastiveLoss",href:"#Lux.SiameseContrastiveLoss"},[s("span",{class:"jlbinding"},"Lux.SiameseContrastiveLoss")],-1)),i[206]||(i[206]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[209]||(i[209]=t('
    julia
    SiameseContrastiveLoss(; margin = true, agg = mean)

    Return the contrastive loss [1] which can be useful for training Siamese Networks. It is given by:

    ',2)),s("mjx-container",I1,[(h(),n("svg",q1,i[207]||(i[207]=[t('',1)]))),i[208]||(i[208]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",{stretchy:"false"},"("),s("mn",null,"1"),s("mo",null,"−"),s("mi",null,"y"),s("mo",{stretchy:"false"},")"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("mn",null,"2")]),s("mo",null,"+"),s("mi",null,"y"),s("mo",null,"∗"),s("mo",{"data-mjx-texclass":"OP",movablelimits:"true"},"max"),s("mo",{stretchy:"false"},"("),s("mn",null,"0"),s("mo",null,","),s("mtext",null,"margin"),s("mo",null,"−"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("msup",null,[s("mo",{stretchy:"false"},")"),s("mn",null,"2")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[210]||(i[210]=t(`

    Specify margin to set the baseline for distance at which pairs are dissimilar.

    Example

    julia
    julia>= [0.5, 1.5, 2.5];
    +
    +julia> SiameseContrastiveLoss()(ŷ, 1:3)  -4.833333333333333
    +true
    +
    +julia> SiameseContrastiveLoss(margin=2)(ŷ, 1:3)  -4.0
    +true

    References

    [1] Hadsell, Raia, Sumit Chopra, and Yann LeCun. "Dimensionality reduction by learning an invariant mapping." 2006 IEEE computer society conference on computer vision and pattern recognition (CVPR'06). Vol. 2. IEEE, 2006.

    source

    `,6))]),s("details",G1,[s("summary",null,[i[211]||(i[211]=s("a",{id:"Lux.SquaredHingeLoss",href:"#Lux.SquaredHingeLoss"},[s("span",{class:"jlbinding"},"Lux.SquaredHingeLoss")],-1)),i[212]||(i[212]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[215]||(i[215]=t('
    julia
    SquaredHingeLoss(; agg = mean)

    Return the squared hinge loss loss given the prediction and true labels y (containing 1 or -1); calculated as:

    ',2)),s("mjx-container",X1,[(h(),n("svg",J1,i[213]||(i[213]=[t('',1)]))),i[214]||(i[214]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"agg"),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"("),s("mo",{"data-mjx-texclass":"OP",movablelimits:"true"},"max"),s("mo",{stretchy:"false"},"("),s("mn",null,"0"),s("mo",null,","),s("mn",null,"1"),s("mo",null,"−"),s("mi",null,"y"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mover",null,[s("mi",null,"y"),s("mo",{stretchy:"false"},"^")])]),s("msup",null,[s("mo",{stretchy:"false"},")"),s("mn",null,"2")]),s("mo",{"data-mjx-texclass":"CLOSE"},")")])])],-1))]),i[216]||(i[216]=t(`

    Usually used with classifiers like Support Vector Machines.

    Example

    julia
    julia> loss = SquaredHingeLoss();
    +
    +julia> y_true = [1, -1, 1, 1];
    +
    +julia> y_pred = [0.1, 0.3, 1, 1.5];
    +
    +julia> loss(y_pred, y_true)  0.625
    +true

    source

    `,4))]),i[291]||(i[291]=s("h2",{id:"LuxOps-Module",tabindex:"-1"},[a("LuxOps Module "),s("a",{class:"header-anchor",href:"#LuxOps-Module","aria-label":'Permalink to "LuxOps Module {#LuxOps-Module}"'},"​")],-1)),s("details",U1,[s("summary",null,[i[217]||(i[217]=s("a",{id:"Lux.LuxOps",href:"#Lux.LuxOps"},[s("span",{class:"jlbinding"},"Lux.LuxOps")],-1)),i[218]||(i[218]=a()),l(e,{type:"info",class:"jlObjectType jlModule",text:"Module"})]),i[219]||(i[219]=t('
    julia
    LuxOps

    This module is a part of Lux.jl. It contains operations that are useful in DL context. Additionally certain operations here alias Base functions to behave more sensibly with GPUArrays.

    source

    ',3))]),s("details",W1,[s("summary",null,[i[220]||(i[220]=s("a",{id:"Lux.LuxOps.eachslice",href:"#Lux.LuxOps.eachslice"},[s("span",{class:"jlbinding"},"Lux.LuxOps.eachslice")],-1)),i[221]||(i[221]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[222]||(i[222]=t('
    julia
    eachslice(x, dims::Val)

    Same as Base.eachslice but doesn't produce a SubArray for the slices if x is a GPUArray.

    Additional dispatches for RNN helpers are also provided for TimeLastIndex and BatchLastIndex.

    source

    ',4))]),s("details",K1,[s("summary",null,[i[223]||(i[223]=s("a",{id:"Lux.LuxOps.foldl_init",href:"#Lux.LuxOps.foldl_init"},[s("span",{class:"jlbinding"},"Lux.LuxOps.foldl_init")],-1)),i[224]||(i[224]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[225]||(i[225]=t(`
    julia
    foldl_init(op, x)
    +foldl_init(op, x, init)

    Exactly same as foldl(op, x; init) in the forward pass. But, gives gradients wrt init in the backward pass.

    source

    `,3))]),s("details",Y1,[s("summary",null,[i[226]||(i[226]=s("a",{id:"Lux.LuxOps.getproperty",href:"#Lux.LuxOps.getproperty"},[s("span",{class:"jlbinding"},"Lux.LuxOps.getproperty")],-1)),i[227]||(i[227]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[228]||(i[228]=t(`
    julia
    getproperty(x, ::Val{v})
    +getproperty(x, ::StaticSymbol{v})

    Similar to Base.getproperty but requires a Val (or Static.StaticSymbol). Additionally, if v is not present in x, then nothing is returned.

    source

    `,3))]),s("details",$1,[s("summary",null,[i[229]||(i[229]=s("a",{id:"Lux.LuxOps.xlogx",href:"#Lux.LuxOps.xlogx"},[s("span",{class:"jlbinding"},"Lux.LuxOps.xlogx")],-1)),i[230]||(i[230]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[231]||(i[231]=t('
    julia
    xlogx(x::Number)

    Return x * log(x) for x ≥ 0, handling x == 0 by taking the limit from above, to get zero.

    source

    ',3))]),s("details",_1,[s("summary",null,[i[232]||(i[232]=s("a",{id:"Lux.LuxOps.xlogy",href:"#Lux.LuxOps.xlogy"},[s("span",{class:"jlbinding"},"Lux.LuxOps.xlogy")],-1)),i[233]||(i[233]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[234]||(i[234]=t('
    julia
    xlogy(x::Number, y::Number)

    Return x * log(y) for y > 0, and zero when x == 0.

    source

    ',3))]),s("details",s2,[s("summary",null,[i[235]||(i[235]=s("a",{id:"Lux.LuxOps.istraining",href:"#Lux.LuxOps.istraining"},[s("span",{class:"jlbinding"},"Lux.LuxOps.istraining")],-1)),i[236]||(i[236]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[237]||(i[237]=t(`
    julia
    istraining(::Val{training})
    +istraining(::StaticBool)
    +istraining(::Bool)
    +istraining(st::NamedTuple)

    Returns true if training is true or if st contains a training field with value true. Else returns false.

    source

    `,3))]),s("details",i2,[s("summary",null,[i[238]||(i[238]=s("a",{id:"Lux.LuxOps.multigate",href:"#Lux.LuxOps.multigate"},[s("span",{class:"jlbinding"},"Lux.LuxOps.multigate")],-1)),i[239]||(i[239]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[240]||(i[240]=t('
    julia
    multigate(x::AbstractArray, ::Val{N})

    Split up x into N equally sized chunks (along dimension 1).

    source

    ',3))]),i[292]||(i[292]=s("h2",{id:"Recursive-Operations",tabindex:"-1"},[a("Recursive Operations "),s("a",{class:"header-anchor",href:"#Recursive-Operations","aria-label":'Permalink to "Recursive Operations {#Recursive-Operations}"'},"​")],-1)),s("details",a2,[s("summary",null,[i[241]||(i[241]=s("a",{id:"Lux.recursive_map",href:"#Lux.recursive_map"},[s("span",{class:"jlbinding"},"Lux.recursive_map")],-1)),i[242]||(i[242]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[243]||(i[243]=t('
    julia
    recursive_map(f, x, args...)

    Similar to fmap(f, args...) but with restricted support for the notion of "leaf" types. However, this allows for more efficient and type stable implementations of recursive operations.

    How this works?

    For the following types it directly defines recursion rules:

    1. AbstractArray: If eltype is isbitstype, then f is applied to the array, else we recurse on the array.

    2. Tuple/NamedTuple: We recurse on the values.

    3. Number/Val/Nothing: We directly apply f.

    4. For all other types, we recurse on the fields using Functors.fmap.

    Note

    In most cases, users should gravitate towards Functors.fmap if it is being used outside of hot loops. Even for other cases, it is always recommended to verify the correctness of this implementation for specific usecases.

    source

    ',7))]),s("details",t2,[s("summary",null,[i[244]||(i[244]=s("a",{id:"Lux.recursive_add!!",href:"#Lux.recursive_add!!"},[s("span",{class:"jlbinding"},"Lux.recursive_add!!")],-1)),i[245]||(i[245]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[246]||(i[246]=t('
    julia
    recursive_add!!(x, y)

    Recursively add the leaves of two nested structures x and y. In Functor language, this is equivalent to doing fmap(+, x, y), but this implementation uses type stable code for common cases.

    Any leaves of x that are arrays and allow in-place addition will be modified in place.

    source

    ',4))]),s("details",e2,[s("summary",null,[i[247]||(i[247]=s("a",{id:"Lux.recursive_copyto!",href:"#Lux.recursive_copyto!"},[s("span",{class:"jlbinding"},"Lux.recursive_copyto!")],-1)),i[248]||(i[248]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[249]||(i[249]=t('
    julia
    recursive_copyto!(x, y)

    Recursively copy the leaves of two nested structures x and y. In Functor language, this is equivalent to doing fmap(copyto!, x, y), but this implementation uses type stable code for common cases. Note that any immutable leaf will lead to an error.

    source

    ',3))]),s("details",l2,[s("summary",null,[i[250]||(i[250]=s("a",{id:"Lux.recursive_eltype",href:"#Lux.recursive_eltype"},[s("span",{class:"jlbinding"},"Lux.recursive_eltype")],-1)),i[251]||(i[251]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[252]||(i[252]=t('
    julia
    recursive_eltype(x, unwrap_ad_types = Val(false))

    Recursively determine the element type of a nested structure x. This is equivalent to doing fmap(Lux.Utils.eltype, x), but this implementation uses type stable code for common cases.

    For ambiguous inputs like nothing and Val types we return Bool as the eltype.

    If unwrap_ad_types is set to Val(true) then for tracing and operator overloading based ADs (ForwardDiff, ReverseDiff, Tracker), this function will return the eltype of the unwrapped value.

    source

    ',5))]),s("details",n2,[s("summary",null,[i[253]||(i[253]=s("a",{id:"Lux.recursive_make_zero",href:"#Lux.recursive_make_zero"},[s("span",{class:"jlbinding"},"Lux.recursive_make_zero")],-1)),i[254]||(i[254]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[255]||(i[255]=t('
    julia
    recursive_make_zero(x)

    Recursively create a zero value for a nested structure x. This is equivalent to doing fmap(zero, x), but this implementation uses type stable code for common cases.

    See also Lux.recursive_make_zero!!.

    source

    ',4))]),s("details",h2,[s("summary",null,[i[256]||(i[256]=s("a",{id:"Lux.recursive_make_zero!!",href:"#Lux.recursive_make_zero!!"},[s("span",{class:"jlbinding"},"Lux.recursive_make_zero!!")],-1)),i[257]||(i[257]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[258]||(i[258]=t('
    julia
    recursive_make_zero!!(x)

    Recursively create a zero value for a nested structure x. Leaves that can be mutated with in-place zeroing will be modified in place.

    See also Lux.recursive_make_zero for fully out-of-place version.

    source

    ',4))]),i[293]||(i[293]=s("h2",{id:"Updating-Floating-Point-Precision",tabindex:"-1"},[a("Updating Floating Point Precision "),s("a",{class:"header-anchor",href:"#Updating-Floating-Point-Precision","aria-label":'Permalink to "Updating Floating Point Precision {#Updating-Floating-Point-Precision}"'},"​")],-1)),i[294]||(i[294]=s("p",null,"By default, Lux uses Float32 for all parameters and states. To update the precision simply pass the parameters / states / arrays into one of the following functions.",-1)),s("details",p2,[s("summary",null,[i[259]||(i[259]=s("a",{id:"Lux.f16",href:"#Lux.f16"},[s("span",{class:"jlbinding"},"Lux.f16")],-1)),i[260]||(i[260]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[261]||(i[261]=t('
    julia
    f16(m)

    Converts the eltype of m floating point values to Float16. Recurses into structs marked with Functors.@functor.

    source

    ',3))]),s("details",r2,[s("summary",null,[i[262]||(i[262]=s("a",{id:"Lux.f32",href:"#Lux.f32"},[s("span",{class:"jlbinding"},"Lux.f32")],-1)),i[263]||(i[263]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[264]||(i[264]=t('
    julia
    f32(m)

    Converts the eltype of m floating point values to Float32. Recurses into structs marked with Functors.@functor.

    source

    ',3))]),s("details",d2,[s("summary",null,[i[265]||(i[265]=s("a",{id:"Lux.f64",href:"#Lux.f64"},[s("span",{class:"jlbinding"},"Lux.f64")],-1)),i[266]||(i[266]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[267]||(i[267]=t('
    julia
    f64(m)

    Converts the eltype of m floating point values to Float64. Recurses into structs marked with Functors.@functor.

    source

    ',3))]),i[295]||(i[295]=s("h2",{id:"Element-Type-Matching",tabindex:"-1"},[a("Element Type Matching "),s("a",{class:"header-anchor",href:"#Element-Type-Matching","aria-label":'Permalink to "Element Type Matching {#Element-Type-Matching}"'},"​")],-1)),s("details",k2,[s("summary",null,[i[268]||(i[268]=s("a",{id:"Lux.match_eltype",href:"#Lux.match_eltype"},[s("span",{class:"jlbinding"},"Lux.match_eltype")],-1)),i[269]||(i[269]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[270]||(i[270]=t('
    julia
    match_eltype(layer, ps, st, args...)

    Helper function to "maybe" (see below) match the element type of args... with the element type of the layer's parameters and states. This is useful for debugging purposes, to track down accidental type-promotions inside Lux layers.

    Extended Help

    Controlling the Behavior via Preferences

    Behavior of this function is controlled via the eltype_mismatch_handling preference. The following options are supported:

    Warning

    We print the warning for type-mismatch only once.

    Element Type Conversions

    For "convert" only the following conversions are done:

    Element Type of parameters/statesElement Type of args...Converted to
    Float64IntegerFloat64
    Float32Float64Float32
    Float32IntegerFloat32
    Float16Float64Float16
    Float16Float32Float16
    Float16IntegerFloat16

    source

    ',11))]),i[296]||(i[296]=s("h2",{id:"Stateful-Layer",tabindex:"-1"},[a("Stateful Layer "),s("a",{class:"header-anchor",href:"#Stateful-Layer","aria-label":'Permalink to "Stateful Layer {#Stateful-Layer}"'},"​")],-1)),s("details",o2,[s("summary",null,[i[271]||(i[271]=s("a",{id:"Lux.StatefulLuxLayer",href:"#Lux.StatefulLuxLayer"},[s("span",{class:"jlbinding"},"Lux.StatefulLuxLayer")],-1)),i[272]||(i[272]=a()),l(e,{type:"info",class:"jlObjectType jlType",text:"Type"})]),i[273]||(i[273]=t('
    julia
    StatefulLuxLayer{FT}(model, ps, st)

    Warning

    This is not a Lux.AbstractLuxLayer

    A convenience wrapper over Lux layers which stores the parameters and states internally. This is meant to be used in internal implementation of layers.

    Usecases

    Static Parameters

    Arguments

    Inputs

    Outputs

    source

    ',14))]),i[297]||(i[297]=s("h2",{id:"Compact-Layer",tabindex:"-1"},[a("Compact Layer "),s("a",{class:"header-anchor",href:"#Compact-Layer","aria-label":'Permalink to "Compact Layer {#Compact-Layer}"'},"​")],-1)),s("details",T2,[s("summary",null,[i[274]||(i[274]=s("a",{id:"Lux.@compact",href:"#Lux.@compact"},[s("span",{class:"jlbinding"},"Lux.@compact")],-1)),i[275]||(i[275]=a()),l(e,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),i[276]||(i[276]=t(`
    julia
    @compact(kw...) do x
    +    ...
    +    @return y # optional (but recommended for best performance)
    +end
    +@compact(kw...) do x, p
    +    ...
    +    @return y # optional (but recommended for best performance)
    +end
    +@compact(forward::Function; name=nothing, dispatch=nothing, parameters...)

    Creates a layer by specifying some parameters, in the form of keywords, and (usually as a do block) a function for the forward pass. You may think of @compact as a specialized let block creating local variables that are trainable in Lux. Declared variable names may be used within the body of the forward function. Note that unlike typical Lux models, the forward function doesn't need to explicitly manage states.

    Defining the version with p allows you to access the parameters in the forward pass. This is useful when using it with SciML tools which require passing in the parameters explicitly.

    Reserved Kwargs:

    1. name: The name of the layer.

    2. dispatch: The constructed layer has the type Lux.CompactLuxLayer{dispatch} which can be used for custom dispatches.

    Tip

    Check the Lux tutorials for more examples of using @compact.

    If you are passing in kwargs by splatting them, they will be passed as is to the function body. This means if your splatted kwargs contain a lux layer that won't be registered in the CompactLuxLayer.

    Special Syntax

    Extended Help

    Examples

    Here is a linear model:

    julia
    julia> using Lux, Random
    +
    +julia> r = @compact(w=ones(3)) do x
    +           @return w .* x
    +       end
    +@compact(
    +    w = 3-element Vector{Float64},
    +) do x
    +    return w .* x
    +end       # Total: 3 parameters,
    +          #        plus 0 states.
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), r);
    +
    +julia> r([1, 2, 3], ps, st)  # x is set to [1, 1, 1].
    +([1.0, 2.0, 3.0], NamedTuple())

    Here is a linear model with bias and activation:

    julia
    julia> d_in = 5
    +5
    +
    +julia> d_out = 3
    +3
    +
    +julia> d = @compact(W=ones(d_out, d_in), b=zeros(d_out), act=relu) do x
    +           y = W * x
    +           @return act.(y .+ b)
    +       end
    +@compact(
    +    W = 3×5 Matrix{Float64},
    +    b = 3-element Vector{Float64},
    +    act = relu,
    +) do x
    +    y = W * x
    +    return act.(y .+ b)
    +end       # Total: 18 parameters,
    +          #        plus 1 states.
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), d);
    +
    +julia> d(ones(5, 2), ps, st)[1] # 3×2 Matrix as output.
    +3×2 Matrix{Float64}:
    + 5.0  5.0
    + 5.0  5.0
    + 5.0  5.0
    +
    +julia> ps_dense = (; weight=ps.W, bias=ps.b);
    +
    +julia> first(d([1, 2, 3, 4, 5], ps, st)) 
    +       first(Dense(d_in => d_out, relu)([1, 2, 3, 4, 5], ps_dense, NamedTuple())) # Equivalent to a dense layer
    +true

    Finally, here is a simple MLP. We can train this model just like any Lux model:

    julia
    julia> n_in = 1;
    +
    +julia> n_out = 1;
    +
    +julia> nlayers = 3;
    +
    +julia> model = @compact(w1=Dense(n_in, 128),
    +           w2=[Dense(128, 128) for i in 1:nlayers], w3=Dense(128, n_out), act=relu) do x
    +           embed = act.(w1(x))
    +           for w in w2
    +               embed = act.(w(embed))
    +           end
    +           out = w3(embed)
    +           @return out
    +       end
    +@compact(
    +    w1 = Dense(1 => 128),               # 256 parameters
    +    w2 = NamedTuple(
    +        1 = Dense(128 => 128),          # 16_512 parameters
    +        2 = Dense(128 => 128),          # 16_512 parameters
    +        3 = Dense(128 => 128),          # 16_512 parameters
    +    ),
    +    w3 = Dense(128 => 1),               # 129 parameters
    +    act = relu,
    +) do x
    +    embed = act.(w1(x))
    +    for w = w2
    +        embed = act.(w(embed))
    +    end
    +    out = w3(embed)
    +    return out
    +end       # Total: 49_921 parameters,
    +          #        plus 1 states.
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), model);
    +
    +julia> size(first(model(randn(n_in, 32), ps, st)))  # 1×32 Matrix as output.
    +(1, 32)
    +
    +julia> using Optimisers, Zygote
    +
    +julia> x_data = collect(-2.0f0:0.1f0:2.0f0)';
    +
    +julia> y_data = 2 .* x_data .- x_data .^ 3;
    +
    +julia> optim = Optimisers.setup(Adam(), ps);
    +
    +julia> loss_initial = sum(abs2, first(model(x_data, ps, st)) .- y_data);
    +
    +julia> for epoch in 1:1000
    +           loss, gs = Zygote.withgradient(
    +               ps -> sum(abs2, first(model(x_data, ps, st)) .- y_data), ps)
    +           Optimisers.update!(optim, ps, gs[1])
    +       end;
    +
    +julia> loss_final = sum(abs2, first(model(x_data, ps, st)) .- y_data);
    +
    +julia> loss_initial > loss_final
    +true

    You may also specify a name for the model, which will be used instead of the default printout, which gives a verbatim representation of the code used to construct the model:

    julia
    julia> model = @compact(w=rand(3), name="Linear(3 => 1)") do x
    +           @return sum(w .* x)
    +       end
    +Linear(3 => 1)      # 3 parameters

    This can be useful when using @compact to hierarchically construct complex models to be used inside a Chain.

    Type Stability

    If your input function f is type-stable but the generated model is not type stable, it should be treated as a bug. We will appreciate issues if you find such cases.

    Parameter Count

    Array Parameter don't print the number of parameters on the side. However, they do account for the total number of parameters printed at the bottom.

    source

    `,23))]),s("details",Q2,[s("summary",null,[i[277]||(i[277]=s("a",{id:"Lux.@init_fn",href:"#Lux.@init_fn"},[s("span",{class:"jlbinding"},"Lux.@init_fn")],-1)),i[278]||(i[278]=a()),l(e,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),i[279]||(i[279]=t(`
    julia
    @init_fn(fn, kind::Symbol = :parameter)

    Create an initializer function for a parameter or state to be used for in a Compact Lux Layer created using @compact.

    Arguments

    Examples

    julia
    julia> using Lux, Random
    +
    +julia> r = @compact(w=@init_fn(rng->randn32(rng, 3, 2)),
    +           b=@init_fn(rng->randn32(rng, 3), :state)) do x
    +           @return w * x .+ b
    +       end;
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), r);
    +
    +julia> size(ps.w)
    +(3, 2)
    +
    +julia> size(st.b)
    +(3,)
    +
    +julia> size(r([1, 2], ps, st)[1])
    +(3,)

    source

    `,7))]),s("details",g2,[s("summary",null,[i[280]||(i[280]=s("a",{id:"Lux.@non_trainable",href:"#Lux.@non_trainable"},[s("span",{class:"jlbinding"},"Lux.@non_trainable")],-1)),i[281]||(i[281]=a()),l(e,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),i[282]||(i[282]=t(`
    julia
    @non_trainable(x)

    Mark a value as non-trainable. This bypasses the regular checks and places the value into the state of the layer.

    Arguments

    Examples

    julia
    julia> using Lux, Random
    +
    +julia> r = @compact(w=ones(3), w_fixed=@non_trainable(rand(3))) do x
    +           @return sum(w .* x .+ w_fixed)
    +       end;
    +
    +julia> ps, st = Lux.setup(Xoshiro(0), r);
    +
    +julia> size(ps.w)
    +(3,)
    +
    +julia> size(st.w_fixed)
    +(3,)
    +
    +julia> res, st_ = r([1, 2, 3], ps, st);
    +
    +julia> st_.w_fixed == st.w_fixed
    +true
    +
    +julia> res isa Number
    +true

    source

    `,7))]),i[298]||(i[298]=s("h2",{id:"miscellaneous",tabindex:"-1"},[a("Miscellaneous "),s("a",{class:"header-anchor",href:"#miscellaneous","aria-label":'Permalink to "Miscellaneous"'},"​")],-1)),s("details",m2,[s("summary",null,[i[283]||(i[283]=s("a",{id:"Lux.set_dispatch_doctor_preferences!",href:"#Lux.set_dispatch_doctor_preferences!"},[s("span",{class:"jlbinding"},"Lux.set_dispatch_doctor_preferences!")],-1)),i[284]||(i[284]=a()),l(e,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),i[285]||(i[285]=t(`
    julia
    set_dispatch_doctor_preferences!(mode::String)
    +set_dispatch_doctor_preferences!(; luxcore::String="disable", luxlib::String="disable")

    Set the dispatch doctor preference for LuxCore and LuxLib packages.

    mode can be "disable", "warn", or "error". For details on the different modes, see the DispatchDoctor.jl documentation.

    If the preferences are already set, then no action is taken. Otherwise the preference is set. For changes to take effect, the Julia session must be restarted.

    source

    `,5))])])}const L2=p(d,[["render",y2]]);export{C2 as __pageData,L2 as default}; diff --git a/previews/PR1023/assets/api_Testing_Functionality_LuxTestUtils.md.8-Wna7gT.js b/previews/PR1023/assets/api_Testing_Functionality_LuxTestUtils.md.8-Wna7gT.js new file mode 100644 index 0000000000..39380266e4 --- /dev/null +++ b/previews/PR1023/assets/api_Testing_Functionality_LuxTestUtils.md.8-Wna7gT.js @@ -0,0 +1,12 @@ +import{_ as n,c as h,a2 as e,j as t,a as i,G as l,B as p,o as d}from"./chunks/framework.DFwXuivk.js";const C=JSON.parse('{"title":"LuxTestUtils","description":"","frontmatter":{},"headers":[],"relativePath":"api/Testing_Functionality/LuxTestUtils.md","filePath":"api/Testing_Functionality/LuxTestUtils.md","lastUpdated":null}'),k={name:"api/Testing_Functionality/LuxTestUtils.md"},r={class:"jldocstring custom-block"},o={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"};function u(y,s,f,b,x,F){const a=p("Badge");return d(),h("div",null,[s[15]||(s[15]=e('

    LuxTestUtils

    Warning

    This is a testing package. Hence, we don't use features like weak dependencies to reduce load times. It is recommended that you exclusively use this package for testing and not add a dependency to it in your main package Project.toml.

    Implements utilities for testing gradient correctness and dynamic dispatch of Lux.jl models.

    Testing using JET.jl

    ',4)),t("details",r,[t("summary",null,[s[0]||(s[0]=t("a",{id:"LuxTestUtils.@jet",href:"#LuxTestUtils.@jet"},[t("span",{class:"jlbinding"},"LuxTestUtils.@jet")],-1)),s[1]||(s[1]=i()),l(a,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),s[2]||(s[2]=e(`
    julia
    @jet f(args...) call_broken=false opt_broken=false

    Run JET tests on the function f with the arguments args.... If JET.jl fails to compile, then the macro will be a no-op.

    Keyword Arguments

    All additional arguments will be forwarded to JET.@test_call and JET.@test_opt.

    Tip

    Instead of specifying target_modules with every call, you can set global target modules using jet_target_modules!.

    julia
    using LuxTestUtils
    +
    +jet_target_modules!(["Lux", "LuxLib"]) # Expects Lux and LuxLib to be present in the module calling \`@jet\`

    Example

    julia
    julia> @jet sum([1, 2, 3]) target_modules=(Base, Core)
    +Test Passed
    +
    +julia> @jet sum(1, 1) target_modules=(Base, Core) opt_broken=true call_broken=true
    +Test Broken
    +  Expression: #= REPL[21]:1 =# JET.@test_opt target_modules = (Base, Core) sum(1, 1)

    source

    `,9))]),t("details",o,[t("summary",null,[s[3]||(s[3]=t("a",{id:"LuxTestUtils.jet_target_modules!",href:"#LuxTestUtils.jet_target_modules!"},[t("span",{class:"jlbinding"},"LuxTestUtils.jet_target_modules!")],-1)),s[4]||(s[4]=i()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[5]||(s[5]=e('
    julia
    jet_target_modules!(list::Vector{String}; force::Bool=false)

    This sets target_modules for all JET tests when using @jet.

    source

    ',3))]),s[16]||(s[16]=t("h2",{id:"Gradient-Correctness",tabindex:"-1"},[i("Gradient Correctness "),t("a",{class:"header-anchor",href:"#Gradient-Correctness","aria-label":'Permalink to "Gradient Correctness {#Gradient-Correctness}"'},"​")],-1)),t("details",g,[t("summary",null,[s[6]||(s[6]=t("a",{id:"LuxTestUtils.test_gradients",href:"#LuxTestUtils.test_gradients"},[t("span",{class:"jlbinding"},"LuxTestUtils.test_gradients")],-1)),s[7]||(s[7]=i()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[8]||(s[8]=e(`
    julia
    test_gradients(f, args...; skip_backends=[], broken_backends=[], kwargs...)

    Test the gradients of f with respect to args using the specified backends.

    BackendADTypeCPUGPUNotes
    Zygote.jlAutoZygote()
    Tracker.jlAutoTracker()
    ReverseDiff.jlAutoReverseDiff()
    ForwardDiff.jlAutoForwardDiff()len ≤ 100
    FiniteDiff.jlAutoFiniteDiff()len ≤ 100
    Enzyme.jlAutoEnzyme()Only Reverse Mode

    Arguments

    Keyword Arguments

    Example

    julia
    julia> f(x, y, z) = x .+ sum(abs2, y.t) + sum(y.x.z)
    +
    +julia> x = (; t=rand(10), x=(z=[2.0],))
    +
    +julia> test_gradients(f, 1.0, x, nothing)

    source

    `,10))]),t("details",c,[t("summary",null,[s[9]||(s[9]=t("a",{id:"LuxTestUtils.@test_gradients",href:"#LuxTestUtils.@test_gradients"},[t("span",{class:"jlbinding"},"LuxTestUtils.@test_gradients")],-1)),s[10]||(s[10]=i()),l(a,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),s[11]||(s[11]=e('
    julia
    @test_gradients(f, args...; kwargs...)

    See the documentation of test_gradients for more details. This macro provides correct line information for the failing tests.

    source

    ',3))]),s[17]||(s[17]=t("h2",{id:"Extensions-to-@test",tabindex:"-1"},[i("Extensions to "),t("code",null,"@test"),i(),t("a",{class:"header-anchor",href:"#Extensions-to-@test","aria-label":'Permalink to "Extensions to `@test` {#Extensions-to-@test}"'},"​")],-1)),t("details",E,[t("summary",null,[s[12]||(s[12]=t("a",{id:"LuxTestUtils.@test_softfail",href:"#LuxTestUtils.@test_softfail"},[t("span",{class:"jlbinding"},"LuxTestUtils.@test_softfail")],-1)),s[13]||(s[13]=i()),l(a,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),s[14]||(s[14]=e('
    julia
    @test_softfail expr

    Evaluate expr and record a test result. If expr throws an exception, the test result will be recorded as an error. If expr returns a value, and it is not a boolean, the test result will be recorded as an error.

    If the test result is false then the test will be recorded as a broken test, else it will be recorded as a pass.

    source

    ',4))])])}const j=n(k,[["render",u]]);export{C as __pageData,j as default}; diff --git a/previews/PR1023/assets/api_Testing_Functionality_LuxTestUtils.md.8-Wna7gT.lean.js b/previews/PR1023/assets/api_Testing_Functionality_LuxTestUtils.md.8-Wna7gT.lean.js new file mode 100644 index 0000000000..39380266e4 --- /dev/null +++ b/previews/PR1023/assets/api_Testing_Functionality_LuxTestUtils.md.8-Wna7gT.lean.js @@ -0,0 +1,12 @@ +import{_ as n,c as h,a2 as e,j as t,a as i,G as l,B as p,o as d}from"./chunks/framework.DFwXuivk.js";const C=JSON.parse('{"title":"LuxTestUtils","description":"","frontmatter":{},"headers":[],"relativePath":"api/Testing_Functionality/LuxTestUtils.md","filePath":"api/Testing_Functionality/LuxTestUtils.md","lastUpdated":null}'),k={name:"api/Testing_Functionality/LuxTestUtils.md"},r={class:"jldocstring custom-block"},o={class:"jldocstring custom-block"},g={class:"jldocstring custom-block"},c={class:"jldocstring custom-block"},E={class:"jldocstring custom-block"};function u(y,s,f,b,x,F){const a=p("Badge");return d(),h("div",null,[s[15]||(s[15]=e('

    LuxTestUtils

    Warning

    This is a testing package. Hence, we don't use features like weak dependencies to reduce load times. It is recommended that you exclusively use this package for testing and not add a dependency to it in your main package Project.toml.

    Implements utilities for testing gradient correctness and dynamic dispatch of Lux.jl models.

    Testing using JET.jl

    ',4)),t("details",r,[t("summary",null,[s[0]||(s[0]=t("a",{id:"LuxTestUtils.@jet",href:"#LuxTestUtils.@jet"},[t("span",{class:"jlbinding"},"LuxTestUtils.@jet")],-1)),s[1]||(s[1]=i()),l(a,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),s[2]||(s[2]=e(`
    julia
    @jet f(args...) call_broken=false opt_broken=false

    Run JET tests on the function f with the arguments args.... If JET.jl fails to compile, then the macro will be a no-op.

    Keyword Arguments

    All additional arguments will be forwarded to JET.@test_call and JET.@test_opt.

    Tip

    Instead of specifying target_modules with every call, you can set global target modules using jet_target_modules!.

    julia
    using LuxTestUtils
    +
    +jet_target_modules!(["Lux", "LuxLib"]) # Expects Lux and LuxLib to be present in the module calling \`@jet\`

    Example

    julia
    julia> @jet sum([1, 2, 3]) target_modules=(Base, Core)
    +Test Passed
    +
    +julia> @jet sum(1, 1) target_modules=(Base, Core) opt_broken=true call_broken=true
    +Test Broken
    +  Expression: #= REPL[21]:1 =# JET.@test_opt target_modules = (Base, Core) sum(1, 1)

    source

    `,9))]),t("details",o,[t("summary",null,[s[3]||(s[3]=t("a",{id:"LuxTestUtils.jet_target_modules!",href:"#LuxTestUtils.jet_target_modules!"},[t("span",{class:"jlbinding"},"LuxTestUtils.jet_target_modules!")],-1)),s[4]||(s[4]=i()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[5]||(s[5]=e('
    julia
    jet_target_modules!(list::Vector{String}; force::Bool=false)

    This sets target_modules for all JET tests when using @jet.

    source

    ',3))]),s[16]||(s[16]=t("h2",{id:"Gradient-Correctness",tabindex:"-1"},[i("Gradient Correctness "),t("a",{class:"header-anchor",href:"#Gradient-Correctness","aria-label":'Permalink to "Gradient Correctness {#Gradient-Correctness}"'},"​")],-1)),t("details",g,[t("summary",null,[s[6]||(s[6]=t("a",{id:"LuxTestUtils.test_gradients",href:"#LuxTestUtils.test_gradients"},[t("span",{class:"jlbinding"},"LuxTestUtils.test_gradients")],-1)),s[7]||(s[7]=i()),l(a,{type:"info",class:"jlObjectType jlFunction",text:"Function"})]),s[8]||(s[8]=e(`
    julia
    test_gradients(f, args...; skip_backends=[], broken_backends=[], kwargs...)

    Test the gradients of f with respect to args using the specified backends.

    BackendADTypeCPUGPUNotes
    Zygote.jlAutoZygote()
    Tracker.jlAutoTracker()
    ReverseDiff.jlAutoReverseDiff()
    ForwardDiff.jlAutoForwardDiff()len ≤ 100
    FiniteDiff.jlAutoFiniteDiff()len ≤ 100
    Enzyme.jlAutoEnzyme()Only Reverse Mode

    Arguments

    Keyword Arguments

    Example

    julia
    julia> f(x, y, z) = x .+ sum(abs2, y.t) + sum(y.x.z)
    +
    +julia> x = (; t=rand(10), x=(z=[2.0],))
    +
    +julia> test_gradients(f, 1.0, x, nothing)

    source

    `,10))]),t("details",c,[t("summary",null,[s[9]||(s[9]=t("a",{id:"LuxTestUtils.@test_gradients",href:"#LuxTestUtils.@test_gradients"},[t("span",{class:"jlbinding"},"LuxTestUtils.@test_gradients")],-1)),s[10]||(s[10]=i()),l(a,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),s[11]||(s[11]=e('
    julia
    @test_gradients(f, args...; kwargs...)

    See the documentation of test_gradients for more details. This macro provides correct line information for the failing tests.

    source

    ',3))]),s[17]||(s[17]=t("h2",{id:"Extensions-to-@test",tabindex:"-1"},[i("Extensions to "),t("code",null,"@test"),i(),t("a",{class:"header-anchor",href:"#Extensions-to-@test","aria-label":'Permalink to "Extensions to `@test` {#Extensions-to-@test}"'},"​")],-1)),t("details",E,[t("summary",null,[s[12]||(s[12]=t("a",{id:"LuxTestUtils.@test_softfail",href:"#LuxTestUtils.@test_softfail"},[t("span",{class:"jlbinding"},"LuxTestUtils.@test_softfail")],-1)),s[13]||(s[13]=i()),l(a,{type:"info",class:"jlObjectType jlMacro",text:"Macro"})]),s[14]||(s[14]=e('
    julia
    @test_softfail expr

    Evaluate expr and record a test result. If expr throws an exception, the test result will be recorded as an error. If expr returns a value, and it is not a boolean, the test result will be recorded as an error.

    If the test result is false then the test will be recorded as a broken test, else it will be recorded as a pass.

    source

    ',4))])])}const j=n(k,[["render",u]]);export{C as __pageData,j as default}; diff --git a/previews/PR1023/assets/app.3aC6K985.js b/previews/PR1023/assets/app.3aC6K985.js new file mode 100644 index 0000000000..ecbe01b561 --- /dev/null +++ b/previews/PR1023/assets/app.3aC6K985.js @@ -0,0 +1 @@ +import{R as p}from"./chunks/theme.BkveSZIg.js";import{R as o,a6 as u,a7 as c,a8 as l,a9 as f,aa as d,ab as m,ac as h,ad as g,ae as A,af as v,d as P,u as R,v as w,s as y,ag as C,ah as b,ai as E,a5 as S}from"./chunks/framework.DFwXuivk.js";function i(e){if(e.extends){const a=i(e.extends);return{...a,...e,async enhanceApp(t){a.enhanceApp&&await a.enhanceApp(t),e.enhanceApp&&await e.enhanceApp(t)}}}return e}const s=i(p),T=P({name:"VitePressApp",setup(){const{site:e,lang:a,dir:t}=R();return w(()=>{y(()=>{document.documentElement.lang=a.value,document.documentElement.dir=t.value})}),e.value.router.prefetchLinks&&C(),b(),E(),s.setup&&s.setup(),()=>S(s.Layout)}});async function D(){globalThis.__VITEPRESS__=!0;const e=j(),a=_();a.provide(c,e);const t=l(e.route);return a.provide(f,t),a.component("Content",d),a.component("ClientOnly",m),Object.defineProperties(a.config.globalProperties,{$frontmatter:{get(){return t.frontmatter.value}},$params:{get(){return t.page.value.params}}}),s.enhanceApp&&await s.enhanceApp({app:a,router:e,siteData:h}),{app:a,router:e,data:t}}function _(){return g(T)}function j(){let e=o,a;return A(t=>{let n=v(t),r=null;return n&&(e&&(a=n),(e||a===n)&&(n=n.replace(/\.js$/,".lean.js")),r=import(n)),o&&(e=!1),r},s.NotFound)}o&&D().then(({app:e,router:a,data:t})=>{a.go().then(()=>{u(a.route,t.site),e.mount("#app")})});export{D as createApp}; diff --git a/previews/PR1023/assets/chunks/@localSearchIndexroot.Div4qI0f.js b/previews/PR1023/assets/chunks/@localSearchIndexroot.Div4qI0f.js new file mode 100644 index 0000000000..179056844d --- /dev/null +++ b/previews/PR1023/assets/chunks/@localSearchIndexroot.Div4qI0f.js @@ -0,0 +1 @@ +const e='{"documentCount":261,"nextId":261,"documentIds":{"0":"/previews/PR1023/api/Accelerator_Support/MLDataDevices#MLDataDevices-API","1":"/previews/PR1023/api/Accelerator_Support/MLDataDevices#preferences","2":"/previews/PR1023/api/Accelerator_Support/MLDataDevices#Data-Transfer","3":"/previews/PR1023/api/Accelerator_Support/MLDataDevices#miscellaneous","4":"/previews/PR1023/api/Accelerator_Support/MLDataDevices#Multi-GPU-Support","5":"/previews/PR1023/api/Accelerator_Support/MLDataDevices#iteration","6":"/previews/PR1023/api/Building_Blocks/LuxCore#luxcore","7":"/previews/PR1023/api/Building_Blocks/LuxCore#Abstract-Types","8":"/previews/PR1023/api/Building_Blocks/LuxCore#general","9":"/previews/PR1023/api/Building_Blocks/LuxCore#parameters","10":"/previews/PR1023/api/Building_Blocks/LuxCore#states","11":"/previews/PR1023/api/Building_Blocks/LuxCore#Layer-size","12":"/previews/PR1023/api/Building_Blocks/LuxLib#LuxLib-API","13":"/previews/PR1023/api/Building_Blocks/LuxLib#Apply-Activation","14":"/previews/PR1023/api/Building_Blocks/LuxLib#Batched-Operations","15":"/previews/PR1023/api/Building_Blocks/LuxLib#Bias-Activation","16":"/previews/PR1023/api/Building_Blocks/LuxLib#Convolutional-Layers","17":"/previews/PR1023/api/Building_Blocks/LuxLib#dropout","18":"/previews/PR1023/api/Building_Blocks/LuxLib#Fully-Connected-Layers","19":"/previews/PR1023/api/Building_Blocks/LuxLib#normalization","20":"/previews/PR1023/api/Building_Blocks/LuxLib#Helper-Functions","21":"/previews/PR1023/api/Building_Blocks/WeightInitializers#WeightInitializers-API","22":"/previews/PR1023/api/Building_Blocks/WeightInitializers#Supported-RNG-Types-WeightInit","23":"/previews/PR1023/api/Building_Blocks/WeightInitializers#API-Reference","24":"/previews/PR1023/api/Building_Blocks/WeightInitializers#Main-Functions","25":"/previews/PR1023/api/Building_Blocks/WeightInitializers#Other-Convenience-Functions","26":"/previews/PR1023/api/Lux/autodiff#autodiff-lux-helpers","27":"/previews/PR1023/api/Lux/autodiff#JVP-and-VJP-Wrappers","28":"/previews/PR1023/api/Lux/autodiff#Batched-AD","29":"/previews/PR1023/api/Lux/autodiff#Nested-2nd-Order-AD","30":"/previews/PR1023/api/Lux/contrib#Experimental-Features","31":"/previews/PR1023/api/Lux/contrib#Parameter-Freezing","32":"/previews/PR1023/api/Lux/contrib#Map-over-Layer","33":"/previews/PR1023/api/Lux/contrib#Debugging-Functionality","34":"/previews/PR1023/api/Lux/contrib#Tied-Parameters","35":"/previews/PR1023/api/Lux/interop#Interoperability-between-Lux-and-other-packages","36":"/previews/PR1023/api/Lux/interop#Switching-from-older-frameworks","37":"/previews/PR1023/api/Lux/interop#flux-to-lux-migrate-api","38":"/previews/PR1023/api/Lux/interop#Using-a-different-backend-for-Lux","39":"/previews/PR1023/api/Lux/interop#Lux-Models-to-Simple-Chains","40":"/previews/PR1023/api/Lux/distributed_utils#Distributed-Utils","41":"/previews/PR1023/api/Lux/distributed_utils#communication-backends","42":"/previews/PR1023/api/Lux/distributed_utils#initialization","43":"/previews/PR1023/api/Lux/distributed_utils#Helper-Functions","44":"/previews/PR1023/api/Lux/distributed_utils#Communication-Primitives","45":"/previews/PR1023/api/Lux/distributed_utils#Optimizers.jl-Integration","46":"/previews/PR1023/api/Lux/distributed_utils#MLUtils.jl-Integration","47":"/previews/PR1023/api/Testing_Functionality/LuxTestUtils#luxtestutils","48":"/previews/PR1023/api/Testing_Functionality/LuxTestUtils#Testing-using-JET.jl","49":"/previews/PR1023/api/Testing_Functionality/LuxTestUtils#Gradient-Correctness","50":"/previews/PR1023/api/Testing_Functionality/LuxTestUtils#Extensions-to-@test","51":"/previews/PR1023/api/Lux/utilities#utilities","52":"/previews/PR1023/api/Lux/utilities#Training-API","53":"/previews/PR1023/api/Lux/utilities#Loss-Functions","54":"/previews/PR1023/api/Lux/utilities#LuxOps-Module","55":"/previews/PR1023/api/Lux/utilities#Recursive-Operations","56":"/previews/PR1023/api/Lux/utilities#Updating-Floating-Point-Precision","57":"/previews/PR1023/api/Lux/utilities#Element-Type-Matching","58":"/previews/PR1023/api/Lux/utilities#Stateful-Layer","59":"/previews/PR1023/api/Lux/utilities#Compact-Layer","60":"/previews/PR1023/api/Lux/utilities#miscellaneous","61":"/previews/PR1023/api/Lux/layers#Built-In-Layers","62":"/previews/PR1023/api/Lux/layers#containers","63":"/previews/PR1023/api/Lux/layers#Convolutional-Layers","64":"/previews/PR1023/api/Lux/layers#Dropout-Layers","65":"/previews/PR1023/api/Lux/layers#Pooling-Layers","66":"/previews/PR1023/api/Lux/layers#Recurrent-Layers","67":"/previews/PR1023/api/Lux/layers#Linear-Layers","68":"/previews/PR1023/api/Lux/layers#Misc.-Helper-Layers","69":"/previews/PR1023/api/Lux/layers#Normalization-Layers","70":"/previews/PR1023/api/Lux/layers#upsampling","71":"/previews/PR1023/#How-to-Install-Lux.jl?","72":"/previews/PR1023/#Want-GPU-Support?","73":"/previews/PR1023/#Want-XLA-Support?","74":"/previews/PR1023/introduction/citation#citation","75":"/previews/PR1023/introduction/#getting-started","76":"/previews/PR1023/introduction/#installation","77":"/previews/PR1023/introduction/#quickstart","78":"/previews/PR1023/introduction/#Defining-Custom-Layers","79":"/previews/PR1023/introduction/#Additional-Packages","80":"/previews/PR1023/introduction/#GPU-Support","81":"/previews/PR1023/introduction/overview#Why-we-wrote-Lux?","82":"/previews/PR1023/introduction/overview#Design-Principles","83":"/previews/PR1023/introduction/overview#Why-use-Lux-over-Flux?","84":"/previews/PR1023/introduction/resources#Resources-to-Get-Started","85":"/previews/PR1023/introduction/updating_to_v1#updating-to-v1","86":"/previews/PR1023/introduction/updating_to_v1#LuxLib.jl","87":"/previews/PR1023/introduction/updating_to_v1#Breaking-Changes","88":"/previews/PR1023/introduction/updating_to_v1#New-Major-Features","89":"/previews/PR1023/introduction/updating_to_v1#LuxCore.jl","90":"/previews/PR1023/introduction/updating_to_v1#Breaking-Changes-2","91":"/previews/PR1023/introduction/updating_to_v1#New-Major-Features-2","92":"/previews/PR1023/introduction/updating_to_v1#WeightInitializers.jl","93":"/previews/PR1023/introduction/updating_to_v1#MLDataDevices.jl","94":"/previews/PR1023/introduction/updating_to_v1#Breaking-Changes-3","95":"/previews/PR1023/introduction/updating_to_v1#New-Major-Features-3","96":"/previews/PR1023/introduction/updating_to_v1#Lux.jl","97":"/previews/PR1023/introduction/updating_to_v1#Breaking-Changes-(Removed-Functionality)","98":"/previews/PR1023/introduction/updating_to_v1#Breaking-Changes-(Moved-Functionality)","99":"/previews/PR1023/introduction/updating_to_v1#Breaking-Changes-(Changes-in-Defaults)","100":"/previews/PR1023/introduction/updating_to_v1#New-Features","101":"/previews/PR1023/manual/autodiff#autodiff-lux","102":"/previews/PR1023/manual/autodiff#overview","103":"/previews/PR1023/manual/autodiff#autodiff-recommendations","104":"/previews/PR1023/manual/autodiff#Support-Class","105":"/previews/PR1023/manual/autodiff#footnotes","106":"/previews/PR1023/manual/dispatch_custom_input#Dispatching-on-Custom-Input-Types","107":"/previews/PR1023/manual/dispatch_custom_input#Which-function-should-participate-in-dispatch?","108":"/previews/PR1023/manual/dispatch_custom_input#Concrete-Example","109":"/previews/PR1023/manual/dispatch_custom_input#Time-Dependent-Chain-Implementation","110":"/previews/PR1023/manual/dispatch_custom_input#Running-the-TDChain","111":"/previews/PR1023/manual/dispatch_custom_input#Writing-the-Correct-Dispatch-Rules","112":"/previews/PR1023/manual/dispatch_custom_input#Using-the-Same-Input-for-Non-TD-Models","113":"/previews/PR1023/manual/compiling_lux_models#reactant-compilation","114":"/previews/PR1023/manual/compiling_lux_models#compile_lux_model_trainstate","115":"/previews/PR1023/manual/gpu_management#GPU-Management","116":"/previews/PR1023/manual/gpu_management#Automatic-Backend-Management-(Recommended-Approach)","117":"/previews/PR1023/manual/gpu_management#Manual-Backend-Management","118":"/previews/PR1023/manual/distributed_utils#Distributed-Data-Parallel-Training","119":"/previews/PR1023/manual/distributed_utils#Guide-to-Integrating-DistributedUtils-into-your-code","120":"/previews/PR1023/manual/distributed_utils#Migration-Guide-from-FluxMPI.jl","121":"/previews/PR1023/manual/distributed_utils#Removed-Functionality","122":"/previews/PR1023/manual/distributed_utils#Key-Differences","123":"/previews/PR1023/manual/distributed_utils#Known-Shortcomings","124":"/previews/PR1023/manual/debugging#debug-lux-layers","125":"/previews/PR1023/manual/debugging#Incorrect-Model-Specification:-Dimension-Mismatch-Problems","126":"/previews/PR1023/manual/debugging#Tracking-down-NaNs","127":"/previews/PR1023/manual/debugging#conclusion","128":"/previews/PR1023/manual/freezing_model_parameters#freezing-model-parameters","129":"/previews/PR1023/manual/freezing_model_parameters#Freezing-Layers-of-a-Particular-Kind","130":"/previews/PR1023/manual/freezing_model_parameters#Freezing-by-Layer-Name","131":"/previews/PR1023/manual/freezing_model_parameters#Freezing-Part-of-the-Parameters","132":"/previews/PR1023/manual/freezing_model_parameters#Freezing-Part-of-a-Chain","133":"/previews/PR1023/manual/migrate_from_flux#migrate-from-flux","134":"/previews/PR1023/manual/migrate_from_flux#Implementing-Custom-Layers","135":"/previews/PR1023/manual/migrate_from_flux#Certain-Important-Implementation-Details","136":"/previews/PR1023/manual/migrate_from_flux#Training/Inference-Mode","137":"/previews/PR1023/manual/migrate_from_flux#Can-we-still-use-Flux-Layers?","138":"/previews/PR1023/manual/interface#lux-interface","139":"/previews/PR1023/manual/interface#Layer-Interface","140":"/previews/PR1023/manual/interface#Singular-Layer","141":"/previews/PR1023/manual/interface#Container-Layer","142":"/previews/PR1023/manual/interface#Parameter-Interface","143":"/previews/PR1023/manual/interface#State-Interface","144":"/previews/PR1023/manual/nested_autodiff#nested_autodiff","145":"/previews/PR1023/manual/nested_autodiff#Loss-Function-containing-Jacobian-Computation","146":"/previews/PR1023/manual/nested_autodiff#Using-Batched-Jacobian-for-Multiple-Inputs","147":"/previews/PR1023/manual/nested_autodiff#Loss-Function-contains-Gradient-Computation","148":"/previews/PR1023/manual/nested_autodiff#Loss-Function-computing-the-Jacobian-of-the-Parameters","149":"/previews/PR1023/manual/nested_autodiff#Hutchinson-Trace-Estimation","150":"/previews/PR1023/manual/nested_autodiff#Computing-using-the-Vector-Jacobian-Product","151":"/previews/PR1023/manual/nested_autodiff#Computing-using-the-Jacobian-Vector-Product","152":"/previews/PR1023/manual/nested_autodiff#Computing-using-the-Full-Jacobian","153":"/previews/PR1023/manual/nn_inside_gpu_kernels#Neural-Networks-Inside-GPU-Kernels","154":"/previews/PR1023/manual/performance_pitfalls#Performance-Pitfalls-and-How-to-Catch-Them","155":"/previews/PR1023/manual/performance_pitfalls#Spurious-Type-Promotion","156":"/previews/PR1023/manual/performance_pitfalls#Scalar-Indexing-on-GPU-Arrays","157":"/previews/PR1023/manual/performance_pitfalls#Type-Instabilities","158":"/previews/PR1023/manual/performance_pitfalls#Faster-Primitives","159":"/previews/PR1023/manual/performance_pitfalls#Optional-Dependencies-for-Performance","160":"/previews/PR1023/manual/performance_pitfalls#Data-Loading-and-Device-Transfer","161":"/previews/PR1023/manual/preferences#Preferences-for-Lux.jl","162":"/previews/PR1023/manual/preferences#Nested-Automatic-Differentiation","163":"/previews/PR1023/manual/preferences#gpu-aware-mpi-preferences","164":"/previews/PR1023/manual/preferences#GPU-Backend-Selection","165":"/previews/PR1023/manual/preferences#automatic-eltypes-preference","166":"/previews/PR1023/manual/preferences#dispatch-doctor-preference","167":"/previews/PR1023/manual/preferences#disable_loop_vectorization","168":"/previews/PR1023/manual/weight_initializers#Initializing-Weights","169":"/previews/PR1023/manual/weight_initializers#Quick-examples","170":"/previews/PR1023/tutorials/beginner/1_Basics#Julia-and-Lux-for-the-Uninitiated","171":"/previews/PR1023/tutorials/beginner/1_Basics#arrays","172":"/previews/PR1023/tutorials/beginner/1_Basics#CUDA-Arrays","173":"/previews/PR1023/tutorials/beginner/1_Basics#im-mutability","174":"/previews/PR1023/tutorials/beginner/1_Basics#Managing-Randomness","175":"/previews/PR1023/tutorials/beginner/1_Basics#Automatic-Differentiation","176":"/previews/PR1023/tutorials/beginner/1_Basics#gradients","177":"/previews/PR1023/tutorials/beginner/1_Basics#Jacobian-Vector-Product","178":"/previews/PR1023/tutorials/beginner/1_Basics#Vector-Jacobian-Product","179":"/previews/PR1023/tutorials/beginner/1_Basics#Linear-Regression","180":"/previews/PR1023/tutorials/beginner/1_Basics#appendix","181":"/previews/PR1023/tutorials/beginner/3_SimpleRNN#Training-a-Simple-LSTM","182":"/previews/PR1023/tutorials/beginner/3_SimpleRNN#Package-Imports","183":"/previews/PR1023/tutorials/beginner/3_SimpleRNN#dataset","184":"/previews/PR1023/tutorials/beginner/3_SimpleRNN#Creating-a-Classifier","185":"/previews/PR1023/tutorials/beginner/3_SimpleRNN#Using-the-@compact-API","186":"/previews/PR1023/tutorials/beginner/3_SimpleRNN#Defining-Accuracy,-Loss-and-Optimiser","187":"/previews/PR1023/tutorials/beginner/3_SimpleRNN#Training-the-Model","188":"/previews/PR1023/tutorials/beginner/3_SimpleRNN#Saving-the-Model","189":"/previews/PR1023/tutorials/beginner/3_SimpleRNN#appendix","190":"/previews/PR1023/tutorials/beginner/4_SimpleChains#MNIST-Classification-with-SimpleChains","191":"/previews/PR1023/tutorials/beginner/4_SimpleChains#Package-Imports","192":"/previews/PR1023/tutorials/beginner/4_SimpleChains#Loading-MNIST","193":"/previews/PR1023/tutorials/beginner/4_SimpleChains#Define-the-Model","194":"/previews/PR1023/tutorials/beginner/4_SimpleChains#Helper-Functions","195":"/previews/PR1023/tutorials/beginner/4_SimpleChains#Define-the-Training-Loop","196":"/previews/PR1023/tutorials/beginner/4_SimpleChains#Finally-Training-the-Model","197":"/previews/PR1023/tutorials/beginner/4_SimpleChains#appendix","198":"/previews/PR1023/tutorials/#tutorials","199":"/previews/PR1023/tutorials/#beginner-tutorials","200":"/previews/PR1023/tutorials/#intermediate-tutorials","201":"/previews/PR1023/tutorials/#advanced-tutorials","202":"/previews/PR1023/tutorials/#larger-models","203":"/previews/PR1023/tutorials/#selected-3rd-party-tutorials","204":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#MNIST-Classification-using-Neural-ODEs","205":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#Package-Imports","206":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#Loading-MNIST","207":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#Define-the-Neural-ODE-Layer","208":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#Create-and-Initialize-the-Neural-ODE-Layer","209":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#Define-Utility-Functions","210":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#training","211":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#Alternate-Implementation-using-Stateful-Layer","212":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#Train-the-new-Stateful-Neural-ODE","213":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#Type-Stability","214":"/previews/PR1023/tutorials/intermediate/1_NeuralODE#appendix","215":"/previews/PR1023/tutorials/beginner/5_OptimizationIntegration#Optimization-Lux-Tutorial","216":"/previews/PR1023/tutorials/beginner/5_OptimizationIntegration#Imports-packages","217":"/previews/PR1023/tutorials/beginner/5_OptimizationIntegration#Generate-some-training-data","218":"/previews/PR1023/tutorials/beginner/5_OptimizationIntegration#Define-the-DataLoader","219":"/previews/PR1023/tutorials/beginner/5_OptimizationIntegration#Training-the-model","220":"/previews/PR1023/tutorials/beginner/5_OptimizationIntegration#Plotting-the-results","221":"/previews/PR1023/tutorials/beginner/5_OptimizationIntegration#appendix","222":"/previews/PR1023/tutorials/beginner/2_PolynomialFitting#Fitting-a-Polynomial-using-MLP","223":"/previews/PR1023/tutorials/beginner/2_PolynomialFitting#Package-Imports","224":"/previews/PR1023/tutorials/beginner/2_PolynomialFitting#dataset","225":"/previews/PR1023/tutorials/beginner/2_PolynomialFitting#Neural-Network","226":"/previews/PR1023/tutorials/beginner/2_PolynomialFitting#optimizer","227":"/previews/PR1023/tutorials/beginner/2_PolynomialFitting#Loss-Function","228":"/previews/PR1023/tutorials/beginner/2_PolynomialFitting#training","229":"/previews/PR1023/tutorials/beginner/2_PolynomialFitting#appendix","230":"/previews/PR1023/tutorials/intermediate/3_HyperNet#Training-a-HyperNetwork-on-MNIST-and-FashionMNIST","231":"/previews/PR1023/tutorials/intermediate/3_HyperNet#Package-Imports","232":"/previews/PR1023/tutorials/intermediate/3_HyperNet#Loading-Datasets","233":"/previews/PR1023/tutorials/intermediate/3_HyperNet#Implement-a-HyperNet-Layer","234":"/previews/PR1023/tutorials/intermediate/3_HyperNet#Create-and-Initialize-the-HyperNet","235":"/previews/PR1023/tutorials/intermediate/3_HyperNet#Define-Utility-Functions","236":"/previews/PR1023/tutorials/intermediate/3_HyperNet#training","237":"/previews/PR1023/tutorials/intermediate/3_HyperNet#appendix","238":"/previews/PR1023/tutorials/intermediate/4_PINN2DPDE#Training-a-PINN-on-2D-PDE","239":"/previews/PR1023/tutorials/intermediate/4_PINN2DPDE#Package-Imports","240":"/previews/PR1023/tutorials/intermediate/4_PINN2DPDE#Problem-Definition","241":"/previews/PR1023/tutorials/intermediate/4_PINN2DPDE#Define-the-Neural-Networks","242":"/previews/PR1023/tutorials/intermediate/4_PINN2DPDE#Define-the-Loss-Functions","243":"/previews/PR1023/tutorials/intermediate/4_PINN2DPDE#Generate-the-Data","244":"/previews/PR1023/tutorials/intermediate/4_PINN2DPDE#training","245":"/previews/PR1023/tutorials/intermediate/4_PINN2DPDE#Visualizing-the-Results","246":"/previews/PR1023/tutorials/intermediate/4_PINN2DPDE#appendix","247":"/previews/PR1023/tutorials/intermediate/2_BayesianNN#Bayesian-Neural-Network","248":"/previews/PR1023/tutorials/intermediate/2_BayesianNN#Generating-data","249":"/previews/PR1023/tutorials/intermediate/2_BayesianNN#Building-the-Neural-Network","250":"/previews/PR1023/tutorials/intermediate/2_BayesianNN#Prediction-Visualization","251":"/previews/PR1023/tutorials/intermediate/2_BayesianNN#appendix","252":"/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm#Training-a-Neural-ODE-to-Model-Gravitational-Waveforms","253":"/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm#Package-Imports","254":"/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm#Define-some-Utility-Functions","255":"/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm#Simulating-the-True-Model","256":"/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm#Defiing-a-Neural-Network-Model","257":"/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm#Setting-Up-for-Training-the-Neural-Network","258":"/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm#Training-the-Neural-Network","259":"/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm#Visualizing-the-Results","260":"/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm#appendix"},"fieldIds":{"title":0,"titles":1,"text":2},"fieldLength":{"0":[1,1,14],"1":[1,1,46],"2":[2,1,156],"3":[1,1,194],"4":[3,1,93],"5":[1,1,114],"6":[1,1,38],"7":[2,1,160],"8":[1,1,214],"9":[1,1,19],"10":[1,1,62],"11":[2,1,77],"12":[1,1,5],"13":[2,1,100],"14":[2,1,44],"15":[2,1,68],"16":[2,1,128],"17":[1,1,160],"18":[3,1,132],"19":[1,1,232],"20":[2,1,91],"21":[1,1,16],"22":[3,1,27],"23":[2,1,1],"24":[2,3,342],"25":[3,3,92],"26":[3,1,1],"27":[4,3,72],"28":[2,3,86],"29":[4,3,13],"30":[2,1,54],"31":[2,2,131],"32":[3,2,124],"33":[2,2,140],"34":[2,2,118],"35":[6,1,1],"36":[4,6,1],"37":[4,10,172],"38":[6,6,1],"39":[5,11,188],"40":[2,1,11],"41":[1,2,29],"42":[1,2,81],"43":[2,2,18],"44":[2,2,58],"45":[3,2,31],"46":[3,2,35],"47":[1,1,48],"48":[4,1,91],"49":[2,1,127],"50":[3,1,33],"51":[1,1,1],"52":[2,1,228],"53":[2,1,449],"54":[2,1,134],"55":[2,1,164],"56":[4,1,45],"57":[3,1,108],"58":[2,1,112],"59":[2,1,358],"60":[1,1,54],"61":[3,1,1],"62":[1,3,292],"63":[2,3,257],"64":[2,3,115],"65":[2,3,168],"66":[2,3,361],"67":[2,3,191],"68":[3,3,243],"69":[2,3,294],"70":[1,3,165],"71":[6,1,47],"72":[4,1,34],"73":[4,1,29],"74":[1,1,67],"75":[2,1,1],"76":[1,2,51],"77":[1,2,402],"78":[3,2,181],"79":[2,2,36],"80":[2,2,17],"81":[5,1,63],"82":[2,5,58],"83":[6,5,218],"84":[4,1,48],"85":[4,1,41],"86":[2,4,1],"87":[2,6,27],"88":[3,6,22],"89":[2,4,1],"90":[2,6,119],"91":[3,6,19],"92":[2,4,30],"93":[2,4,48],"94":[2,6,22],"95":[3,6,30],"96":[2,4,1],"97":[5,5,117],"98":[5,5,54],"99":[5,5,68],"100":[2,5,63],"101":[2,1,35],"102":[1,2,34],"103":[1,2,50],"104":[2,2,65],"105":[1,2,67],"106":[5,1,1],"107":[7,5,36],"108":[2,5,40],"109":[4,7,72],"110":[3,7,70],"111":[5,7,47],"112":[8,7,46],"113":[6,1,493],"114":[4,6,156],"115":[2,1,71],"116":[6,2,76],"117":[3,2,44],"118":[4,1,27],"119":[7,4,122],"120":[5,4,42],"121":[2,9,28],"122":[2,9,79],"123":[2,4,52],"124":[3,1,76],"125":[6,3,156],"126":[3,3,190],"127":[1,3,51],"128":[3,1,27],"129":[6,3,123],"130":[4,3,53],"131":[5,3,43],"132":[5,3,49],"133":[5,1,67],"134":[3,5,164],"135":[4,5,1],"136":[3,9,49],"137":[7,5,34],"138":[2,1,80],"139":[2,2,1],"140":[2,3,239],"141":[2,3,158],"142":[2,2,151],"143":[2,2,47],"144":[3,1,169],"145":[5,3,263],"146":[6,8,155],"147":[5,3,219],"148":[7,3,216],"149":[3,3,88],"150":[6,6,46],"151":[6,6,31],"152":[5,6,113],"153":[5,1,286],"154":[7,1,18],"155":[3,7,149],"156":[5,7,32],"157":[2,7,39],"158":[2,7,43],"159":[4,7,39],"160":[5,7,75],"161":[4,1,49],"162":[3,4,21],"163":[4,4,40],"164":[3,4,33],"165":[3,4,23],"166":[2,4,61],"167":[4,4,58],"168":[2,1,133],"169":[2,2,64],"170":[6,1,77],"171":[1,6,286],"172":[2,7,86],"173":[3,6,110],"174":[2,6,130],"175":[2,6,96],"176":[1,8,72],"177":[3,8,106],"178":[3,8,30],"179":[2,6,253],"180":[1,6,150],"181":[4,1,38],"182":[2,4,12],"183":[1,4,95],"184":[3,4,160],"185":[4,4,74],"186":[5,4,56],"187":[3,4,526],"188":[3,4,48],"189":[1,4,149],"190":[4,1,33],"191":[2,4,15],"192":[2,4,60],"193":[3,4,64],"194":[2,4,38],"195":[4,4,73],"196":[4,4,124],"197":[1,4,110],"198":[1,1,1],"199":[2,1,1],"200":[2,1,1],"201":[2,1,1],"202":[2,1,41],"203":[4,1,65],"204":[5,1,24],"205":[2,5,23],"206":[2,5,64],"207":[5,5,139],"208":[7,5,60],"209":[3,5,37],"210":[1,5,234],"211":[5,5,60],"212":[6,5,71],"213":[2,5,180],"214":[1,5,150],"215":[6,1,78],"216":[2,6,29],"217":[4,6,58],"218":[3,6,70],"219":[3,6,244],"220":[3,6,47],"221":[1,6,150],"222":[5,1,16],"223":[2,5,12],"224":[1,5,274],"225":[2,5,37],"226":[1,5,18],"227":[2,5,112],"228":[1,5,150],"229":[1,5,150],"230":[7,1,1],"231":[2,7,18],"232":[2,7,41],"233":[4,7,76],"234":[5,7,42],"235":[3,7,39],"236":[1,7,244],"237":[1,7,150],"238":[6,1,45],"239":[2,6,31],"240":[2,6,26],"241":[4,6,55],"242":[4,6,71],"243":[3,6,86],"244":[1,6,1041],"245":[3,6,73],"246":[1,6,150],"247":[3,1,72],"248":[2,3,105],"249":[4,3,546],"250":[2,3,174],"251":[1,3,103],"252":[8,1,21],"253":[2,8,13],"254":[4,8,202],"255":[4,8,124],"256":[5,8,1353],"257":[7,8,73],"258":[4,8,1251],"259":[3,8,83],"260":[1,8,103]},"averageFieldLength":[2.954022988505747,3.6091954022988504,107.27586206896551],"storedFields":{"0":{"title":"MLDataDevices","titles":[]},"1":{"title":"Preferences","titles":["MLDataDevices"]},"2":{"title":"Data Transfer","titles":["MLDataDevices"]},"3":{"title":"Miscellaneous","titles":["MLDataDevices"]},"4":{"title":"Multi-GPU Support","titles":["MLDataDevices"]},"5":{"title":"Iteration","titles":["MLDataDevices"]},"6":{"title":"LuxCore","titles":[]},"7":{"title":"Abstract Types","titles":["LuxCore"]},"8":{"title":"General","titles":["LuxCore"]},"9":{"title":"Parameters","titles":["LuxCore"]},"10":{"title":"States","titles":["LuxCore"]},"11":{"title":"Layer size","titles":["LuxCore"]},"12":{"title":"LuxLib","titles":[]},"13":{"title":"Apply Activation","titles":["LuxLib"]},"14":{"title":"Batched Operations","titles":["LuxLib"]},"15":{"title":"Bias Activation","titles":["LuxLib"]},"16":{"title":"Convolutional Layers","titles":["LuxLib"]},"17":{"title":"Dropout","titles":["LuxLib"]},"18":{"title":"Fully Connected Layers","titles":["LuxLib"]},"19":{"title":"Normalization","titles":["LuxLib"]},"20":{"title":"Helper Functions","titles":["LuxLib"]},"21":{"title":"WeightInitializers","titles":[]},"22":{"title":"Supported RNG Types","titles":["WeightInitializers"]},"23":{"title":"API Reference","titles":["WeightInitializers"]},"24":{"title":"Main Functions","titles":["WeightInitializers","API Reference"]},"25":{"title":"Other Convenience Functions","titles":["WeightInitializers","API Reference"]},"26":{"title":"Automatic Differentiation Helpers","titles":[]},"27":{"title":"JVP & VJP Wrappers","titles":["Automatic Differentiation Helpers"]},"28":{"title":"Batched AD","titles":["Automatic Differentiation Helpers"]},"29":{"title":"Nested 2nd Order AD","titles":["Automatic Differentiation Helpers"]},"30":{"title":"Experimental Features","titles":[]},"31":{"title":"Parameter Freezing","titles":["Experimental Features"]},"32":{"title":"Map over Layer","titles":["Experimental Features"]},"33":{"title":"Debugging Functionality","titles":["Experimental Features"]},"34":{"title":"Tied Parameters","titles":["Experimental Features"]},"35":{"title":"Interoperability between Lux and other packages","titles":[]},"36":{"title":"Switching from older frameworks","titles":["Interoperability between Lux and other packages"]},"37":{"title":"Flux Models to Lux Models","titles":["Interoperability between Lux and other packages","Switching from older frameworks"]},"38":{"title":"Using a different backend for Lux","titles":["Interoperability between Lux and other packages"]},"39":{"title":"Lux Models to Simple Chains","titles":["Interoperability between Lux and other packages","Using a different backend for Lux"]},"40":{"title":"Distributed Utils","titles":[]},"41":{"title":"Backends","titles":["Distributed Utils"]},"42":{"title":"Initialization","titles":["Distributed Utils"]},"43":{"title":"Helper Functions","titles":["Distributed Utils"]},"44":{"title":"Communication Primitives","titles":["Distributed Utils"]},"45":{"title":"Optimizers.jl Integration","titles":["Distributed Utils"]},"46":{"title":"MLUtils.jl Integration","titles":["Distributed Utils"]},"47":{"title":"LuxTestUtils","titles":[]},"48":{"title":"Testing using JET.jl","titles":["LuxTestUtils"]},"49":{"title":"Gradient Correctness","titles":["LuxTestUtils"]},"50":{"title":"Extensions to @test","titles":["LuxTestUtils"]},"51":{"title":"Utilities","titles":[]},"52":{"title":"Training API","titles":["Utilities"]},"53":{"title":"Loss Functions","titles":["Utilities"]},"54":{"title":"LuxOps Module","titles":["Utilities"]},"55":{"title":"Recursive Operations","titles":["Utilities"]},"56":{"title":"Updating Floating Point Precision","titles":["Utilities"]},"57":{"title":"Element Type Matching","titles":["Utilities"]},"58":{"title":"Stateful Layer","titles":["Utilities"]},"59":{"title":"Compact Layer","titles":["Utilities"]},"60":{"title":"Miscellaneous","titles":["Utilities"]},"61":{"title":"Built-In Layers","titles":[]},"62":{"title":"Containers","titles":["Built-In Layers"]},"63":{"title":"Convolutional Layers","titles":["Built-In Layers"]},"64":{"title":"Dropout Layers","titles":["Built-In Layers"]},"65":{"title":"Pooling Layers","titles":["Built-In Layers"]},"66":{"title":"Recurrent Layers","titles":["Built-In Layers"]},"67":{"title":"Linear Layers","titles":["Built-In Layers"]},"68":{"title":"Misc. Helper Layers","titles":["Built-In Layers"]},"69":{"title":"Normalization Layers","titles":["Built-In Layers"]},"70":{"title":"Upsampling","titles":["Built-In Layers"]},"71":{"title":"How to Install Lux.jl?","titles":[]},"72":{"title":"Want GPU Support?","titles":[]},"73":{"title":"Want XLA Support?","titles":[]},"74":{"title":"Citation","titles":[]},"75":{"title":"Getting Started","titles":[]},"76":{"title":"Installation","titles":["Getting Started"]},"77":{"title":"Quickstart","titles":["Getting Started"]},"78":{"title":"Defining Custom Layers","titles":["Getting Started"]},"79":{"title":"Additional Packages","titles":["Getting Started"]},"80":{"title":"GPU Support","titles":["Getting Started"]},"81":{"title":"Why we wrote Lux?","titles":[]},"82":{"title":"Design Principles","titles":["Why we wrote Lux?"]},"83":{"title":"Why use Lux over Flux?","titles":["Why we wrote Lux?"]},"84":{"title":"Resources to Get Started","titles":[]},"85":{"title":"Updating to Lux v1","titles":[]},"86":{"title":"LuxLib.jl","titles":["Updating to Lux v1"]},"87":{"title":"Breaking Changes","titles":["Updating to Lux v1","LuxLib.jl"]},"88":{"title":"New Major Features","titles":["Updating to Lux v1","LuxLib.jl"]},"89":{"title":"LuxCore.jl","titles":["Updating to Lux v1"]},"90":{"title":"Breaking Changes","titles":["Updating to Lux v1","LuxCore.jl"]},"91":{"title":"New Major Features","titles":["Updating to Lux v1","LuxCore.jl"]},"92":{"title":"WeightInitializers.jl","titles":["Updating to Lux v1"]},"93":{"title":"MLDataDevices.jl","titles":["Updating to Lux v1"]},"94":{"title":"Breaking Changes","titles":["Updating to Lux v1","MLDataDevices.jl"]},"95":{"title":"New Major Features","titles":["Updating to Lux v1","MLDataDevices.jl"]},"96":{"title":"Lux.jl","titles":["Updating to Lux v1"]},"97":{"title":"Breaking Changes (Removed Functionality)","titles":["Updating to Lux v1","Lux.jl"]},"98":{"title":"Breaking Changes (Moved Functionality)","titles":["Updating to Lux v1","Lux.jl"]},"99":{"title":"Breaking Changes (Changes in Defaults)","titles":["Updating to Lux v1","Lux.jl"]},"100":{"title":"New Features","titles":["Updating to Lux v1","Lux.jl"]},"101":{"title":"Automatic Differentiation","titles":[]},"102":{"title":"Overview","titles":["Automatic Differentiation"]},"103":{"title":"Recommendations","titles":["Automatic Differentiation"]},"104":{"title":"Support Class","titles":["Automatic Differentiation"]},"105":{"title":"Footnotes","titles":["Automatic Differentiation"]},"106":{"title":"Dispatching on Custom Input Types","titles":[]},"107":{"title":"Which function should participate in dispatch?","titles":["Dispatching on Custom Input Types"]},"108":{"title":"Concrete Example","titles":["Dispatching on Custom Input Types"]},"109":{"title":"Time-Dependent Chain Implementation","titles":["Dispatching on Custom Input Types","Concrete Example"]},"110":{"title":"Running the TDChain","titles":["Dispatching on Custom Input Types","Concrete Example"]},"111":{"title":"Writing the Correct Dispatch Rules","titles":["Dispatching on Custom Input Types","Concrete Example"]},"112":{"title":"Using the Same Input for Non-TD Models","titles":["Dispatching on Custom Input Types","Concrete Example"]},"113":{"title":"Compiling Lux Models using Reactant.jl","titles":[]},"114":{"title":"Using the TrainState API","titles":["Compiling Lux Models using Reactant.jl"]},"115":{"title":"GPU Management","titles":[]},"116":{"title":"Automatic Backend Management (Recommended Approach)","titles":["GPU Management"]},"117":{"title":"Manual Backend Management","titles":["GPU Management"]},"118":{"title":"Distributed Data Parallel Training","titles":[]},"119":{"title":"Guide to Integrating DistributedUtils into your code","titles":["Distributed Data Parallel Training"]},"120":{"title":"Migration Guide from FluxMPI.jl","titles":["Distributed Data Parallel Training"]},"121":{"title":"Removed Functionality","titles":["Distributed Data Parallel Training","Migration Guide from FluxMPI.jl"]},"122":{"title":"Key Differences","titles":["Distributed Data Parallel Training","Migration Guide from FluxMPI.jl"]},"123":{"title":"Known Shortcomings","titles":["Distributed Data Parallel Training"]},"124":{"title":"Debugging Lux Models","titles":[]},"125":{"title":"Incorrect Model Specification: Dimension Mismatch Problems","titles":["Debugging Lux Models"]},"126":{"title":"Tracking down NaNs","titles":["Debugging Lux Models"]},"127":{"title":"Conclusion","titles":["Debugging Lux Models"]},"128":{"title":"Freezing Model Parameters","titles":[]},"129":{"title":"Freezing Layers of a Particular Kind","titles":["Freezing Model Parameters"]},"130":{"title":"Freezing by Layer Name","titles":["Freezing Model Parameters"]},"131":{"title":"Freezing Part of the Parameters","titles":["Freezing Model Parameters"]},"132":{"title":"Freezing Part of a Chain","titles":["Freezing Model Parameters"]},"133":{"title":"Migrating from Flux to Lux","titles":[]},"134":{"title":"Implementing Custom Layers","titles":["Migrating from Flux to Lux"]},"135":{"title":"Certain Important Implementation Details","titles":["Migrating from Flux to Lux"]},"136":{"title":"Training/Inference Mode","titles":["Migrating from Flux to Lux","Certain Important Implementation Details"]},"137":{"title":"Can we still use Flux Layers?","titles":["Migrating from Flux to Lux"]},"138":{"title":"Lux Interface","titles":[]},"139":{"title":"Layer Interface","titles":["Lux Interface"]},"140":{"title":"Singular Layer","titles":["Lux Interface","Layer Interface"]},"141":{"title":"Container Layer","titles":["Lux Interface","Layer Interface"]},"142":{"title":"Parameter Interface","titles":["Lux Interface"]},"143":{"title":"State Interface","titles":["Lux Interface"]},"144":{"title":"Nested Automatic Differentiation","titles":[]},"145":{"title":"Loss Function containing Jacobian Computation","titles":["Nested Automatic Differentiation"]},"146":{"title":"Using Batched Jacobian for Multiple Inputs","titles":["Nested Automatic Differentiation","Loss Function containing Jacobian Computation"]},"147":{"title":"Loss Function contains Gradient Computation","titles":["Nested Automatic Differentiation"]},"148":{"title":"Loss Function computing the Jacobian of the Parameters","titles":["Nested Automatic Differentiation"]},"149":{"title":"Hutchinson Trace Estimation","titles":["Nested Automatic Differentiation"]},"150":{"title":"Computing using the Vector-Jacobian Product","titles":["Nested Automatic Differentiation","Hutchinson Trace Estimation"]},"151":{"title":"Computing using the Jacobian-Vector Product","titles":["Nested Automatic Differentiation","Hutchinson Trace Estimation"]},"152":{"title":"Computing using the Full Jacobian","titles":["Nested Automatic Differentiation","Hutchinson Trace Estimation"]},"153":{"title":"Neural Networks Inside GPU Kernels","titles":[]},"154":{"title":"Performance Pitfalls & How to Catch Them","titles":[]},"155":{"title":"Spurious Type-Promotion","titles":["Performance Pitfalls & How to Catch Them"]},"156":{"title":"Scalar Indexing on GPU Arrays","titles":["Performance Pitfalls & How to Catch Them"]},"157":{"title":"Type Instabilities","titles":["Performance Pitfalls & How to Catch Them"]},"158":{"title":"Faster Primitives","titles":["Performance Pitfalls & How to Catch Them"]},"159":{"title":"Optional Dependencies for Performance","titles":["Performance Pitfalls & How to Catch Them"]},"160":{"title":"Data Loading and Device Transfer","titles":["Performance Pitfalls & How to Catch Them"]},"161":{"title":"Preferences for Lux.jl","titles":[]},"162":{"title":"Nested Automatic Differentiation","titles":["Preferences for Lux.jl"]},"163":{"title":"GPU-Aware MPI Support","titles":["Preferences for Lux.jl"]},"164":{"title":"GPU Backend Selection","titles":["Preferences for Lux.jl"]},"165":{"title":"Automatic Eltype Conversion","titles":["Preferences for Lux.jl"]},"166":{"title":"Dispatch Doctor","titles":["Preferences for Lux.jl"]},"167":{"title":"Disabling Loop Vectorization / Octavian","titles":["Preferences for Lux.jl"]},"168":{"title":"Initializing Weights","titles":[]},"169":{"title":"Quick examples","titles":["Initializing Weights"]},"170":{"title":"Julia & Lux for the Uninitiated","titles":[]},"171":{"title":"Arrays","titles":["Julia & Lux for the Uninitiated"]},"172":{"title":"CUDA Arrays","titles":["Julia & Lux for the Uninitiated","Arrays"]},"173":{"title":"(Im)mutability","titles":["Julia & Lux for the Uninitiated"]},"174":{"title":"Managing Randomness","titles":["Julia & Lux for the Uninitiated"]},"175":{"title":"Automatic Differentiation","titles":["Julia & Lux for the Uninitiated"]},"176":{"title":"Gradients","titles":["Julia & Lux for the Uninitiated","Automatic Differentiation"]},"177":{"title":"Jacobian-Vector Product","titles":["Julia & Lux for the Uninitiated","Automatic Differentiation"]},"178":{"title":"Vector-Jacobian Product","titles":["Julia & Lux for the Uninitiated","Automatic Differentiation"]},"179":{"title":"Linear Regression","titles":["Julia & Lux for the Uninitiated"]},"180":{"title":"Appendix","titles":["Julia & Lux for the Uninitiated"]},"181":{"title":"Training a Simple LSTM","titles":[]},"182":{"title":"Package Imports","titles":["Training a Simple LSTM"]},"183":{"title":"Dataset","titles":["Training a Simple LSTM"]},"184":{"title":"Creating a Classifier","titles":["Training a Simple LSTM"]},"185":{"title":"Using the @compact API","titles":["Training a Simple LSTM"]},"186":{"title":"Defining Accuracy, Loss and Optimiser","titles":["Training a Simple LSTM"]},"187":{"title":"Training the Model","titles":["Training a Simple LSTM"]},"188":{"title":"Saving the Model","titles":["Training a Simple LSTM"]},"189":{"title":"Appendix","titles":["Training a Simple LSTM"]},"190":{"title":"MNIST Classification with SimpleChains","titles":[]},"191":{"title":"Package Imports","titles":["MNIST Classification with SimpleChains"]},"192":{"title":"Loading MNIST","titles":["MNIST Classification with SimpleChains"]},"193":{"title":"Define the Model","titles":["MNIST Classification with SimpleChains"]},"194":{"title":"Helper Functions","titles":["MNIST Classification with SimpleChains"]},"195":{"title":"Define the Training Loop","titles":["MNIST Classification with SimpleChains"]},"196":{"title":"Finally Training the Model","titles":["MNIST Classification with SimpleChains"]},"197":{"title":"Appendix","titles":["MNIST Classification with SimpleChains"]},"198":{"title":"Tutorials","titles":[]},"199":{"title":"Beginner Tutorials","titles":["Tutorials"]},"200":{"title":"Intermediate Tutorials","titles":["Tutorials"]},"201":{"title":"Advanced Tutorials","titles":["Tutorials"]},"202":{"title":"Larger Models","titles":["Tutorials"]},"203":{"title":"Selected 3rd Party Tutorials","titles":["Tutorials"]},"204":{"title":"MNIST Classification using Neural ODEs","titles":[]},"205":{"title":"Package Imports","titles":["MNIST Classification using Neural ODEs"]},"206":{"title":"Loading MNIST","titles":["MNIST Classification using Neural ODEs"]},"207":{"title":"Define the Neural ODE Layer","titles":["MNIST Classification using Neural ODEs"]},"208":{"title":"Create and Initialize the Neural ODE Layer","titles":["MNIST Classification using Neural ODEs"]},"209":{"title":"Define Utility Functions","titles":["MNIST Classification using Neural ODEs"]},"210":{"title":"Training","titles":["MNIST Classification using Neural ODEs"]},"211":{"title":"Alternate Implementation using Stateful Layer","titles":["MNIST Classification using Neural ODEs"]},"212":{"title":"Train the new Stateful Neural ODE","titles":["MNIST Classification using Neural ODEs"]},"213":{"title":"Type Stability","titles":["MNIST Classification using Neural ODEs"]},"214":{"title":"Appendix","titles":["MNIST Classification using Neural ODEs"]},"215":{"title":"Training Lux Models using Optimization.jl","titles":[]},"216":{"title":"Imports packages","titles":["Training Lux Models using Optimization.jl"]},"217":{"title":"Generate some training data","titles":["Training Lux Models using Optimization.jl"]},"218":{"title":"Define the DataLoader","titles":["Training Lux Models using Optimization.jl"]},"219":{"title":"Training the model","titles":["Training Lux Models using Optimization.jl"]},"220":{"title":"Plotting the results","titles":["Training Lux Models using Optimization.jl"]},"221":{"title":"Appendix","titles":["Training Lux Models using Optimization.jl"]},"222":{"title":"Fitting a Polynomial using MLP","titles":[]},"223":{"title":"Package Imports","titles":["Fitting a Polynomial using MLP"]},"224":{"title":"Dataset","titles":["Fitting a Polynomial using MLP"]},"225":{"title":"Neural Network","titles":["Fitting a Polynomial using MLP"]},"226":{"title":"Optimizer","titles":["Fitting a Polynomial using MLP"]},"227":{"title":"Loss Function","titles":["Fitting a Polynomial using MLP"]},"228":{"title":"Training","titles":["Fitting a Polynomial using MLP"]},"229":{"title":"Appendix","titles":["Fitting a Polynomial using MLP"]},"230":{"title":"Training a HyperNetwork on MNIST and FashionMNIST","titles":[]},"231":{"title":"Package Imports","titles":["Training a HyperNetwork on MNIST and FashionMNIST"]},"232":{"title":"Loading Datasets","titles":["Training a HyperNetwork on MNIST and FashionMNIST"]},"233":{"title":"Implement a HyperNet Layer","titles":["Training a HyperNetwork on MNIST and FashionMNIST"]},"234":{"title":"Create and Initialize the HyperNet","titles":["Training a HyperNetwork on MNIST and FashionMNIST"]},"235":{"title":"Define Utility Functions","titles":["Training a HyperNetwork on MNIST and FashionMNIST"]},"236":{"title":"Training","titles":["Training a HyperNetwork on MNIST and FashionMNIST"]},"237":{"title":"Appendix","titles":["Training a HyperNetwork on MNIST and FashionMNIST"]},"238":{"title":"Training a PINN on 2D PDE","titles":[]},"239":{"title":"Package Imports","titles":["Training a PINN on 2D PDE"]},"240":{"title":"Problem Definition","titles":["Training a PINN on 2D PDE"]},"241":{"title":"Define the Neural Networks","titles":["Training a PINN on 2D PDE"]},"242":{"title":"Define the Loss Functions","titles":["Training a PINN on 2D PDE"]},"243":{"title":"Generate the Data","titles":["Training a PINN on 2D PDE"]},"244":{"title":"Training","titles":["Training a PINN on 2D PDE"]},"245":{"title":"Visualizing the Results","titles":["Training a PINN on 2D PDE"]},"246":{"title":"Appendix","titles":["Training a PINN on 2D PDE"]},"247":{"title":"Bayesian Neural Network","titles":[]},"248":{"title":"Generating data","titles":["Bayesian Neural Network"]},"249":{"title":"Building the Neural Network","titles":["Bayesian Neural Network"]},"250":{"title":"Prediction Visualization","titles":["Bayesian Neural Network"]},"251":{"title":"Appendix","titles":["Bayesian Neural Network"]},"252":{"title":"Training a Neural ODE to Model Gravitational Waveforms","titles":[]},"253":{"title":"Package Imports","titles":["Training a Neural ODE to Model Gravitational Waveforms"]},"254":{"title":"Define some Utility Functions","titles":["Training a Neural ODE to Model Gravitational Waveforms"]},"255":{"title":"Simulating the True Model","titles":["Training a Neural ODE to Model Gravitational Waveforms"]},"256":{"title":"Defiing a Neural Network Model","titles":["Training a Neural ODE to Model Gravitational Waveforms"]},"257":{"title":"Setting Up for Training the Neural Network","titles":["Training a Neural ODE to Model Gravitational Waveforms"]},"258":{"title":"Training the Neural Network","titles":["Training a Neural ODE to Model Gravitational Waveforms"]},"259":{"title":"Visualizing the Results","titles":["Training a Neural ODE to Model Gravitational Waveforms"]},"260":{"title":"Appendix","titles":["Training a Neural ODE to Model Gravitational Waveforms"]}},"dirtCount":0,"index":[["π",{"2":{"254":2,"255":1}}],["√",{"2":{"254":2}}],["√t",{"2":{"24":2}}],["↦",{"2":{"254":1}}],["ϕ̇",{"2":{"255":2,"256":2}}],["ϕ",{"2":{"254":5,"255":1,"256":1}}],["χ̇",{"2":{"255":2,"256":2}}],["χ",{"2":{"254":4,"255":4,"256":2}}],["~",{"2":{"249":2}}],["θ|x",{"2":{"250":2}}],["θ",{"2":{"219":2,"249":2,"250":9,"257":3}}],["₋₋₋kwargs₋₋₋",{"2":{"213":4}}],["₋₋₋no",{"2":{"213":3}}],["│",{"2":{"213":3,"244":4}}],["─",{"2":{"213":3}}],["÷",{"2":{"183":4}}],["∥22we",{"2":{"179":1}}],["⟶∑i=1k12∥yi−fw",{"2":{"179":1}}],["∇f",{"2":{"176":3}}],["∇offending",{"2":{"126":2}}],["$",{"2":{"245":1}}],["$i",{"2":{"174":2,"250":1}}],["$name",{"2":{"32":1}}],["⋮",{"2":{"153":4}}],["∞",{"2":{"145":4,"146":4,"147":4,"148":4,"152":8}}],["∘",{"2":{"144":4,"147":1,"242":3}}],["└──",{"2":{"213":3}}],["└",{"2":{"125":1,"145":2,"244":4}}],["┌",{"2":{"125":1,"145":2,"244":4}}],["∂w",{"2":{"242":2}}],["∂v",{"2":{"242":2}}],["∂y",{"2":{"242":4}}],["∂u",{"2":{"242":10}}],["∂t",{"2":{"147":7,"242":2}}],["∂xyt",{"2":{"242":4}}],["∂x",{"2":{"145":7,"146":7,"148":7,"152":11,"242":4}}],["∂ps",{"2":{"113":4,"145":8,"146":8,"147":8,"148":8,"152":11}}],["∂f∂x",{"2":{"27":2}}],["↩︎",{"2":{"105":8}}],["❌",{"2":{"102":5}}],["❓",{"2":{"102":6}}],["\\tfashionmnist\\ttraining",{"2":{"236":1}}],["\\tfashionmnist\\ttime",{"2":{"236":50}}],["\\ttest",{"2":{"210":45,"212":9,"236":102}}],["\\ttime",{"2":{"210":45,"212":9}}],["\\tloss",{"2":{"114":11}}],["\\t",{"2":{"78":11,"196":60,"228":6,"236":51,"244":400}}],["quantiles",{"2":{"249":1}}],["quadrupole",{"2":{"254":10}}],["quadratic",{"2":{"224":1,"228":1}}],["quadro",{"2":{"189":2}}],["questions",{"2":{"84":3,"144":1,"175":1}}],["quick",{"0":{"169":1},"2":{"170":1}}],["quickstart",{"0":{"77":1},"2":{"84":1}}],["quite",{"2":{"81":1,"173":1,"175":1}}],["quoting",{"2":{"113":1}}],["quot",{"2":{"1":2,"8":2,"17":4,"18":1,"19":8,"24":12,"53":8,"55":2,"57":16,"59":2,"60":6,"62":4,"68":2,"69":2,"77":4,"122":2,"134":4,"155":2,"164":8}}],["⋅n+z⋅hprevarguments",{"2":{"66":1}}],["↗",{"2":{"62":2}}],["↘",{"2":{"62":2}}],["→",{"2":{"62":5}}],["8c79",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["830047991223153e",{"2":{"258":1}}],["8305089262040196e",{"2":{"258":1}}],["8305636f",{"2":{"256":1}}],["8320104200392956e",{"2":{"258":1}}],["83204f",{"2":{"256":1}}],["8328445f",{"2":{"256":1}}],["8353274611788524e",{"2":{"258":1}}],["8355891705979897e",{"2":{"258":1}}],["8355807f",{"2":{"256":1}}],["8354533f",{"2":{"256":1}}],["8356404f",{"2":{"256":1}}],["8311624052447006e",{"2":{"258":1}}],["831631642649848e",{"2":{"258":1}}],["8316316f",{"2":{"256":1}}],["831381f",{"2":{"256":1}}],["8317274f",{"2":{"179":1}}],["8371021557932062e",{"2":{"258":1}}],["8372193f",{"2":{"256":1}}],["8376",{"2":{"249":1}}],["8374606",{"2":{"227":1}}],["837991",{"2":{"148":1}}],["8346457",{"2":{"224":2}}],["8340728",{"2":{"148":1}}],["83",{"2":{"196":5,"210":6,"212":1,"236":1}}],["836520186927469e",{"2":{"258":1}}],["836",{"2":{"193":2}}],["8393",{"2":{"171":1}}],["8393034",{"2":{"171":1}}],["839303",{"2":{"171":2}}],["8333237298210174e",{"2":{"258":1}}],["833333333333333",{"2":{"53":1}}],["833672802398019e",{"2":{"258":1}}],["8330512f",{"2":{"256":1}}],["833524f",{"2":{"256":1}}],["833518",{"2":{"172":1}}],["8337032",{"2":{"129":1}}],["892468235768816e",{"2":{"258":1}}],["892144f",{"2":{"256":1}}],["890699186331531e",{"2":{"258":1}}],["890690381046875e",{"2":{"258":1}}],["8906862f",{"2":{"256":1}}],["8905505f",{"2":{"256":1}}],["8904",{"2":{"249":1}}],["8946",{"2":{"249":1}}],["898799628394211e",{"2":{"258":1}}],["8981124186062922e",{"2":{"258":1}}],["898851f",{"2":{"256":1}}],["8984",{"2":{"249":1}}],["89858943",{"2":{"147":1}}],["8978888f",{"2":{"256":1}}],["8972864",{"2":{"224":1}}],["8976378",{"2":{"224":2}}],["893717e",{"2":{"219":1}}],["89",{"2":{"196":2,"236":4}}],["8969011",{"2":{"224":1}}],["896",{"2":{"193":2}}],["8990",{"2":{"249":1}}],["899766",{"2":{"171":1}}],["8999977",{"2":{"148":1}}],["81911717151185e",{"2":{"258":1}}],["8192515f",{"2":{"256":1}}],["81226592446107e",{"2":{"258":1}}],["812392f",{"2":{"256":1}}],["8186904187735986e",{"2":{"258":1}}],["818771f",{"2":{"256":1}}],["813496721283482e",{"2":{"258":1}}],["8134747926928233e",{"2":{"258":1}}],["813401560482127e",{"2":{"258":1}}],["813453f",{"2":{"256":1}}],["813701563686835e",{"2":{"258":1}}],["813278f",{"2":{"256":1}}],["813609f",{"2":{"256":1}}],["8100",{"2":{"249":1}}],["816281",{"2":{"224":1}}],["8110236",{"2":{"224":2}}],["81",{"2":{"196":3,"210":7,"212":1,"236":14,"249":1}}],["8173783982243132",{"2":{"153":2}}],["815336",{"2":{"148":1}}],["81446123",{"2":{"227":1}}],["81481",{"2":{"210":2,"212":1}}],["8146973e",{"2":{"147":2}}],["8147778",{"2":{"113":1}}],["881092397505103e",{"2":{"258":1}}],["8812",{"2":{"249":1}}],["8876375645610345e",{"2":{"258":1}}],["887765164166148e",{"2":{"258":1}}],["887439f",{"2":{"256":1}}],["8874685f",{"2":{"256":1}}],["8862770325360788e",{"2":{"258":1}}],["8862090861358614e",{"2":{"258":1}}],["886204f",{"2":{"256":1}}],["8865496f",{"2":{"256":1}}],["885557754969983e",{"2":{"258":1}}],["885181f",{"2":{"256":1}}],["885339f",{"2":{"256":1}}],["8852221",{"2":{"148":1}}],["884882862087531e",{"2":{"258":1}}],["8840191347848076e",{"2":{"258":1}}],["884766f",{"2":{"256":1}}],["8841477f",{"2":{"256":1}}],["880321120734988e",{"2":{"258":1}}],["8800975f",{"2":{"256":1}}],["8808688f",{"2":{"256":1}}],["88",{"2":{"236":25}}],["8821303",{"2":{"224":1}}],["88214725",{"2":{"148":1}}],["889379232687275e",{"2":{"258":1}}],["889217f",{"2":{"256":1}}],["88951594",{"2":{"224":1}}],["889",{"2":{"214":1}}],["88889",{"2":{"210":1}}],["883664f0",{"2":{"145":1}}],["861781792408604e",{"2":{"258":1}}],["864963571264616e",{"2":{"258":1}}],["864745f",{"2":{"256":1}}],["863495209602258e",{"2":{"258":1}}],["8632966f",{"2":{"256":1}}],["8638",{"2":{"249":1}}],["860529948821097e",{"2":{"258":1}}],["8602",{"2":{"249":1}}],["8601828553599953",{"2":{"174":1}}],["8601870861800127",{"2":{"153":2}}],["868463810140957e",{"2":{"258":1}}],["868031915455153e",{"2":{"258":1}}],["868724311989627e",{"2":{"258":1}}],["868308f",{"2":{"256":1}}],["868859f",{"2":{"256":1}}],["8688824",{"2":{"224":1}}],["8689",{"2":{"249":1}}],["86",{"2":{"236":2}}],["86614174",{"2":{"224":2}}],["8678976f",{"2":{"256":1}}],["8672",{"2":{"249":1}}],["867202",{"2":{"145":1}}],["8674763752817414",{"2":{"153":1}}],["8674763752817416",{"2":{"153":1}}],["869632",{"2":{"145":1}}],["8620004f",{"2":{"256":1}}],["862480861009647",{"2":{"153":2}}],["86290836",{"2":{"129":1}}],["8626451f",{"2":{"113":5}}],["855562705065513e",{"2":{"258":1}}],["8555611f",{"2":{"256":1}}],["851286588716759e",{"2":{"258":1}}],["851014f",{"2":{"256":1}}],["85185",{"2":{"210":2}}],["8567413f",{"2":{"256":1}}],["8534",{"2":{"249":1}}],["85344f",{"2":{"77":1}}],["85",{"2":{"196":1,"210":4,"236":2}}],["8501",{"2":{"244":1}}],["85048s\\ttraining",{"2":{"236":1}}],["85050875",{"2":{"224":1}}],["850",{"2":{"193":2}}],["857109069472575e",{"2":{"258":1}}],["857129e",{"2":{"219":1}}],["857126",{"2":{"172":1}}],["8576512",{"2":{"224":1}}],["857257",{"2":{"172":1}}],["8573820474674845",{"2":{"171":1}}],["859405",{"2":{"147":1,"148":1}}],["8541596",{"2":{"145":1}}],["806619980087237e",{"2":{"258":1}}],["8067698",{"2":{"147":1}}],["8032760151279896e",{"2":{"258":1}}],["8030385957553316e",{"2":{"258":1}}],["8030583f",{"2":{"256":1}}],["803776944039973e",{"2":{"258":1}}],["8038574f",{"2":{"256":1}}],["8031135f",{"2":{"256":1}}],["8031547",{"2":{"224":1}}],["8031496",{"2":{"224":2}}],["8096896989837945e",{"2":{"258":1}}],["809528f",{"2":{"256":1}}],["8094",{"2":{"249":1}}],["809456",{"2":{"171":1}}],["8050",{"2":{"249":1}}],["8013359",{"2":{"224":1}}],["80s",{"2":{"196":1}}],["80",{"2":{"180":1,"196":1,"210":10,"212":2,"214":1,"221":1,"229":1,"236":5,"237":1,"246":1,"248":1}}],["8048109",{"2":{"227":1}}],["80465555",{"2":{"179":1}}],["80423f",{"2":{"77":1}}],["8001",{"2":{"179":1,"244":1}}],["800792614736468",{"2":{"153":2}}],["8003627",{"2":{"147":1}}],["800",{"2":{"114":1}}],["8f",{"2":{"114":1,"179":1}}],["8731227105327503e",{"2":{"258":1}}],["873387646805597e",{"2":{"258":1}}],["873253f",{"2":{"256":1}}],["879934235450455e",{"2":{"258":1}}],["8798057233994109e",{"2":{"258":1}}],["870946348088488e",{"2":{"258":1}}],["8709976f",{"2":{"256":1}}],["872209719202946e",{"2":{"258":1}}],["8723276f",{"2":{"256":1}}],["8712764366426587e",{"2":{"258":1}}],["8714978f",{"2":{"256":1}}],["87143785f0",{"2":{"77":1}}],["8718843f",{"2":{"256":1}}],["8713104f",{"2":{"256":1}}],["8787",{"2":{"249":1}}],["875082",{"2":{"224":1}}],["874391613601782e",{"2":{"258":1}}],["8743932f",{"2":{"256":1}}],["87431f",{"2":{"77":1}}],["8740157",{"2":{"224":2}}],["8776116f",{"2":{"256":1}}],["8775695f",{"2":{"256":1}}],["8771",{"2":{"249":1}}],["877497",{"2":{"177":1,"178":1}}],["87702435",{"2":{"113":1}}],["87",{"2":{"125":1,"196":2,"236":1}}],["828415258935756e",{"2":{"258":1}}],["82805836",{"2":{"129":1}}],["825388138923504e",{"2":{"258":1}}],["825502f",{"2":{"256":1}}],["8217748231112443e",{"2":{"258":1}}],["8219034f",{"2":{"256":1}}],["823967307297597e",{"2":{"258":1}}],["823969f",{"2":{"256":1}}],["8268793412463466e",{"2":{"258":1}}],["820522772013102e",{"2":{"258":1}}],["820559241234105e",{"2":{"258":1}}],["820250917871861e",{"2":{"258":1}}],["820468f",{"2":{"256":1}}],["820306f",{"2":{"256":1}}],["82030004",{"2":{"224":1}}],["820133f",{"2":{"256":1}}],["827072f",{"2":{"256":1}}],["8277",{"2":{"249":1}}],["8271f",{"2":{"77":1}}],["829187735092528e",{"2":{"258":1}}],["829975f",{"2":{"256":1}}],["829441f",{"2":{"256":1}}],["82945824",{"2":{"77":1}}],["829764f",{"2":{"256":1}}],["8297",{"2":{"249":1}}],["82293516",{"2":{"224":1}}],["82",{"2":{"210":6,"212":2,"236":2}}],["8",{"2":{"53":1,"62":2,"68":1,"77":27,"113":28,"145":1,"147":2,"148":3,"171":2,"173":4,"183":1,"187":15,"196":2,"210":5,"212":1,"219":2,"224":1,"226":1,"228":1,"236":2,"249":8,"251":1,"256":73,"258":72,"260":1}}],["848158295162834e",{"2":{"258":1}}],["848705f",{"2":{"256":1}}],["843297049045521e",{"2":{"258":1}}],["843734576651803e",{"2":{"258":1}}],["843735f",{"2":{"256":1}}],["8434587f",{"2":{"256":1}}],["8412067816565533e",{"2":{"258":1}}],["841231",{"2":{"148":1}}],["8414666421339533e",{"2":{"258":1}}],["8413555f",{"2":{"256":1}}],["841769f",{"2":{"256":1}}],["8409087462921232e",{"2":{"258":1}}],["8409087f",{"2":{"256":1}}],["840588",{"2":{"145":1}}],["8499767",{"2":{"224":1}}],["8490221",{"2":{"142":1}}],["8424188",{"2":{"224":1}}],["8425196",{"2":{"224":2}}],["8454118",{"2":{"148":1}}],["84576",{"2":{"77":1}}],["847106",{"2":{"148":1}}],["846457",{"2":{"148":1}}],["84",{"2":{"39":2,"193":6,"196":4,"210":1,"212":1,"236":30}}],["δ",{"2":{"53":1,"126":3,"217":2}}],["ϵ",{"2":{"53":1}}],["ŷ",{"2":{"53":6}}],["∈",{"2":{"53":2,"254":1}}],["∗y+α∗size",{"2":{"53":1}}],["∗y+α∗0",{"2":{"53":1}}],["∗y^−logσ",{"2":{"53":1}}],["∗log⁡",{"2":{"53":1}}],["−log⁡",{"2":{"53":1}}],["−∑y~log⁡",{"2":{"53":1}}],["−",{"2":{"53":1}}],["−y~∗log⁡",{"2":{"53":1}}],["−x",{"2":{"24":1}}],["≈∑θ∼p",{"2":{"250":1}}],["≈",{"2":{"53":25,"59":1,"116":1,"117":1,"174":2}}],["9f",{"2":{"244":8}}],["9365659316733255e",{"2":{"258":1}}],["936639f",{"2":{"256":1}}],["938388500402002e",{"2":{"258":1}}],["9383338f",{"2":{"256":1}}],["933786275208068e",{"2":{"258":1}}],["9338737",{"2":{"148":1}}],["931439427087599e",{"2":{"258":1}}],["931216f",{"2":{"256":1}}],["939203097486151e",{"2":{"258":1}}],["9394017f",{"2":{"256":1}}],["937424637028749e",{"2":{"258":1}}],["9370079",{"2":{"224":2}}],["9304534471406444e",{"2":{"258":1}}],["9303988f",{"2":{"256":1}}],["9307",{"2":{"249":1}}],["934592878737014e",{"2":{"258":1}}],["934357165828628e",{"2":{"258":1}}],["934061075320488e",{"2":{"258":1}}],["9340394f",{"2":{"256":1}}],["9340093",{"2":{"147":1}}],["934296f",{"2":{"256":1}}],["934451f",{"2":{"256":1}}],["93",{"2":{"236":4}}],["93s",{"2":{"196":1}}],["911940442133451e",{"2":{"258":1}}],["9192097860775e",{"2":{"258":1}}],["914788743029572e",{"2":{"258":1}}],["91466f",{"2":{"256":1}}],["9156087437515224e",{"2":{"258":1}}],["9155748f",{"2":{"256":1}}],["918210845072637e",{"2":{"258":1}}],["91873466200093e",{"2":{"258":1}}],["918156f",{"2":{"256":1}}],["9183998644002725e",{"2":{"258":1}}],["918367f",{"2":{"256":1}}],["9183702f",{"2":{"256":1}}],["9189075f",{"2":{"256":1}}],["918918",{"2":{"168":1}}],["91",{"2":{"236":1}}],["9166",{"2":{"249":1}}],["9161865",{"2":{"224":1}}],["9164896",{"2":{"148":1}}],["9109",{"2":{"249":1}}],["9108207",{"2":{"224":1}}],["9102",{"2":{"249":1}}],["910244+0",{"2":{"168":1}}],["910251",{"2":{"147":1}}],["912982921471255e",{"2":{"258":1}}],["912472846567275e",{"2":{"258":1}}],["912103f",{"2":{"256":1}}],["912105f",{"2":{"256":1}}],["91273f",{"2":{"256":1}}],["9127",{"2":{"249":1}}],["912781",{"2":{"152":1}}],["9127817",{"2":{"152":1}}],["912782",{"2":{"152":1}}],["912085e",{"2":{"219":1}}],["9134969753949765e",{"2":{"258":1}}],["9134986f",{"2":{"256":1}}],["9139614",{"2":{"148":1}}],["9130077",{"2":{"113":2}}],["958207788192736e",{"2":{"258":1}}],["9587246f",{"2":{"256":1}}],["9567026296011234e",{"2":{"258":1}}],["9565042615867675e",{"2":{"258":1}}],["956531097259353e",{"2":{"258":1}}],["9568513f",{"2":{"256":1}}],["9564746f",{"2":{"256":1}}],["956207f",{"2":{"256":1}}],["959342346522558e",{"2":{"258":1}}],["9592484f",{"2":{"256":1}}],["959182",{"2":{"148":1}}],["951912240250197e",{"2":{"258":1}}],["9515",{"2":{"249":1}}],["9517864f",{"2":{"256":1}}],["9517",{"2":{"249":1}}],["9511775",{"2":{"147":1}}],["9547",{"2":{"249":1}}],["95401394",{"2":{"224":1}}],["95",{"2":{"236":6}}],["950769350341129e",{"2":{"258":1}}],["9500",{"2":{"249":1}}],["9500444",{"2":{"147":1}}],["9501",{"2":{"244":1}}],["9501405",{"2":{"148":1}}],["957465832090611e",{"2":{"258":1}}],["95778104411677e",{"2":{"258":1}}],["9577397",{"2":{"147":1}}],["957604f",{"2":{"256":1}}],["9572f",{"2":{"77":1}}],["9789807952793187e",{"2":{"258":1}}],["9797835f",{"2":{"256":1}}],["979117f",{"2":{"256":1}}],["971820054173809e",{"2":{"258":1}}],["971899",{"2":{"125":1}}],["9717022f",{"2":{"256":1}}],["9709534420796504e",{"2":{"258":1}}],["970758097357983e",{"2":{"258":1}}],["9700760428110564e",{"2":{"258":1}}],["970076f",{"2":{"256":1}}],["9708",{"2":{"249":1}}],["975404150768842e",{"2":{"258":1}}],["975404f",{"2":{"256":1}}],["975102f",{"2":{"256":1}}],["975649",{"2":{"172":1}}],["9746445112757968e",{"2":{"258":1}}],["974608f",{"2":{"256":1}}],["9746785f",{"2":{"256":1}}],["974749327778115e",{"2":{"258":1}}],["9747",{"2":{"249":1}}],["9742292",{"2":{"224":1}}],["97",{"2":{"236":13,"249":1}}],["97390362430873e",{"2":{"258":1}}],["9736013f",{"2":{"256":1}}],["97378695",{"2":{"224":1}}],["9734574",{"2":{"145":1}}],["976872622998566e",{"2":{"258":1}}],["976154225206352e",{"2":{"258":1}}],["976745439341422e",{"2":{"258":1}}],["97671f",{"2":{"256":1}}],["9767632",{"2":{"224":1}}],["976547f",{"2":{"256":1}}],["976018f",{"2":{"256":1}}],["9766699015845924",{"2":{"174":4}}],["97667",{"2":{"171":1}}],["977806e",{"2":{"219":1}}],["972592319912836e",{"2":{"258":1}}],["9720407135201326e",{"2":{"258":1}}],["97229f",{"2":{"256":1}}],["9721554734769875",{"2":{"153":2}}],["9727281",{"2":{"147":1}}],["901289366088074e",{"2":{"258":1}}],["901344f",{"2":{"256":1}}],["9019142280758281",{"2":{"153":2}}],["90669384515076e",{"2":{"258":1}}],["906812428289934e",{"2":{"258":1}}],["9068636f",{"2":{"256":1}}],["906182f",{"2":{"256":1}}],["904660221269333e",{"2":{"258":1}}],["9046262f",{"2":{"256":1}}],["9045",{"2":{"249":1}}],["9043228",{"2":{"145":1}}],["90",{"2":{"236":7}}],["9055119",{"2":{"224":2}}],["90508",{"2":{"129":1,"132":1}}],["902982902377702",{"2":{"153":2}}],["90910274",{"2":{"148":1}}],["9094505",{"2":{"145":1}}],["90757f",{"2":{"256":1}}],["9071",{"2":{"249":1}}],["9076505",{"2":{"227":1}}],["9076533",{"2":{"145":1}}],["9079035",{"2":{"224":1}}],["907732547757515e",{"2":{"258":1}}],["90779305",{"2":{"224":1}}],["90772897",{"2":{"129":1}}],["900379821647747e",{"2":{"258":1}}],["9005415f",{"2":{"256":1}}],["9001",{"2":{"179":1,"244":1}}],["900",{"2":{"114":1}}],["966151805736721e",{"2":{"258":1}}],["96378157482609e",{"2":{"258":1}}],["963479f",{"2":{"256":1}}],["961453046663694e",{"2":{"258":1}}],["9613244f",{"2":{"256":1}}],["9640",{"2":{"249":1}}],["9693294904156052e",{"2":{"258":1}}],["9693878",{"2":{"148":1}}],["9694",{"2":{"249":1}}],["965008",{"2":{"227":1}}],["965117",{"2":{"129":1}}],["9679338",{"2":{"224":1}}],["967811",{"2":{"172":1}}],["960426726956115e",{"2":{"258":1}}],["9604645f",{"2":{"113":4}}],["9605094294431785e",{"2":{"258":1}}],["9605053f",{"2":{"256":1}}],["9603328f",{"2":{"256":1}}],["96062994",{"2":{"224":2}}],["968504",{"2":{"224":2}}],["96296",{"2":{"212":1}}],["9626998",{"2":{"147":1}}],["96",{"2":{"210":1,"236":4}}],["988268108294746e",{"2":{"258":1}}],["9882484f",{"2":{"256":1}}],["98882767685585e",{"2":{"258":1}}],["986306783187381e",{"2":{"258":1}}],["9861705f",{"2":{"256":1}}],["9870096962857977e",{"2":{"258":1}}],["9871584f",{"2":{"256":1}}],["987689",{"2":{"145":1}}],["9893063856043093e",{"2":{"258":1}}],["989081f",{"2":{"256":1}}],["9894476f",{"2":{"256":1}}],["9831288741057685e",{"2":{"258":1}}],["983779f",{"2":{"256":1}}],["98396176",{"2":{"126":1}}],["9817209585128185e",{"2":{"258":1}}],["981772f",{"2":{"256":1}}],["981339",{"2":{"171":1}}],["984415f",{"2":{"256":1}}],["9847",{"2":{"249":1}}],["9849229",{"2":{"227":1}}],["9849193f",{"2":{"113":1}}],["9857415354524423e",{"2":{"258":1}}],["9853",{"2":{"249":1}}],["9856883",{"2":{"224":1}}],["982162476",{"2":{"244":2}}],["98",{"2":{"236":2}}],["9803549",{"2":{"224":1}}],["980",{"2":{"159":1}}],["9802322f",{"2":{"113":2}}],["98023f",{"2":{"113":4}}],["94725415727431e",{"2":{"258":1}}],["9470896",{"2":{"132":1}}],["9494716267371664e",{"2":{"258":1}}],["9493575f",{"2":{"256":1}}],["946991870318129e",{"2":{"258":1}}],["9468864f",{"2":{"256":1}}],["946576f",{"2":{"256":1}}],["9460",{"2":{"249":1}}],["9426629359795904e",{"2":{"258":1}}],["9426613f",{"2":{"256":1}}],["94259596",{"2":{"227":1}}],["9414",{"2":{"249":1}}],["9413",{"2":{"249":1}}],["9418648",{"2":{"224":1}}],["9489941",{"2":{"224":1}}],["948899e",{"2":{"219":1}}],["94",{"2":{"196":2,"236":5}}],["9436797",{"2":{"179":1}}],["9452923791531558",{"2":{"153":2}}],["94557f",{"2":{"77":1}}],["9402",{"2":{"249":1}}],["9405848223512736",{"2":{"174":4}}],["940585",{"2":{"171":1}}],["940697f",{"2":{"113":1}}],["9407f",{"2":{"113":1}}],["9g",{"2":{"78":1}}],["926265819473804e",{"2":{"258":1}}],["926104f",{"2":{"256":1}}],["9206294f",{"2":{"256":1}}],["9206433",{"2":{"145":1}}],["924044f",{"2":{"256":1}}],["9248211",{"2":{"224":1}}],["927370250939e",{"2":{"258":1}}],["9273719f",{"2":{"256":1}}],["9277156206981564e",{"2":{"258":1}}],["927852f",{"2":{"256":1}}],["9239096664218282e",{"2":{"258":1}}],["923950547913545",{"2":{"153":2}}],["9230",{"2":{"249":1}}],["92",{"2":{"236":5}}],["925761321516884e",{"2":{"258":1}}],["925543f",{"2":{"256":1}}],["9253495",{"2":{"224":1}}],["92593",{"2":{"210":1,"212":1}}],["9290712462545305e",{"2":{"258":1}}],["92913383",{"2":{"224":2}}],["929f",{"2":{"77":1}}],["928300473541879e",{"2":{"258":1}}],["92832f",{"2":{"77":1}}],["928957f",{"2":{"256":1}}],["928609",{"2":{"145":1}}],["92155594",{"2":{"176":4}}],["9214196",{"2":{"148":1}}],["921",{"2":{"59":1}}],["9905443621775474e",{"2":{"258":1}}],["990784f",{"2":{"256":1}}],["9907212f",{"2":{"256":1}}],["994963002255082e",{"2":{"258":1}}],["99489f",{"2":{"256":1}}],["9941s\\ttraining",{"2":{"210":1}}],["99698f",{"2":{"256":1}}],["99105622876621e",{"2":{"258":1}}],["9919431f",{"2":{"256":1}}],["9913",{"2":{"249":1}}],["9916",{"2":{"249":1}}],["9970604863645144e",{"2":{"258":1}}],["997003",{"2":{"77":6}}],["997900877469654e",{"2":{"258":1}}],["9971247",{"2":{"227":1}}],["9938078753612105e",{"2":{"258":1}}],["9938063f",{"2":{"256":1}}],["9934639",{"2":{"224":1}}],["9930804",{"2":{"224":1}}],["9921047624183742e",{"2":{"258":1}}],["992126",{"2":{"224":2}}],["992662",{"2":{"145":1}}],["99s",{"2":{"196":1}}],["99",{"2":{"148":1,"236":7}}],["999546326240993e",{"2":{"258":1}}],["9995505f",{"2":{"256":1}}],["9999881",{"2":{"126":2}}],["999986",{"2":{"125":1}}],["99998605",{"2":{"125":1}}],["999",{"2":{"77":7,"226":1,"228":1}}],["99900760833609",{"2":{"53":1}}],["9",{"2":{"53":4,"62":2,"77":15,"97":1,"113":25,"129":2,"132":2,"145":1,"147":1,"148":2,"152":1,"171":1,"179":1,"187":14,"192":1,"195":2,"196":2,"206":1,"210":52,"212":10,"219":1,"226":1,"228":1,"232":2,"236":2,"244":4,"249":3,"256":68,"258":91}}],["✖",{"2":{"49":4}}],["✔️",{"2":{"102":13}}],["✔",{"2":{"49":8}}],["`θ`",{"2":{"250":1}}],["`x`",{"2":{"250":1}}],["`circbuff",{"2":{"244":4}}],["`carry`",{"2":{"184":2}}],["`p",{"2":{"207":1}}],["`ps",{"2":{"141":1}}],["`iterators",{"2":{"184":1}}],["`eachslice`",{"2":{"184":1}}],["`∇`",{"2":{"176":1}}],["`autoforwarddiff",{"2":{"146":1}}],["`autozygote",{"2":{"146":1}}],["`a`",{"2":{"134":3}}],["`val",{"2":{"145":2}}],["`training`",{"2":{"145":2}}],["`zygote",{"2":{"145":1}}],["`denselayerparameters`",{"2":{"142":2}}],["`namedtuple`",{"2":{"142":2}}],["`model",{"2":{"141":1}}],["`st`",{"2":{"141":1,"256":2}}],["`st",{"2":{"141":1}}],["`lag",{"2":{"244":4}}],["`lstm",{"2":{"184":1}}],["`linear",{"2":{"141":2}}],["`l",{"2":{"140":1}}],["`luxcore",{"2":{"145":2}}],["`luxcore`",{"2":{"140":1}}],["`lux",{"2":{"145":2}}],["`lux``",{"2":{"172":1}}],["`lux`",{"2":{"140":1}}],["`b`",{"2":{"134":2}}],["```",{"2":{"116":1}}],["`",{"2":{"48":1,"77":2,"116":1,"140":1,"141":1,"145":2,"146":2,"176":1,"244":8}}],["`octavian",{"2":{"18":1}}],["×",{"2":{"28":6,"180":1,"183":2,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["×dn−2×1×1`",{"2":{"69":1}}],["×dn−2×1×1",{"2":{"19":1}}],["×dn−2×1×dn",{"2":{"19":1,"69":1}}],["≥",{"2":{"28":2,"54":1,"244":1}}],["znver2",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["zip",{"2":{"114":1,"244":1}}],["zips",{"2":{"32":1}}],["zyg",{"2":{"113":2}}],["zygotevjp",{"2":{"213":13}}],["zygote",{"2":{"27":1,"28":1,"49":1,"52":1,"53":1,"59":2,"77":3,"78":1,"83":1,"102":1,"103":3,"113":3,"126":2,"133":2,"134":2,"144":3,"145":1,"146":1,"147":3,"148":3,"152":3,"170":1,"173":1,"175":3,"176":4,"181":1,"182":1,"191":1,"205":1,"223":1,"228":1,"231":1,"239":1,"242":3}}],["zenodo",{"2":{"74":3}}],["zeroing",{"2":{"32":4,"55":1}}],["zero",{"2":{"24":3,"32":3,"53":2,"54":2,"55":9,"63":1,"64":3,"67":1,"114":1,"146":1,"171":1}}],["zeroed",{"2":{"24":3}}],["zerosc64",{"2":{"25":1}}],["zerosc32",{"2":{"25":1}}],["zerosc16",{"2":{"25":1}}],["zeros64",{"2":{"25":1}}],["zeros32",{"2":{"25":1,"140":2}}],["zeros16",{"2":{"25":1}}],["zeros",{"2":{"24":3,"25":6,"153":2,"171":1,"243":3,"248":1,"249":1}}],["z=σ",{"2":{"66":1}}],["z=",{"2":{"49":1}}],["z",{"2":{"49":2,"67":3,"249":2,"250":8}}],["≤",{"2":{"24":2,"49":2,"67":2}}],["6e",{"2":{"219":1}}],["6d",{"2":{"179":1}}],["662390022157407e",{"2":{"258":1}}],["6620877f",{"2":{"256":1}}],["6671649930003353e",{"2":{"258":1}}],["667418f",{"2":{"256":1}}],["667572",{"2":{"224":1}}],["6691067f",{"2":{"256":1}}],["66503580961444e",{"2":{"258":1}}],["665036f",{"2":{"256":1}}],["665241",{"2":{"53":10}}],["6611",{"2":{"249":1}}],["66",{"2":{"236":1,"256":1}}],["668592285001469e",{"2":{"258":1}}],["66852736",{"2":{"227":1}}],["668697474479114e",{"2":{"258":1}}],["668678f",{"2":{"256":1}}],["6689298310180207e",{"2":{"258":1}}],["668865f",{"2":{"256":1}}],["6687s\\ttraining",{"2":{"210":1}}],["6636",{"2":{"249":1}}],["663036",{"2":{"172":1}}],["6637242",{"2":{"147":1}}],["6642563709240284",{"2":{"153":2}}],["66667",{"2":{"210":15,"212":4}}],["666682",{"2":{"147":1}}],["666965",{"2":{"168":1}}],["6663244",{"2":{"147":1}}],["6825445799958772e",{"2":{"258":1}}],["6826858f",{"2":{"256":1}}],["6869735f",{"2":{"256":1}}],["6867142",{"2":{"148":1}}],["6812578402239385e",{"2":{"258":1}}],["681153407472689e",{"2":{"258":1}}],["681556884584203e",{"2":{"258":1}}],["6814776f",{"2":{"256":1}}],["681881f",{"2":{"256":1}}],["681728",{"2":{"172":1}}],["684526344168517e",{"2":{"258":1}}],["6843263455821043e",{"2":{"258":1}}],["684328f",{"2":{"256":1}}],["68475f",{"2":{"256":1}}],["6846",{"2":{"249":1}}],["6897",{"2":{"249":1}}],["6806961727405877e",{"2":{"258":1}}],["6809148f",{"2":{"256":1}}],["6809s\\ttraining",{"2":{"210":1}}],["6803184f",{"2":{"256":1}}],["680748",{"2":{"129":1}}],["68",{"2":{"196":1,"210":2,"212":2,"236":12,"249":1}}],["6830945313415872",{"2":{"174":1}}],["6852",{"2":{"249":1}}],["6859683",{"2":{"224":1}}],["6850394",{"2":{"224":2}}],["685079",{"2":{"171":1}}],["6853896",{"2":{"148":1}}],["687197171509937e",{"2":{"258":1}}],["687611",{"2":{"168":1}}],["687264",{"2":{"148":1}}],["688665",{"2":{"148":1}}],["6886741",{"2":{"129":1}}],["616627081790752e",{"2":{"258":1}}],["616297e",{"2":{"219":1}}],["619984446919158e",{"2":{"258":1}}],["619761f",{"2":{"256":1}}],["6189",{"2":{"249":1}}],["6134",{"2":{"249":1}}],["6133",{"2":{"249":1}}],["6138451",{"2":{"113":1}}],["61384505",{"2":{"113":1}}],["611601055091557e",{"2":{"258":1}}],["6110276f",{"2":{"256":1}}],["611487f",{"2":{"256":1}}],["6117",{"2":{"249":1}}],["61155146",{"2":{"224":1}}],["611584190904272",{"2":{"153":2}}],["61439842349583e",{"2":{"258":1}}],["6143286",{"2":{"129":1}}],["6144036f",{"2":{"256":1}}],["6141",{"2":{"249":1}}],["61417323",{"2":{"224":2}}],["615999e",{"2":{"219":1}}],["61",{"2":{"196":4,"236":2}}],["61s",{"2":{"196":1}}],["610066669886397e",{"2":{"258":1}}],["610954484572779e",{"2":{"258":1}}],["610",{"2":{"148":1}}],["6120",{"2":{"24":1}}],["65272434768583e",{"2":{"258":1}}],["652588f",{"2":{"256":1}}],["659026f",{"2":{"256":1}}],["6539359281687062e",{"2":{"258":1}}],["6538628f",{"2":{"256":1}}],["6531713f",{"2":{"256":1}}],["6535434",{"2":{"224":2}}],["65895286029777e",{"2":{"258":1}}],["658340408977685e",{"2":{"258":1}}],["65836f",{"2":{"256":1}}],["658150186014573e",{"2":{"258":1}}],["658024f",{"2":{"256":1}}],["6515710383585896e",{"2":{"258":1}}],["651593f",{"2":{"256":1}}],["651895079845446e",{"2":{"258":1}}],["6514532f",{"2":{"256":1}}],["65178",{"2":{"147":1}}],["6563449731910304e",{"2":{"258":1}}],["6563153f",{"2":{"256":1}}],["656403847694467e",{"2":{"258":1}}],["6564055f",{"2":{"256":1}}],["6560552f",{"2":{"256":1}}],["656613f",{"2":{"113":1}}],["6575795737574026e",{"2":{"258":1}}],["65756f",{"2":{"256":1}}],["657734864928179e",{"2":{"258":1}}],["657715f",{"2":{"256":1}}],["657238908292169e",{"2":{"258":1}}],["657121f",{"2":{"256":1}}],["6571946",{"2":{"227":1}}],["657670184695808",{"2":{"153":2}}],["6547962285971415e",{"2":{"258":1}}],["6544176571757114e",{"2":{"258":1}}],["654431041909667e",{"2":{"258":1}}],["654219f",{"2":{"256":1}}],["6542325f",{"2":{"256":1}}],["6541045372146618e",{"2":{"258":1}}],["6541045f",{"2":{"256":1}}],["6541584",{"2":{"113":1}}],["6541586",{"2":{"113":1}}],["6545s\\ttraining",{"2":{"210":1}}],["65s",{"2":{"196":2}}],["65",{"2":{"196":2,"236":7}}],["655926594729437e",{"2":{"258":1}}],["6556360448565952",{"2":{"174":1}}],["655881",{"2":{"171":1}}],["6501",{"2":{"244":1}}],["650",{"2":{"69":3}}],["6360471179527155e",{"2":{"258":1}}],["636308",{"2":{"113":1}}],["63545641557769e",{"2":{"258":1}}],["6358913f",{"2":{"256":1}}],["635585f",{"2":{"256":1}}],["639748305645662e",{"2":{"258":1}}],["6399299392038005e",{"2":{"258":1}}],["639995029443175e",{"2":{"258":1}}],["639981f",{"2":{"256":1}}],["639694f",{"2":{"256":1}}],["6398664f",{"2":{"256":1}}],["632363959711673e",{"2":{"258":1}}],["6323408",{"2":{"129":1}}],["6326631945454614e",{"2":{"258":1}}],["632513f",{"2":{"256":1}}],["632825f",{"2":{"256":1}}],["63",{"2":{"236":2}}],["6389992",{"2":{"224":1}}],["63838756",{"2":{"147":1}}],["63s",{"2":{"196":3}}],["6349",{"2":{"249":1}}],["6340362477836592",{"2":{"174":1}}],["634591",{"2":{"168":1}}],["634549",{"2":{"168":1}}],["6373950186975e",{"2":{"258":1}}],["6375236f",{"2":{"256":1}}],["6370531107315014",{"2":{"153":2}}],["6372185",{"2":{"148":1}}],["63795453",{"2":{"113":1}}],["628958736380742e",{"2":{"258":1}}],["623731567513991e",{"2":{"258":1}}],["6238932f",{"2":{"256":1}}],["626252144136782e",{"2":{"258":1}}],["62625877100596",{"2":{"171":1}}],["6264146f",{"2":{"256":1}}],["629487392133382e",{"2":{"258":1}}],["629434f",{"2":{"256":1}}],["6293702f",{"2":{"256":1}}],["6291356f",{"2":{"256":1}}],["629631411937894e",{"2":{"258":1}}],["62963",{"2":{"210":2}}],["6214",{"2":{"249":1}}],["621958",{"2":{"171":1}}],["6202692103360195e",{"2":{"258":1}}],["6202136",{"2":{"224":1}}],["6203204f",{"2":{"256":1}}],["620634e",{"2":{"219":1}}],["62",{"2":{"196":1,"236":6}}],["622147232060664e",{"2":{"258":1}}],["622255416849729e",{"2":{"258":1}}],["6222606f",{"2":{"256":1}}],["6220472",{"2":{"224":2}}],["62249",{"2":{"187":1}}],["622865",{"2":{"172":1}}],["627806789166615e",{"2":{"258":1}}],["627547315686887e",{"2":{"258":1}}],["6279626f",{"2":{"256":1}}],["6274668f",{"2":{"256":1}}],["627",{"2":{"180":1}}],["6248834716321566e",{"2":{"258":1}}],["6243835f",{"2":{"256":1}}],["624383955429775",{"2":{"174":1}}],["624384",{"2":{"171":1}}],["62450767",{"2":{"113":1}}],["625",{"2":{"53":1}}],["607417686210196e",{"2":{"258":1}}],["6076053f0",{"2":{"53":2}}],["6044882553123984e",{"2":{"258":1}}],["604637f",{"2":{"256":1}}],["6049256",{"2":{"148":1}}],["6033599157364382e",{"2":{"258":1}}],["6033402f",{"2":{"256":1}}],["603158081399841e",{"2":{"258":1}}],["6032386f",{"2":{"256":1}}],["601651715047773e",{"2":{"258":1}}],["6017776f",{"2":{"256":1}}],["60199269735477e",{"2":{"258":1}}],["6019122f",{"2":{"256":1}}],["6019s\\ttraining",{"2":{"210":1}}],["6069056f",{"2":{"256":1}}],["6064619",{"2":{"113":1}}],["60",{"2":{"249":1}}],["609839f",{"2":{"256":1}}],["609",{"2":{"229":1}}],["60926",{"2":{"187":1}}],["60205",{"2":{"187":1}}],["600944758858865e",{"2":{"258":1}}],["600945f",{"2":{"256":1}}],["6003383",{"2":{"224":1}}],["6001",{"2":{"179":1,"244":1}}],["600",{"2":{"114":1}}],["69845381959591e",{"2":{"258":1}}],["698534f",{"2":{"256":1}}],["6983237",{"2":{"224":1}}],["696834403034666e",{"2":{"258":1}}],["696635568373544e",{"2":{"258":1}}],["6967f",{"2":{"256":1}}],["696777f",{"2":{"256":1}}],["6961s\\ttraining",{"2":{"210":1}}],["6970",{"2":{"249":1}}],["6920981",{"2":{"224":1}}],["6909376f",{"2":{"256":1}}],["6909446526419574",{"2":{"153":2}}],["6904922",{"2":{"224":1}}],["6943",{"2":{"249":1}}],["6945s\\ttraining",{"2":{"210":1}}],["69472f",{"2":{"77":1}}],["6913705",{"2":{"145":1}}],["69",{"2":{"109":1,"196":1,"210":4}}],["671958580433138e",{"2":{"258":1}}],["6712",{"2":{"249":1}}],["676674859214285e",{"2":{"258":1}}],["6763725f",{"2":{"256":1}}],["67468551327775e",{"2":{"258":1}}],["6742",{"2":{"249":1}}],["6720764f",{"2":{"256":1}}],["6726513",{"2":{"145":1}}],["673372781360077e",{"2":{"258":1}}],["6733686f",{"2":{"256":1}}],["6734",{"2":{"249":1}}],["675406561435374e",{"2":{"258":1}}],["675355844242426e",{"2":{"258":1}}],["675354f",{"2":{"256":1}}],["675253327561265e",{"2":{"258":1}}],["675258f",{"2":{"256":1}}],["675202f",{"2":{"256":1}}],["6752",{"2":{"249":1}}],["67595f",{"2":{"77":1}}],["6773329978313097e",{"2":{"258":1}}],["6771653",{"2":{"224":2}}],["6776220912718907",{"2":{"174":1}}],["67",{"2":{"196":1,"210":1,"236":2}}],["67dffc4a8ae",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["6785214671499055e",{"2":{"258":1}}],["678753282527489e",{"2":{"258":1}}],["6786386f",{"2":{"256":1}}],["67861",{"2":{"171":1}}],["678952f",{"2":{"256":1}}],["6788",{"2":{"249":1}}],["6784163",{"2":{"77":1}}],["67909",{"2":{"171":1}}],["67908657",{"2":{"171":1}}],["679087",{"2":{"171":2}}],["6798847",{"2":{"147":1}}],["67094",{"2":{"168":1}}],["6702257",{"2":{"145":1}}],["6",{"2":{"24":1,"39":2,"62":3,"77":7,"113":1,"145":1,"147":5,"148":7,"152":1,"171":2,"173":3,"179":1,"180":5,"187":14,"189":5,"193":8,"196":2,"197":1,"210":5,"212":1,"214":5,"219":1,"221":5,"224":6,"229":5,"236":2,"237":5,"244":4,"246":5,"249":11,"250":6,"251":1,"255":2,"256":155,"258":140,"260":1}}],["641519834556517e",{"2":{"258":1}}],["641554f",{"2":{"256":1}}],["647209725259526e",{"2":{"258":1}}],["647512f",{"2":{"256":1}}],["6477456",{"2":{"145":1}}],["643686970250403e",{"2":{"258":1}}],["643671f",{"2":{"256":1}}],["6431774f",{"2":{"256":1}}],["6431484",{"2":{"227":1}}],["644874135215723e",{"2":{"258":1}}],["6448233",{"2":{"224":1}}],["644748f",{"2":{"256":1}}],["64495987",{"2":{"224":1}}],["6456693",{"2":{"224":2}}],["6456416023530093",{"2":{"174":1}}],["64s",{"2":{"196":4}}],["6423511984038721",{"2":{"153":2}}],["6424197",{"2":{"147":1}}],["64644",{"2":{"224":1}}],["6469914",{"2":{"129":1}}],["64605f",{"2":{"77":1}}],["6407s\\ttraining",{"2":{"210":1}}],["6409345",{"2":{"147":1}}],["6409691",{"2":{"113":1}}],["64058f",{"2":{"77":1}}],["64",{"2":{"18":1,"69":18,"78":1,"180":2,"189":2,"197":2,"214":2,"221":2,"229":2,"234":2,"237":2,"246":2,"251":2,"256":1,"260":2}}],["β",{"2":{"19":4,"69":1,"217":2}}],["γ=0",{"2":{"53":2}}],["γ",{"2":{"19":4,"53":1,"69":1,"217":2}}],["7620185511350382e",{"2":{"258":1}}],["762887823359229e",{"2":{"258":1}}],["762854f",{"2":{"256":1}}],["7695354106393765e",{"2":{"258":1}}],["7693168f",{"2":{"256":1}}],["763966862924076e",{"2":{"258":1}}],["7603287505671327e",{"2":{"258":1}}],["76047f",{"2":{"256":1}}],["7684656463219359e",{"2":{"258":1}}],["768272518848395e",{"2":{"258":1}}],["7681238f",{"2":{"256":1}}],["7689272356710357",{"2":{"153":2}}],["7618628f",{"2":{"256":1}}],["76158035",{"2":{"224":1}}],["7661056156141256e",{"2":{"258":1}}],["7660716f",{"2":{"256":1}}],["7663455",{"2":{"224":1}}],["7655532817475244e",{"2":{"258":1}}],["765436f",{"2":{"256":1}}],["7651",{"2":{"249":1}}],["7652s\\ttraining",{"2":{"210":1}}],["7641012f",{"2":{"256":1}}],["76425457",{"2":{"224":1}}],["7649314",{"2":{"148":1}}],["76",{"2":{"210":6,"212":2,"219":2,"236":1}}],["7673453",{"2":{"129":1}}],["7672513",{"2":{"113":1}}],["7330701212140458e",{"2":{"258":1}}],["733913193559242e",{"2":{"258":1}}],["73341",{"2":{"224":1}}],["736524718549436e",{"2":{"258":1}}],["7360107f",{"2":{"256":1}}],["736687f",{"2":{"256":1}}],["7315879385597635e",{"2":{"258":1}}],["7319557f",{"2":{"256":1}}],["731059",{"2":{"53":2}}],["7329085f",{"2":{"256":1}}],["7340418f",{"2":{"256":1}}],["73593758502623e",{"2":{"258":1}}],["7350606878614316e",{"2":{"258":1}}],["7351893f",{"2":{"256":1}}],["735175e",{"2":{"219":1}}],["7352",{"2":{"249":1}}],["7356",{"2":{"249":1}}],["7370",{"2":{"249":1}}],["73",{"2":{"210":1,"212":1}}],["7384",{"2":{"249":1}}],["7384486",{"2":{"224":1}}],["73806",{"2":{"172":1}}],["738356",{"2":{"171":1}}],["738118",{"2":{"168":1}}],["730941",{"2":{"148":1}}],["7585076f",{"2":{"256":1}}],["7580993408473766",{"2":{"17":1}}],["756287482090278e",{"2":{"258":1}}],["75656f",{"2":{"256":1}}],["7560",{"2":{"249":1}}],["755625885458661e",{"2":{"258":1}}],["755045016605607e",{"2":{"258":1}}],["755353f",{"2":{"256":1}}],["7557187f",{"2":{"256":1}}],["7559453",{"2":{"224":1}}],["7578509984385065e",{"2":{"258":1}}],["757845666385657e",{"2":{"258":1}}],["7579024f",{"2":{"256":1}}],["757684f",{"2":{"256":1}}],["759934321327946e",{"2":{"258":1}}],["759224381255062e",{"2":{"258":1}}],["759226f",{"2":{"256":1}}],["7597575f",{"2":{"256":1}}],["759412",{"2":{"148":1}}],["7533",{"2":{"249":1}}],["7516752609879734e",{"2":{"258":1}}],["7517093f",{"2":{"256":1}}],["7517",{"2":{"249":1}}],["751377",{"2":{"147":1}}],["75",{"2":{"189":2,"196":1,"210":2,"212":1,"236":27,"249":1,"255":1,"256":2,"259":4}}],["7502",{"2":{"251":1,"260":1}}],["7501",{"2":{"244":1}}],["750",{"2":{"180":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["7541821489811035e",{"2":{"258":1}}],["7541456",{"2":{"224":1}}],["754547096199631e",{"2":{"258":1}}],["754041f",{"2":{"256":1}}],["754715311919196e",{"2":{"258":1}}],["7547153f",{"2":{"256":1}}],["754747",{"2":{"148":1}}],["754463",{"2":{"148":1}}],["77165061776422e",{"2":{"258":1}}],["77165353",{"2":{"224":2}}],["771785f",{"2":{"256":1}}],["7789",{"2":{"249":1}}],["7795275",{"2":{"224":2}}],["7794657",{"2":{"129":1}}],["77778",{"2":{"210":2}}],["77",{"2":{"196":3,"210":1,"236":1}}],["7746656838366666",{"2":{"174":1}}],["7733535276924052",{"2":{"174":4}}],["773354",{"2":{"171":1}}],["7766",{"2":{"171":1}}],["776598",{"2":{"171":2}}],["77207",{"2":{"148":1}}],["7708043948215367e",{"2":{"258":1}}],["7707993f",{"2":{"256":1}}],["7703",{"2":{"249":1}}],["77037",{"2":{"147":1}}],["7701346738750905",{"2":{"153":2}}],["7700396",{"2":{"147":1}}],["717287f",{"2":{"256":1}}],["7170077f",{"2":{"256":1}}],["717863343114228",{"2":{"153":2}}],["714178245605662e",{"2":{"258":1}}],["714127f",{"2":{"256":1}}],["7149",{"2":{"249":1}}],["7190746037156566e",{"2":{"258":1}}],["7190406f",{"2":{"256":1}}],["7199",{"2":{"249":1}}],["7195462169922173",{"2":{"153":1}}],["7195462169922175",{"2":{"153":1}}],["7121",{"2":{"249":1}}],["7127",{"2":{"249":1}}],["7123551",{"2":{"224":1}}],["712979078066394",{"2":{"153":2}}],["718831192524184e",{"2":{"258":1}}],["7189655f",{"2":{"256":1}}],["7183194",{"2":{"224":1}}],["7181164",{"2":{"145":1}}],["71",{"2":{"210":2,"236":25}}],["711329",{"2":{"168":1}}],["716953030457042e",{"2":{"258":1}}],["7165354",{"2":{"224":2}}],["7165512278088038",{"2":{"153":2}}],["716134755899883",{"2":{"153":2}}],["713",{"2":{"228":1}}],["713567516238075",{"2":{"153":2}}],["713316",{"2":{"113":1}}],["74798377544105e",{"2":{"258":1}}],["7479796f",{"2":{"256":1}}],["743225794321932e",{"2":{"258":1}}],["74355f",{"2":{"256":1}}],["744432262555797e",{"2":{"258":1}}],["744489",{"2":{"145":1}}],["744298f",{"2":{"256":1}}],["7499601008592375e",{"2":{"258":1}}],["749018888913114e",{"2":{"258":1}}],["749019f",{"2":{"256":1}}],["7497615f",{"2":{"256":1}}],["7426",{"2":{"249":1}}],["7429947",{"2":{"132":1}}],["741140353969072e",{"2":{"258":1}}],["7418004521451195e",{"2":{"258":1}}],["7417953f",{"2":{"256":1}}],["741348",{"2":{"224":1}}],["741432e",{"2":{"219":1}}],["7480315",{"2":{"224":2}}],["7482s\\ttraining",{"2":{"210":1}}],["7453s\\ttraining",{"2":{"210":1}}],["740481244175033e",{"2":{"258":1}}],["740463571041781e",{"2":{"258":1}}],["740195902526728e",{"2":{"258":1}}],["7401575",{"2":{"224":2}}],["740831f",{"2":{"256":1}}],["74074",{"2":{"210":3}}],["740228f",{"2":{"256":1}}],["7402",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["74",{"2":{"196":2,"210":5,"236":1}}],["746724024805487e",{"2":{"258":1}}],["74688f",{"2":{"256":1}}],["7468008914093891",{"2":{"174":4}}],["746801",{"2":{"171":1}}],["74694291453392",{"2":{"174":4}}],["746943",{"2":{"171":1}}],["701475736317054e",{"2":{"258":1}}],["701421f",{"2":{"256":1}}],["7018592",{"2":{"145":1}}],["7022292942612736e",{"2":{"258":1}}],["7023705f",{"2":{"256":1}}],["7024",{"2":{"249":1}}],["705129465048722e",{"2":{"258":1}}],["705088f",{"2":{"256":1}}],["7054554",{"2":{"147":1}}],["707016922563427e",{"2":{"258":1}}],["707022f",{"2":{"256":1}}],["7071",{"2":{"249":1}}],["707534",{"2":{"171":1}}],["70866144",{"2":{"224":2}}],["7089496198123055",{"2":{"153":2}}],["70",{"2":{"210":1,"236":2}}],["70s",{"2":{"196":1}}],["7034908391069555e",{"2":{"258":1}}],["7034612f",{"2":{"256":1}}],["70370",{"2":{"210":1}}],["70390546",{"2":{"129":1}}],["70330536",{"2":{"77":1}}],["700204900366091e",{"2":{"258":1}}],["700555913897953e",{"2":{"258":1}}],["7000491f",{"2":{"256":1}}],["700682f",{"2":{"256":1}}],["7001468",{"2":{"224":1}}],["7001",{"2":{"179":1,"244":1}}],["700",{"2":{"114":1}}],["7260704245755892e",{"2":{"258":1}}],["7262116f",{"2":{"256":1}}],["7262075",{"2":{"147":1}}],["722413040553145e",{"2":{"258":1}}],["722431f",{"2":{"256":1}}],["722629658759928e",{"2":{"258":1}}],["727705f",{"2":{"256":1}}],["7273",{"2":{"249":1}}],["7207358604479152e",{"2":{"258":1}}],["72045172219962e",{"2":{"258":1}}],["7204714f",{"2":{"256":1}}],["7208916f",{"2":{"256":1}}],["720012450849063e",{"2":{"258":1}}],["7200",{"2":{"249":1}}],["725478406142474e",{"2":{"258":1}}],["7251385f",{"2":{"256":1}}],["725939f",{"2":{"256":1}}],["7256s\\ttraining",{"2":{"210":1}}],["7252903f",{"2":{"113":8}}],["7233s\\ttraining",{"2":{"210":1}}],["7237332f",{"2":{"256":1}}],["7237308297251812",{"2":{"174":1}}],["72373",{"2":{"171":1}}],["723731",{"2":{"171":2}}],["72",{"2":{"196":2,"210":3,"236":2}}],["724314096937818e",{"2":{"258":1}}],["724099",{"2":{"168":1}}],["72471225",{"2":{"147":1}}],["72428167",{"2":{"129":1}}],["72908926",{"2":{"148":1}}],["7296474",{"2":{"147":1}}],["7292344",{"2":{"145":1}}],["729",{"2":{"77":6}}],["7960815854218598e",{"2":{"258":1}}],["7961534013830336e",{"2":{"258":1}}],["7961547f",{"2":{"256":1}}],["79656f",{"2":{"77":1}}],["7904824214768077e",{"2":{"258":1}}],["790459f",{"2":{"256":1}}],["790244215940256e",{"2":{"258":1}}],["7902099f",{"2":{"256":1}}],["7900256f",{"2":{"256":1}}],["791531329919498e",{"2":{"258":1}}],["791788048756661e",{"2":{"258":1}}],["791397f",{"2":{"256":1}}],["791657102029507e",{"2":{"258":1}}],["7916545f",{"2":{"256":1}}],["79167f",{"2":{"256":1}}],["7911112",{"2":{"147":1}}],["798564920321022e",{"2":{"258":1}}],["798309777852946e",{"2":{"258":1}}],["798372f",{"2":{"256":1}}],["7987635f",{"2":{"256":1}}],["7984714f",{"2":{"256":1}}],["798027",{"2":{"147":1}}],["797923954154539e",{"2":{"258":1}}],["797249286049889e",{"2":{"258":1}}],["7972153f",{"2":{"256":1}}],["797877f",{"2":{"256":1}}],["797798f",{"2":{"256":1}}],["7977",{"2":{"249":1}}],["792201099155815e",{"2":{"258":1}}],["792483530564015e",{"2":{"258":1}}],["7929953f",{"2":{"256":1}}],["7926198f",{"2":{"256":1}}],["79250443",{"2":{"147":1}}],["794593878814658e",{"2":{"258":1}}],["7949f",{"2":{"256":1}}],["794908",{"2":{"147":1}}],["794645f",{"2":{"256":1}}],["7942",{"2":{"249":1}}],["7990667",{"2":{"227":1}}],["79",{"2":{"196":2,"210":4,"236":2,"249":1}}],["7930196f",{"2":{"256":1}}],["793159",{"2":{"171":1}}],["7939677f",{"2":{"113":1}}],["793463f",{"2":{"77":1}}],["783550650917726e",{"2":{"258":1}}],["7834335f",{"2":{"256":1}}],["7834",{"2":{"249":1}}],["7834251",{"2":{"147":1}}],["785475893762671e",{"2":{"258":1}}],["7858436f",{"2":{"256":1}}],["7877107780226786e",{"2":{"258":1}}],["787216884450972e",{"2":{"258":1}}],["7874921f",{"2":{"256":1}}],["787159",{"2":{"145":1}}],["789595166018335e",{"2":{"258":1}}],["7896003f",{"2":{"256":1}}],["7891",{"2":{"249":1}}],["7897024",{"2":{"224":1}}],["78818554",{"2":{"224":1}}],["78814f",{"2":{"113":1}}],["78",{"2":{"196":2,"210":4,"212":1,"236":8}}],["7817315740767116",{"2":{"174":1}}],["7811481",{"2":{"145":1}}],["780496650624453e",{"2":{"258":1}}],["780416f",{"2":{"256":1}}],["780720795213713e",{"2":{"258":1}}],["7807505f",{"2":{"256":1}}],["78000563",{"2":{"141":1}}],["7808904",{"2":{"74":2}}],["78226817",{"2":{"140":1}}],["784768",{"2":{"147":1,"148":1}}],["784",{"2":{"69":6,"208":1,"213":6,"234":1}}],["7",{"2":{"19":9,"53":5,"62":4,"77":17,"113":10,"145":5,"147":2,"148":5,"152":1,"173":3,"179":1,"180":4,"187":14,"189":4,"196":2,"197":1,"210":5,"212":1,"214":4,"219":1,"221":4,"224":5,"229":4,"236":2,"237":4,"246":4,"249":6,"251":1,"256":86,"258":81,"260":1}}],["5g",{"2":{"228":1}}],["5gb",{"2":{"180":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["5fs",{"2":{"236":1}}],["5f",{"2":{"187":3,"210":2}}],["5f0",{"2":{"129":1,"132":1,"152":1,"186":1,"248":12}}],["543586632671935e",{"2":{"258":1}}],["543438f",{"2":{"256":1}}],["547109861680222e",{"2":{"258":1}}],["547557546171363e",{"2":{"258":1}}],["5475575f",{"2":{"256":1}}],["547244f",{"2":{"256":1}}],["5476424498276177",{"2":{"174":4}}],["547642",{"2":{"171":1}}],["5424696",{"2":{"224":1}}],["540",{"2":{"213":8}}],["5410s\\ttraining",{"2":{"210":1}}],["54145",{"2":{"187":1}}],["54",{"2":{"210":1}}],["5487s\\ttraining",{"2":{"210":1}}],["54s",{"2":{"196":1}}],["549",{"2":{"189":1}}],["54452",{"2":{"172":1}}],["5×3",{"2":{"171":8,"172":1}}],["5×5",{"2":{"24":1,"171":3}}],["586637084258842e",{"2":{"258":1}}],["5865027f",{"2":{"256":1}}],["5865265807660498",{"2":{"153":2}}],["589678398173646e",{"2":{"258":1}}],["58988",{"2":{"187":1}}],["588019011190834e",{"2":{"258":1}}],["584664033477361e",{"2":{"258":1}}],["5840",{"2":{"249":1}}],["581389251976027e",{"2":{"258":1}}],["581163f",{"2":{"256":1}}],["581295f",{"2":{"256":1}}],["5812",{"2":{"249":1}}],["585004f",{"2":{"256":1}}],["5852",{"2":{"249":1}}],["5834",{"2":{"249":1}}],["5839",{"2":{"249":1}}],["582265f",{"2":{"256":1}}],["5821",{"2":{"249":1}}],["58263564",{"2":{"227":1}}],["5826772",{"2":{"224":2}}],["5806",{"2":{"249":1}}],["5809",{"2":{"249":1}}],["58",{"2":{"210":3,"212":1}}],["58s",{"2":{"196":1}}],["5878860127399476e",{"2":{"258":1}}],["5878204f",{"2":{"256":1}}],["5878153",{"2":{"147":1}}],["5876874f",{"2":{"256":1}}],["58721",{"2":{"171":1}}],["58720636",{"2":{"171":1}}],["58720636f0",{"2":{"171":1}}],["587206",{"2":{"171":2}}],["5879354f",{"2":{"113":1}}],["522537929677314e",{"2":{"258":1}}],["522353f",{"2":{"256":1}}],["5228403f",{"2":{"256":1}}],["52219116290928e",{"2":{"258":1}}],["5221656",{"2":{"179":1}}],["522139",{"2":{"148":1}}],["520783950803548e",{"2":{"258":1}}],["52069f",{"2":{"256":1}}],["52024",{"2":{"224":1}}],["529634939538247e",{"2":{"258":1}}],["5296175f",{"2":{"256":1}}],["529213339976429e",{"2":{"258":1}}],["52986150885597e",{"2":{"258":1}}],["529440633670552e",{"2":{"258":1}}],["5294424085621645e",{"2":{"258":1}}],["5294725f",{"2":{"256":1}}],["5291936f",{"2":{"256":1}}],["52999f",{"2":{"256":1}}],["5295787f",{"2":{"256":1}}],["52628386",{"2":{"224":1}}],["5267549745189349",{"2":{"153":2}}],["527559",{"2":{"224":2}}],["52717",{"2":{"147":1}}],["524374612150913e",{"2":{"258":1}}],["524130965307436e",{"2":{"258":1}}],["5241326f",{"2":{"256":1}}],["524213f",{"2":{"256":1}}],["524008",{"2":{"171":1}}],["524781",{"2":{"148":1}}],["5210742834996898",{"2":{"153":2}}],["5281",{"2":{"74":2}}],["573939469147337e",{"2":{"258":1}}],["574102f",{"2":{"256":1}}],["5744788f",{"2":{"256":1}}],["579538001829758e",{"2":{"258":1}}],["5795405f",{"2":{"256":1}}],["579287381605193e",{"2":{"258":1}}],["5794",{"2":{"249":1}}],["571455501395316e",{"2":{"258":1}}],["5713518534683e",{"2":{"258":1}}],["571386f",{"2":{"256":1}}],["5718",{"2":{"254":2}}],["57122",{"2":{"187":1}}],["578374863",{"2":{"244":2}}],["57882756",{"2":{"224":1}}],["57",{"2":{"196":1,"210":5}}],["5779160135512695e",{"2":{"258":1}}],["5779067839062536",{"2":{"153":2}}],["5777901f",{"2":{"256":1}}],["577181",{"2":{"171":1}}],["577344",{"2":{"168":1}}],["5776367e",{"2":{"148":1}}],["5776052f0",{"2":{"53":1}}],["57671577",{"2":{"142":1}}],["5659839070115587e",{"2":{"258":1}}],["565186202150628e",{"2":{"258":1}}],["5658362f",{"2":{"256":1}}],["5653224f",{"2":{"256":1}}],["566199759079577e",{"2":{"258":1}}],["5661397f",{"2":{"256":1}}],["56617f",{"2":{"256":1}}],["5663",{"2":{"249":1}}],["564368145209885e",{"2":{"258":1}}],["564073420716439e",{"2":{"258":1}}],["564423f",{"2":{"256":1}}],["56447",{"2":{"187":1}}],["5641674f",{"2":{"256":1}}],["5681s\\ttraining",{"2":{"210":1}}],["5680085614623662",{"2":{"153":2}}],["56",{"2":{"210":1,"236":3}}],["56756171288473e",{"2":{"258":1}}],["5675557670686644",{"2":{"174":1}}],["5673",{"2":{"249":2}}],["56779",{"2":{"171":1}}],["567794",{"2":{"171":2}}],["560410048665009e",{"2":{"258":1}}],["560108f",{"2":{"256":1}}],["560",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["56055",{"2":{"171":1}}],["56069607",{"2":{"113":1}}],["5627227",{"2":{"145":1}}],["561137f",{"2":{"113":1}}],["59384056905484e",{"2":{"258":1}}],["5938457f",{"2":{"256":1}}],["59312571500579e",{"2":{"258":1}}],["591715673292766e",{"2":{"258":1}}],["59150601242843e",{"2":{"258":1}}],["59156f",{"2":{"256":1}}],["591388f",{"2":{"256":1}}],["594901071724866e",{"2":{"258":1}}],["594828f",{"2":{"256":1}}],["594261",{"2":{"148":1}}],["590605020305797e",{"2":{"258":1}}],["5905245f",{"2":{"256":1}}],["5905511",{"2":{"224":2}}],["590483f",{"2":{"256":1}}],["596364033875597e",{"2":{"258":1}}],["596337728232256e",{"2":{"258":1}}],["596343f",{"2":{"256":1}}],["5967318f",{"2":{"256":1}}],["592439178333956e",{"2":{"258":1}}],["5924462f",{"2":{"256":1}}],["59231762668163e",{"2":{"258":1}}],["5925146f",{"2":{"256":1}}],["59259",{"2":{"212":1}}],["5922205f",{"2":{"256":1}}],["5928234f",{"2":{"256":1}}],["5956",{"2":{"249":1}}],["59543324",{"2":{"227":1}}],["5983",{"2":{"249":1}}],["598505080",{"2":{"244":2}}],["5981s\\ttraining",{"2":{"210":1}}],["59",{"2":{"148":1,"236":1}}],["5971424250558162e",{"2":{"258":1}}],["5970878f",{"2":{"256":1}}],["5979974",{"2":{"145":1}}],["5975106",{"2":{"77":1}}],["5991",{"2":{"249":1}}],["5999714",{"2":{"129":1}}],["5994072",{"2":{"113":1}}],["5994074",{"2":{"113":1}}],["5309145760393373e",{"2":{"258":1}}],["530094398681183e",{"2":{"258":1}}],["5300995f",{"2":{"256":1}}],["5321982751010306e",{"2":{"258":1}}],["538697890277846e",{"2":{"258":1}}],["5386",{"2":{"249":1}}],["5381101016248151",{"2":{"153":2}}],["53935",{"2":{"187":1}}],["531196274547547e",{"2":{"258":1}}],["531469f",{"2":{"256":1}}],["53144f",{"2":{"77":1}}],["5319747f",{"2":{"256":1}}],["5310851",{"2":{"179":1}}],["536541432280625e",{"2":{"258":1}}],["5365916f",{"2":{"256":1}}],["5365074f",{"2":{"256":1}}],["5365157",{"2":{"148":1}}],["5367087714739696e",{"2":{"258":1}}],["536743e",{"2":{"152":1}}],["5367613",{"2":{"147":1}}],["53",{"2":{"126":1,"236":1,"249":1}}],["5378918",{"2":{"77":1}}],["5345716",{"2":{"77":1}}],["5d",{"2":{"70":1,"219":1,"244":2,"257":1}}],["518794570890029e",{"2":{"258":1}}],["518474f",{"2":{"256":1}}],["5186525179887896e",{"2":{"258":1}}],["518639f",{"2":{"256":1}}],["518623f",{"2":{"256":1}}],["51852",{"2":{"210":1}}],["5194407585035466e",{"2":{"258":1}}],["5193468f",{"2":{"256":1}}],["51968503",{"2":{"224":2}}],["51961",{"2":{"187":1}}],["5178",{"2":{"249":1}}],["51165134",{"2":{"227":1}}],["5117s\\ttraining",{"2":{"212":1}}],["5168627687707705e",{"2":{"258":1}}],["5168116f",{"2":{"256":1}}],["5167208",{"2":{"227":1}}],["51676",{"2":{"187":1}}],["5164032",{"2":{"179":1}}],["51524514",{"2":{"179":1}}],["51",{"2":{"69":3,"125":1,"219":2,"228":1,"236":1}}],["5124930246777475e",{"2":{"258":1}}],["512449243825297e",{"2":{"258":1}}],["5124384f",{"2":{"256":1}}],["5120886f",{"2":{"256":1}}],["512961f",{"2":{"256":1}}],["512",{"2":{"59":3,"243":1}}],["5087153015683612e",{"2":{"258":1}}],["5085385f",{"2":{"256":1}}],["5090809772185105e",{"2":{"258":1}}],["509500602576635e",{"2":{"258":1}}],["5095518f",{"2":{"256":1}}],["5099870307573793e",{"2":{"258":1}}],["5091981f",{"2":{"256":1}}],["5036084697388845e",{"2":{"258":1}}],["503709899504179e",{"2":{"258":1}}],["5037024f",{"2":{"256":1}}],["503714f",{"2":{"256":1}}],["503186",{"2":{"172":1}}],["5031421",{"2":{"113":1}}],["5053",{"2":{"249":1}}],["501663869321251e",{"2":{"258":1}}],["5016017",{"2":{"147":1}}],["5015081f",{"2":{"256":1}}],["501",{"2":{"244":1}}],["5045s\\ttraining",{"2":{"210":1}}],["50638831618315e",{"2":{"258":1}}],["5063842f",{"2":{"256":1}}],["50630",{"2":{"187":1}}],["5064s\\ttraining",{"2":{"210":1}}],["506485",{"2":{"172":1}}],["502413",{"2":{"168":1}}],["502312852219817",{"2":{"53":1}}],["5009556",{"2":{"227":1}}],["5000×30×1",{"2":{"249":1}}],["50000",{"2":{"244":100}}],["5000",{"2":{"189":2,"244":1,"249":5}}],["5001",{"2":{"179":1,"244":1}}],["500",{"2":{"114":1,"183":2,"244":1}}],["50798f",{"2":{"77":1}}],["50",{"2":{"63":2,"69":3,"196":15,"228":1,"236":106,"249":1}}],["5∗δ",{"2":{"53":1}}],["5∗|y−y^|2if",{"2":{"53":1}}],["558879510424328e",{"2":{"258":1}}],["55262799853952e",{"2":{"258":1}}],["552683f",{"2":{"256":1}}],["557831007680469e",{"2":{"258":1}}],["557053046448518e",{"2":{"258":1}}],["557242417810331e",{"2":{"258":1}}],["5573554f",{"2":{"256":1}}],["557371f",{"2":{"256":1}}],["5542184f",{"2":{"256":1}}],["55476f",{"2":{"77":1}}],["5501",{"2":{"244":1}}],["5564",{"2":{"249":1}}],["55658394",{"2":{"224":1}}],["556251e",{"2":{"219":1}}],["5511811",{"2":{"224":2}}],["55556",{"2":{"210":2}}],["5553797706980106",{"2":{"174":1}}],["559035f",{"2":{"256":1}}],["5590551",{"2":{"224":2}}],["5594571",{"2":{"224":1}}],["5595843665394066",{"2":{"174":1}}],["55989707",{"2":{"148":1}}],["553916042586079e",{"2":{"258":1}}],["5532",{"2":{"171":1}}],["553631",{"2":{"147":1}}],["5530689",{"2":{"147":1}}],["55",{"2":{"53":1,"212":1,"236":1}}],["5where",{"2":{"53":1}}],["5",{"2":{"19":9,"24":8,"32":2,"39":4,"53":15,"59":11,"63":2,"69":6,"74":1,"77":16,"97":1,"102":1,"109":5,"110":3,"113":5,"115":1,"125":1,"132":1,"145":2,"147":1,"148":2,"168":6,"171":29,"172":1,"173":3,"177":3,"179":6,"180":3,"187":14,"189":3,"193":14,"196":2,"210":5,"211":2,"212":1,"213":40,"214":3,"216":1,"217":1,"219":1,"221":3,"224":8,"228":2,"229":3,"236":2,"237":3,"239":1,"246":3,"248":4,"249":19,"250":1,"254":4,"255":2,"256":777,"258":726,"259":3}}],["^2",{"2":{"255":2,"256":1}}],["^",{"2":{"19":9,"59":1,"78":1,"113":1,"114":1,"254":2}}],["λβ",{"2":{"17":1}}],["α",{"2":{"17":3,"53":3,"217":2,"250":3}}],["+=",{"2":{"194":2,"209":2,"235":2,"244":1,"249":1}}],["+ϵ∗γ+βwhere",{"2":{"69":1}}],["+ϵ∗γ+βand",{"2":{"19":1}}],["+",{"2":{"16":1,"18":1,"24":3,"32":1,"37":1,"49":2,"52":1,"55":1,"59":4,"62":5,"63":4,"65":6,"67":4,"70":1,"88":1,"140":2,"145":1,"146":1,"158":2,"171":4,"179":3,"183":2,"217":1,"224":1,"242":4,"243":3,"245":1,"248":4,"249":1,"254":13,"255":1,"256":2}}],["ys",{"2":{"245":6}}],["y∈",{"2":{"243":1}}],["ylabel=",{"2":{"224":1,"228":1,"245":1,"248":1,"255":1,"256":1,"259":2}}],["y=x2−2x",{"2":{"224":1}}],["y=x−e",{"2":{"19":1,"69":1}}],["yᵢ",{"2":{"114":2}}],["yes",{"2":{"82":1}}],["year",{"2":{"74":2}}],["yet",{"2":{"37":1,"113":1}}],["y3",{"2":{"62":1}}],["y2",{"2":{"62":1,"248":2}}],["y1",{"2":{"62":1,"248":2}}],["yann",{"2":{"53":1}}],["y+ϵ",{"2":{"53":1}}],["yi∈rm",{"2":{"179":1}}],["yi",{"2":{"53":2,"179":1}}],["y~=",{"2":{"53":2}}],["y~",{"2":{"53":4}}],["y^2+y∗max",{"2":{"53":1}}],["y^−y∗log⁡",{"2":{"53":1}}],["y^−y",{"2":{"53":1}}],["y^",{"2":{"53":7}}],["y^+ϵ",{"2":{"53":3}}],["ŷ",{"2":{"53":11,"145":2,"146":2,"147":2,"186":2,"187":3}}],["yoshua",{"2":{"24":2}}],["yourself",{"2":{"203":1}}],["your",{"0":{"119":1},"2":{"37":2,"47":1,"59":2,"69":3,"85":1,"123":1,"124":2,"126":1,"137":2,"138":1,"140":2,"141":2,"142":3,"144":1,"145":2,"157":1,"161":1,"163":2,"188":1}}],["you",{"2":{"2":1,"6":2,"33":2,"37":1,"47":1,"48":1,"52":3,"59":5,"71":3,"74":2,"76":3,"77":1,"78":1,"79":1,"97":1,"105":1,"113":2,"114":1,"119":2,"123":1,"124":3,"125":2,"126":2,"127":1,"130":1,"133":2,"137":2,"138":1,"140":8,"141":6,"142":5,"144":5,"145":4,"146":1,"153":1,"156":1,"157":2,"163":2,"168":1,"171":1,"172":3,"173":1,"175":1,"181":1,"185":1,"188":1,"202":1,"203":1,"210":2,"225":1,"233":1,"243":1,"256":1}}],["yuxin",{"2":{"19":1}}],["y",{"2":{"14":2,"15":2,"19":1,"24":3,"28":5,"49":3,"53":63,"54":3,"55":6,"58":1,"59":10,"62":8,"63":2,"65":9,"67":10,"68":6,"69":4,"77":1,"78":4,"111":4,"113":11,"114":2,"126":2,"140":3,"141":4,"145":7,"146":7,"153":2,"160":5,"179":11,"183":4,"184":5,"185":3,"186":12,"187":5,"192":6,"194":2,"195":4,"206":6,"209":2,"210":2,"217":4,"224":5,"228":5,"232":4,"233":2,"235":2,"236":2,"243":7,"245":1,"248":1,"254":6,"256":3}}],["σ=identity",{"2":{"19":1}}],["σ",{"2":{"13":10,"15":5,"16":3,"18":3,"19":7,"158":3}}],["know",{"2":{"104":1,"125":1,"144":1,"256":1}}],["known",{"0":{"123":1},"2":{"24":2,"52":1,"104":1}}],["knet",{"2":{"81":1}}],["k",{"2":{"63":6,"67":4,"179":1,"207":2,"211":2}}],["kwarg",{"2":{"97":2,"98":1}}],["kwargs",{"2":{"25":24,"33":1,"42":2,"49":4,"59":3,"62":9,"68":2,"98":1,"168":2,"169":2,"195":1,"207":7,"210":2,"211":4,"213":4}}],["kw",{"2":{"59":2}}],["kullback",{"2":{"53":1}}],["kl",{"2":{"53":1}}],["kldivergenceloss",{"2":{"53":5}}],["klambauer",{"2":{"17":1}}],["ki−1",{"2":{"63":1,"65":3}}],["kind",{"0":{"129":1},"2":{"34":1,"39":1,"59":2,"62":1,"125":1,"129":1}}],["kinds",{"2":{"8":1}}],["kiros",{"2":{"19":1}}],["kaiming",{"2":{"19":1,"24":4,"63":2,"67":1,"168":6}}],["keith",{"2":{"252":1}}],["keep",{"2":{"136":1}}],["kept",{"2":{"133":1}}],["kernelabstractions",{"2":{"20":1,"153":7}}],["kernels",{"0":{"153":1},"2":{"16":1,"153":3}}],["kernel",{"2":{"16":1,"20":1,"24":1,"63":5,"153":6}}],["keys",{"2":{"97":1,"109":1,"143":2}}],["keypath=keypath",{"2":{"33":1}}],["keypath",{"2":{"32":7,"97":1,"98":1,"125":4,"126":10,"130":2,"131":4}}],["key",{"0":{"122":1},"2":{"10":2,"118":1}}],["keywords",{"2":{"59":1,"70":1,"169":1}}],["keyword",{"2":{"2":1,"10":1,"33":2,"37":1,"48":1,"49":2,"62":5,"63":2,"64":4,"65":3,"66":2,"67":4,"68":2,"69":4,"70":2,"87":1,"99":1,"100":1,"169":1}}],["hₓ",{"2":{"254":4}}],["h₊",{"2":{"254":4}}],["h12",{"2":{"254":12}}],["h11",{"2":{"254":12}}],["h22",{"2":{"254":12}}],["hmc",{"2":{"249":2}}],["hcat",{"2":{"243":1,"249":1}}],["hn",{"2":{"233":2}}],["hnew",{"2":{"66":6}}],["hnew=activation",{"2":{"66":1}}],["hnew=",{"2":{"66":1}}],["hypernet",{"0":{"233":1,"234":1},"2":{"233":4,"234":1}}],["hypernetwork",{"0":{"230":1},"1":{"231":1,"232":1,"233":1,"234":1,"235":1,"236":1,"237":1}}],["hh",{"2":{"66":6,"100":1}}],["h",{"2":{"65":6,"66":3,"70":4,"192":1,"206":1,"254":14}}],["home",{"2":{"142":1}}],["hosts",{"2":{"79":1}}],["hold",{"2":{"77":1,"82":1}}],["hot",{"2":{"55":1}}],["how",{"0":{"71":1,"154":1},"1":{"155":1,"156":1,"157":1,"158":1,"159":1,"160":1},"2":{"39":1,"53":2,"55":1,"62":2,"66":3,"69":8,"76":1,"77":1,"83":1,"113":1,"114":1,"124":1,"126":2,"128":1,"134":1,"140":1,"142":1,"144":1,"148":1,"153":1,"157":1,"161":2,"171":2,"177":1,"190":1,"207":1,"215":1,"233":1,"247":1,"249":1,"250":1}}],["however",{"2":{"8":1,"11":1,"55":1,"59":1,"62":1,"77":1,"81":1,"99":1,"105":1,"122":1,"127":1,"148":1,"167":1,"173":2,"175":1,"202":1,"207":1,"215":3,"238":1,"254":1,"256":2}}],["hutchinson",{"0":{"149":1},"1":{"150":1,"151":1,"152":1},"2":{"149":2,"150":3,"151":2,"152":8}}],["huber",{"2":{"53":1}}],["huberloss",{"2":{"53":3}}],["human",{"2":{"24":2}}],["https",{"2":{"24":1,"66":1,"68":1,"71":1,"74":1,"177":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"254":2,"260":1}}],["heatmap",{"2":{"245":1}}],["head",{"2":{"83":1,"184":1}}],["heavily",{"2":{"58":1}}],["heavy",{"2":{"6":1}}],["height",{"2":{"63":1}}],["hence",{"2":{"37":1,"47":1,"134":1,"136":1,"150":1,"174":1,"175":1,"196":1,"207":1,"219":1,"256":1}}],["helps",{"2":{"207":1}}],["help",{"2":{"30":1,"31":1,"32":1,"33":2,"53":2,"57":1,"59":1,"62":6,"63":2,"65":3,"66":2,"68":1,"69":4,"70":1,"124":1,"157":1}}],["helpers",{"0":{"26":1},"1":{"27":1,"28":1,"29":1},"2":{"54":1}}],["helper",{"0":{"20":1,"43":1,"68":1,"194":1},"2":{"52":1,"57":1,"250":1}}],["here",{"2":{"30":1,"33":1,"52":2,"54":1,"59":3,"77":1,"81":1,"104":1,"108":1,"119":1,"141":1,"145":3,"146":1,"147":1,"160":1,"161":1,"171":3,"177":2,"207":1,"219":1,"241":1,"248":1,"249":2}}],["hessian",{"2":{"24":1}}],["he",{"2":{"19":1,"24":2}}],["historical",{"2":{"207":1}}],["historically",{"2":{"30":1}}],["hidden",{"2":{"66":43,"184":6,"185":3,"241":11,"244":2,"249":1}}],["hierarchically",{"2":{"59":1}}],["hinge",{"2":{"53":2}}],["hingeloss",{"2":{"53":2}}],["hinton",{"2":{"19":1}}],["highlight",{"2":{"122":1}}],["highly",{"2":{"53":1}}],["higher",{"2":{"70":1,"147":1,"155":1}}],["highest",{"2":{"16":1,"104":1,"155":1,"250":1}}],["high",{"2":{"62":1,"153":1,"171":1,"177":1}}],["hi",{"2":{"24":2}}],["hit",{"2":{"8":1}}],["hamiltonian",{"2":{"249":2}}],["hat",{"2":{"220":2}}],["had",{"2":{"175":1}}],["hadsell",{"2":{"53":1}}],["hand",{"2":{"171":1}}],["handles",{"2":{"83":1,"185":1}}],["handle",{"2":{"66":1,"115":1,"153":1,"207":1,"249":1}}],["handling",{"2":{"54":1,"57":1,"138":1,"155":1,"165":1}}],["happened",{"2":{"155":1}}],["happening",{"2":{"146":1,"160":1}}],["happens",{"2":{"125":1,"144":1,"160":1,"165":1}}],["haven",{"2":{"37":1}}],["have",{"2":{"24":1,"28":1,"30":2,"63":1,"66":1,"68":1,"83":2,"84":1,"90":1,"94":2,"97":3,"98":1,"99":2,"100":1,"104":3,"105":1,"123":1,"125":1,"126":2,"127":2,"133":2,"137":1,"140":1,"141":1,"142":1,"144":2,"145":1,"146":1,"152":1,"155":1,"172":1,"173":1,"174":1,"175":3,"184":3,"219":1,"234":1,"249":1,"250":2,"254":1}}],["having",{"2":{"6":1,"34":1,"59":1}}],["harder",{"2":{"83":1,"124":1}}],["hardware",{"2":{"82":1}}],["hard",{"2":{"11":1,"53":1,"126":1,"140":1,"180":2,"189":2,"197":1,"214":2,"221":2,"229":2,"237":2,"246":2,"251":1,"260":1}}],["has",{"2":{"8":3,"31":1,"37":2,"59":1,"63":1,"65":3,"70":1,"81":1,"83":1,"87":2,"90":6,"94":1,"97":7,"98":4,"99":1,"100":1,"115":1,"118":1,"121":1,"124":1,"125":4,"141":1,"148":1,"170":1,"171":2,"175":1,"249":1,"252":1,"256":1}}],["2f",{"2":{"195":2,"236":4}}],["2fs",{"2":{"195":1}}],["2`",{"2":{"141":1}}],["2725223808094874e",{"2":{"258":1}}],["272721f",{"2":{"256":1}}],["27278",{"2":{"187":1}}],["2749996546054805e",{"2":{"258":1}}],["27471745",{"2":{"227":1}}],["2719231823646323e",{"2":{"258":1}}],["2719572f",{"2":{"256":1}}],["27199",{"2":{"187":1}}],["2714",{"2":{"249":1}}],["2717",{"2":{"249":1}}],["27",{"2":{"236":3,"249":1}}],["2751283f",{"2":{"256":1}}],["27501",{"2":{"244":1}}],["2755905",{"2":{"224":2}}],["27545732",{"2":{"113":1}}],["276",{"2":{"219":1}}],["27809",{"2":{"187":1}}],["2705874f",{"2":{"256":1}}],["27051234",{"2":{"179":1}}],["2709",{"2":{"249":1}}],["27001",{"2":{"244":1}}],["2701178",{"2":{"224":1}}],["27035674",{"2":{"179":1}}],["27989",{"2":{"187":1}}],["27993",{"2":{"172":1}}],["2797048270773437",{"2":{"153":2}}],["2791573282471997",{"2":{"153":2}}],["2775897257042654e",{"2":{"258":1}}],["2774485f",{"2":{"256":1}}],["2774315",{"2":{"145":1}}],["2771789",{"2":{"179":1}}],["2771862617010155",{"2":{"153":2}}],["27373654",{"2":{"129":1}}],["27th",{"2":{"24":1}}],["2×4",{"2":{"173":1}}],["2×5",{"2":{"168":6}}],["2×32",{"2":{"113":2}}],["2×2",{"2":{"53":2,"171":1}}],["291935883311706e",{"2":{"258":1}}],["2913357",{"2":{"113":1}}],["294218440682454e",{"2":{"258":1}}],["2952432908764275e",{"2":{"258":1}}],["295220071081669e",{"2":{"258":1}}],["295691901867082e",{"2":{"258":1}}],["29561827",{"2":{"179":1}}],["295399f",{"2":{"256":1}}],["2951654f",{"2":{"256":1}}],["2958178f",{"2":{"256":1}}],["2950",{"2":{"249":1}}],["29501",{"2":{"244":1}}],["293719743255049e",{"2":{"258":1}}],["2936054823415126e",{"2":{"258":1}}],["2936013f",{"2":{"256":1}}],["293973f",{"2":{"256":1}}],["29304f",{"2":{"256":1}}],["29315922",{"2":{"227":1}}],["2932029",{"2":{"227":1}}],["293211",{"2":{"113":1}}],["2938747",{"2":{"227":1}}],["292667f",{"2":{"256":1}}],["29206026",{"2":{"227":1}}],["292002",{"2":{"168":1}}],["2922556",{"2":{"224":1}}],["29001",{"2":{"244":1}}],["290738e",{"2":{"219":1}}],["2904677",{"2":{"132":1}}],["29",{"2":{"196":1,"236":4,"249":1}}],["29822",{"2":{"187":1}}],["29828635",{"2":{"179":1}}],["298787",{"2":{"148":1}}],["299914f",{"2":{"256":1}}],["2991",{"2":{"249":1}}],["2992126",{"2":{"224":2}}],["2990853",{"2":{"179":1}}],["29944375",{"2":{"179":1}}],["29955",{"2":{"168":1}}],["29630",{"2":{"210":2,"212":1}}],["296372",{"2":{"168":1}}],["296496",{"2":{"171":1}}],["297959481822617",{"2":{"153":2}}],["269410690885596e",{"2":{"258":1}}],["269528f",{"2":{"256":1}}],["2695",{"2":{"249":1}}],["262982490594223e",{"2":{"258":1}}],["262321101998668e",{"2":{"258":1}}],["2626234f",{"2":{"256":1}}],["266176096487563e",{"2":{"258":1}}],["266125f",{"2":{"256":1}}],["26657984",{"2":{"113":1}}],["26335f",{"2":{"256":1}}],["2630118f",{"2":{"256":1}}],["26311737",{"2":{"113":1}}],["264572131259922e",{"2":{"258":1}}],["264592f",{"2":{"256":1}}],["2647",{"2":{"249":1}}],["26477236",{"2":{"113":2}}],["2648",{"2":{"249":1}}],["26",{"2":{"219":2,"236":4,"249":1}}],["260601765274357e",{"2":{"258":1}}],["2606924",{"2":{"148":1}}],["2607505f",{"2":{"256":1}}],["260054f",{"2":{"256":1}}],["26001",{"2":{"244":1}}],["260598",{"2":{"227":1}}],["26051",{"2":{"187":1}}],["2681656",{"2":{"224":1}}],["26836",{"2":{"187":1}}],["2689521",{"2":{"113":2}}],["268941",{"2":{"53":2}}],["2615936",{"2":{"147":1}}],["2672",{"2":{"249":1}}],["26793814",{"2":{"227":1}}],["26771653",{"2":{"224":2}}],["267644",{"2":{"147":1,"148":1}}],["26700416",{"2":{"113":1}}],["26700422",{"2":{"113":1}}],["26501",{"2":{"244":1}}],["265788",{"2":{"168":1}}],["265372",{"2":{"168":1}}],["265",{"2":{"78":1}}],["221976109172776e",{"2":{"258":1}}],["221925f",{"2":{"256":1}}],["221552e",{"2":{"219":1}}],["2292",{"2":{"249":1}}],["2290224145974982",{"2":{"153":2}}],["2261",{"2":{"249":1}}],["226",{"2":{"219":1}}],["22635892",{"2":{"179":1}}],["226381",{"2":{"77":1}}],["220983f",{"2":{"256":1}}],["2201962f",{"2":{"256":1}}],["22001",{"2":{"244":1}}],["220",{"2":{"213":6}}],["22s",{"2":{"196":1}}],["2271",{"2":{"249":1}}],["227",{"2":{"189":1}}],["227513",{"2":{"168":1}}],["2282993424901562e",{"2":{"258":1}}],["2282188f",{"2":{"256":1}}],["2287",{"2":{"249":1}}],["22807482",{"2":{"224":1}}],["22858",{"2":{"187":1}}],["22846f",{"2":{"77":1}}],["22501",{"2":{"244":1}}],["22536",{"2":{"187":1}}],["225",{"2":{"184":1,"207":1,"213":18,"218":2,"241":1}}],["22543387",{"2":{"77":1}}],["2226060144401e",{"2":{"258":1}}],["222533f",{"2":{"256":1}}],["222528",{"2":{"148":1}}],["2221499155987366e",{"2":{"258":1}}],["2221465",{"2":{"148":1}}],["2221302f",{"2":{"256":1}}],["22222",{"2":{"210":2,"212":1}}],["2227837233928576",{"2":{"153":2}}],["2228831",{"2":{"113":1}}],["22",{"2":{"145":1,"187":14,"196":3,"210":2,"236":3,"254":14}}],["2236740293487285e",{"2":{"258":1}}],["22363997",{"2":{"113":1}}],["2236399",{"2":{"113":1}}],["223768f",{"2":{"256":1}}],["2237958",{"2":{"77":1}}],["224721432633562e",{"2":{"258":1}}],["224716f",{"2":{"256":1}}],["2243",{"2":{"249":1}}],["22406094",{"2":{"113":1}}],["22459084",{"2":{"77":1}}],["254837966103736e",{"2":{"258":1}}],["254858f",{"2":{"256":1}}],["2545935",{"2":{"77":1}}],["259200784451272e",{"2":{"258":1}}],["25926",{"2":{"210":3,"212":1}}],["259047550168292e",{"2":{"258":1}}],["259751885578468e",{"2":{"258":1}}],["259769539422367e",{"2":{"258":1}}],["2591022f",{"2":{"256":1}}],["2551456557831785e",{"2":{"258":1}}],["255126f",{"2":{"256":1}}],["2557",{"2":{"249":1}}],["2555",{"2":{"249":1}}],["25501",{"2":{"244":1}}],["25587f",{"2":{"77":1}}],["25001",{"2":{"244":1}}],["2501",{"2":{"244":1}}],["250",{"2":{"228":2,"250":1,"255":1}}],["25055695",{"2":{"177":1,"178":1}}],["2587820853669075e",{"2":{"258":1}}],["258982f",{"2":{"256":1}}],["2581186",{"2":{"224":1}}],["2586653",{"2":{"113":1}}],["251112255853661e",{"2":{"258":1}}],["25148f",{"2":{"256":1}}],["251",{"2":{"219":1}}],["25",{"2":{"171":1,"187":15,"219":2,"236":18,"249":1}}],["25235",{"2":{"187":1}}],["2523673",{"2":{"148":1}}],["25278285",{"2":{"179":1}}],["2525357728685884",{"2":{"153":2}}],["252985",{"2":{"148":1}}],["252925",{"2":{"148":1}}],["25378025",{"2":{"113":2}}],["25389904",{"2":{"113":1}}],["25385493",{"2":{"113":1}}],["257",{"2":{"77":1}}],["25662464",{"2":{"129":1}}],["256",{"2":{"39":1,"59":1,"77":6,"193":3,"234":2}}],["242221072784985e",{"2":{"258":1}}],["246592613383105e",{"2":{"258":1}}],["2465195f",{"2":{"256":1}}],["246999495547461e",{"2":{"258":1}}],["2464001",{"2":{"113":1}}],["249837953228266e",{"2":{"258":1}}],["2493594644959365e",{"2":{"258":1}}],["2493553f",{"2":{"256":1}}],["249765f",{"2":{"256":1}}],["247574581556296e",{"2":{"258":1}}],["2474334f",{"2":{"256":1}}],["2473672f",{"2":{"256":1}}],["2436798f",{"2":{"256":1}}],["24501",{"2":{"244":1}}],["24528",{"2":{"187":1}}],["244965778004472e",{"2":{"258":1}}],["2440945",{"2":{"224":2}}],["2440s\\ttraining",{"2":{"212":1}}],["244728",{"2":{"53":10}}],["24s",{"2":{"196":1}}],["241937",{"2":{"224":1}}],["2415948",{"2":{"148":1}}],["24150778",{"2":{"114":1}}],["24169",{"2":{"113":1}}],["24",{"2":{"109":2,"180":3,"187":14,"189":3,"197":2,"210":1,"214":3,"221":3,"229":3,"236":3,"237":3,"246":3,"249":2}}],["2400206858192544e",{"2":{"258":1}}],["24001",{"2":{"244":1}}],["24099025",{"2":{"77":1}}],["240",{"2":{"69":3}}],["2337440052111937e",{"2":{"258":1}}],["2332152f",{"2":{"256":1}}],["23325463",{"2":{"129":1}}],["233838f",{"2":{"256":1}}],["2328475104014735e",{"2":{"258":1}}],["23234403",{"2":{"227":1}}],["23242",{"2":{"147":1}}],["235529298154295e",{"2":{"258":1}}],["235881f",{"2":{"256":1}}],["2353735f",{"2":{"256":1}}],["23501",{"2":{"244":1}}],["2354317",{"2":{"224":1}}],["2351742f",{"2":{"113":3}}],["23847",{"2":{"187":1}}],["23497",{"2":{"187":1}}],["2392714567514397e",{"2":{"258":1}}],["23921265",{"2":{"147":1}}],["239715669473555e",{"2":{"258":1}}],["239756",{"2":{"172":1}}],["2399035f",{"2":{"256":1}}],["23992883",{"2":{"179":1}}],["2391352f",{"2":{"256":1}}],["230769931154801e",{"2":{"258":1}}],["230593f",{"2":{"256":1}}],["23001",{"2":{"244":1}}],["23063",{"2":{"187":1}}],["23095",{"2":{"171":1}}],["230954",{"2":{"171":2}}],["23021114",{"2":{"113":1}}],["231428097633459e",{"2":{"258":1}}],["2316127664525524e",{"2":{"258":1}}],["23162955",{"2":{"113":1}}],["231554f",{"2":{"256":1}}],["231583f",{"2":{"256":1}}],["23192",{"2":{"187":1}}],["231723",{"2":{"168":1}}],["23710957",{"2":{"142":1}}],["2366",{"2":{"249":1}}],["236220861232494e",{"2":{"258":1}}],["23622048",{"2":{"224":2}}],["23626f",{"2":{"77":1}}],["2361472",{"2":{"129":1}}],["23",{"2":{"62":2,"180":1,"187":14,"189":1,"196":1,"197":1,"210":2,"214":1,"221":1,"229":1,"236":3,"237":1,"246":1,"249":2,"251":1,"260":1}}],["2090578175650714e",{"2":{"258":1}}],["2099041101766958e",{"2":{"258":1}}],["2089847f",{"2":{"256":1}}],["20881107",{"2":{"129":1}}],["2077576643115068e",{"2":{"258":1}}],["2077423f",{"2":{"256":1}}],["207402437854578e",{"2":{"258":1}}],["2078835f",{"2":{"256":1}}],["205883f",{"2":{"256":1}}],["2058508f",{"2":{"256":1}}],["2058456",{"2":{"227":1}}],["2050",{"2":{"249":1}}],["20501",{"2":{"244":1}}],["20579764",{"2":{"227":1}}],["20548",{"2":{"168":1}}],["20472442",{"2":{"224":2}}],["2042089",{"2":{"113":1}}],["202168920657988e",{"2":{"258":1}}],["2021",{"2":{"252":1}}],["2024",{"2":{"180":2,"189":2,"197":1,"214":2,"221":2,"229":2,"237":2,"246":2,"251":1,"260":1}}],["20277858",{"2":{"179":1}}],["2023",{"2":{"74":2}}],["2060910206493225e",{"2":{"258":1}}],["2060241847311866e",{"2":{"258":1}}],["206027643163116e",{"2":{"258":1}}],["2063097f",{"2":{"256":1}}],["2067",{"2":{"249":1}}],["206476",{"2":{"168":1}}],["20668754",{"2":{"147":1}}],["20001",{"2":{"244":1}}],["20001543",{"2":{"179":1}}],["2000",{"2":{"192":1}}],["2001",{"2":{"179":1,"244":1}}],["200958",{"2":{"168":1}}],["200837",{"2":{"168":1}}],["200",{"2":{"114":1,"213":18}}],["20053944",{"2":{"113":1}}],["2006",{"2":{"53":2}}],["203036",{"2":{"113":1}}],["20",{"2":{"62":1,"69":3,"77":1,"110":1,"147":1,"171":2,"179":3,"187":14,"208":5,"213":24,"236":2,"249":7}}],["2019703f",{"2":{"256":1}}],["201186e",{"2":{"219":1}}],["20114",{"2":{"171":1}}],["201145",{"2":{"171":2}}],["201",{"2":{"213":18,"219":1,"228":1}}],["2010",{"2":{"24":3}}],["2016",{"2":{"19":2,"53":2,"69":1}}],["20188306",{"2":{"113":1}}],["2018",{"2":{"19":1}}],["2015",{"2":{"19":1,"24":2}}],["201421e",{"2":{"219":1}}],["2014",{"2":{"17":1,"24":1}}],["2017",{"2":{"17":1,"53":2}}],["217265270448975e",{"2":{"258":1}}],["2176506828313445e",{"2":{"258":1}}],["217103f",{"2":{"256":1}}],["2177766f",{"2":{"256":1}}],["2170",{"2":{"249":1}}],["2125984",{"2":{"224":2}}],["21252f",{"2":{"77":1}}],["2101027f",{"2":{"256":1}}],["21001",{"2":{"244":1}}],["210",{"2":{"213":18}}],["21501",{"2":{"244":1}}],["21531",{"2":{"187":1}}],["21529",{"2":{"187":1}}],["2130",{"2":{"249":1}}],["21305",{"2":{"187":1}}],["21368",{"2":{"187":1}}],["21475",{"2":{"187":1}}],["211",{"2":{"213":6}}],["21147",{"2":{"187":1}}],["2111273",{"2":{"148":1}}],["21844",{"2":{"187":1}}],["21856f",{"2":{"77":1}}],["21660",{"2":{"187":1}}],["21690917",{"2":{"179":1}}],["21672015",{"2":{"129":1}}],["219214508866447e",{"2":{"258":1}}],["2192001",{"2":{"148":1}}],["219997657115324e",{"2":{"258":1}}],["2191",{"2":{"249":1}}],["21940619",{"2":{"224":1}}],["2197981041108443",{"2":{"171":1}}],["21950458",{"2":{"113":1}}],["21",{"2":{"48":1,"69":1,"187":14,"210":3,"236":2,"249":6}}],["288874433275588e",{"2":{"258":1}}],["288794f",{"2":{"256":1}}],["288165e",{"2":{"219":1}}],["28817",{"2":{"187":1}}],["2879368316582974e",{"2":{"258":1}}],["2876315f",{"2":{"256":1}}],["2877752f",{"2":{"256":1}}],["2877",{"2":{"249":1}}],["28725442",{"2":{"113":1}}],["285395328782717e",{"2":{"258":1}}],["2852",{"2":{"249":1}}],["28501",{"2":{"244":1}}],["28565",{"2":{"187":1}}],["28037381132333e",{"2":{"258":1}}],["2804533343636294e",{"2":{"258":1}}],["28042415",{"2":{"113":1}}],["280248f",{"2":{"256":1}}],["28059455f",{"2":{"256":1}}],["28001",{"2":{"244":1}}],["289465276899174e",{"2":{"258":1}}],["28946856",{"2":{"227":1}}],["289329f",{"2":{"256":1}}],["2899156",{"2":{"227":1}}],["2896426",{"2":{"224":1}}],["2896142",{"2":{"147":1}}],["281252",{"2":{"224":1}}],["281053",{"2":{"168":1}}],["282435f",{"2":{"256":1}}],["282736e",{"2":{"219":1}}],["28289196",{"2":{"77":1}}],["2838754f",{"2":{"256":1}}],["2833",{"2":{"249":1}}],["28337",{"2":{"187":1}}],["2835",{"2":{"249":1}}],["28355134",{"2":{"113":1}}],["28307",{"2":{"187":1}}],["283445im",{"2":{"168":1}}],["2860145909590977e",{"2":{"258":1}}],["2866589738261037e",{"2":{"258":1}}],["28662",{"2":{"187":1}}],["2869315f",{"2":{"256":1}}],["2869913410456831",{"2":{"153":2}}],["2864522",{"2":{"148":1}}],["28682f",{"2":{"77":1}}],["284324986204202e",{"2":{"258":1}}],["284439f",{"2":{"256":1}}],["28440",{"2":{"187":1}}],["2849667",{"2":{"148":1}}],["2842",{"2":{"147":1}}],["28",{"2":{"39":4,"180":1,"189":1,"193":2,"195":2,"197":1,"213":2,"214":1,"221":1,"229":1,"232":4,"236":3,"237":1,"246":1,"249":1,"251":1,"260":1}}],["2=dense",{"2":{"32":1}}],["2nd",{"0":{"29":1},"2":{"102":1,"109":1,"240":2,"242":1}}],["2d",{"0":{"238":1},"1":{"239":1,"240":1,"241":1,"242":1,"243":1,"244":1,"245":1,"246":1},"2":{"24":2,"63":3,"64":2,"65":3,"195":2,"238":1}}],["2",{"2":{"5":5,"24":5,"28":2,"31":5,"32":4,"34":8,"37":4,"39":4,"48":1,"49":1,"53":22,"59":13,"62":30,"63":9,"65":15,"66":11,"67":2,"68":15,"69":6,"70":3,"77":49,"78":5,"102":7,"109":1,"110":1,"111":2,"113":32,"114":4,"116":1,"117":1,"125":21,"126":41,"129":3,"130":2,"131":2,"132":4,"133":6,"134":6,"140":3,"141":12,"142":2,"145":7,"146":4,"147":13,"148":13,"152":1,"153":23,"155":5,"168":8,"171":20,"172":1,"173":4,"174":3,"176":1,"177":1,"180":4,"183":5,"184":1,"185":1,"187":15,"188":1,"189":5,"192":1,"193":18,"196":2,"197":2,"206":1,"207":1,"208":1,"210":5,"212":1,"213":67,"214":4,"217":6,"219":8,"220":5,"221":4,"224":14,"225":1,"227":6,"228":3,"229":4,"234":1,"236":4,"237":5,"242":4,"243":10,"245":4,"246":4,"248":2,"249":34,"254":50,"255":8,"256":96,"258":95}}],["v=v",{"2":{"242":1}}],["vtav",{"2":{"149":1}}],["vvt",{"2":{"149":1}}],["v∈rd",{"2":{"149":1}}],["vs",{"2":{"138":1,"219":1}}],["v0",{"2":{"74":1,"97":1,"115":1,"211":1}}],["voila",{"2":{"125":1}}],["vocabulary",{"2":{"67":2}}],["volterra",{"2":{"217":2}}],["vol",{"2":{"53":1}}],["volumetric",{"2":{"53":1}}],["vcat",{"2":{"66":1,"183":1,"254":1}}],["v",{"2":{"27":2,"53":1,"54":3,"69":1,"90":1,"150":5,"151":5,"152":10,"176":4,"177":2,"178":1,"241":4,"242":10,"254":21}}],["vjp",{"0":{"27":1},"2":{"27":1,"150":7,"152":16,"175":3,"178":4,"228":3}}],["visualization",{"0":{"250":1}}],["visualizing",{"0":{"245":1,"259":1}}],["visualize",{"2":{"224":1,"250":1,"259":1}}],["vision",{"2":{"19":1,"24":2,"53":4}}],["virtual",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["vi",{"2":{"149":1}}],["vitj",{"2":{"149":1}}],["viewaxis",{"2":{"213":68}}],["views",{"2":{"207":2,"242":1,"254":1}}],["view",{"2":{"68":4,"173":1,"249":1,"250":1}}],["victor",{"2":{"19":1,"69":1}}],["via",{"2":{"3":1,"5":2,"6":1,"7":1,"18":1,"24":1,"40":1,"52":2,"57":2,"79":2,"83":2,"97":1,"98":1,"100":1,"113":1,"119":1,"122":1,"153":1,"174":1,"176":4,"177":1,"249":1}}],["vanilla",{"2":{"113":1}}],["various",{"2":{"79":1,"83":1,"101":1,"215":1}}],["variants",{"2":{"158":1}}],["variance",{"2":{"17":2,"19":8,"69":6,"249":1}}],["variationalhiddendropout",{"2":{"64":5}}],["variable",{"2":{"59":2,"97":1,"249":1}}],["variables",{"2":{"52":2,"59":1,"77":1,"83":2,"241":1,"249":1,"254":1}}],["var",{"2":{"19":5,"59":1,"69":7,"110":3,"125":2,"126":2,"129":1,"132":1,"145":2,"184":1,"207":1,"213":24,"218":2,"241":1,"244":4}}],["validate",{"2":{"187":1}}],["validated",{"2":{"1":1}}],["validation",{"2":{"183":1,"187":101}}],["valid",{"2":{"69":1,"140":1,"164":1}}],["val",{"2":{"10":2,"17":4,"19":2,"33":3,"39":1,"53":4,"54":5,"55":4,"62":7,"64":1,"125":1,"126":2,"129":2,"132":2,"183":4,"184":1,"185":1,"187":2,"213":13,"218":1,"243":8,"245":3}}],["valued",{"2":{"176":1}}],["value>",{"2":{"161":3}}],["value",{"2":{"3":1,"8":1,"10":2,"17":1,"19":4,"33":1,"44":2,"50":1,"53":6,"54":1,"55":3,"59":6,"62":1,"66":5,"69":6,"126":1,"146":2,"179":16,"183":1,"241":1,"244":4,"249":1,"250":4}}],["valuestorage",{"2":{"213":3}}],["values",{"2":{"3":2,"42":2,"52":4,"53":1,"55":1,"56":3,"70":1,"227":1}}],["vec",{"2":{"152":2,"184":1,"185":1,"207":4,"233":1,"243":1,"245":1}}],["vectors",{"2":{"66":1,"67":2,"69":3,"149":1,"174":6,"247":1}}],["vectorization",{"0":{"167":1},"2":{"20":1,"159":1,"167":1}}],["vectorize",{"2":{"13":1}}],["vector",{"0":{"150":1,"151":1,"177":1,"178":1},"2":{"15":1,"18":1,"24":2,"27":9,"34":2,"48":1,"53":3,"59":2,"66":16,"67":5,"83":1,"110":2,"144":2,"149":4,"150":1,"151":1,"153":3,"171":4,"174":2,"175":5,"176":1,"177":3,"178":1,"179":1,"188":1,"207":3,"210":1,"218":1,"249":4,"250":1,"254":1}}],["vendor",{"2":{"20":1}}],["vedaldi",{"2":{"19":1,"69":1}}],["verbatim",{"2":{"59":1}}],["verified",{"2":{"152":1}}],["verification",{"2":{"8":1}}],["verify",{"2":{"55":1,"145":1,"146":1,"147":1,"148":1,"152":1}}],["versioninfo",{"2":{"180":3,"189":3,"197":3,"214":3,"221":3,"229":3,"237":3,"246":3,"251":3,"260":3}}],["versioning",{"2":{"145":2}}],["versions",{"2":{"97":1,"159":1,"167":2}}],["version",{"2":{"31":1,"52":2,"55":1,"59":1,"71":3,"74":1,"76":1,"90":1,"108":1,"140":1,"150":1,"180":1,"189":1,"197":1,"203":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["very",{"2":{"7":1,"67":1,"77":1,"83":1,"113":2,"124":1,"125":1,"126":2,"133":1,"134":1,"170":1,"171":1,"254":1,"258":1}}],["v1",{"0":{"85":1},"1":{"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"96":1,"97":1,"98":1,"99":1,"100":1},"2":{"7":1,"63":2,"76":4,"85":2,"88":1,"115":1}}],["||",{"2":{"78":1,"114":1,"179":1,"228":1,"244":1}}],["|>",{"2":{"77":2,"78":3,"113":4,"114":2,"116":1,"117":3,"153":2,"160":2,"179":1,"187":3,"208":2,"210":1,"218":1,"219":2,"220":1,"227":1,"228":1,"233":2,"236":3,"244":3,"256":1}}],["|p|−di×",{"2":{"63":1,"65":3}}],["|y^−y|",{"2":{"53":1}}],["|y−y^|−0",{"2":{"53":1}}],["|y−y^|≤δδ∗",{"2":{"53":1}}],["|",{"2":{"3":4,"95":1,"116":1,"125":5,"126":13,"245":1}}],["x~",{"2":{"250":1}}],["x~|θ",{"2":{"250":1}}],["x~|x",{"2":{"250":1}}],["x∈",{"2":{"243":1}}],["xyt",{"2":{"242":17,"243":18,"244":10}}],["xi∈rn",{"2":{"179":1}}],["xi",{"2":{"179":2}}],["xᵢ",{"2":{"114":4}}],["xdev",{"2":{"113":5,"114":3}}],["x3",{"2":{"62":1}}],["x3c",{"2":{"3":3,"4":2,"7":2,"16":1,"18":1,"42":3,"63":4,"66":2,"109":2,"111":2,"134":1,"140":1,"141":1,"161":6,"176":1,"184":1,"207":2,"211":2,"213":2,"219":1,"241":1,"244":2,"254":2}}],["x2s",{"2":{"248":8}}],["x2",{"2":{"62":3,"248":2,"250":18}}],["x26",{"2":{"34":6,"74":1,"116":1,"130":2,"131":4,"180":4,"189":4,"197":4,"214":4,"219":2,"221":4,"229":4,"237":4,"244":4,"246":4,"251":4,"254":4,"260":4}}],["x1s",{"2":{"248":8}}],["x1",{"2":{"62":3,"248":2,"250":18}}],["xlogy",{"2":{"54":1}}],["xlogx",{"2":{"54":1}}],["xlabel=",{"2":{"224":1,"228":1,"245":1,"248":1,"255":1,"256":1,"259":2}}],["xladevice",{"2":{"2":2}}],["xla",{"0":{"73":1},"2":{"2":1,"73":3,"113":5,"114":1}}],["x=",{"2":{"49":1}}],["xoshiro",{"2":{"24":3,"34":1,"59":5,"78":1,"125":1,"129":2,"153":1,"155":1,"174":3,"187":1,"236":1}}],["xavier",{"2":{"24":4}}],["xs",{"2":{"20":2,"245":6,"248":1,"249":3}}],["xt0s",{"2":{"248":5}}],["xt1s",{"2":{"248":5}}],["xt",{"2":{"19":2,"111":1,"112":1}}],["x86",{"2":{"18":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["x",{"2":{"3":12,"5":12,"7":3,"8":12,"11":2,"13":10,"14":2,"15":10,"16":3,"17":8,"18":3,"19":26,"20":1,"24":7,"27":6,"28":10,"37":2,"39":2,"49":5,"53":2,"54":18,"55":16,"58":2,"59":31,"62":24,"63":23,"64":9,"65":27,"66":20,"67":15,"68":30,"69":13,"70":14,"77":4,"78":12,"107":3,"109":9,"110":2,"111":9,"113":14,"114":3,"116":4,"117":9,"120":3,"125":4,"126":10,"129":3,"132":2,"133":6,"134":10,"140":6,"141":5,"142":7,"144":6,"145":10,"146":12,"148":8,"150":2,"151":2,"152":9,"153":3,"155":3,"158":3,"160":5,"171":7,"172":2,"173":4,"176":7,"177":5,"178":1,"179":11,"183":6,"184":8,"185":8,"186":2,"187":4,"192":6,"194":2,"195":4,"206":6,"207":10,"209":2,"210":2,"211":2,"213":13,"217":4,"224":9,"228":8,"232":4,"233":2,"235":2,"236":2,"243":7,"245":1,"248":1,"249":5,"250":4,"254":6,"258":2}}],["3+0",{"2":{"180":2,"189":2,"214":2,"221":2,"229":2,"237":2,"246":2}}],["378415916922863e",{"2":{"258":1}}],["378669f",{"2":{"256":1}}],["37353035495063e",{"2":{"258":1}}],["3778545333899853e",{"2":{"258":1}}],["3770075837870637e",{"2":{"258":1}}],["3776574f",{"2":{"256":1}}],["379534671375904e",{"2":{"258":1}}],["379643f",{"2":{"256":1}}],["3794003f",{"2":{"256":1}}],["371757254343718e",{"2":{"258":1}}],["371999f",{"2":{"256":1}}],["3719285",{"2":{"148":1}}],["37164f",{"2":{"256":1}}],["375803287721997e",{"2":{"258":1}}],["375525f",{"2":{"256":1}}],["375605f",{"2":{"256":1}}],["37501",{"2":{"244":1}}],["376348934677044e",{"2":{"258":1}}],["376383",{"2":{"148":1}}],["3761932f",{"2":{"256":1}}],["376",{"2":{"219":1}}],["370699221848523e",{"2":{"258":1}}],["3703315f",{"2":{"256":1}}],["37037",{"2":{"210":2}}],["3705",{"2":{"249":1}}],["3700089653294145e",{"2":{"258":1}}],["37001",{"2":{"244":1}}],["3700787",{"2":{"224":2}}],["3707023",{"2":{"145":1}}],["37",{"2":{"210":5,"212":1,"236":3}}],["3743772164259254e",{"2":{"258":1}}],["3743814f",{"2":{"256":1}}],["37442",{"2":{"187":1}}],["3742405e",{"2":{"179":1}}],["3727",{"2":{"249":1}}],["37275374",{"2":{"224":1}}],["37273",{"2":{"187":1}}],["3729234",{"2":{"147":1}}],["3rd",{"0":{"203":1},"2":{"147":1}}],["3466413243580365e",{"2":{"258":1}}],["346597740406128e",{"2":{"258":1}}],["3465246f",{"2":{"256":1}}],["3499498933566629e",{"2":{"258":1}}],["3490",{"2":{"249":1}}],["341166465760129e",{"2":{"258":1}}],["341247f",{"2":{"256":1}}],["3417534f",{"2":{"256":1}}],["3410565",{"2":{"141":1}}],["3401",{"2":{"249":1}}],["34001",{"2":{"244":1}}],["34501",{"2":{"244":1}}],["345025",{"2":{"148":1}}],["34",{"2":{"236":4,"249":1}}],["342055776591052e",{"2":{"258":1}}],["342431f",{"2":{"256":1}}],["3427s\\ttraining",{"2":{"210":1}}],["342598059437742e",{"2":{"258":1}}],["342598f",{"2":{"256":1}}],["3425480235499926e",{"2":{"258":1}}],["34254",{"2":{"171":1}}],["34253937",{"2":{"171":1}}],["342539",{"2":{"171":2}}],["34430",{"2":{"187":1}}],["3481284f",{"2":{"256":1}}],["34892",{"2":{"187":1}}],["34855f",{"2":{"77":1}}],["34717593",{"2":{"179":1}}],["3435347112437137e",{"2":{"258":1}}],["34351700231383653",{"2":{"174":1}}],["3436353225087703",{"2":{"153":2}}],["34383082",{"2":{"129":1}}],["3614834957383448e",{"2":{"258":1}}],["3612849f",{"2":{"256":1}}],["3669",{"2":{"249":1}}],["36001",{"2":{"244":1}}],["3602331",{"2":{"147":1}}],["3645461",{"2":{"224":1}}],["36428708",{"2":{"145":1}}],["3637495",{"2":{"224":1}}],["36360",{"2":{"187":1}}],["36",{"2":{"210":1,"236":6}}],["367697994880486e",{"2":{"258":1}}],["367479f",{"2":{"256":1}}],["36752",{"2":{"187":1}}],["36731",{"2":{"187":1}}],["36858",{"2":{"187":1}}],["36875",{"2":{"187":1}}],["36829436",{"2":{"179":1}}],["3697903f",{"2":{"256":1}}],["3694",{"2":{"249":1}}],["36940",{"2":{"187":1}}],["3690",{"2":{"249":1}}],["3693867",{"2":{"224":1}}],["36938f",{"2":{"77":1}}],["3691778381831775",{"2":{"174":1}}],["369178",{"2":{"171":2}}],["36918",{"2":{"171":1}}],["365534516855869e",{"2":{"258":1}}],["365417f",{"2":{"256":1}}],["36542922",{"2":{"147":1}}],["3653",{"2":{"249":1}}],["36501",{"2":{"244":1}}],["3650193059617517",{"2":{"153":2}}],["362463491334985e",{"2":{"258":1}}],["362476e",{"2":{"219":1}}],["3628",{"2":{"249":1}}],["36220473",{"2":{"224":2}}],["36222499022985155",{"2":{"153":2}}],["362593",{"2":{"113":1}}],["3124391035907058e",{"2":{"258":1}}],["31261595f",{"2":{"256":1}}],["316120971502455e",{"2":{"258":1}}],["316235f",{"2":{"256":1}}],["31629",{"2":{"187":1}}],["3112979954427944e",{"2":{"258":1}}],["31128f",{"2":{"77":1}}],["3114323f",{"2":{"256":1}}],["319621193513683e",{"2":{"258":1}}],["3195915f",{"2":{"256":1}}],["3192",{"2":{"249":1}}],["313172040517409e",{"2":{"258":1}}],["3132378691852178e",{"2":{"258":1}}],["313226f",{"2":{"113":3}}],["3130104f",{"2":{"256":1}}],["3133318f",{"2":{"256":1}}],["314900175632126e",{"2":{"258":1}}],["314866f",{"2":{"256":1}}],["3147238",{"2":{"77":1}}],["3152995329292506e",{"2":{"258":1}}],["3155",{"2":{"249":1}}],["31550723",{"2":{"113":1}}],["31501",{"2":{"244":1}}],["310938454045174e",{"2":{"258":1}}],["310288f",{"2":{"256":1}}],["31001",{"2":{"244":1}}],["3108876",{"2":{"147":1}}],["31",{"2":{"236":2,"249":4}}],["3170582",{"2":{"224":1}}],["31783",{"2":{"187":1}}],["31825",{"2":{"187":1}}],["31861955",{"2":{"145":1}}],["354605944720767e",{"2":{"258":1}}],["3546874015197246e",{"2":{"258":1}}],["354723f",{"2":{"256":1}}],["3548491f",{"2":{"256":1}}],["354464",{"2":{"113":1}}],["355745724285063e",{"2":{"258":1}}],["355378f",{"2":{"256":1}}],["35501",{"2":{"244":1}}],["3558193508137715",{"2":{"153":2}}],["350649531660612e",{"2":{"258":1}}],["35000455f",{"2":{"256":1}}],["35001",{"2":{"244":1}}],["350598f",{"2":{"256":1}}],["3501",{"2":{"244":1}}],["35395628",{"2":{"224":1}}],["35653025",{"2":{"224":1}}],["35638642",{"2":{"147":1}}],["352049f",{"2":{"256":1}}],["3524",{"2":{"249":1}}],["352137e",{"2":{"219":1}}],["3523193",{"2":{"179":1}}],["35",{"2":{"180":2,"189":2,"214":2,"221":2,"229":2,"236":2,"237":2,"246":2,"249":1}}],["35828328997143e",{"2":{"258":1}}],["358686406737273e",{"2":{"258":1}}],["358432f",{"2":{"256":1}}],["35891f",{"2":{"256":1}}],["35817",{"2":{"171":1}}],["35836592",{"2":{"77":1}}],["351272907782971e",{"2":{"258":1}}],["351414f",{"2":{"256":1}}],["35149138733595564",{"2":{"174":4}}],["351491",{"2":{"171":1}}],["351",{"2":{"219":1}}],["351662",{"2":{"168":1}}],["35181466",{"2":{"129":1}}],["35188f",{"2":{"77":1}}],["35152f",{"2":{"77":1}}],["3867493591407574e",{"2":{"258":1}}],["3864",{"2":{"249":1}}],["389362033133095e",{"2":{"258":1}}],["3890766f",{"2":{"256":1}}],["38911813",{"2":{"113":1}}],["3891182",{"2":{"113":1}}],["3882204f",{"2":{"256":1}}],["3886",{"2":{"249":1}}],["381803612733881e",{"2":{"258":1}}],["38187847",{"2":{"129":1}}],["381918f",{"2":{"256":1}}],["3871171f",{"2":{"256":1}}],["3871873",{"2":{"227":1}}],["38798f",{"2":{"77":1}}],["38",{"2":{"212":1,"236":31}}],["38501",{"2":{"244":1}}],["3850993",{"2":{"129":1}}],["38527",{"2":{"187":1}}],["38353+0",{"2":{"168":1}}],["3834447782571341",{"2":{"153":1}}],["3834447782571344",{"2":{"153":1}}],["38200346",{"2":{"224":1}}],["38210",{"2":{"187":1}}],["382971",{"2":{"168":1}}],["38242024",{"2":{"148":1}}],["3805734986938413e",{"2":{"258":1}}],["3802712f",{"2":{"256":1}}],["38001",{"2":{"244":1}}],["380777f0",{"2":{"146":1}}],["38068f",{"2":{"77":1}}],["3841858f",{"2":{"113":2}}],["3244648022071265e",{"2":{"258":1}}],["324573311314421e",{"2":{"258":1}}],["324579f",{"2":{"256":1}}],["3245436f",{"2":{"256":1}}],["322569629714677e",{"2":{"258":1}}],["322511396639211e",{"2":{"258":1}}],["3227511f",{"2":{"256":1}}],["3223725f",{"2":{"256":1}}],["322819611637084e",{"2":{"258":1}}],["3228196f",{"2":{"256":1}}],["3228356f",{"2":{"256":1}}],["325688641110906e",{"2":{"258":1}}],["3257183f",{"2":{"256":1}}],["32501",{"2":{"244":1}}],["323950257632361e",{"2":{"258":1}}],["323737990391989e",{"2":{"258":1}}],["323678f",{"2":{"256":1}}],["3236964f",{"2":{"256":1}}],["323290834246129e",{"2":{"258":1}}],["3232892f",{"2":{"256":1}}],["32322538",{"2":{"129":1}}],["3291370849220616e",{"2":{"258":1}}],["3291591",{"2":{"227":1}}],["3290859f",{"2":{"256":1}}],["3294",{"2":{"249":1}}],["32984197",{"2":{"77":1}}],["328542",{"2":{"224":1}}],["32839986131789933",{"2":{"153":2}}],["326251684987132e",{"2":{"258":1}}],["32623518",{"2":{"129":1}}],["3261258f",{"2":{"256":1}}],["326",{"2":{"219":1}}],["321010028958637e",{"2":{"258":1}}],["321205158288444e",{"2":{"258":1}}],["321239f",{"2":{"256":1}}],["321",{"2":{"213":6}}],["321506",{"2":{"168":1}}],["320218691612119e",{"2":{"258":1}}],["3202228f",{"2":{"256":1}}],["3209295f",{"2":{"256":1}}],["32001",{"2":{"244":1}}],["320",{"2":{"213":6}}],["3270",{"2":{"249":1}}],["32734",{"2":{"187":1}}],["3279041356366077",{"2":{"153":2}}],["32",{"2":{"37":2,"59":2,"78":13,"113":9,"114":2,"125":1,"126":1,"193":2,"217":1,"219":4,"225":1,"234":2,"236":2,"244":1,"251":1,"256":8,"260":1}}],["3=dense",{"2":{"32":1}}],["3dv",{"2":{"53":1}}],["3d",{"2":{"19":1,"28":1,"53":1,"146":1,"187":1,"228":1,"236":2}}],["308795144189355e",{"2":{"258":1}}],["308678f",{"2":{"256":1}}],["3041862f",{"2":{"256":1}}],["304024560017399e",{"2":{"258":1}}],["3040",{"2":{"249":1}}],["3048",{"2":{"249":1}}],["3035",{"2":{"249":1}}],["303938",{"2":{"168":1}}],["305767668749807e",{"2":{"258":1}}],["3056505f",{"2":{"256":1}}],["30569053",{"2":{"227":1}}],["30501",{"2":{"244":1}}],["3050475",{"2":{"227":1}}],["305844",{"2":{"147":1,"148":1}}],["3076732498812634e",{"2":{"258":1}}],["3076393f",{"2":{"256":1}}],["3070866",{"2":{"224":2}}],["30792",{"2":{"187":1}}],["3071294",{"2":{"148":1}}],["30215",{"2":{"171":1}}],["30673835",{"2":{"224":1}}],["30674052",{"2":{"179":1}}],["306641",{"2":{"168":1}}],["306147",{"2":{"168":1}}],["309488175216532e",{"2":{"258":1}}],["3095005f",{"2":{"256":1}}],["3092156f",{"2":{"256":1}}],["3092",{"2":{"249":1}}],["3096182856296826e",{"2":{"258":1}}],["3096",{"2":{"249":1}}],["3098s\\ttraining",{"2":{"210":1}}],["3097294",{"2":{"179":1}}],["309",{"2":{"145":2}}],["300216473724298e",{"2":{"258":1}}],["3008",{"2":{"249":1}}],["30001",{"2":{"244":1}}],["3001",{"2":{"179":1,"244":1}}],["300",{"2":{"114":1}}],["30117603902139e",{"2":{"258":1}}],["3014227f",{"2":{"256":1}}],["3013947f",{"2":{"256":1}}],["301",{"2":{"77":1,"219":1}}],["30",{"2":{"17":1,"24":1,"236":2,"249":1}}],["3×2",{"2":{"59":2}}],["3×5",{"2":{"53":4,"59":1}}],["3×3×1×1",{"2":{"24":1}}],["3×7",{"2":{"5":2}}],["3×13",{"2":{"5":4}}],["337618800087514e",{"2":{"258":1}}],["3375676f",{"2":{"256":1}}],["33758628",{"2":{"112":1}}],["3329717f",{"2":{"256":1}}],["339913343563779e",{"2":{"258":1}}],["3398236140253248e",{"2":{"258":1}}],["339872f",{"2":{"256":1}}],["339079",{"2":{"148":1}}],["3364754522626191e",{"2":{"258":1}}],["33647545f",{"2":{"256":1}}],["3367574154698542e",{"2":{"258":1}}],["3367505",{"2":{"129":1}}],["3367626f",{"2":{"256":1}}],["3332665183731736e",{"2":{"258":1}}],["333132f",{"2":{"256":1}}],["3335",{"2":{"249":1}}],["3333333333333335",{"2":{"249":1}}],["33333",{"2":{"210":15,"212":2}}],["335103447970256e",{"2":{"258":1}}],["3356",{"2":{"249":1}}],["33501",{"2":{"244":1}}],["33544478",{"2":{"224":1}}],["330848781748973e",{"2":{"258":1}}],["330596f",{"2":{"256":1}}],["33001",{"2":{"244":1}}],["33070865",{"2":{"224":2}}],["33413691371061e",{"2":{"258":1}}],["334885f",{"2":{"256":1}}],["334019f",{"2":{"256":1}}],["3343754",{"2":{"224":1}}],["3344351",{"2":{"148":1}}],["33442986",{"2":{"113":1}}],["3385826",{"2":{"224":2}}],["33812",{"2":{"187":1}}],["33",{"2":{"5":1,"77":2,"78":1,"236":2}}],["391325145180741e",{"2":{"258":1}}],["3916494f",{"2":{"256":1}}],["397206566888977e",{"2":{"258":1}}],["397045f",{"2":{"256":1}}],["3977319",{"2":{"148":1}}],["39207641150316e",{"2":{"258":1}}],["392205f",{"2":{"256":1}}],["3928175",{"2":{"145":1}}],["3956",{"2":{"249":1}}],["3952",{"2":{"249":1}}],["39501",{"2":{"244":1}}],["39588368",{"2":{"224":1}}],["395306",{"2":{"145":1}}],["393219233924548e",{"2":{"258":1}}],["393382f",{"2":{"256":1}}],["3935",{"2":{"249":1}}],["39300445",{"2":{"227":1}}],["39370078",{"2":{"224":2}}],["3939896",{"2":{"148":1}}],["398904685654539e",{"2":{"258":1}}],["398294330749349e",{"2":{"258":1}}],["398324f",{"2":{"256":1}}],["398038",{"2":{"224":1}}],["39800483",{"2":{"148":1}}],["39841",{"2":{"168":1}}],["3960",{"2":{"249":1}}],["39666",{"2":{"187":1}}],["396323",{"2":{"168":1}}],["3969839f",{"2":{"113":1}}],["39001",{"2":{"244":1}}],["390200114697191",{"2":{"153":2}}],["3903124",{"2":{"113":1}}],["394425035937008e",{"2":{"258":1}}],["3945151042422434e",{"2":{"258":1}}],["3945151f",{"2":{"256":1}}],["3942307655311696",{"2":{"153":2}}],["3940224213371761",{"2":{"153":2}}],["39",{"2":{"2":1,"4":2,"8":1,"10":1,"13":2,"16":1,"18":1,"25":1,"32":1,"34":1,"37":1,"47":1,"52":1,"53":1,"54":1,"57":3,"59":7,"62":1,"66":1,"68":1,"69":3,"70":1,"77":2,"83":2,"90":2,"93":1,"97":1,"104":3,"105":1,"107":1,"108":1,"113":2,"114":1,"120":2,"122":1,"123":1,"125":1,"126":1,"127":1,"129":1,"134":2,"136":1,"137":1,"140":5,"141":1,"142":3,"143":1,"144":4,"145":4,"146":1,"147":2,"148":1,"152":3,"153":2,"155":1,"170":5,"171":8,"173":2,"176":1,"177":1,"179":1,"184":3,"186":1,"188":2,"207":1,"210":1,"215":2,"218":1,"224":1,"225":1,"228":1,"233":1,"236":3,"248":1,"249":4,"254":1,"255":1,"256":2}}],["3",{"2":{"2":1,"5":3,"24":5,"32":7,"37":2,"39":1,"48":1,"52":1,"53":30,"59":27,"62":17,"63":2,"64":2,"66":4,"68":4,"69":3,"77":10,"78":4,"102":2,"109":3,"110":1,"112":1,"113":16,"114":1,"116":1,"117":1,"125":12,"126":7,"129":4,"132":6,"140":1,"142":1,"145":4,"147":12,"148":7,"153":2,"171":23,"172":1,"173":3,"174":7,"180":6,"184":1,"185":1,"187":14,"189":6,"192":1,"193":9,"195":1,"196":3,"206":1,"208":2,"210":5,"212":1,"213":56,"214":7,"217":1,"219":2,"221":6,"224":7,"227":4,"229":6,"236":7,"237":6,"241":3,"242":2,"243":1,"244":2,"246":6,"249":17,"250":1,"254":12,"255":1,"256":114,"258":114}}],["4t",{"2":{"243":1}}],["4th",{"2":{"130":1}}],["4fs",{"2":{"210":1}}],["4x",{"2":{"196":1}}],["462765896848049e",{"2":{"258":1}}],["4628530865437775e",{"2":{"258":1}}],["46296725f",{"2":{"256":1}}],["463671589639137e",{"2":{"258":1}}],["4637447f",{"2":{"256":1}}],["463205e",{"2":{"219":1}}],["46327f",{"2":{"77":1}}],["468194840898577e",{"2":{"258":1}}],["468081f",{"2":{"256":1}}],["4687857",{"2":{"148":1}}],["4690876f",{"2":{"256":1}}],["46956",{"2":{"187":1}}],["467133750304492e",{"2":{"258":1}}],["4672994f",{"2":{"256":1}}],["467304557648373e",{"2":{"258":1}}],["4673",{"2":{"249":1}}],["467061f",{"2":{"256":1}}],["4670s\\ttraining",{"2":{"212":1}}],["46707",{"2":{"187":1}}],["465639278681154e",{"2":{"258":1}}],["46501",{"2":{"244":1}}],["46514034",{"2":{"179":1}}],["46",{"2":{"236":4,"249":1}}],["4644",{"2":{"249":1}}],["464567",{"2":{"224":2}}],["46435",{"2":{"187":1}}],["4660s\\ttraining",{"2":{"210":1}}],["46650",{"2":{"187":1}}],["460102608766662e",{"2":{"258":1}}],["460157f",{"2":{"256":1}}],["4608546680837024e",{"2":{"258":1}}],["4608598f",{"2":{"256":1}}],["46088",{"2":{"168":1}}],["46001",{"2":{"244":1}}],["46061087",{"2":{"224":1}}],["4604845",{"2":{"148":1}}],["461908",{"2":{"171":1}}],["4619778701480337",{"2":{"153":2}}],["4614",{"2":{"147":1}}],["489013233208069e",{"2":{"258":1}}],["489286f",{"2":{"256":1}}],["48983693",{"2":{"224":1}}],["4870843604346265e",{"2":{"258":1}}],["4875466284262025e",{"2":{"258":1}}],["487876745829595e",{"2":{"258":1}}],["4872443f",{"2":{"256":1}}],["4877626f",{"2":{"256":1}}],["48712",{"2":{"187":1}}],["48501",{"2":{"244":1}}],["4851346",{"2":{"142":1}}],["480848124758183e",{"2":{"258":1}}],["48001",{"2":{"244":1}}],["48027995",{"2":{"224":1}}],["480",{"2":{"213":3}}],["484482646614072e",{"2":{"258":1}}],["484146297200571e",{"2":{"258":1}}],["484308f",{"2":{"256":1}}],["4843s\\ttraining",{"2":{"210":1}}],["484",{"2":{"221":1,"246":1}}],["484056",{"2":{"168":1}}],["483936f",{"2":{"256":1}}],["48399",{"2":{"187":1}}],["4833s\\ttraining",{"2":{"210":2}}],["48351598",{"2":{"179":1}}],["48",{"2":{"180":3,"189":3,"197":3,"214":3,"221":3,"229":3,"236":2,"237":3,"246":3}}],["48263642",{"2":{"179":1}}],["48203f",{"2":{"77":1}}],["486850991491895e",{"2":{"258":1}}],["486757f",{"2":{"256":1}}],["4869s\\ttraining",{"2":{"210":1}}],["486214",{"2":{"168":1}}],["486550215883336",{"2":{"153":2}}],["4880",{"2":{"249":1}}],["488028235902512",{"2":{"153":2}}],["48818898",{"2":{"224":2}}],["488105",{"2":{"147":1,"148":1}}],["4883s\\ttraining",{"2":{"210":1}}],["488623",{"2":{"148":1}}],["4815772158581993e",{"2":{"258":1}}],["4817182f",{"2":{"256":1}}],["4812806f",{"2":{"256":1}}],["48148",{"2":{"210":6,"212":1}}],["48193252",{"2":{"145":1}}],["4810884",{"2":{"145":1}}],["48137343",{"2":{"129":1}}],["427166403251309e",{"2":{"258":1}}],["427351f",{"2":{"256":1}}],["42734325f",{"2":{"256":1}}],["427741",{"2":{"168":1}}],["4225",{"2":{"249":1}}],["422918",{"2":{"171":1}}],["42501",{"2":{"244":1}}],["42519686",{"2":{"224":2}}],["4269528f",{"2":{"256":1}}],["426",{"2":{"219":1}}],["42669478",{"2":{"113":1}}],["424563150879349e",{"2":{"258":1}}],["424427f",{"2":{"256":1}}],["4246s\\ttraining",{"2":{"210":1}}],["4249s\\ttraining",{"2":{"210":1}}],["4242767",{"2":{"179":1}}],["42345",{"2":{"187":1}}],["421512118089048e",{"2":{"258":1}}],["4212396f",{"2":{"256":1}}],["42189494",{"2":{"179":1}}],["4216236",{"2":{"129":1}}],["42",{"2":{"168":2,"210":1,"236":2}}],["42001",{"2":{"244":1}}],["420058350197999",{"2":{"153":1}}],["42005835019799886",{"2":{"153":1}}],["420698",{"2":{"147":1,"148":1}}],["4038439459663462e",{"2":{"258":1}}],["4032575419883154e",{"2":{"258":1}}],["40354207",{"2":{"179":1}}],["4090828249161067e",{"2":{"258":1}}],["4096227808196114e",{"2":{"258":1}}],["4095086f",{"2":{"256":1}}],["404467307588655e",{"2":{"258":1}}],["4040064f",{"2":{"256":1}}],["4046085f",{"2":{"256":1}}],["40473",{"2":{"171":1}}],["404728",{"2":{"171":2}}],["4059",{"2":{"249":1}}],["40501",{"2":{"244":1}}],["4051151",{"2":{"176":4}}],["4061",{"2":{"249":1}}],["40623155",{"2":{"227":1}}],["4066515",{"2":{"148":1}}],["4072927f",{"2":{"256":1}}],["40727592",{"2":{"227":1}}],["407458f",{"2":{"256":1}}],["40741",{"2":{"210":3}}],["40789893",{"2":{"179":1}}],["40",{"2":{"210":5,"212":1,"236":2}}],["4016872012579864e",{"2":{"258":1}}],["4014816558009666e",{"2":{"258":1}}],["4010213f",{"2":{"256":1}}],["4013906f",{"2":{"256":1}}],["4013454f",{"2":{"256":1}}],["40138",{"2":{"187":1}}],["4017",{"2":{"249":1}}],["4018757",{"2":{"224":1}}],["4015749",{"2":{"224":2}}],["401",{"2":{"219":1}}],["401215",{"2":{"111":1}}],["402269012345384e",{"2":{"258":1}}],["40229",{"2":{"171":1}}],["402395f",{"2":{"256":1}}],["40202",{"2":{"187":1}}],["40gb",{"2":{"180":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["40001",{"2":{"244":1}}],["4001",{"2":{"179":1,"244":1}}],["4007292",{"2":{"147":1}}],["4007905",{"2":{"145":1}}],["400",{"2":{"114":1}}],["457336095192161e",{"2":{"258":1}}],["4574848f",{"2":{"256":1}}],["458355186830901e",{"2":{"258":1}}],["458304f",{"2":{"256":1}}],["4585489",{"2":{"129":1}}],["4566929",{"2":{"224":2}}],["451140371706867e",{"2":{"258":1}}],["4512766f",{"2":{"256":1}}],["451",{"2":{"219":1}}],["4510427",{"2":{"129":1}}],["45",{"2":{"196":2,"236":2}}],["455298758814693e",{"2":{"258":1}}],["4552384158732863",{"2":{"174":4}}],["455238",{"2":{"171":1}}],["4553927f",{"2":{"256":1}}],["45501",{"2":{"244":1}}],["45583528",{"2":{"224":1}}],["4555s\\ttraining",{"2":{"212":1}}],["45555",{"2":{"187":1}}],["4543",{"2":{"249":1}}],["45454",{"2":{"187":1}}],["45405",{"2":{"187":1}}],["454679",{"2":{"168":1}}],["4524014",{"2":{"224":1}}],["45247704",{"2":{"179":1}}],["45298263",{"2":{"77":1}}],["459884613971525e",{"2":{"258":1}}],["4599854f",{"2":{"256":1}}],["4590s\\ttraining",{"2":{"212":1}}],["459019",{"2":{"171":1}}],["4593922",{"2":{"176":4}}],["45001",{"2":{"244":1}}],["4500963619011972",{"2":{"153":2}}],["4501",{"2":{"244":1}}],["45016125",{"2":{"179":1}}],["450581f",{"2":{"113":5}}],["45325348",{"2":{"140":1}}],["419305852046229e",{"2":{"258":1}}],["4199278980586825e",{"2":{"258":1}}],["4191773f",{"2":{"256":1}}],["41919118",{"2":{"179":1}}],["4130665f",{"2":{"256":1}}],["411455535249629e",{"2":{"258":1}}],["4114895f",{"2":{"256":1}}],["4112944",{"2":{"113":1}}],["4112945",{"2":{"113":1}}],["41501",{"2":{"244":1}}],["4158s\\ttraining",{"2":{"210":1}}],["4158693023143286",{"2":{"153":2}}],["415858",{"2":{"113":1}}],["4106397790526715e",{"2":{"258":1}}],["4102529597685917e",{"2":{"258":1}}],["410893f",{"2":{"256":1}}],["4104298f",{"2":{"256":1}}],["41001",{"2":{"244":1}}],["4101033",{"2":{"147":1}}],["41",{"2":{"236":2}}],["41s",{"2":{"196":1}}],["416",{"2":{"193":2}}],["41436",{"2":{"187":1}}],["414769",{"2":{"171":1}}],["4144732",{"2":{"148":1}}],["4121728149894085e",{"2":{"258":1}}],["412904049237955e",{"2":{"258":1}}],["412377774589985e",{"2":{"258":1}}],["41238892",{"2":{"147":1}}],["412571f",{"2":{"256":1}}],["41205355f",{"2":{"256":1}}],["41246277",{"2":{"129":1}}],["436665347784126e",{"2":{"258":1}}],["436349f",{"2":{"256":1}}],["43676835",{"2":{"147":1}}],["430702f",{"2":{"256":1}}],["4308",{"2":{"249":1}}],["43001",{"2":{"244":1}}],["430503378973277e",{"2":{"258":1}}],["43054",{"2":{"187":1}}],["4305115e",{"2":{"152":1}}],["4305781",{"2":{"129":1}}],["437079917672853e",{"2":{"258":1}}],["4376688703008655e",{"2":{"258":1}}],["4376142f",{"2":{"256":1}}],["4376572711003852",{"2":{"153":2}}],["4371308",{"2":{"224":1}}],["43501",{"2":{"244":1}}],["4353992",{"2":{"224":1}}],["435768im",{"2":{"168":1}}],["432939f",{"2":{"256":1}}],["4329s\\ttraining",{"2":{"210":1}}],["4322f",{"2":{"77":1}}],["43af",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["4330568316563104e",{"2":{"258":1}}],["4330709",{"2":{"224":2}}],["4339262",{"2":{"179":1}}],["433656",{"2":{"168":1}}],["43350348",{"2":{"147":1}}],["4319346874291314",{"2":{"171":1}}],["4314566",{"2":{"148":1}}],["4318977",{"2":{"129":1}}],["43968",{"2":{"187":1}}],["4397957",{"2":{"145":1}}],["4391564",{"2":{"113":1}}],["43",{"2":{"90":1,"196":1,"236":4}}],["4382721",{"2":{"224":1}}],["43846482",{"2":{"179":1}}],["438519",{"2":{"113":1}}],["43866f",{"2":{"77":1}}],["4389",{"2":{"68":1}}],["4785306464488654e",{"2":{"258":1}}],["4782290236328528e",{"2":{"258":1}}],["478229f",{"2":{"256":1}}],["4786794f",{"2":{"256":1}}],["47872233",{"2":{"145":1}}],["47001",{"2":{"244":1}}],["4705s\\ttraining",{"2":{"212":1}}],["4774039933302285e",{"2":{"258":1}}],["4773998f",{"2":{"256":1}}],["4778283",{"2":{"224":1}}],["4779s\\ttraining",{"2":{"212":1}}],["47794",{"2":{"187":1}}],["476",{"2":{"219":1}}],["4763277207638013",{"2":{"153":1}}],["4763277207638008",{"2":{"153":1}}],["4745s\\ttraining",{"2":{"212":1}}],["4743s\\ttraining",{"2":{"210":1}}],["47501",{"2":{"244":1}}],["4759s\\ttraining",{"2":{"212":1}}],["47551f",{"2":{"77":1}}],["4793218561715685e",{"2":{"258":1}}],["4793s\\ttraining",{"2":{"210":1}}],["4795204f",{"2":{"256":1}}],["4791",{"2":{"249":1}}],["4797s\\ttraining",{"2":{"210":1}}],["4736s\\ttraining",{"2":{"210":1}}],["47301",{"2":{"187":1}}],["4730743722547668",{"2":{"153":2}}],["47",{"2":{"193":2,"196":1,"236":2}}],["472015f",{"2":{"256":1}}],["4721",{"2":{"249":1}}],["472",{"2":{"66":1}}],["4d",{"2":{"70":3,"114":2}}],["491066409234073e",{"2":{"258":1}}],["4913s\\ttraining",{"2":{"210":1}}],["497985633837404e",{"2":{"258":1}}],["497809f",{"2":{"256":1}}],["494286639139337e",{"2":{"258":1}}],["494417764139279e",{"2":{"258":1}}],["4944s\\ttraining",{"2":{"210":1}}],["4941695f",{"2":{"256":1}}],["494194f",{"2":{"256":1}}],["4943102f",{"2":{"256":1}}],["492693586983839e",{"2":{"258":1}}],["492339657888808e",{"2":{"258":1}}],["492374f",{"2":{"256":1}}],["492756f",{"2":{"256":1}}],["492532f",{"2":{"256":1}}],["4968",{"2":{"249":1}}],["496063",{"2":{"224":2}}],["495449085710086e",{"2":{"258":1}}],["495445f",{"2":{"256":1}}],["49501",{"2":{"244":1}}],["4958s\\ttraining",{"2":{"210":1}}],["490493707697897e",{"2":{"258":1}}],["4903156614295779e",{"2":{"258":1}}],["4903765f",{"2":{"256":1}}],["49001",{"2":{"244":1}}],["4901871f",{"2":{"256":1}}],["4901161f",{"2":{"113":6}}],["49012f",{"2":{"113":2}}],["493123858118412e",{"2":{"258":1}}],["493495f",{"2":{"256":1}}],["493303f",{"2":{"256":1}}],["49379812986347e",{"2":{"258":1}}],["4937",{"2":{"249":1}}],["4936414",{"2":{"224":1}}],["493911e",{"2":{"219":1}}],["49804282",{"2":{"224":1}}],["4987s\\ttraining",{"2":{"210":1}}],["4981351",{"2":{"113":1}}],["49s",{"2":{"196":1}}],["49941",{"2":{"187":1}}],["49998975",{"2":{"113":1}}],["49913f",{"2":{"77":1}}],["49",{"2":{"59":1,"210":1,"225":1,"228":1,"236":2}}],["44606024837531e",{"2":{"258":1}}],["446214",{"2":{"147":1}}],["449831360919828e",{"2":{"258":1}}],["449443374177408e",{"2":{"258":1}}],["449116796064852e",{"2":{"258":1}}],["4490756f",{"2":{"256":1}}],["449231f",{"2":{"256":1}}],["444955304815956e",{"2":{"258":1}}],["444654066698e",{"2":{"258":1}}],["444654f",{"2":{"256":1}}],["444653f",{"2":{"256":1}}],["44439f",{"2":{"77":1}}],["447967812336081e",{"2":{"258":1}}],["4471059f",{"2":{"256":1}}],["447208471755424e",{"2":{"258":1}}],["4472069f",{"2":{"256":1}}],["4472",{"2":{"249":1}}],["44746",{"2":{"171":1}}],["4420",{"2":{"249":1}}],["4459045f",{"2":{"256":1}}],["4456",{"2":{"249":1}}],["44501",{"2":{"244":1}}],["44571686",{"2":{"148":1}}],["4403349209426575e",{"2":{"258":1}}],["4404693f",{"2":{"256":1}}],["44048917",{"2":{"179":1}}],["44001",{"2":{"244":1}}],["44096947",{"2":{"227":1}}],["44078717",{"2":{"224":1}}],["4418456",{"2":{"179":1}}],["448837656809808e",{"2":{"258":1}}],["4488101521328277",{"2":{"174":1}}],["448416448082938e",{"2":{"258":1}}],["448415f",{"2":{"256":1}}],["448444544395662e",{"2":{"258":1}}],["448155930075574e",{"2":{"258":1}}],["448661f",{"2":{"256":1}}],["448615f",{"2":{"256":1}}],["44827f",{"2":{"256":2}}],["44807646",{"2":{"114":1}}],["44397",{"2":{"148":1}}],["4437156",{"2":{"147":1}}],["44",{"2":{"34":1,"196":2,"236":3,"249":1}}],["4",{"2":{"2":1,"24":1,"31":1,"32":1,"34":8,"52":2,"53":2,"59":2,"64":1,"66":4,"68":1,"69":5,"77":3,"78":1,"102":1,"109":8,"112":6,"113":2,"114":4,"129":5,"132":8,"133":8,"134":4,"140":2,"141":2,"145":9,"146":2,"147":3,"148":11,"152":7,"153":16,"155":2,"171":15,"173":5,"176":2,"179":1,"180":3,"187":17,"189":1,"193":2,"195":1,"196":2,"210":5,"212":1,"213":33,"214":2,"221":3,"224":6,"227":1,"229":3,"232":1,"236":2,"237":2,"244":9,"246":3,"248":9,"249":20,"254":7,"255":1,"256":87,"258":84}}],["0f4",{"2":{"255":1}}],["0f",{"2":{"195":1,"208":2}}],["0f0",{"2":{"59":2,"78":2,"111":2,"112":1,"152":2,"183":2,"207":4,"211":2,"217":4,"224":2,"243":8,"245":6,"248":4,"255":1}}],["0+560",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["0x1911b814c02405e8",{"2":{"174":1}}],["0x12c522b8034ae186",{"2":{"129":1}}],["0x8c49bc52dc8a77ea",{"2":{"174":1}}],["0x8e0c3a65079041bb",{"2":{"129":1}}],["0x48d73dc42d195740",{"2":{"174":1}}],["0x4fa3403dd074e603",{"2":{"129":1}}],["0xdb2fa90498613fdf",{"2":{"174":1}}],["0x22a21880af5dc689",{"2":{"129":1,"174":1}}],["0x21617f7747d97206",{"2":{"129":1}}],["0e",{"2":{"77":7,"226":1,"228":1}}],["0816634619367045e",{"2":{"258":1}}],["081312573465576e",{"2":{"258":1}}],["081374966037613e",{"2":{"258":1}}],["081341f",{"2":{"256":1}}],["0813",{"2":{"249":1}}],["08456632229046e",{"2":{"258":1}}],["08456781",{"2":{"77":1}}],["084889967158913e",{"2":{"258":1}}],["084790373079785e",{"2":{"258":1}}],["084713f",{"2":{"256":1}}],["084621f",{"2":{"256":1}}],["0849266f",{"2":{"256":1}}],["0842",{"2":{"249":1}}],["0843",{"2":{"249":1}}],["0825014163252523e",{"2":{"258":1}}],["082086",{"2":{"228":1}}],["0829282",{"2":{"145":1}}],["0831",{"2":{"249":1}}],["08392",{"2":{"187":1}}],["08332",{"2":{"187":1}}],["08377",{"2":{"187":1}}],["08321",{"2":{"187":1}}],["0836414",{"2":{"168":1}}],["08",{"2":{"177":1,"236":1}}],["085324463612487e",{"2":{"258":1}}],["08530",{"2":{"187":1}}],["08519f",{"2":{"256":1}}],["08517",{"2":{"171":1}}],["085170805",{"2":{"171":1}}],["0851708",{"2":{"171":2}}],["08526564",{"2":{"77":1}}],["088878859968207e",{"2":{"258":1}}],["08885",{"2":{"187":1}}],["088651381793096e",{"2":{"258":1}}],["088428f",{"2":{"256":1}}],["0884834705765853",{"2":{"153":2}}],["0885",{"2":{"249":1}}],["08873f",{"2":{"256":1}}],["0887",{"2":{"249":1}}],["08820387",{"2":{"224":1}}],["088205874",{"2":{"113":1}}],["0867",{"2":{"249":1}}],["0865",{"2":{"249":1}}],["0866141",{"2":{"224":2}}],["08667634",{"2":{"113":2}}],["08694684883050086",{"2":{"174":4}}],["0869468",{"2":{"171":1}}],["086429894",{"2":{"147":1}}],["0876",{"2":{"249":1}}],["0878s\\ttraining",{"2":{"210":1}}],["08713347",{"2":{"142":1}}],["08791955",{"2":{"113":1}}],["089740254112125e",{"2":{"258":1}}],["089046f",{"2":{"256":1}}],["08922641",{"2":{"224":1}}],["08989",{"2":{"187":1}}],["08931",{"2":{"187":1}}],["0895166f",{"2":{"256":1}}],["08957",{"2":{"187":1}}],["089530945",{"2":{"113":1}}],["08953094",{"2":{"113":1}}],["08993f",{"2":{"77":1}}],["0807072869203e",{"2":{"258":1}}],["080702f",{"2":{"256":1}}],["0803379",{"2":{"224":1}}],["0801",{"2":{"78":1}}],["08085155",{"2":{"78":1}}],["08022",{"2":{"19":1,"69":1}}],["036118470414422e",{"2":{"258":1}}],["03652s\\ttraining",{"2":{"236":1}}],["03603",{"2":{"187":1}}],["03f0",{"2":{"226":1}}],["03",{"2":{"219":5,"226":1,"228":1}}],["03704",{"2":{"210":3}}],["03756",{"2":{"187":1}}],["037500158",{"2":{"113":1}}],["03760",{"2":{"187":1}}],["0341980153017373e",{"2":{"258":1}}],["03413",{"2":{"187":1}}],["0340694f",{"2":{"256":1}}],["03451",{"2":{"187":1}}],["03470",{"2":{"187":1}}],["03471",{"2":{"187":1}}],["034259234",{"2":{"179":1}}],["035957735307443e",{"2":{"258":1}}],["035956f",{"2":{"256":1}}],["0359416f",{"2":{"256":1}}],["0359064f",{"2":{"256":1}}],["03593602223536e",{"2":{"258":1}}],["03593",{"2":{"187":1}}],["035556547",{"2":{"244":1}}],["0355555",{"2":{"171":1}}],["03571",{"2":{"187":1}}],["03545",{"2":{"187":1}}],["03546",{"2":{"187":1}}],["0350433",{"2":{"77":1}}],["033714804938979e",{"2":{"258":1}}],["0337452f",{"2":{"256":1}}],["0336273946695764e",{"2":{"258":1}}],["0336598f",{"2":{"256":1}}],["033461203275912e",{"2":{"258":1}}],["0335736f",{"2":{"256":1}}],["033320315",{"2":{"244":1}}],["03336",{"2":{"187":1}}],["03322105",{"2":{"224":1}}],["0338569",{"2":{"147":1}}],["0330944",{"2":{"77":1}}],["03306928",{"2":{"77":1}}],["031768262",{"2":{"244":1}}],["03113",{"2":{"187":1}}],["03114",{"2":{"187":1}}],["03189",{"2":{"187":1}}],["03134",{"2":{"187":1}}],["03142",{"2":{"187":1}}],["031414255389526885",{"2":{"153":2}}],["031403534",{"2":{"113":1}}],["031403527",{"2":{"113":1}}],["031503614",{"2":{"113":1}}],["0315817",{"2":{"77":1}}],["0325831839591016e",{"2":{"258":1}}],["03258145",{"2":{"179":1}}],["0326901484674764e",{"2":{"258":1}}],["0326096f",{"2":{"256":1}}],["03261588",{"2":{"113":1}}],["032615878",{"2":{"113":1}}],["032951f",{"2":{"256":1}}],["032705",{"2":{"224":1}}],["03279",{"2":{"187":1}}],["03210",{"2":{"187":1}}],["03209",{"2":{"187":1}}],["0320963",{"2":{"113":1}}],["03202",{"2":{"187":1}}],["032846544",{"2":{"147":1}}],["03246",{"2":{"187":1}}],["032405667",{"2":{"113":1}}],["032405674",{"2":{"113":1}}],["0324213",{"2":{"113":1}}],["03242131",{"2":{"113":1}}],["0398300579904996e",{"2":{"258":1}}],["03933",{"2":{"187":1}}],["03963",{"2":{"187":1}}],["039647065",{"2":{"113":2}}],["03979",{"2":{"187":1}}],["039132368",{"2":{"77":1}}],["030331207",{"2":{"244":1}}],["03031",{"2":{"187":1}}],["0300585830023534e",{"2":{"258":1}}],["030016",{"2":{"228":1}}],["03006",{"2":{"187":1}}],["03040",{"2":{"187":1}}],["03070261",{"2":{"114":1}}],["030926049",{"2":{"113":1}}],["030926052",{"2":{"113":1}}],["03094203",{"2":{"77":1}}],["030881835",{"2":{"113":2}}],["0301",{"2":{"78":1}}],["0302464",{"2":{"77":1}}],["03893",{"2":{"187":1}}],["0381317",{"2":{"148":1}}],["0381727",{"2":{"147":1}}],["03804328",{"2":{"77":1}}],["038",{"2":{"69":3}}],["02f0",{"2":{"245":2}}],["02",{"2":{"219":16}}],["021918516761999e",{"2":{"258":1}}],["02199",{"2":{"187":1}}],["021166507",{"2":{"244":1}}],["02133s\\ttraining",{"2":{"236":1}}],["02139s\\ttraining",{"2":{"236":1}}],["02122s\\ttraining",{"2":{"236":1}}],["02128s\\ttraining",{"2":{"236":1}}],["02124s\\ttraining",{"2":{"236":1}}],["02155s\\ttraining",{"2":{"236":1}}],["02159",{"2":{"187":1}}],["02186s\\ttraining",{"2":{"236":1}}],["02173s\\ttraining",{"2":{"236":1}}],["02170",{"2":{"187":2}}],["02109s\\ttraining",{"2":{"236":1}}],["02107s\\ttraining",{"2":{"236":1}}],["02106s\\ttraining",{"2":{"236":1}}],["02105s\\ttraining",{"2":{"236":1}}],["02105",{"2":{"187":1}}],["02142s\\ttraining",{"2":{"236":1}}],["02146",{"2":{"187":1}}],["02141",{"2":{"187":1}}],["02140",{"2":{"187":1}}],["02143306",{"2":{"114":1}}],["025072887351924e",{"2":{"258":1}}],["0256",{"2":{"249":1}}],["025140665",{"2":{"244":1}}],["025281426",{"2":{"244":1}}],["025583776",{"2":{"244":1}}],["02555",{"2":{"187":1}}],["02595s\\ttraining",{"2":{"236":1}}],["02531s\\ttraining",{"2":{"236":1}}],["02535537",{"2":{"179":1}}],["02535769",{"2":{"147":1}}],["02540",{"2":{"187":1}}],["02579",{"2":{"187":1}}],["02589",{"2":{"187":1}}],["0298817f",{"2":{"256":1}}],["029164422",{"2":{"244":1}}],["02918s\\ttraining",{"2":{"236":1}}],["02907s\\ttraining",{"2":{"236":1}}],["02904",{"2":{"187":1}}],["02924",{"2":{"187":1}}],["029290024",{"2":{"77":1}}],["02942",{"2":{"187":1}}],["02955",{"2":{"187":1}}],["02964765308691042",{"2":{"174":4}}],["0296477",{"2":{"171":1}}],["0289066f",{"2":{"256":1}}],["0289622f",{"2":{"256":1}}],["0288",{"2":{"249":1}}],["028305896",{"2":{"244":1}}],["028128654",{"2":{"244":1}}],["02819s\\ttraining",{"2":{"236":1}}],["0287440289475135e",{"2":{"258":1}}],["02870s\\ttraining",{"2":{"236":1}}],["028738942",{"2":{"147":1}}],["02807s\\ttraining",{"2":{"236":1}}],["02845",{"2":{"187":1}}],["028461456",{"2":{"129":1}}],["0285962",{"2":{"147":1}}],["02827571",{"2":{"113":1}}],["028275706",{"2":{"113":1}}],["028251555",{"2":{"77":1}}],["0275997081162693e",{"2":{"258":1}}],["027620461",{"2":{"244":1}}],["02768",{"2":{"187":1}}],["02781s\\ttraining",{"2":{"236":1}}],["02782",{"2":{"187":1}}],["02797s\\ttraining",{"2":{"236":1}}],["02730",{"2":{"187":1}}],["02709",{"2":{"187":1}}],["02712",{"2":{"187":1}}],["02716",{"2":{"187":1}}],["0277897",{"2":{"224":1}}],["02773",{"2":{"187":1}}],["027702922",{"2":{"77":1}}],["027273500",{"2":{"244":1}}],["02722",{"2":{"187":1}}],["027226416",{"2":{"113":1}}],["027226413",{"2":{"113":1}}],["02720",{"2":{"187":1}}],["020216225636689e",{"2":{"258":1}}],["020212f",{"2":{"256":1}}],["02029s\\ttraining",{"2":{"236":2}}],["02023s\\ttraining",{"2":{"236":1}}],["020389127",{"2":{"244":1}}],["02038s\\ttraining",{"2":{"236":1}}],["02034s\\ttraining",{"2":{"236":2}}],["02035s\\ttraining",{"2":{"236":2}}],["02037s\\ttraining",{"2":{"236":2}}],["02039s\\ttraining",{"2":{"236":2}}],["02030s\\ttraining",{"2":{"236":1}}],["020524397597996e",{"2":{"258":1}}],["02053s\\ttraining",{"2":{"236":1}}],["02055s\\ttraining",{"2":{"236":1}}],["02054s\\ttraining",{"2":{"236":2}}],["02051s\\ttraining",{"2":{"236":1}}],["0209",{"2":{"249":1}}],["02094s\\ttraining",{"2":{"236":1}}],["02097s\\ttraining",{"2":{"236":1}}],["02093s\\ttraining",{"2":{"236":2}}],["02092s\\ttraining",{"2":{"236":1}}],["02098s\\ttraining",{"2":{"236":2}}],["02091s\\ttraining",{"2":{"236":1}}],["02099",{"2":{"187":1}}],["02048185210222e",{"2":{"258":1}}],["02048s\\ttraining",{"2":{"236":2}}],["0204",{"2":{"249":1}}],["020493284",{"2":{"244":1}}],["02047",{"2":{"187":1}}],["02088s\\ttraining",{"2":{"236":1}}],["02082s\\ttraining",{"2":{"236":1}}],["02085s\\ttraining",{"2":{"236":1}}],["02084s\\ttraining",{"2":{"236":6}}],["02080s\\ttraining",{"2":{"236":5}}],["02083s\\ttraining",{"2":{"236":4}}],["0206105f",{"2":{"256":1}}],["020624701",{"2":{"244":1}}],["02062s\\ttraining",{"2":{"236":1}}],["02065s\\ttraining",{"2":{"236":1}}],["02067s\\ttraining",{"2":{"236":2}}],["02068s\\ttraining",{"2":{"236":2}}],["02060s\\ttraining",{"2":{"236":2}}],["02060",{"2":{"187":1}}],["02066",{"2":{"187":1}}],["02006",{"2":{"187":2}}],["020748f",{"2":{"256":1}}],["02078s\\ttraining",{"2":{"236":1}}],["02072s\\ttraining",{"2":{"236":1}}],["0207279",{"2":{"140":1}}],["02079s\\ttraining",{"2":{"236":2}}],["0207926",{"2":{"77":1}}],["02075s\\ttraining",{"2":{"236":4}}],["02070",{"2":{"187":1}}],["02019",{"2":{"187":1}}],["02011",{"2":{"187":1}}],["02017",{"2":{"187":1}}],["0201",{"2":{"78":1}}],["023125907652439e",{"2":{"258":1}}],["02310s\\ttraining",{"2":{"236":1}}],["0231775",{"2":{"77":1}}],["0232951195917684e",{"2":{"258":1}}],["02322s\\ttraining",{"2":{"236":1}}],["02323",{"2":{"187":1}}],["02382s\\ttraining",{"2":{"236":1}}],["02362s\\ttraining",{"2":{"236":1}}],["023622",{"2":{"224":2}}],["0233s\\ttraining",{"2":{"210":1}}],["02337",{"2":{"187":1}}],["02377",{"2":{"187":1}}],["02397",{"2":{"187":1}}],["02358",{"2":{"187":1}}],["02307",{"2":{"187":1}}],["02301",{"2":{"187":1}}],["023031702",{"2":{"77":1}}],["022997f",{"2":{"256":1}}],["02297s\\ttraining",{"2":{"236":1}}],["022618050",{"2":{"244":1}}],["02260",{"2":{"187":1}}],["022739200",{"2":{"244":1}}],["022735020",{"2":{"244":1}}],["0227737",{"2":{"77":1}}],["022150228",{"2":{"244":1}}],["02212",{"2":{"187":1}}],["02200s\\ttraining",{"2":{"236":1}}],["02201",{"2":{"187":1}}],["022243f",{"2":{"256":1}}],["022293953",{"2":{"244":1}}],["02228s\\ttraining",{"2":{"236":1}}],["02221s\\ttraining",{"2":{"236":1}}],["022215",{"2":{"228":1}}],["02243",{"2":{"187":1}}],["022434518",{"2":{"77":1}}],["02250s\\ttraining",{"2":{"236":1}}],["02258",{"2":{"187":1}}],["02259",{"2":{"187":1}}],["02282",{"2":{"187":1}}],["0228109822209213",{"2":{"153":2}}],["02238",{"2":{"187":1}}],["02234",{"2":{"187":1}}],["026451373181859e",{"2":{"258":1}}],["026481f",{"2":{"256":1}}],["026170366",{"2":{"244":1}}],["02612",{"2":{"187":1}}],["026282774",{"2":{"244":1}}],["02626s\\ttraining",{"2":{"236":1}}],["02654s\\ttraining",{"2":{"236":1}}],["026516732",{"2":{"77":1}}],["02632s\\ttraining",{"2":{"236":1}}],["02638",{"2":{"187":1}}],["02631",{"2":{"187":1}}],["02667",{"2":{"187":1}}],["026851978",{"2":{"77":1}}],["0242",{"2":{"249":1}}],["0246",{"2":{"249":1}}],["0240",{"2":{"249":1}}],["02417",{"2":{"187":1}}],["024526f",{"2":{"256":1}}],["02452",{"2":{"187":1}}],["02454",{"2":{"187":1}}],["02442s\\ttraining",{"2":{"236":1}}],["0244214",{"2":{"77":1}}],["02449",{"2":{"187":1}}],["0244548f",{"2":{"113":1}}],["024",{"2":{"77":1}}],["094517070430916e",{"2":{"258":1}}],["0945268f",{"2":{"256":1}}],["094825845363752e",{"2":{"258":1}}],["094444f",{"2":{"256":1}}],["0941325f",{"2":{"256":1}}],["09",{"2":{"236":1,"249":1}}],["093673153265391e",{"2":{"258":1}}],["0935473f",{"2":{"256":1}}],["0935077",{"2":{"254":2}}],["09351656",{"2":{"177":1,"178":1}}],["093925126",{"2":{"179":1}}],["098986999663594e",{"2":{"258":1}}],["09852",{"2":{"171":1}}],["0985227",{"2":{"171":2}}],["0987538",{"2":{"168":1}}],["098861866",{"2":{"77":1}}],["0913593358445652",{"2":{"153":1}}],["091359335844565",{"2":{"153":1}}],["0914626",{"2":{"148":1}}],["0927202964011898e",{"2":{"258":1}}],["0922906254648934e",{"2":{"258":1}}],["092271f",{"2":{"256":1}}],["092407166867638e",{"2":{"258":1}}],["092556916177105e",{"2":{"258":1}}],["092557f",{"2":{"256":1}}],["09299411",{"2":{"114":1}}],["09289699",{"2":{"113":1}}],["0965",{"2":{"249":1}}],["09693718",{"2":{"227":1}}],["09699093",{"2":{"147":1}}],["096988946",{"2":{"129":1}}],["09692798",{"2":{"77":1}}],["09643307",{"2":{"113":2}}],["095649014502691e",{"2":{"258":1}}],["0956474f",{"2":{"256":1}}],["09515f",{"2":{"256":1}}],["095568806",{"2":{"227":1}}],["0954186",{"2":{"113":1}}],["09599f",{"2":{"77":1}}],["0990384f",{"2":{"256":1}}],["0997s\\ttraining",{"2":{"210":1}}],["0991955",{"2":{"113":1}}],["09919551",{"2":{"113":1}}],["099906564",{"2":{"113":1}}],["09926938",{"2":{"113":1}}],["0973",{"2":{"249":1}}],["0971",{"2":{"249":1}}],["097182155",{"2":{"113":1}}],["09701932",{"2":{"179":1}}],["097253",{"2":{"129":1}}],["09724942",{"2":{"113":1}}],["09724939",{"2":{"113":1}}],["097701035",{"2":{"113":2}}],["09785451",{"2":{"77":1}}],["090701e",{"2":{"219":1}}],["09085",{"2":{"187":1}}],["09092",{"2":{"187":1}}],["09098f",{"2":{"77":1}}],["0903271",{"2":{"113":2}}],["0901",{"2":{"78":1}}],["0900306",{"2":{"53":10}}],["0782",{"2":{"249":1}}],["078782f",{"2":{"256":1}}],["0787",{"2":{"249":1}}],["07874016",{"2":{"224":2}}],["07",{"2":{"236":1}}],["0733",{"2":{"249":1}}],["07375115",{"2":{"227":1}}],["073442355",{"2":{"77":1}}],["07711",{"2":{"187":1}}],["07702",{"2":{"171":1}}],["0770206",{"2":{"171":2}}],["07704306",{"2":{"77":1}}],["0756254592508004e",{"2":{"258":1}}],["07565363",{"2":{"227":1}}],["07561",{"2":{"187":1}}],["075873e",{"2":{"219":1}}],["075135306",{"2":{"147":1}}],["0765035541076204e",{"2":{"258":1}}],["0762799f",{"2":{"256":1}}],["07613",{"2":{"187":1}}],["076404385",{"2":{"113":1}}],["07640441",{"2":{"113":1}}],["072139238441361e",{"2":{"258":1}}],["0725677217871096e",{"2":{"258":1}}],["07250",{"2":{"187":1}}],["0722369",{"2":{"168":1}}],["0728675615927385",{"2":{"53":1}}],["0798727871371625e",{"2":{"258":1}}],["0795486f",{"2":{"256":1}}],["07975",{"2":{"187":1}}],["07964921",{"2":{"114":1}}],["079208925",{"2":{"112":1}}],["0742047",{"2":{"224":1}}],["07425846",{"2":{"113":1}}],["07425845",{"2":{"113":1}}],["07462",{"2":{"187":1}}],["07412187",{"2":{"77":1}}],["0706044612614154e",{"2":{"258":1}}],["0709",{"2":{"224":1}}],["0701",{"2":{"78":1}}],["070524f",{"2":{"256":1}}],["07058401",{"2":{"77":1}}],["07057328",{"2":{"77":1}}],["071837f",{"2":{"256":1}}],["07155",{"2":{"187":1}}],["071482725",{"2":{"179":1}}],["07133968",{"2":{"125":1}}],["07167f",{"2":{"77":1}}],["07125676",{"2":{"77":1}}],["0440254502292897e",{"2":{"258":1}}],["0440255f",{"2":{"256":1}}],["0444",{"2":{"249":1}}],["04416",{"2":{"228":1}}],["04415",{"2":{"187":1}}],["0419127269538136e",{"2":{"258":1}}],["04199602",{"2":{"179":1}}],["041894423301891e",{"2":{"258":1}}],["0418944f",{"2":{"256":1}}],["041146f",{"2":{"256":1}}],["04164f",{"2":{"256":1}}],["041541956",{"2":{"244":1}}],["04136",{"2":{"187":1}}],["04109",{"2":{"187":1}}],["041031003",{"2":{"145":1}}],["04108f",{"2":{"77":1}}],["049888293545121e",{"2":{"258":1}}],["049828763467198e",{"2":{"258":1}}],["04989187031691e",{"2":{"258":1}}],["04989",{"2":{"187":1}}],["049461f",{"2":{"256":1}}],["049417756",{"2":{"113":1}}],["049417753",{"2":{"113":1}}],["049568f",{"2":{"256":1}}],["04974",{"2":{"187":1}}],["04965",{"2":{"187":1}}],["04903387",{"2":{"179":1}}],["0435",{"2":{"249":1}}],["0435721",{"2":{"77":1}}],["04373",{"2":{"187":1}}],["04374",{"2":{"187":1}}],["04304",{"2":{"187":1}}],["04389",{"2":{"187":1}}],["043883",{"2":{"171":1}}],["0464649423930583e",{"2":{"258":1}}],["046465f",{"2":{"256":1}}],["04647",{"2":{"187":1}}],["0469896im",{"2":{"168":1}}],["0469301",{"2":{"148":1}}],["0462954",{"2":{"148":1}}],["0404076179055e",{"2":{"258":1}}],["0403345f",{"2":{"256":1}}],["040083f",{"2":{"256":1}}],["040918160",{"2":{"244":1}}],["04085",{"2":{"187":1}}],["04024",{"2":{"187":1}}],["0402095",{"2":{"147":1}}],["040194979405464e",{"2":{"258":1}}],["04019f",{"2":{"77":1}}],["0401",{"2":{"78":1}}],["045743054559194e",{"2":{"258":1}}],["0454068102045332e",{"2":{"258":1}}],["045441f",{"2":{"256":1}}],["0453728f",{"2":{"256":1}}],["04551310",{"2":{"114":1}}],["04566476",{"2":{"113":1}}],["047244094",{"2":{"224":2}}],["0479814",{"2":{"168":1}}],["0474757im",{"2":{"168":1}}],["047897488",{"2":{"113":2}}],["047356773",{"2":{"77":1}}],["048608029328477e",{"2":{"258":1}}],["048482f",{"2":{"256":1}}],["04836",{"2":{"187":1}}],["04801",{"2":{"187":1}}],["0480501",{"2":{"77":1}}],["048109",{"2":{"148":1}}],["048133414",{"2":{"113":2}}],["048522998",{"2":{"132":1}}],["04853325",{"2":{"113":1}}],["048533253",{"2":{"113":1}}],["048811335",{"2":{"113":2}}],["04d",{"2":{"78":1}}],["042499166",{"2":{"244":1}}],["04243",{"2":{"187":1}}],["0428307",{"2":{"224":1}}],["04283",{"2":{"187":1}}],["04201",{"2":{"187":1}}],["0420834",{"2":{"77":1}}],["04264",{"2":{"187":1}}],["04265762",{"2":{"179":1}}],["0425432",{"2":{"147":1}}],["042254835",{"2":{"113":1}}],["04225484",{"2":{"113":1}}],["042256515",{"2":{"113":1}}],["04224006",{"2":{"77":1}}],["04226003",{"2":{"77":1}}],["0616435f",{"2":{"256":1}}],["061805167244798e",{"2":{"258":1}}],["0618",{"2":{"249":1}}],["0613",{"2":{"249":1}}],["06135",{"2":{"187":1}}],["0672",{"2":{"249":1}}],["067872316",{"2":{"77":1}}],["0681546356619121e",{"2":{"258":1}}],["068733352839627e",{"2":{"258":1}}],["0684749f",{"2":{"256":1}}],["0683171f",{"2":{"256":1}}],["068682f",{"2":{"256":1}}],["0686756",{"2":{"224":1}}],["06895",{"2":{"187":1}}],["06433817",{"2":{"224":1}}],["06475",{"2":{"187":1}}],["06450",{"2":{"19":1}}],["0690823",{"2":{"227":1}}],["06929",{"2":{"187":1}}],["06942138",{"2":{"77":1}}],["062907",{"2":{"228":1}}],["06222",{"2":{"187":1}}],["06246",{"2":{"187":1}}],["062155924699545",{"2":{"153":1}}],["0621559246995447",{"2":{"153":1}}],["062079933",{"2":{"147":1}}],["066128",{"2":{"148":1}}],["06612328",{"2":{"114":1}}],["06618893",{"2":{"113":1}}],["06675106",{"2":{"113":1}}],["066751055",{"2":{"113":1}}],["0633",{"2":{"249":1}}],["0630s\\ttraining",{"2":{"210":1}}],["06304",{"2":{"187":1}}],["06301335",{"2":{"113":1}}],["06325f",{"2":{"77":1}}],["063480526",{"2":{"77":1}}],["0606723670860167e",{"2":{"258":1}}],["0606383f",{"2":{"256":1}}],["0607064f",{"2":{"256":1}}],["06027697",{"2":{"113":1}}],["06026962",{"2":{"77":1}}],["0601",{"2":{"78":1}}],["060364496",{"2":{"77":1}}],["06053336",{"2":{"77":1}}],["065944076971189e",{"2":{"258":1}}],["065827f",{"2":{"256":1}}],["06519687",{"2":{"114":1}}],["06550143",{"2":{"77":1}}],["065317236",{"2":{"77":1}}],["06",{"2":{"53":1,"196":2}}],["052428f",{"2":{"256":1}}],["05218964",{"2":{"179":1}}],["0554495196434365e",{"2":{"258":1}}],["055339454980837e",{"2":{"258":1}}],["055722f",{"2":{"256":1}}],["0551837f",{"2":{"256":1}}],["0551181",{"2":{"224":2}}],["0510",{"2":{"249":1}}],["05f0",{"2":{"244":2,"245":1}}],["058959538695134e",{"2":{"258":1}}],["0588656f",{"2":{"256":1}}],["0584",{"2":{"249":1}}],["05808",{"2":{"187":1}}],["05835",{"2":{"187":2}}],["0585f",{"2":{"77":1}}],["0546",{"2":{"249":1}}],["0540",{"2":{"249":1}}],["0540537",{"2":{"77":1}}],["05429",{"2":{"187":1}}],["059597105191893e",{"2":{"258":1}}],["059518166",{"2":{"113":2}}],["0597315f",{"2":{"256":1}}],["05983",{"2":{"187":1}}],["05935",{"2":{"187":1}}],["0575573146133675e",{"2":{"258":1}}],["057045f",{"2":{"256":1}}],["057005208",{"2":{"177":1,"178":1}}],["0578545",{"2":{"227":1}}],["05779423",{"2":{"129":1}}],["05729505",{"2":{"113":1}}],["053549669652573e",{"2":{"258":1}}],["053401f",{"2":{"256":1}}],["0534",{"2":{"249":1}}],["0536",{"2":{"249":1}}],["053627778",{"2":{"113":1}}],["05303",{"2":{"187":1}}],["053747915",{"2":{"113":2}}],["0568",{"2":{"249":1}}],["0569",{"2":{"249":1}}],["05645",{"2":{"187":1}}],["0564903986057956",{"2":{"153":2}}],["05657739601024536",{"2":{"174":1}}],["056",{"2":{"78":3,"256":1}}],["0501",{"2":{"78":1}}],["05058f",{"2":{"77":1}}],["050089",{"2":{"77":1}}],["05",{"2":{"53":1,"249":1}}],["00",{"2":{"196":7,"236":43}}],["008724037",{"2":{"244":1}}],["008772802",{"2":{"244":1}}],["008732248",{"2":{"244":1}}],["008153505",{"2":{"244":1}}],["008185850",{"2":{"244":1}}],["008925664",{"2":{"244":1}}],["008405063",{"2":{"244":1}}],["008404830",{"2":{"244":1}}],["00846",{"2":{"187":1}}],["008026988",{"2":{"244":1}}],["008074892",{"2":{"244":1}}],["008014920",{"2":{"244":1}}],["00804",{"2":{"187":1}}],["00803",{"2":{"187":1}}],["00861",{"2":{"187":1}}],["00866",{"2":{"187":1}}],["00822",{"2":{"187":1}}],["00823197",{"2":{"171":1}}],["00830",{"2":{"187":2}}],["008556721",{"2":{"244":1}}],["00856",{"2":{"187":2}}],["00853",{"2":{"187":1}}],["008808360",{"2":{"244":1}}],["00884",{"2":{"187":1}}],["00883",{"2":{"187":2}}],["00888",{"2":{"187":2}}],["00886",{"2":{"187":1}}],["008870317",{"2":{"77":1}}],["007187600",{"2":{"244":1}}],["007129070",{"2":{"244":1}}],["007004f",{"2":{"256":1}}],["007075997",{"2":{"244":1}}],["00706411",{"2":{"77":1}}],["007501942",{"2":{"244":1}}],["007509941",{"2":{"244":1}}],["007593059",{"2":{"244":1}}],["007535893",{"2":{"244":1}}],["007676640",{"2":{"244":1}}],["007679918",{"2":{"244":1}}],["00762",{"2":{"187":1}}],["00766",{"2":{"187":1}}],["00760",{"2":{"187":1}}],["00769",{"2":{"187":1}}],["007885863",{"2":{"244":1}}],["00784",{"2":{"187":1}}],["00781",{"2":{"187":1}}],["00747",{"2":{"187":1}}],["00742",{"2":{"187":1}}],["00775",{"2":{"187":1}}],["007325693",{"2":{"244":1}}],["007372384",{"2":{"244":1}}],["007333768",{"2":{"244":1}}],["007363341",{"2":{"244":1}}],["00730061367726e",{"2":{"258":1}}],["00730",{"2":{"187":1}}],["0073489705",{"2":{"113":2}}],["007208704839708e",{"2":{"258":1}}],["007220342",{"2":{"244":1}}],["007273634",{"2":{"244":1}}],["00726",{"2":{"187":1}}],["00721",{"2":{"187":1}}],["007249862",{"2":{"113":1}}],["0072498624",{"2":{"113":1}}],["007947534",{"2":{"244":1}}],["007905648",{"2":{"244":1}}],["00791",{"2":{"187":1}}],["007950513",{"2":{"244":1}}],["00795",{"2":{"187":1}}],["007984845",{"2":{"147":1}}],["0092905f",{"2":{"256":1}}],["009256126",{"2":{"244":1}}],["00920",{"2":{"187":1}}],["009313912",{"2":{"244":1}}],["009895653",{"2":{"244":1}}],["009887908",{"2":{"244":1}}],["00987",{"2":{"187":1}}],["009766437",{"2":{"224":1}}],["00960",{"2":{"187":1}}],["009693242",{"2":{"244":1}}],["00969",{"2":{"187":1}}],["009514628",{"2":{"244":1}}],["009516605",{"2":{"244":1}}],["00958",{"2":{"187":1}}],["00955",{"2":{"187":1}}],["00952",{"2":{"187":1}}],["00950",{"2":{"187":1}}],["009578831",{"2":{"77":1}}],["009987052",{"2":{"244":1}}],["00995",{"2":{"187":1}}],["00993",{"2":{"187":1}}],["009963844931984",{"2":{"153":2}}],["00945",{"2":{"187":1}}],["00947",{"2":{"187":1}}],["00940",{"2":{"187":1}}],["009083126",{"2":{"244":1}}],["009084041f0",{"2":{"53":1}}],["00903",{"2":{"187":1}}],["00902",{"2":{"187":1}}],["009196523930294e",{"2":{"258":1}}],["009196416",{"2":{"244":1}}],["00915",{"2":{"187":1}}],["00914141",{"2":{"179":1}}],["00913097",{"2":{"168":1}}],["0051406f",{"2":{"256":1}}],["005112350",{"2":{"244":1}}],["005315070",{"2":{"244":1}}],["005351806",{"2":{"244":1}}],["0053856913",{"2":{"77":1}}],["005200472",{"2":{"244":1}}],["005807751",{"2":{"244":1}}],["005835793",{"2":{"244":1}}],["005824474",{"2":{"244":1}}],["00582",{"2":{"187":1}}],["005978104",{"2":{"244":1}}],["005463609",{"2":{"244":1}}],["005461216",{"2":{"244":1}}],["005433898",{"2":{"244":1}}],["005628760",{"2":{"244":1}}],["005615299",{"2":{"244":1}}],["00564f",{"2":{"77":1}}],["005f0",{"2":{"244":1}}],["005",{"2":{"219":1}}],["005065940",{"2":{"244":1}}],["005044522",{"2":{"244":1}}],["005014097",{"2":{"77":1}}],["005000000000000009",{"2":{"53":1}}],["006305961",{"2":{"244":1}}],["006221022",{"2":{"244":1}}],["006288857",{"2":{"113":1}}],["0062888456",{"2":{"113":1}}],["006572613",{"2":{"244":1}}],["0065859724",{"2":{"77":1}}],["0069668216036951e",{"2":{"258":1}}],["006962581",{"2":{"244":1}}],["0069865f",{"2":{"256":1}}],["0069556f",{"2":{"256":1}}],["006942283",{"2":{"244":1}}],["006906096",{"2":{"244":1}}],["0069942693",{"2":{"113":1}}],["006616294",{"2":{"244":1}}],["006642802",{"2":{"244":1}}],["00662",{"2":{"187":1}}],["0066712513",{"2":{"179":1}}],["006432486",{"2":{"77":1}}],["006105572",{"2":{"244":1}}],["0061099795",{"2":{"77":1}}],["006184267",{"2":{"77":1}}],["006736353",{"2":{"77":1}}],["0067729075",{"2":{"77":1}}],["004855067",{"2":{"244":1}}],["004880759",{"2":{"244":1}}],["00488f",{"2":{"77":1}}],["004657542",{"2":{"244":1}}],["004607514",{"2":{"244":1}}],["0045826f",{"2":{"256":1}}],["004590358",{"2":{"244":1}}],["004518208",{"2":{"244":1}}],["004542338",{"2":{"244":1}}],["004978007",{"2":{"244":1}}],["004947479",{"2":{"244":1}}],["004958895",{"2":{"244":1}}],["004958282",{"2":{"244":1}}],["004790282",{"2":{"244":1}}],["004397592",{"2":{"244":1}}],["004335414",{"2":{"244":1}}],["004338491",{"2":{"244":1}}],["004365115",{"2":{"244":1}}],["004326937",{"2":{"244":1}}],["004329988",{"2":{"244":1}}],["0042583882232845e",{"2":{"258":1}}],["004253434",{"2":{"244":1}}],["004238f",{"2":{"256":1}}],["004287243",{"2":{"113":2}}],["0044148341895383e",{"2":{"258":1}}],["0044189203",{"2":{"77":1}}],["004434146",{"2":{"244":1}}],["004466736",{"2":{"244":1}}],["004491198",{"2":{"244":1}}],["004043682",{"2":{"244":1}}],["004047669",{"2":{"77":1}}],["004061943",{"2":{"244":1}}],["00407581",{"2":{"179":1}}],["004119421",{"2":{"244":1}}],["004116789",{"2":{"244":1}}],["0041674743",{"2":{"113":1}}],["0041674753",{"2":{"113":1}}],["004169049",{"2":{"77":1}}],["004144425",{"2":{"77":1}}],["001398915",{"2":{"244":1}}],["00139126",{"2":{"77":1}}],["001329915",{"2":{"244":1}}],["001325711",{"2":{"244":1}}],["001325290",{"2":{"244":1}}],["001367094",{"2":{"244":1}}],["001362987",{"2":{"244":1}}],["001362466",{"2":{"244":1}}],["001364744",{"2":{"244":1}}],["001380907",{"2":{"244":1}}],["001386037",{"2":{"244":1}}],["001346401",{"2":{"244":1}}],["001356683",{"2":{"244":1}}],["001336156",{"2":{"244":1}}],["001307026",{"2":{"244":1}}],["001303701",{"2":{"244":1}}],["001302390",{"2":{"244":1}}],["001302087",{"2":{"244":1}}],["001300987",{"2":{"244":1}}],["001309370",{"2":{"244":1}}],["001305370",{"2":{"244":1}}],["001636085",{"2":{"244":1}}],["001639404",{"2":{"244":1}}],["001659834",{"2":{"244":1}}],["001658659",{"2":{"244":1}}],["001672024",{"2":{"244":1}}],["001671217",{"2":{"244":1}}],["001649067",{"2":{"244":1}}],["001608545",{"2":{"244":1}}],["001694928",{"2":{"244":1}}],["001690981",{"2":{"244":1}}],["001615586",{"2":{"244":1}}],["001611185",{"2":{"244":1}}],["001592739",{"2":{"244":1}}],["001594031",{"2":{"244":1}}],["001531350",{"2":{"244":1}}],["0015313211",{"2":{"77":1}}],["001541014",{"2":{"244":1}}],["001513747",{"2":{"244":1}}],["001510418",{"2":{"244":1}}],["001517879",{"2":{"244":1}}],["001560361",{"2":{"244":1}}],["001566568",{"2":{"244":1}}],["001564218",{"2":{"244":1}}],["001571818",{"2":{"244":1}}],["001",{"2":{"219":1}}],["001093546",{"2":{"244":1}}],["001014936",{"2":{"244":1}}],["001011056",{"2":{"244":1}}],["00101147",{"2":{"179":1}}],["001068081",{"2":{"244":1}}],["001060384",{"2":{"244":1}}],["001060399",{"2":{"244":1}}],["00106574",{"2":{"77":1}}],["001085206",{"2":{"244":1}}],["001085730",{"2":{"244":1}}],["001085884",{"2":{"244":1}}],["001089040",{"2":{"244":1}}],["001008533",{"2":{"244":1}}],["001009728",{"2":{"244":1}}],["001049175",{"2":{"244":1}}],["001044580",{"2":{"244":1}}],["001041825",{"2":{"244":1}}],["001047856",{"2":{"244":1}}],["001053359",{"2":{"244":1}}],["001050717",{"2":{"244":1}}],["001058994",{"2":{"244":1}}],["001059842",{"2":{"244":1}}],["0010350421",{"2":{"224":1}}],["001f0",{"2":{"78":1,"114":1,"210":1,"236":1}}],["0012",{"2":{"249":1}}],["001202180",{"2":{"244":1}}],["001209691",{"2":{"244":1}}],["001203537",{"2":{"244":1}}],["001257007",{"2":{"244":1}}],["001258897",{"2":{"244":1}}],["001272172",{"2":{"244":1}}],["001279382",{"2":{"244":1}}],["00122f",{"2":{"256":1}}],["001228882",{"2":{"244":1}}],["001224264",{"2":{"244":1}}],["001240770",{"2":{"244":1}}],["001243982",{"2":{"244":1}}],["001243673",{"2":{"244":1}}],["001241080",{"2":{"244":1}}],["001245214",{"2":{"244":1}}],["001218763",{"2":{"244":1}}],["001215764",{"2":{"244":1}}],["001292084",{"2":{"244":1}}],["00126273",{"2":{"77":1}}],["001289588",{"2":{"244":1}}],["00128162",{"2":{"77":1}}],["0012843215",{"2":{"77":1}}],["0018825f",{"2":{"256":1}}],["001886566",{"2":{"244":1}}],["001884541",{"2":{"244":1}}],["001864895",{"2":{"244":1}}],["001825325",{"2":{"244":1}}],["001837625",{"2":{"244":1}}],["001894138",{"2":{"244":1}}],["001845157",{"2":{"244":1}}],["001849154",{"2":{"244":1}}],["001848093",{"2":{"244":1}}],["001879478",{"2":{"244":1}}],["001871931",{"2":{"244":1}}],["00187748",{"2":{"77":1}}],["0018058",{"2":{"77":1}}],["0018510937",{"2":{"77":1}}],["001438607183606e",{"2":{"258":1}}],["001439294",{"2":{"244":1}}],["001448896",{"2":{"244":1}}],["001448493",{"2":{"244":1}}],["001479216",{"2":{"244":1}}],["001498525",{"2":{"244":1}}],["001494603",{"2":{"244":1}}],["001492234",{"2":{"244":1}}],["001485110",{"2":{"244":1}}],["001454655",{"2":{"244":1}}],["00145586",{"2":{"77":1}}],["001404967",{"2":{"244":1}}],["001409405",{"2":{"244":1}}],["001402911",{"2":{"244":1}}],["00140763051",{"2":{"78":1}}],["0014175134",{"2":{"77":1}}],["001185708",{"2":{"244":1}}],["001182971",{"2":{"244":1}}],["001168622",{"2":{"244":1}}],["001160439",{"2":{"244":1}}],["001101400",{"2":{"244":1}}],["001103305",{"2":{"244":1}}],["001110448",{"2":{"244":1}}],["001113559",{"2":{"244":1}}],["001141232",{"2":{"244":1}}],["001143823",{"2":{"244":1}}],["001148389",{"2":{"244":1}}],["001171167",{"2":{"244":1}}],["001179150",{"2":{"244":1}}],["00117228",{"2":{"77":1}}],["001126162",{"2":{"244":1}}],["001191893",{"2":{"244":1}}],["001197650",{"2":{"244":1}}],["001136703",{"2":{"244":1}}],["001135292",{"2":{"244":1}}],["001135202",{"2":{"244":1}}],["001138862",{"2":{"244":1}}],["001153235",{"2":{"244":1}}],["001154157",{"2":{"244":1}}],["00115296",{"2":{"77":1}}],["00176466762311e",{"2":{"258":1}}],["001764537",{"2":{"244":1}}],["001720798",{"2":{"244":1}}],["001728887",{"2":{"244":1}}],["001789054",{"2":{"244":1}}],["001770784",{"2":{"244":1}}],["001747428",{"2":{"244":1}}],["001717428",{"2":{"244":1}}],["001714717",{"2":{"244":1}}],["001715113",{"2":{"244":1}}],["001731674",{"2":{"244":1}}],["001730468",{"2":{"244":1}}],["0017369908",{"2":{"77":1}}],["001798752",{"2":{"244":1}}],["001798573",{"2":{"244":1}}],["001792779",{"2":{"244":1}}],["0017900232",{"2":{"77":1}}],["00175152",{"2":{"77":1}}],["00170922",{"2":{"77":1}}],["001930058",{"2":{"244":1}}],["001994215",{"2":{"244":1}}],["001959185",{"2":{"244":1}}],["0019504696",{"2":{"77":1}}],["001972227",{"2":{"244":1}}],["001975382",{"2":{"244":1}}],["001970405",{"2":{"244":1}}],["001973281",{"2":{"77":1}}],["001919697",{"2":{"244":1}}],["001913586",{"2":{"244":1}}],["0019153744",{"2":{"77":1}}],["001940841",{"2":{"244":1}}],["001982885",{"2":{"244":1}}],["00198415",{"2":{"179":1}}],["00198767",{"2":{"77":1}}],["0019262917",{"2":{"77":1}}],["002989073",{"2":{"244":1}}],["002972272",{"2":{"244":1}}],["002935605",{"2":{"244":1}}],["002511334",{"2":{"244":1}}],["002511769",{"2":{"244":1}}],["002553018",{"2":{"244":1}}],["002556076",{"2":{"244":1}}],["002371583",{"2":{"244":1}}],["002343247",{"2":{"244":1}}],["002318957",{"2":{"244":1}}],["002301548",{"2":{"244":1}}],["002303589",{"2":{"244":1}}],["002304791",{"2":{"244":1}}],["002395016",{"2":{"244":1}}],["002358936",{"2":{"244":1}}],["002834306",{"2":{"244":1}}],["002806861",{"2":{"244":1}}],["002853032",{"2":{"244":1}}],["0028297466",{"2":{"113":1}}],["0028297475",{"2":{"113":1}}],["002670718",{"2":{"244":1}}],["002677995",{"2":{"244":1}}],["002668741",{"2":{"244":1}}],["002668936",{"2":{"244":1}}],["002606506",{"2":{"244":1}}],["002613829",{"2":{"244":1}}],["002696904",{"2":{"244":1}}],["002695386",{"2":{"244":1}}],["0026271285",{"2":{"126":1}}],["002236427",{"2":{"244":1}}],["002234935",{"2":{"244":1}}],["0022308934",{"2":{"77":1}}],["002276814",{"2":{"244":1}}],["002210422",{"2":{"244":1}}],["002218451",{"2":{"244":1}}],["002247394",{"2":{"244":1}}],["0022497",{"2":{"224":1}}],["002262217",{"2":{"244":1}}],["002201537",{"2":{"244":1}}],["002068657",{"2":{"244":1}}],["002089650",{"2":{"244":1}}],["002081697",{"2":{"244":1}}],["002059042",{"2":{"244":1}}],["0020579377",{"2":{"113":1}}],["002057937",{"2":{"113":1}}],["002023818",{"2":{"244":1}}],["002015869",{"2":{"244":1}}],["002019164",{"2":{"244":1}}],["002037087",{"2":{"244":1}}],["00209504",{"2":{"77":1}}],["002752088",{"2":{"244":1}}],["00270753",{"2":{"77":1}}],["0027386106",{"2":{"77":1}}],["0027955552",{"2":{"77":1}}],["002155375",{"2":{"244":1}}],["002129085",{"2":{"244":1}}],["002125610",{"2":{"244":1}}],["002123826",{"2":{"244":1}}],["0021203319",{"2":{"77":1}}],["00219681",{"2":{"77":1}}],["00214946",{"2":{"77":1}}],["002106787",{"2":{"77":1}}],["002417301",{"2":{"244":1}}],["002489866",{"2":{"244":1}}],["002474443",{"2":{"244":1}}],["002448601",{"2":{"244":1}}],["0024971329",{"2":{"77":1}}],["0024323382",{"2":{"77":1}}],["003299790",{"2":{"244":1}}],["0038856f",{"2":{"256":1}}],["003847855",{"2":{"244":1}}],["003813077",{"2":{"244":1}}],["0038745",{"2":{"77":1}}],["003463188",{"2":{"244":1}}],["003488734",{"2":{"244":1}}],["0034101289",{"2":{"77":1}}],["003329928",{"2":{"244":1}}],["003180855",{"2":{"244":1}}],["003136263",{"2":{"244":1}}],["003132161",{"2":{"244":1}}],["0031376407",{"2":{"77":1}}],["003162773",{"2":{"244":1}}],["003125851",{"2":{"244":1}}],["003911218",{"2":{"244":1}}],["003920683",{"2":{"244":1}}],["00390526722",{"2":{"78":1}}],["003504427",{"2":{"244":1}}],["003519468",{"2":{"244":1}}],["00351666",{"2":{"77":1}}],["003553676",{"2":{"244":1}}],["003585588",{"2":{"244":1}}],["003658900",{"2":{"244":1}}],["003630795",{"2":{"244":1}}],["0036810287",{"2":{"113":1}}],["0036810301",{"2":{"113":1}}],["00364828",{"2":{"77":1}}],["003095849",{"2":{"244":1}}],["003031955",{"2":{"244":1}}],["003061282",{"2":{"244":1}}],["00306169",{"2":{"77":1}}],["003071612",{"2":{"244":1}}],["003027094",{"2":{"77":1}}],["0037677741147184e",{"2":{"258":1}}],["0037725805",{"2":{"77":1}}],["003750000000000005",{"2":{"53":1}}],["000846881",{"2":{"244":1}}],["000847362",{"2":{"244":1}}],["000826713",{"2":{"244":1}}],["000826687",{"2":{"244":1}}],["000824789",{"2":{"244":1}}],["000868335",{"2":{"244":1}}],["000866074",{"2":{"244":1}}],["000864926",{"2":{"244":1}}],["000835373",{"2":{"244":1}}],["000835131",{"2":{"244":1}}],["000831873",{"2":{"244":1}}],["000887047",{"2":{"244":1}}],["000883626",{"2":{"244":1}}],["000881248",{"2":{"244":1}}],["000873007",{"2":{"244":1}}],["000871024327",{"2":{"78":1}}],["000892342",{"2":{"244":1}}],["000892691",{"2":{"244":1}}],["000890729",{"2":{"244":1}}],["000893347",{"2":{"244":1}}],["000894285",{"2":{"244":1}}],["000857553",{"2":{"244":1}}],["000809421",{"2":{"244":1}}],["000805100",{"2":{"244":1}}],["000807529",{"2":{"244":1}}],["000816396",{"2":{"244":1}}],["000814481",{"2":{"244":1}}],["000043311",{"2":{"244":1}}],["000046194",{"2":{"244":1}}],["000044412",{"2":{"244":1}}],["000098905",{"2":{"244":1}}],["000098134",{"2":{"244":1}}],["000092742",{"2":{"244":1}}],["000094398",{"2":{"244":1}}],["000097348",{"2":{"244":1}}],["000097578",{"2":{"244":1}}],["000097049",{"2":{"244":1}}],["000095254",{"2":{"244":1}}],["000058640",{"2":{"244":1}}],["000056836",{"2":{"244":1}}],["000059547",{"2":{"244":1}}],["000052356",{"2":{"244":1}}],["000067247",{"2":{"244":1}}],["000088090",{"2":{"244":1}}],["000086152",{"2":{"244":1}}],["000089840",{"2":{"244":1}}],["000083818",{"2":{"244":1}}],["000083883",{"2":{"244":1}}],["000085040",{"2":{"244":1}}],["000081115",{"2":{"244":1}}],["000087234",{"2":{"244":1}}],["000079111",{"2":{"244":1}}],["000070152",{"2":{"244":1}}],["000075086",{"2":{"244":1}}],["000077215",{"2":{"244":1}}],["000071670",{"2":{"244":1}}],["00000",{"2":{"187":100,"210":18,"212":3}}],["000",{"2":{"189":2,"250":1}}],["0002490765888576313",{"2":{"258":1}}],["0002499269396489655",{"2":{"258":1}}],["00024680436727769566",{"2":{"258":1}}],["0002468032",{"2":{"256":1}}],["00024188793929002712",{"2":{"258":1}}],["00024188824",{"2":{"256":1}}],["0002456494818520329",{"2":{"258":1}}],["00024581934080877734",{"2":{"258":1}}],["0002458211",{"2":{"256":1}}],["00024530327293901074",{"2":{"258":1}}],["00024530233",{"2":{"256":1}}],["000242183",{"2":{"244":1}}],["000242905",{"2":{"244":1}}],["000242692",{"2":{"244":1}}],["00022319819681359897",{"2":{"258":1}}],["00022319547",{"2":{"256":1}}],["00022803118840484076",{"2":{"258":1}}],["00022803275",{"2":{"256":1}}],["0002255303360520187",{"2":{"258":1}}],["00022553114",{"2":{"256":1}}],["00022001809519496887",{"2":{"258":1}}],["00022001681",{"2":{"256":1}}],["00022275520391604623",{"2":{"258":1}}],["00022275365",{"2":{"256":1}}],["00022212154556822418",{"2":{"258":1}}],["00022212125",{"2":{"256":1}}],["00022925964940814742",{"2":{"258":1}}],["00022925969",{"2":{"256":1}}],["000229884",{"2":{"244":1}}],["0002617368496312524",{"2":{"258":1}}],["00026839277162856644",{"2":{"258":1}}],["000262231730353226",{"2":{"258":1}}],["000262229",{"2":{"256":1}}],["0002632548694413957",{"2":{"258":1}}],["00026348081994910527",{"2":{"258":1}}],["00026348335",{"2":{"256":1}}],["000263541",{"2":{"244":1}}],["0002643397254979961",{"2":{"258":1}}],["00026434002",{"2":{"256":1}}],["000264404",{"2":{"244":1}}],["000269295",{"2":{"244":1}}],["00027947947796219696",{"2":{"258":1}}],["00027448492384949514",{"2":{"258":1}}],["00027448655",{"2":{"256":1}}],["0002783849588653411",{"2":{"258":1}}],["00027838128",{"2":{"256":1}}],["00027343908268942475",{"2":{"258":1}}],["0002734399",{"2":{"256":1}}],["000273393",{"2":{"244":1}}],["000275985",{"2":{"244":1}}],["000271556",{"2":{"244":1}}],["000277635",{"2":{"244":1}}],["000270049",{"2":{"244":1}}],["000270824",{"2":{"244":1}}],["00020246197007451418",{"2":{"258":1}}],["00020004856283175256",{"2":{"258":1}}],["00020004802",{"2":{"256":1}}],["00020347867044057805",{"2":{"258":1}}],["0002034794",{"2":{"256":1}}],["00020355819903670398",{"2":{"258":1}}],["00020355567",{"2":{"256":1}}],["00020949787956694324",{"2":{"258":1}}],["00020949625",{"2":{"256":1}}],["00020962827",{"2":{"256":1}}],["000209925",{"2":{"244":1}}],["00020498502796661137",{"2":{"258":1}}],["0002041848850161636",{"2":{"258":1}}],["00020418508",{"2":{"256":1}}],["00020400019188546685",{"2":{"258":1}}],["00020400074",{"2":{"256":1}}],["00020486202807255978",{"2":{"258":1}}],["00020486339",{"2":{"256":1}}],["000204869",{"2":{"244":1}}],["00020153183148601252",{"2":{"258":1}}],["00020131683498034742",{"2":{"258":1}}],["0002013159",{"2":{"256":1}}],["000201183",{"2":{"244":1}}],["00020766168928458141",{"2":{"258":1}}],["00020766298",{"2":{"256":1}}],["00020756972453081547",{"2":{"258":1}}],["00020756968",{"2":{"256":1}}],["000205284",{"2":{"244":1}}],["00020623337629364102",{"2":{"258":1}}],["0002062297",{"2":{"256":1}}],["00020664584287765776",{"2":{"258":1}}],["00020664533",{"2":{"256":1}}],["000206055",{"2":{"244":1}}],["000206944",{"2":{"244":1}}],["00020849705",{"2":{"146":1}}],["00023398604088942988",{"2":{"258":1}}],["00023398332",{"2":{"256":1}}],["00023802626882250268",{"2":{"258":1}}],["00023802661",{"2":{"256":1}}],["000230181",{"2":{"244":1}}],["000239237",{"2":{"244":1}}],["000239130808",{"2":{"78":1}}],["0002525701222495951",{"2":{"258":1}}],["0002513967113294505",{"2":{"258":1}}],["0002513969",{"2":{"256":1}}],["0002581998517329251",{"2":{"258":1}}],["00025819617",{"2":{"256":1}}],["000250679",{"2":{"244":1}}],["000257633",{"2":{"244":1}}],["000253915",{"2":{"244":1}}],["00025326014",{"2":{"146":1}}],["0002868396494856868",{"2":{"258":1}}],["000286281",{"2":{"244":1}}],["00028729026752222437",{"2":{"258":1}}],["00028775482287253247",{"2":{"258":1}}],["000287677",{"2":{"244":1}}],["0002833453437722856",{"2":{"258":1}}],["00028334607",{"2":{"256":1}}],["0002810887685884818",{"2":{"258":1}}],["00028108715",{"2":{"256":1}}],["000288360",{"2":{"244":1}}],["000280093",{"2":{"244":1}}],["000289123",{"2":{"244":1}}],["00021228104648558522",{"2":{"258":1}}],["0002122768197366312",{"2":{"258":1}}],["00021227564",{"2":{"256":1}}],["0002199700421808594",{"2":{"258":1}}],["00021997328",{"2":{"256":1}}],["00021753645330624839",{"2":{"258":1}}],["00021753427",{"2":{"256":1}}],["00021785643895516307",{"2":{"258":1}}],["00021785761",{"2":{"256":1}}],["000217459",{"2":{"244":1}}],["00021502601437128844",{"2":{"258":1}}],["0002150255",{"2":{"256":1}}],["000215771",{"2":{"244":1}}],["00021102186769819464",{"2":{"258":1}}],["0002110241",{"2":{"256":1}}],["0002118628977327435",{"2":{"258":1}}],["00021186467",{"2":{"256":1}}],["000211123",{"2":{"244":1}}],["0002186446728800824",{"2":{"258":1}}],["0002186435",{"2":{"256":1}}],["00021899425587510813",{"2":{"258":1}}],["00021899202",{"2":{"256":1}}],["00021853374723662707",{"2":{"258":1}}],["00021853072",{"2":{"256":1}}],["000218087",{"2":{"244":1}}],["00021324839605452688",{"2":{"258":1}}],["00021324691",{"2":{"256":1}}],["00021318687129256048",{"2":{"258":1}}],["00021318468",{"2":{"256":1}}],["00021312398929900116",{"2":{"258":1}}],["00021312517",{"2":{"256":1}}],["000213564",{"2":{"244":1}}],["000213855",{"2":{"244":1}}],["000216420",{"2":{"244":1}}],["000214095",{"2":{"244":1}}],["000214067404",{"2":{"78":1}}],["00029214500403527884",{"2":{"258":1}}],["0002921465",{"2":{"256":1}}],["00029203",{"2":{"179":1}}],["000298148",{"2":{"244":1}}],["000291289",{"2":{"244":1}}],["000296087",{"2":{"244":1}}],["000410463",{"2":{"244":1}}],["000412207",{"2":{"244":1}}],["000412151",{"2":{"244":1}}],["000412629",{"2":{"244":1}}],["000454265",{"2":{"244":1}}],["000454922556",{"2":{"78":1}}],["000455096",{"2":{"244":1}}],["0004019133853071172",{"2":{"258":1}}],["00040191333",{"2":{"256":1}}],["000401171",{"2":{"244":1}}],["000405329",{"2":{"244":1}}],["000408040",{"2":{"244":1}}],["000490567",{"2":{"244":1}}],["000485339",{"2":{"244":1}}],["000489585",{"2":{"244":1}}],["000486189",{"2":{"244":1}}],["000482833",{"2":{"244":1}}],["000482373",{"2":{"244":1}}],["000484853",{"2":{"244":1}}],["000421408",{"2":{"244":1}}],["000421422",{"2":{"244":1}}],["000426714",{"2":{"244":1}}],["000426463",{"2":{"244":1}}],["000425117",{"2":{"244":1}}],["000422994",{"2":{"244":1}}],["000420685",{"2":{"244":1}}],["000461797",{"2":{"244":1}}],["000461412",{"2":{"244":1}}],["000460401",{"2":{"244":1}}],["00046014786",{"2":{"145":1}}],["000477057",{"2":{"244":1}}],["000474958",{"2":{"244":1}}],["000473843",{"2":{"244":1}}],["000435325",{"2":{"244":1}}],["000432069",{"2":{"244":1}}],["000431564",{"2":{"244":1}}],["000438132",{"2":{"77":1}}],["000449657",{"2":{"244":1}}],["000445312",{"2":{"244":1}}],["000444564",{"2":{"244":1}}],["000448536",{"2":{"244":1}}],["000447986",{"2":{"244":1}}],["000442930",{"2":{"244":1}}],["000441076729",{"2":{"78":1}}],["0006298057986045238",{"2":{"258":1}}],["0006275043556428826",{"2":{"258":1}}],["000620959",{"2":{"244":1}}],["000622923",{"2":{"244":1}}],["000624455",{"2":{"244":1}}],["000600817",{"2":{"244":1}}],["000609521",{"2":{"77":1}}],["0006785503088444641",{"2":{"258":1}}],["000678939082443919",{"2":{"258":1}}],["000673423",{"2":{"244":1}}],["000675569",{"2":{"244":1}}],["0006917778715618791",{"2":{"258":1}}],["000691815",{"2":{"244":1}}],["000694873",{"2":{"244":1}}],["000699265",{"2":{"77":1}}],["0006345405282430247",{"2":{"258":1}}],["000635906",{"2":{"244":1}}],["000637475",{"2":{"244":1}}],["000641108",{"2":{"244":1}}],["000645338",{"2":{"244":1}}],["000649345",{"2":{"244":1}}],["000640270",{"2":{"244":1}}],["000648518",{"2":{"244":1}}],["0006558525313057186",{"2":{"258":1}}],["0006537941531990138",{"2":{"258":1}}],["000652327",{"2":{"244":1}}],["000652603",{"2":{"244":1}}],["000650020",{"2":{"244":1}}],["000659882",{"2":{"244":1}}],["0006690719304301911",{"2":{"258":1}}],["000664698",{"2":{"244":1}}],["000667115",{"2":{"244":1}}],["000667028",{"2":{"77":1}}],["0006669606334663165",{"2":{"258":1}}],["000666251",{"2":{"244":1}}],["000666125",{"2":{"244":1}}],["0006100933551841793",{"2":{"258":1}}],["0006194189803236911",{"2":{"258":1}}],["000619220",{"2":{"244":1}}],["0006119800360087953",{"2":{"258":1}}],["0006189535229626955",{"2":{"258":1}}],["000618138",{"2":{"244":1}}],["000613936",{"2":{"244":1}}],["000612554",{"2":{"244":1}}],["000612726",{"2":{"77":1}}],["000687853",{"2":{"244":1}}],["000685531646908e",{"2":{"258":1}}],["0006855f",{"2":{"256":1}}],["000685339",{"2":{"244":1}}],["000685782",{"2":{"244":1}}],["000688489",{"2":{"244":1}}],["00068473816",{"2":{"145":1}}],["000689046",{"2":{"77":1}}],["000382126",{"2":{"244":1}}],["000386392",{"2":{"244":1}}],["000381213",{"2":{"244":1}}],["000389668",{"2":{"244":1}}],["000387762",{"2":{"244":1}}],["0003164608754771367",{"2":{"258":1}}],["00031629009864845084",{"2":{"258":1}}],["000310548806501568",{"2":{"258":1}}],["000310122",{"2":{"244":1}}],["000314013",{"2":{"244":1}}],["000314716",{"2":{"244":1}}],["000312205",{"2":{"244":1}}],["000317277",{"2":{"244":1}}],["000317301",{"2":{"244":1}}],["000313576",{"2":{"244":1}}],["000311768",{"2":{"244":1}}],["00036359251154835363",{"2":{"258":1}}],["000363892",{"2":{"244":1}}],["00036426097493794357",{"2":{"258":1}}],["000362759",{"2":{"244":1}}],["000367492",{"2":{"244":1}}],["000367264",{"2":{"244":1}}],["000369106",{"2":{"244":1}}],["000368751",{"2":{"244":1}}],["000366831",{"2":{"244":1}}],["000366380",{"2":{"244":1}}],["00036629336",{"2":{"78":1}}],["0003223211408476348",{"2":{"258":1}}],["000322635",{"2":{"244":1}}],["000324281",{"2":{"244":1}}],["000321921",{"2":{"244":1}}],["000326662",{"2":{"244":1}}],["000326938",{"2":{"244":1}}],["000323999",{"2":{"244":1}}],["000376061",{"2":{"244":1}}],["000379668",{"2":{"244":1}}],["000379169",{"2":{"244":1}}],["000378937",{"2":{"244":1}}],["000378884",{"2":{"244":1}}],["000374305",{"2":{"244":1}}],["000374875",{"2":{"77":1}}],["000377450",{"2":{"244":1}}],["000372513",{"2":{"244":1}}],["00035285661928918116",{"2":{"258":1}}],["0003528559",{"2":{"256":1}}],["000350503",{"2":{"244":1}}],["000350560",{"2":{"244":1}}],["000353724",{"2":{"244":1}}],["000354412",{"2":{"244":1}}],["000351864",{"2":{"244":1}}],["000359855",{"2":{"244":1}}],["0003029815590890083",{"2":{"258":1}}],["000301691",{"2":{"244":1}}],["000306839",{"2":{"244":1}}],["000306047",{"2":{"244":1}}],["000305183",{"2":{"244":1}}],["000300986",{"2":{"244":1}}],["000300984",{"2":{"244":1}}],["000308547",{"2":{"244":1}}],["000307154",{"2":{"244":2}}],["0003352144023956782",{"2":{"258":1}}],["00033521306",{"2":{"256":1}}],["000335865",{"2":{"244":1}}],["000334467",{"2":{"244":1}}],["000330688",{"2":{"244":1}}],["000330550",{"2":{"244":1}}],["000333685",{"2":{"244":1}}],["0003410561690304e",{"2":{"258":1}}],["000346362",{"2":{"244":1}}],["000348117",{"2":{"244":1}}],["000344165",{"2":{"244":1}}],["000344849",{"2":{"244":1}}],["000345872",{"2":{"244":1}}],["000347842",{"2":{"244":1}}],["000392804",{"2":{"244":1}}],["0003920444",{"2":{"77":1}}],["000395994",{"2":{"244":1}}],["000391877",{"2":{"244":1}}],["000391076",{"2":{"77":1}}],["000559556",{"2":{"244":1}}],["000554417",{"2":{"244":1}}],["000554349",{"2":{"244":1}}],["000554918",{"2":{"77":1}}],["000506370",{"2":{"244":1}}],["000503808",{"2":{"244":1}}],["000545968",{"2":{"244":1}}],["000545245",{"2":{"244":1}}],["000549527",{"2":{"244":1}}],["000540564",{"2":{"244":1}}],["000547043",{"2":{"244":1}}],["000547293",{"2":{"244":1}}],["000543516",{"2":{"244":1}}],["0005930016240738988",{"2":{"258":1}}],["00059415f",{"2":{"256":1}}],["000590442",{"2":{"244":1}}],["000595116",{"2":{"244":1}}],["000595709",{"2":{"244":1}}],["000599332",{"2":{"244":1}}],["0005922087",{"2":{"113":1}}],["00059220614",{"2":{"113":1}}],["000585735044956384",{"2":{"258":1}}],["000583868",{"2":{"244":1}}],["000583094",{"2":{"244":1}}],["000580873",{"2":{"244":1}}],["000580056",{"2":{"244":1}}],["000580705",{"2":{"77":1}}],["000525872",{"2":{"244":1}}],["000525994",{"2":{"244":1}}],["000522715",{"2":{"244":1}}],["000521560",{"2":{"244":1}}],["000512687",{"2":{"244":1}}],["000511645",{"2":{"244":1}}],["000516831",{"2":{"244":1}}],["000516864",{"2":{"244":1}}],["000510494",{"2":{"244":1}}],["000510198",{"2":{"77":1}}],["000575209",{"2":{"244":1}}],["000579479",{"2":{"244":1}}],["000577084",{"2":{"244":1}}],["000574894",{"2":{"77":1}}],["000560744",{"2":{"244":1}}],["000566683",{"2":{"244":1}}],["000561465",{"2":{"244":1}}],["000564703",{"2":{"244":1}}],["000563284",{"2":{"77":1}}],["000531920086844552",{"2":{"258":1}}],["000539345",{"2":{"244":1}}],["000530431",{"2":{"244":1}}],["000537486",{"2":{"244":1}}],["000536315",{"2":{"244":1}}],["000535839",{"2":{"244":1}}],["00053332",{"2":{"179":1}}],["0005f0",{"2":{"244":1}}],["0007601062108833979",{"2":{"258":1}}],["0007655331122073681",{"2":{"258":1}}],["0007668987434951661",{"2":{"258":1}}],["0007623020384361817",{"2":{"258":1}}],["000763064690569369",{"2":{"258":1}}],["000764329",{"2":{"244":1}}],["000726597",{"2":{"244":1}}],["000723986",{"2":{"244":1}}],["000723805",{"2":{"244":1}}],["0007118292427099427",{"2":{"258":1}}],["000710499",{"2":{"244":1}}],["000714949",{"2":{"244":1}}],["0007451075583788393",{"2":{"258":1}}],["0007406296612836417",{"2":{"258":1}}],["000740137",{"2":{"244":1}}],["000744279",{"2":{"244":1}}],["000746255",{"2":{"244":1}}],["0007800752735170239",{"2":{"258":1}}],["000780730",{"2":{"244":1}}],["000788119",{"2":{"244":1}}],["000784697",{"2":{"244":1}}],["000781053",{"2":{"244":1}}],["0007374361934195449",{"2":{"258":1}}],["000734937",{"2":{"244":1}}],["000732894",{"2":{"244":1}}],["000731462",{"2":{"77":1}}],["000792289",{"2":{"244":1}}],["000792221",{"2":{"244":1}}],["000798627",{"2":{"244":1}}],["000798481",{"2":{"244":1}}],["000798861",{"2":{"244":1}}],["000796866",{"2":{"244":1}}],["0007559035208590189",{"2":{"258":1}}],["0007597268657267519",{"2":{"258":1}}],["000756769",{"2":{"244":1}}],["000754971",{"2":{"244":1}}],["000752965",{"2":{"244":1}}],["000753467",{"2":{"244":1}}],["0007058507704826389",{"2":{"258":1}}],["000705982",{"2":{"244":1}}],["0007047920986039328",{"2":{"258":1}}],["0007031695500064645",{"2":{"257":1}}],["000709375",{"2":{"244":1}}],["000708074",{"2":{"244":1}}],["000707158",{"2":{"244":1}}],["0007726682904175011",{"2":{"258":1}}],["000778712",{"2":{"244":1}}],["000778960",{"2":{"244":1}}],["000776893",{"2":{"244":1}}],["00077649",{"2":{"77":1}}],["0007736237",{"2":{"179":1}}],["00077338",{"2":{"77":1}}],["000925605",{"2":{"244":1}}],["000924496",{"2":{"244":1}}],["000924424",{"2":{"244":1}}],["000963809",{"2":{"244":1}}],["000964463",{"2":{"244":1}}],["000944194",{"2":{"244":1}}],["000942026",{"2":{"77":1}}],["0009014060900150451",{"2":{"258":1}}],["000901216",{"2":{"244":1}}],["000907963",{"2":{"244":1}}],["000908168",{"2":{"244":1}}],["000906830",{"2":{"244":1}}],["000939374",{"2":{"244":1}}],["000938448",{"2":{"244":1}}],["000936727",{"2":{"77":1}}],["000952036",{"2":{"244":1}}],["000994050",{"2":{"244":1}}],["000992391663909964",{"2":{"53":2}}],["000972152",{"2":{"244":1}}],["000971555",{"2":{"244":1}}],["000975201",{"2":{"244":1}}],["000983244",{"2":{"244":1}}],["000987124",{"2":{"244":1}}],["000910802",{"2":{"77":1}}],["0001808081529319296",{"2":{"258":1}}],["00018083596017091005",{"2":{"258":1}}],["00018083502",{"2":{"256":1}}],["0001857728045888528",{"2":{"258":1}}],["00018577027",{"2":{"256":1}}],["00018453788574943842",{"2":{"258":1}}],["00018453944",{"2":{"256":1}}],["00018446107866088244",{"2":{"258":1}}],["00018445784",{"2":{"256":1}}],["0001894672295971893",{"2":{"258":1}}],["00018915046177849762",{"2":{"258":1}}],["00018915265",{"2":{"256":1}}],["0001896380680225474",{"2":{"258":1}}],["00018963483",{"2":{"256":1}}],["0001875596907888751",{"2":{"258":1}}],["0001875602",{"2":{"256":1}}],["00018783405818480347",{"2":{"258":1}}],["00018783257",{"2":{"256":1}}],["0001878250669456718",{"2":{"258":1}}],["00018782426",{"2":{"256":1}}],["00018290032760381962",{"2":{"258":1}}],["00018290084",{"2":{"256":1}}],["000182339",{"2":{"244":1}}],["00018630029843940332",{"2":{"258":1}}],["00018630148",{"2":{"256":1}}],["00018631458019254248",{"2":{"258":1}}],["0001863126",{"2":{"256":1}}],["000186362",{"2":{"244":1}}],["000188773670293046",{"2":{"258":1}}],["00018886184149778757",{"2":{"258":1}}],["00018885931",{"2":{"256":1}}],["00018807361701314002",{"2":{"258":1}}],["00018807476",{"2":{"256":1}}],["00018836302550319988",{"2":{"258":1}}],["00018836417",{"2":{"256":1}}],["0001836579110966653",{"2":{"258":1}}],["00018365905",{"2":{"256":1}}],["00018349985190049597",{"2":{"258":1}}],["00018349661",{"2":{"256":1}}],["00018126487184791354",{"2":{"258":1}}],["00018126491",{"2":{"256":1}}],["00018191160965620935",{"2":{"258":1}}],["00018191025",{"2":{"256":1}}],["0001470346",{"2":{"256":1}}],["0001479886705053106",{"2":{"258":1}}],["00014798867",{"2":{"256":1}}],["00014670176761210474",{"2":{"258":1}}],["0001467045",{"2":{"256":1}}],["00014613289522483094",{"2":{"258":1}}],["00014613128",{"2":{"256":1}}],["00014963759089978677",{"2":{"258":1}}],["00014963915",{"2":{"256":1}}],["00014978825428568356",{"2":{"258":1}}],["00014978845",{"2":{"256":1}}],["00014901728508984237",{"2":{"258":1}}],["00014901724",{"2":{"256":1}}],["00014347062888975663",{"2":{"258":1}}],["00014347043",{"2":{"256":1}}],["0001430022140035097",{"2":{"258":1}}],["00014300141",{"2":{"256":1}}],["00014363772124889842",{"2":{"258":1}}],["00014363631",{"2":{"256":1}}],["00014380303581491364",{"2":{"258":1}}],["00014380175",{"2":{"256":1}}],["00014221790314839118",{"2":{"258":1}}],["00014294157695580832",{"2":{"258":1}}],["00014294294",{"2":{"256":1}}],["00014271316531487365",{"2":{"258":1}}],["00014271175",{"2":{"256":1}}],["00014278427277797807",{"2":{"258":1}}],["0001427831",{"2":{"256":1}}],["0001451982247019862",{"2":{"258":1}}],["0001451994",{"2":{"256":1}}],["0001458106483786667",{"2":{"258":1}}],["00014580866",{"2":{"256":1}}],["00014114850188573898",{"2":{"258":1}}],["00014114701",{"2":{"256":1}}],["00014127795572361934",{"2":{"258":1}}],["00014127647",{"2":{"256":1}}],["00014158792791438645",{"2":{"258":1}}],["00014158712",{"2":{"256":1}}],["00014140418538267642",{"2":{"258":1}}],["00014140282",{"2":{"256":1}}],["00014189324493474678",{"2":{"258":1}}],["00014189305",{"2":{"256":1}}],["00014185687834121196",{"2":{"258":1}}],["00014185574",{"2":{"256":1}}],["00014490865705834625",{"2":{"258":1}}],["00014499773574109525",{"2":{"258":1}}],["00014499597",{"2":{"256":1}}],["00014489410813912218",{"2":{"258":1}}],["00014489138",{"2":{"256":1}}],["00014446147067062346",{"2":{"258":1}}],["00014446281",{"2":{"256":1}}],["00014417267966825424",{"2":{"258":1}}],["00014417266",{"2":{"256":1}}],["000144504",{"2":{"244":1}}],["0001404153598317011",{"2":{"258":1}}],["0001404138",{"2":{"256":1}}],["00014005942652650644",{"2":{"258":1}}],["00014005817",{"2":{"256":1}}],["0001407644831892413",{"2":{"258":1}}],["00014076312",{"2":{"256":1}}],["0001409684119112487",{"2":{"258":1}}],["00014096715",{"2":{"256":1}}],["00014092800692845208",{"2":{"258":1}}],["00014092802",{"2":{"256":1}}],["00014819514965658817",{"2":{"258":1}}],["0001481795515022614",{"2":{"258":1}}],["00014817737",{"2":{"256":1}}],["00014876642015572325",{"2":{"258":1}}],["00014876756",{"2":{"256":1}}],["0001488337285506493",{"2":{"258":1}}],["00014883529",{"2":{"256":1}}],["0001488012529500193",{"2":{"258":1}}],["00014880052",{"2":{"256":1}}],["00014834594226025125",{"2":{"258":1}}],["00014834417",{"2":{"256":1}}],["00014832810497694322",{"2":{"258":1}}],["00014832508",{"2":{"256":1}}],["000148993",{"2":{"244":1}}],["000148591",{"2":{"244":1}}],["000148517",{"2":{"244":1}}],["000148092",{"2":{"244":1}}],["0001149526606846353",{"2":{"258":1}}],["00011495117",{"2":{"256":1}}],["00011415624260246616",{"2":{"258":1}}],["00011415843",{"2":{"256":1}}],["00011464547633668842",{"2":{"258":1}}],["00011464552",{"2":{"256":1}}],["00011716449332012918",{"2":{"258":1}}],["00011716584",{"2":{"256":1}}],["000117897",{"2":{"244":1}}],["00011554073066990985",{"2":{"258":1}}],["00011553917",{"2":{"256":1}}],["00011513248383255072",{"2":{"258":1}}],["00011513229",{"2":{"256":1}}],["000115742",{"2":{"244":1}}],["00011102239",{"2":{"256":1}}],["0001116824420093857",{"2":{"258":1}}],["000111681264",{"2":{"256":1}}],["00011169085",{"2":{"256":1}}],["00011152755889004006",{"2":{"258":1}}],["00011152873",{"2":{"256":1}}],["00011150827257231838",{"2":{"258":1}}],["00011150861",{"2":{"256":1}}],["00011087438556735437",{"2":{"258":1}}],["00011087512",{"2":{"256":1}}],["00011017695424389561",{"2":{"258":1}}],["000110176996",{"2":{"256":1}}],["0001103895511510568",{"2":{"258":1}}],["00011038904",{"2":{"256":1}}],["000110352164",{"2":{"256":1}}],["00011043210291248863",{"2":{"258":1}}],["00011043076",{"2":{"256":1}}],["00011047212284005137",{"2":{"258":1}}],["000110470944",{"2":{"256":1}}],["00011379346751748679",{"2":{"258":1}}],["000113792055",{"2":{"256":1}}],["00011386213777636062",{"2":{"258":1}}],["00011386037",{"2":{"256":1}}],["00011352873634304405",{"2":{"258":1}}],["000113528695",{"2":{"256":1}}],["0001134765304370363",{"2":{"258":1}}],["000113473805",{"2":{"256":1}}],["00011349437545529134",{"2":{"258":1}}],["00011349276",{"2":{"256":1}}],["0001183475003287118",{"2":{"258":1}}],["00011835118",{"2":{"256":1}}],["00011886521815564398",{"2":{"258":1}}],["0001188636",{"2":{"256":1}}],["00011808232089585478",{"2":{"258":1}}],["00011807908",{"2":{"256":1}}],["00011916897342822298",{"2":{"258":1}}],["00011917023",{"2":{"256":1}}],["00011994591647468147",{"2":{"258":1}}],["00011994621",{"2":{"256":1}}],["0001198203454551221",{"2":{"258":1}}],["000119821285",{"2":{"256":1}}],["00011954859500940973",{"2":{"258":1}}],["00011954861",{"2":{"256":1}}],["00011612435116104449",{"2":{"258":1}}],["0001165205896688079",{"2":{"258":1}}],["00011651945",{"2":{"256":1}}],["0001166163855982284",{"2":{"258":1}}],["000116617644",{"2":{"256":1}}],["00011662117",{"2":{"256":1}}],["000116407",{"2":{"244":1}}],["00011254559713089998",{"2":{"258":1}}],["000112544185",{"2":{"256":1}}],["00011257896267100275",{"2":{"258":1}}],["00011258058",{"2":{"256":1}}],["00011204942281473427",{"2":{"258":1}}],["000112045745",{"2":{"256":1}}],["00011209536786942717",{"2":{"258":1}}],["000112096546",{"2":{"256":1}}],["00011231616388879872",{"2":{"258":1}}],["00011231499",{"2":{"256":1}}],["0001123014067158958",{"2":{"258":1}}],["00011230302",{"2":{"256":1}}],["000112325",{"2":{"244":1}}],["0001126797506002084",{"2":{"258":1}}],["00011267975",{"2":{"256":1}}],["00017131796566862998",{"2":{"258":1}}],["00017131938",{"2":{"256":1}}],["00017451975788575945",{"2":{"258":1}}],["0001745207",{"2":{"256":1}}],["00017882297184160633",{"2":{"258":1}}],["00017882141",{"2":{"256":1}}],["00017823634932780417",{"2":{"258":1}}],["00017823472",{"2":{"256":1}}],["00017567796685359055",{"2":{"258":1}}],["00017567938",{"2":{"256":1}}],["00017568215070787923",{"2":{"258":1}}],["0001756822",{"2":{"256":1}}],["00017383462605184317",{"2":{"258":1}}],["00017383661",{"2":{"256":1}}],["00017394858766238031",{"2":{"258":1}}],["00017394606",{"2":{"256":1}}],["00017396886437305597",{"2":{"258":1}}],["0001739711",{"2":{"256":1}}],["000173648",{"2":{"244":1}}],["00017699173886778834",{"2":{"258":1}}],["00017699254",{"2":{"256":1}}],["0001767271828648438",{"2":{"258":1}}],["00017672713",{"2":{"256":1}}],["000176415",{"2":{"244":1}}],["00017212704993630417",{"2":{"258":1}}],["00017212381",{"2":{"256":1}}],["0001723964976034678",{"2":{"258":1}}],["00017239648",{"2":{"256":1}}],["0001704151460019333",{"2":{"258":1}}],["00017041352",{"2":{"256":1}}],["000170466",{"2":{"244":1}}],["0001705027921873409",{"2":{"258":1}}],["00017050117",{"2":{"256":1}}],["00017056108229737688",{"2":{"258":1}}],["00017055974",{"2":{"256":1}}],["00017094639107074062",{"2":{"258":1}}],["0001709462",{"2":{"256":1}}],["000170909",{"2":{"244":1}}],["000152272582514836",{"2":{"258":1}}],["0001522711",{"2":{"256":1}}],["000152438",{"2":{"244":1}}],["00015634505311589412",{"2":{"258":1}}],["00015634432",{"2":{"256":1}}],["00015645179894330214",{"2":{"258":1}}],["00015645399",{"2":{"256":1}}],["0001567016370659357",{"2":{"258":1}}],["00015670038",{"2":{"256":1}}],["00015301452843417457",{"2":{"258":1}}],["00015301318",{"2":{"256":1}}],["00015314961888256108",{"2":{"258":1}}],["00015314738",{"2":{"256":1}}],["00015030227487425012",{"2":{"258":1}}],["00015030308",{"2":{"256":1}}],["00015080839034529197",{"2":{"258":1}}],["00015080615",{"2":{"256":1}}],["00015074402171666687",{"2":{"258":1}}],["0001507413",{"2":{"256":1}}],["00015075013636039298",{"2":{"258":1}}],["00015075131",{"2":{"256":1}}],["00015476912753538866",{"2":{"258":1}}],["00015476714",{"2":{"256":1}}],["00015428776362736243",{"2":{"258":1}}],["00015428747",{"2":{"256":1}}],["00015405477083903202",{"2":{"258":1}}],["0001540578",{"2":{"256":1}}],["0001599443881589351",{"2":{"258":1}}],["00015994276",{"2":{"256":1}}],["0001596619975043766",{"2":{"258":1}}],["00015965947",{"2":{"256":1}}],["00015956830428694228",{"2":{"258":1}}],["00015956702",{"2":{"256":1}}],["00015985763",{"2":{"256":1}}],["000159178",{"2":{"244":1}}],["00015784326688372873",{"2":{"258":1}}],["00015784599",{"2":{"256":1}}],["00015777339571309255",{"2":{"258":1}}],["00015777664",{"2":{"256":1}}],["00015733710275121706",{"2":{"258":1}}],["00015733847",{"2":{"256":1}}],["00015794244",{"2":{"256":1}}],["000155708078882868",{"2":{"258":1}}],["0001557044",{"2":{"256":1}}],["00015591537521681518",{"2":{"258":1}}],["00015591538",{"2":{"256":1}}],["000155360",{"2":{"244":1}}],["000158418922225437",{"2":{"258":1}}],["00015841947",{"2":{"256":1}}],["00015866126997585836",{"2":{"258":1}}],["00015866013",{"2":{"256":1}}],["00015823049761818606",{"2":{"258":1}}],["0001582305",{"2":{"256":1}}],["00015885850500284198",{"2":{"258":1}}],["00015886013",{"2":{"256":1}}],["000158824",{"2":{"244":1}}],["00015804220060926176",{"2":{"258":1}}],["00015804444",{"2":{"256":1}}],["000158011",{"2":{"244":1}}],["00015853766855071058",{"2":{"258":1}}],["00015853895",{"2":{"256":1}}],["00015852095670218798",{"2":{"258":1}}],["0001585242",{"2":{"256":1}}],["00015171601755514588",{"2":{"258":1}}],["00015171764",{"2":{"256":1}}],["00015125235405503577",{"2":{"258":1}}],["00015125364",{"2":{"256":1}}],["000151947",{"2":{"244":1}}],["00015113852",{"2":{"78":1}}],["00012349287369784785",{"2":{"258":1}}],["00012349125",{"2":{"256":1}}],["0001234360747694236",{"2":{"258":1}}],["00012343613",{"2":{"256":1}}],["00012118670611379568",{"2":{"258":1}}],["000121186655",{"2":{"256":1}}],["0001219988123774184",{"2":{"258":1}}],["000121999954",{"2":{"256":1}}],["00012130559544732033",{"2":{"258":1}}],["0001213054",{"2":{"256":1}}],["0001213026629998597",{"2":{"258":1}}],["000121300895",{"2":{"256":1}}],["00012170795414022059",{"2":{"258":1}}],["00012170542",{"2":{"256":1}}],["0001217353794618502",{"2":{"258":1}}],["00012173791",{"2":{"256":1}}],["00012463124305617427",{"2":{"258":1}}],["00012463176",{"2":{"256":1}}],["00012440203827985923",{"2":{"258":1}}],["00012440086",{"2":{"256":1}}],["00012488920042009213",{"2":{"258":1}}],["00012488794",{"2":{"256":1}}],["00012482319459028085",{"2":{"258":1}}],["00012482349",{"2":{"256":1}}],["000124517",{"2":{"244":1}}],["00012202420828122748",{"2":{"258":1}}],["00012202202",{"2":{"256":1}}],["00012245742605217693",{"2":{"258":1}}],["00012246045",{"2":{"256":1}}],["000122752",{"2":{"244":1}}],["00012955887295863943",{"2":{"258":1}}],["00012956029",{"2":{"256":1}}],["00012909989975738056",{"2":{"258":1}}],["00012909896",{"2":{"256":1}}],["000129240",{"2":{"244":1}}],["00012010027486086995",{"2":{"258":1}}],["00012010008",{"2":{"256":1}}],["00012084182776637331",{"2":{"258":1}}],["00012083959",{"2":{"256":1}}],["00012027687926529734",{"2":{"258":1}}],["000120279605",{"2":{"256":1}}],["000120209",{"2":{"244":1}}],["00012051352325637061",{"2":{"258":1}}],["00012051571",{"2":{"256":1}}],["00012053572576909303",{"2":{"258":1}}],["00012053447",{"2":{"256":1}}],["00012040373969018368",{"2":{"258":1}}],["00012040491",{"2":{"256":1}}],["00012046805390532141",{"2":{"258":1}}],["00012046669",{"2":{"256":1}}],["0001209456858081137",{"2":{"258":1}}],["0001209435",{"2":{"256":1}}],["00012096426448434415",{"2":{"258":1}}],["00012096228",{"2":{"256":1}}],["00012097960195391954",{"2":{"258":1}}],["00012098054",{"2":{"256":1}}],["00012843436442797423",{"2":{"258":1}}],["00012843356",{"2":{"256":1}}],["00012854390597528387",{"2":{"258":1}}],["00012854532",{"2":{"256":1}}],["00012810562177911647",{"2":{"258":1}}],["0001281093",{"2":{"256":1}}],["00012899090320893898",{"2":{"258":1}}],["00012899227",{"2":{"256":1}}],["00012837586173230223",{"2":{"258":1}}],["00012837549729740222",{"2":{"258":1}}],["0001283755",{"2":{"256":1}}],["00012837445",{"2":{"256":1}}],["00012680011723641984",{"2":{"258":1}}],["00012680284",{"2":{"256":1}}],["00012648670390523896",{"2":{"258":1}}],["00012648669",{"2":{"256":1}}],["00012602771247782337",{"2":{"258":1}}],["00012602791",{"2":{"256":1}}],["0001260364820157201",{"2":{"258":1}}],["00012603487",{"2":{"256":1}}],["000126034",{"2":{"244":1}}],["00012614081788351716",{"2":{"258":1}}],["00012614082",{"2":{"256":1}}],["00012619214",{"2":{"256":1}}],["0001261932841008933",{"2":{"258":1}}],["000126193",{"2":{"244":1}}],["0001251600404585374",{"2":{"258":1}}],["00012516121",{"2":{"256":1}}],["00012580699153153993",{"2":{"258":1}}],["00012580563",{"2":{"256":1}}],["00012554405803506647",{"2":{"258":1}}],["00012554288",{"2":{"256":1}}],["000125504",{"2":{"244":1}}],["000125214",{"2":{"244":1}}],["00012792775604919142",{"2":{"258":1}}],["00012792795",{"2":{"256":1}}],["00012773238308776916",{"2":{"258":1}}],["00012773061",{"2":{"256":1}}],["000127500",{"2":{"244":1}}],["000127040",{"2":{"244":1}}],["00019707955175439121",{"2":{"258":1}}],["00019707732",{"2":{"256":1}}],["0001949130208774972",{"2":{"258":1}}],["00019490978",{"2":{"256":1}}],["00019688376128515473",{"2":{"258":1}}],["0001968822",{"2":{"256":1}}],["00019673402018270558",{"2":{"258":1}}],["00019673149",{"2":{"256":1}}],["00019664003525500526",{"2":{"258":1}}],["00019664227",{"2":{"256":1}}],["00019581083788087008",{"2":{"258":1}}],["00019581003",{"2":{"256":1}}],["000195276",{"2":{"244":1}}],["00019904956265658853",{"2":{"258":1}}],["00019951475656018904",{"2":{"258":1}}],["00019951252",{"2":{"256":1}}],["00019920513737794275",{"2":{"258":1}}],["0001992019",{"2":{"256":1}}],["00019057139251162198",{"2":{"258":1}}],["0001905701",{"2":{"256":1}}],["0001900224125655004",{"2":{"258":1}}],["00019002314",{"2":{"256":1}}],["00019000546964540016",{"2":{"258":1}}],["00019000433",{"2":{"256":1}}],["00019256481027693886",{"2":{"258":1}}],["00019256481",{"2":{"256":1}}],["000192454",{"2":{"244":1}}],["00019121416627619492",{"2":{"258":1}}],["00019121302",{"2":{"256":1}}],["000191290",{"2":{"244":1}}],["00019179450464456877",{"2":{"258":1}}],["0001917945",{"2":{"256":1}}],["000191858",{"2":{"244":1}}],["000193357",{"2":{"244":1}}],["0001379418799237672",{"2":{"258":1}}],["00013794337",{"2":{"256":1}}],["00013727221734980522",{"2":{"258":1}}],["00013727378",{"2":{"256":1}}],["0001370050498933148",{"2":{"258":1}}],["00013700667",{"2":{"256":1}}],["0001374086051073796",{"2":{"258":1}}],["00013740954",{"2":{"256":1}}],["00013338869107729496",{"2":{"258":1}}],["00013338713",{"2":{"256":1}}],["00013350738303919544",{"2":{"258":1}}],["00013350612",{"2":{"256":1}}],["00013367596429323178",{"2":{"258":1}}],["00013367516",{"2":{"256":1}}],["00013343652180953494",{"2":{"258":1}}],["00013343793",{"2":{"256":1}}],["00013003496219733888",{"2":{"258":1}}],["00013003442",{"2":{"256":1}}],["00013046564673253685",{"2":{"258":1}}],["00013046447",{"2":{"256":1}}],["00013070163613558867",{"2":{"258":1}}],["00013070022",{"2":{"256":1}}],["00013075985485535278",{"2":{"258":1}}],["00013075661",{"2":{"256":1}}],["00013926439531860177",{"2":{"258":1}}],["00013926311",{"2":{"256":1}}],["00013964464442063195",{"2":{"258":1}}],["00013964466",{"2":{"256":1}}],["00013594893440536723",{"2":{"258":1}}],["00013548510987301847",{"2":{"258":1}}],["00013548507",{"2":{"256":1}}],["0001353020358718552",{"2":{"258":1}}],["00013530202",{"2":{"256":1}}],["00013411393144137563",{"2":{"258":1}}],["00013411244",{"2":{"256":1}}],["00013423368739006882",{"2":{"258":1}}],["00013423587",{"2":{"256":1}}],["0001346032825532413",{"2":{"258":1}}],["00013460332",{"2":{"256":1}}],["00013440107879836335",{"2":{"258":1}}],["00013440159",{"2":{"256":1}}],["00013441975689922577",{"2":{"258":1}}],["00013441942",{"2":{"256":1}}],["000134948",{"2":{"244":1}}],["00013644567",{"2":{"256":1}}],["00013670434496207865",{"2":{"258":1}}],["00013670279",{"2":{"256":1}}],["000136768",{"2":{"244":1}}],["00013689039392027894",{"2":{"258":1}}],["0001368259211361555",{"2":{"258":1}}],["00013682224",{"2":{"256":1}}],["00013688966",{"2":{"256":1}}],["00013693632350120444",{"2":{"258":1}}],["00013693758",{"2":{"256":1}}],["00013698306221478497",{"2":{"258":1}}],["00013698272",{"2":{"256":1}}],["00013183734513909863",{"2":{"258":1}}],["00013183871",{"2":{"256":1}}],["00013121",{"2":{"77":1}}],["00013218620384015446",{"2":{"258":1}}],["00013218693",{"2":{"256":1}}],["00013202513905659954",{"2":{"258":1}}],["00013202691",{"2":{"256":1}}],["000132906",{"2":{"244":1}}],["000132676",{"2":{"244":1}}],["0001386036428206891",{"2":{"258":1}}],["00013860513",{"2":{"256":1}}],["00013812434840174004",{"2":{"258":1}}],["0001381259",{"2":{"256":1}}],["00013851774701857685",{"2":{"258":1}}],["00013851613",{"2":{"256":1}}],["00013891490315598058",{"2":{"258":1}}],["0001389151",{"2":{"256":1}}],["0001389750686939419",{"2":{"258":1}}],["00013897507",{"2":{"256":1}}],["00013876694755914318",{"2":{"258":1}}],["00013876813",{"2":{"256":1}}],["00013879031114625496",{"2":{"258":1}}],["00013878937",{"2":{"256":1}}],["000138344",{"2":{"244":1}}],["000138281",{"2":{"244":1}}],["00010721222946217883",{"2":{"258":1}}],["00010721372",{"2":{"256":1}}],["00010732032423426213",{"2":{"258":1}}],["0001073215",{"2":{"256":1}}],["000107661435",{"2":{"256":1}}],["0001012360614986088",{"2":{"258":1}}],["000101237405",{"2":{"256":1}}],["00010150989688050917",{"2":{"258":1}}],["000101511156",{"2":{"256":1}}],["00010147917742093715",{"2":{"258":1}}],["000101480946",{"2":{"256":1}}],["00010231919476816056",{"2":{"258":1}}],["00010232037",{"2":{"256":1}}],["00010273569582579912",{"2":{"258":1}}],["00010273267",{"2":{"256":1}}],["0001098871899253261",{"2":{"258":1}}],["0001098857",{"2":{"256":1}}],["00010925266430604168",{"2":{"258":1}}],["00010925013",{"2":{"256":1}}],["00010946925572303252",{"2":{"258":1}}],["000109471024",{"2":{"256":1}}],["00010973300186015771",{"2":{"258":1}}],["00010973305",{"2":{"256":1}}],["00010993534715816276",{"2":{"258":1}}],["000109935296",{"2":{"256":1}}],["00010965629871498955",{"2":{"258":1}}],["00010965635",{"2":{"256":1}}],["00010916361212345545",{"2":{"258":1}}],["00010916037",{"2":{"256":1}}],["00010048912436888892",{"2":{"258":1}}],["00010048893",{"2":{"256":1}}],["0001006101422255249",{"2":{"258":1}}],["00010061703434636945",{"2":{"258":1}}],["00010061238",{"2":{"256":1}}],["00010061589",{"2":{"256":1}}],["00010083142796794092",{"2":{"258":1}}],["00010083148",{"2":{"256":1}}],["00010089095367259683",{"2":{"258":1}}],["00010089986537074956",{"2":{"258":1}}],["000100898724",{"2":{"256":1}}],["00010088954",{"2":{"256":1}}],["00010018986203897818",{"2":{"258":1}}],["00010018988",{"2":{"256":1}}],["00010013678339739477",{"2":{"258":1}}],["00010013644",{"2":{"256":1}}],["00010480915075684338",{"2":{"258":1}}],["00010481041",{"2":{"256":1}}],["00010403923961609531",{"2":{"258":1}}],["00010403922",{"2":{"256":1}}],["00010437838415968476",{"2":{"258":1}}],["00010437497",{"2":{"256":1}}],["00010437932",{"2":{"256":1}}],["00010432666022084597",{"2":{"258":1}}],["00010432666",{"2":{"256":1}}],["0001083203541869752",{"2":{"258":1}}],["00010830837167709316",{"2":{"258":1}}],["00010830701",{"2":{"256":1}}],["00010831981",{"2":{"256":1}}],["00010804031796229549",{"2":{"258":1}}],["000108040615",{"2":{"256":1}}],["000108091",{"2":{"244":1}}],["00010300965372656689",{"2":{"258":1}}],["000103008395",{"2":{"256":1}}],["00010367071994954402",{"2":{"258":1}}],["00010366936",{"2":{"256":1}}],["000103729",{"2":{"244":1}}],["00010688368502063092",{"2":{"258":1}}],["0001068853",{"2":{"256":1}}],["0001066986724909327",{"2":{"258":1}}],["00010669961",{"2":{"256":1}}],["00010622539984718038",{"2":{"258":1}}],["000106225416",{"2":{"256":1}}],["00010607316932376794",{"2":{"258":1}}],["00010607168",{"2":{"256":1}}],["00010604089829978496",{"2":{"258":1}}],["000106042826",{"2":{"256":1}}],["000106039486",{"2":{"256":1}}],["00010611540904559503",{"2":{"258":1}}],["00010611511",{"2":{"256":1}}],["000106173",{"2":{"244":1}}],["000106987",{"2":{"244":1}}],["000106323",{"2":{"244":1}}],["00010553547110531008",{"2":{"258":1}}],["00010551",{"2":{"179":1}}],["00010518199787465417",{"2":{"258":1}}],["000105181956",{"2":{"256":1}}],["00010523371055775168",{"2":{"258":1}}],["00010523489",{"2":{"256":1}}],["00010527361928688237",{"2":{"258":1}}],["00010527357",{"2":{"256":1}}],["000105296",{"2":{"77":1}}],["000105879",{"2":{"244":1}}],["000105440",{"2":{"244":1}}],["00010546855",{"2":{"179":1}}],["00016460367875694885",{"2":{"258":1}}],["00016460502",{"2":{"256":1}}],["00016409756248726888",{"2":{"258":1}}],["0001640962",{"2":{"256":1}}],["000164069",{"2":{"244":1}}],["00016907019128666848",{"2":{"258":1}}],["00016907272",{"2":{"256":1}}],["00016939627506129852",{"2":{"258":1}}],["00016939598",{"2":{"256":1}}],["00016715774173337443",{"2":{"258":1}}],["00016715754",{"2":{"256":1}}],["00016787690513411888",{"2":{"258":1}}],["00016787944",{"2":{"256":1}}],["000167605052819033",{"2":{"258":1}}],["00016760328",{"2":{"256":1}}],["00016751327939321407",{"2":{"258":1}}],["0001675149",{"2":{"256":1}}],["00016839187238794638",{"2":{"258":1}}],["00016839153",{"2":{"256":1}}],["00016875701052950528",{"2":{"258":1}}],["00016875502",{"2":{"256":1}}],["00016878",{"2":{"179":1}}],["00016270945045985903",{"2":{"258":1}}],["00016271313",{"2":{"256":1}}],["00016215534042576774",{"2":{"258":1}}],["00016215538",{"2":{"256":1}}],["000162085",{"2":{"244":1}}],["000162970",{"2":{"244":1}}],["00016650287957765261",{"2":{"258":1}}],["00016650361",{"2":{"256":1}}],["00016632921699478355",{"2":{"258":1}}],["0001663314",{"2":{"256":1}}],["0001669987949387632",{"2":{"258":1}}],["00016699555",{"2":{"256":1}}],["000166804",{"2":{"244":1}}],["000166462",{"2":{"244":1}}],["000161607",{"2":{"244":1}}],["000161545",{"2":{"244":1}}],["00016038087856332518",{"2":{"258":1}}],["00016037932",{"2":{"256":1}}],["00016029613555288032",{"2":{"258":1}}],["0001602952",{"2":{"256":1}}],["000160591",{"2":{"244":1}}],["000160725",{"2":{"244":1}}],["00016370910928528192",{"2":{"258":1}}],["00016370777",{"2":{"256":1}}],["00016382765105970868",{"2":{"258":1}}],["00016382785",{"2":{"256":1}}],["000163823",{"2":{"244":1}}],["000163182",{"2":{"244":1}}],["00016539799701918752",{"2":{"258":1}}],["00016539948",{"2":{"256":1}}],["0001655896404118224",{"2":{"258":1}}],["00016559058",{"2":{"256":1}}],["0001650614655355806",{"2":{"258":1}}],["00016506345",{"2":{"256":1}}],["000165069",{"2":{"244":1}}],["000165743",{"2":{"244":1}}],["000165657",{"2":{"77":1}}],["0001",{"2":{"77":7,"78":1}}],["0001f0",{"2":{"77":1}}],["013499700",{"2":{"244":1}}],["01343",{"2":{"187":2}}],["013011228",{"2":{"244":1}}],["01335",{"2":{"187":1}}],["01337",{"2":{"187":1}}],["01311",{"2":{"187":1}}],["01317",{"2":{"187":1}}],["01313",{"2":{"187":1}}],["01359",{"2":{"187":1}}],["01355",{"2":{"187":1}}],["0138933f",{"2":{"256":1}}],["01381",{"2":{"187":1}}],["01388",{"2":{"187":1}}],["01377",{"2":{"187":1}}],["01366",{"2":{"187":1}}],["01361",{"2":{"187":1}}],["01360056680392e",{"2":{"258":1}}],["01360",{"2":{"187":1}}],["01364",{"2":{"187":1}}],["01390",{"2":{"187":1}}],["01395",{"2":{"187":1}}],["01398",{"2":{"187":1}}],["013992591",{"2":{"113":1}}],["013992601",{"2":{"113":1}}],["017799046",{"2":{"244":1}}],["017750096",{"2":{"244":1}}],["01777",{"2":{"187":1}}],["017215939",{"2":{"244":1}}],["0172s\\ttraining",{"2":{"210":1}}],["017197266",{"2":{"244":1}}],["0171745",{"2":{"168":1}}],["017614847",{"2":{"244":1}}],["017605182",{"2":{"244":1}}],["017645847",{"2":{"244":1}}],["01763",{"2":{"187":1}}],["01730",{"2":{"187":1}}],["01782",{"2":{"187":1}}],["01747",{"2":{"187":1}}],["01745",{"2":{"187":1}}],["01740",{"2":{"187":1}}],["017432783",{"2":{"113":2}}],["01796",{"2":{"187":1}}],["01795",{"2":{"187":1}}],["01752",{"2":{"187":1}}],["016228525",{"2":{"244":1}}],["01627",{"2":{"187":1}}],["016118063",{"2":{"244":1}}],["016490150",{"2":{"244":1}}],["01642",{"2":{"187":1}}],["01647",{"2":{"187":1}}],["016479947",{"2":{"113":2}}],["01653",{"2":{"187":1}}],["01656",{"2":{"187":1}}],["016987354",{"2":{"244":1}}],["01693",{"2":{"187":1}}],["01691",{"2":{"187":1}}],["01696",{"2":{"187":1}}],["01608",{"2":{"187":1}}],["0163",{"2":{"249":1}}],["01631",{"2":{"187":1}}],["016386209",{"2":{"244":1}}],["01638",{"2":{"187":1}}],["01639",{"2":{"187":1}}],["01630",{"2":{"187":1}}],["01636",{"2":{"187":1}}],["0168695",{"2":{"145":1}}],["01f0",{"2":{"145":1,"146":1,"179":2,"187":1}}],["019427970",{"2":{"244":1}}],["019484218",{"2":{"244":1}}],["019155467",{"2":{"244":1}}],["01911576",{"2":{"113":1}}],["019115759",{"2":{"113":1}}],["019567011",{"2":{"244":1}}],["01953",{"2":{"187":1}}],["019859709",{"2":{"244":1}}],["01987s\\ttraining",{"2":{"236":1}}],["01988",{"2":{"187":1}}],["0193",{"2":{"249":1}}],["01937",{"2":{"187":1}}],["019325165",{"2":{"244":1}}],["01932",{"2":{"187":1}}],["01976",{"2":{"187":1}}],["019791335",{"2":{"113":1}}],["019791333",{"2":{"113":1}}],["01900",{"2":{"187":1}}],["01963",{"2":{"187":1}}],["01965834",{"2":{"129":1}}],["019236464",{"2":{"77":1}}],["018483378",{"2":{"244":1}}],["0189805",{"2":{"224":1}}],["018008159",{"2":{"244":1}}],["018073166",{"2":{"244":1}}],["01802",{"2":{"187":1}}],["01809",{"2":{"187":1}}],["01868",{"2":{"187":1}}],["01866",{"2":{"187":1}}],["01821",{"2":{"187":1}}],["01826",{"2":{"187":1}}],["01824",{"2":{"187":2}}],["01810",{"2":{"187":1}}],["018884756",{"2":{"113":1}}],["018884761",{"2":{"113":1}}],["018338893",{"2":{"113":1}}],["018338889",{"2":{"113":1}}],["018706074",{"2":{"244":1}}],["018701272",{"2":{"77":1}}],["018723227",{"2":{"244":1}}],["01872",{"2":{"187":1}}],["01872db4",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["018743665453639813",{"2":{"174":1}}],["0187668",{"2":{"113":1}}],["015280124",{"2":{"244":1}}],["015216017",{"2":{"244":1}}],["01520",{"2":{"187":1}}],["01523",{"2":{"187":1}}],["01501",{"2":{"187":1}}],["01504",{"2":{"187":1}}],["01511",{"2":{"187":1}}],["015340659",{"2":{"244":1}}],["01530",{"2":{"187":1}}],["01537",{"2":{"187":1}}],["015478307",{"2":{"227":1}}],["015494239",{"2":{"244":1}}],["01549",{"2":{"187":1}}],["01542492",{"2":{"114":1}}],["015748031",{"2":{"224":2}}],["01570",{"2":{"187":1}}],["01578",{"2":{"187":1}}],["01579",{"2":{"187":2}}],["015937408",{"2":{"129":1,"132":1}}],["0155126",{"2":{"113":1}}],["0158726",{"2":{"77":1}}],["010755754",{"2":{"244":1}}],["01071",{"2":{"187":1}}],["010920972",{"2":{"244":1}}],["010936455",{"2":{"244":1}}],["01098",{"2":{"187":1}}],["010452257",{"2":{"244":1}}],["010404",{"2":{"145":1}}],["010336538",{"2":{"244":1}}],["01033",{"2":{"187":2}}],["01031",{"2":{"187":1}}],["01021",{"2":{"187":1}}],["0102189295",{"2":{"113":1}}],["010218928",{"2":{"113":1}}],["01026",{"2":{"187":2}}],["010004668",{"2":{"244":1}}],["01006",{"2":{"187":1}}],["01005",{"2":{"187":1}}],["01002",{"2":{"187":1}}],["01009",{"2":{"187":1}}],["0100971125",{"2":{"77":1}}],["010518193",{"2":{"244":1}}],["010586374",{"2":{"244":1}}],["01058",{"2":{"187":1}}],["01053",{"2":{"187":1}}],["0105465",{"2":{"77":1}}],["010629211",{"2":{"244":1}}],["01068",{"2":{"187":1}}],["01060",{"2":{"187":2}}],["010637204",{"2":{"113":1}}],["010637202",{"2":{"113":1}}],["0108138f",{"2":{"256":1}}],["010898398",{"2":{"244":1}}],["010876314",{"2":{"244":1}}],["01082",{"2":{"187":1}}],["0108668577150213",{"2":{"171":1}}],["0101",{"2":{"78":1}}],["01273",{"2":{"187":1}}],["012775686",{"2":{"244":1}}],["01277",{"2":{"187":1}}],["0122",{"2":{"249":1}}],["01229",{"2":{"187":1}}],["01227",{"2":{"187":1}}],["01286",{"2":{"187":2}}],["012002973",{"2":{"244":1}}],["01200",{"2":{"187":1}}],["012323526",{"2":{"244":1}}],["01238",{"2":{"187":1}}],["0123139",{"2":{"77":1}}],["012140292",{"2":{"244":1}}],["01212",{"2":{"187":1}}],["01211",{"2":{"187":1}}],["012183795",{"2":{"113":1}}],["012183794",{"2":{"113":1}}],["01294",{"2":{"187":1}}],["01293",{"2":{"187":1}}],["01297",{"2":{"187":1}}],["01292",{"2":{"187":1}}],["0129954im",{"2":{"168":1}}],["012508835",{"2":{"244":1}}],["01259",{"2":{"187":1}}],["01253",{"2":{"187":1}}],["012522168",{"2":{"77":1}}],["014400685",{"2":{"244":1}}],["014530762",{"2":{"244":1}}],["014555071",{"2":{"244":1}}],["014340003",{"2":{"244":1}}],["014307282",{"2":{"244":1}}],["01431",{"2":{"187":1}}],["014708381",{"2":{"244":1}}],["01471",{"2":{"187":1}}],["014021916211703e",{"2":{"258":1}}],["014098606",{"2":{"244":1}}],["01404",{"2":{"187":1}}],["01405",{"2":{"187":1}}],["0149",{"2":{"249":1}}],["01493",{"2":{"187":1}}],["01496",{"2":{"187":2}}],["014815190",{"2":{"244":1}}],["01481",{"2":{"187":1}}],["01489",{"2":{"187":1}}],["014877922",{"2":{"113":1}}],["014241929",{"2":{"244":1}}],["014243508",{"2":{"244":1}}],["01423",{"2":{"187":1}}],["01425",{"2":{"187":1}}],["0142814",{"2":{"77":1}}],["01468",{"2":{"187":1}}],["0146587",{"2":{"77":1}}],["01416",{"2":{"187":1}}],["01415047",{"2":{"113":1}}],["014150472",{"2":{"113":1}}],["014100174",{"2":{"77":1}}],["011457845",{"2":{"244":1}}],["011284535",{"2":{"244":1}}],["01129",{"2":{"187":1}}],["01120",{"2":{"187":1}}],["011247103",{"2":{"244":1}}],["01124",{"2":{"187":2}}],["011505678",{"2":{"244":1}}],["01155",{"2":{"187":1}}],["011598296",{"2":{"244":1}}],["01159",{"2":{"187":2}}],["011037273",{"2":{"244":1}}],["011087346",{"2":{"244":1}}],["011062279",{"2":{"244":1}}],["011073254",{"2":{"244":1}}],["01104",{"2":{"187":1}}],["01102",{"2":{"187":2}}],["01186",{"2":{"187":1}}],["01183",{"2":{"187":1}}],["01111",{"2":{"187":1}}],["01112",{"2":{"187":2}}],["011100831f0",{"2":{"53":1}}],["011374202",{"2":{"244":1}}],["011342090",{"2":{"244":1}}],["01134",{"2":{"187":1}}],["01130",{"2":{"187":2}}],["01138",{"2":{"187":1}}],["011915382",{"2":{"244":1}}],["01191",{"2":{"187":1}}],["011906523",{"2":{"244":1}}],["01190",{"2":{"187":1}}],["01194",{"2":{"187":3}}],["011937321",{"2":{"179":1}}],["011611394",{"2":{"113":1}}],["011611392",{"2":{"113":1}}],["011734666",{"2":{"77":1}}],["011739168",{"2":{"77":1}}],["01",{"2":{"24":3,"53":2,"179":1,"219":4,"258":1}}],["0",{"2":{"2":1,"4":1,"7":3,"11":1,"19":3,"24":44,"34":2,"49":2,"53":122,"54":4,"59":16,"62":3,"64":3,"67":2,"68":10,"69":1,"74":1,"77":204,"78":14,"109":1,"110":1,"112":2,"113":292,"114":11,"119":1,"125":5,"126":37,"129":54,"132":25,"140":6,"141":1,"142":7,"145":18,"146":5,"147":35,"148":23,"152":7,"153":358,"155":1,"168":57,"170":1,"171":155,"172":15,"173":3,"174":62,"176":12,"177":9,"178":4,"179":72,"180":11,"183":1,"186":1,"187":452,"189":11,"192":1,"193":2,"194":2,"195":7,"197":3,"206":1,"207":2,"208":1,"209":2,"210":26,"211":1,"212":8,"213":19,"214":11,"217":4,"219":2,"221":11,"224":139,"225":1,"226":4,"227":40,"228":11,"229":11,"232":2,"235":2,"236":105,"237":11,"243":7,"244":800,"245":6,"246":11,"248":4,"249":65,"251":3,"254":4,"255":9,"256":489,"257":1,"258":409,"260":3}}],["1e",{"2":{"219":1,"254":1}}],["1g",{"2":{"180":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["1×16",{"2":{"147":1,"148":1}}],["1×32",{"2":{"59":1,"78":1}}],["1`",{"2":{"141":3}}],["1st",{"2":{"130":1}}],["11414934993136e",{"2":{"258":1}}],["1143",{"2":{"249":1}}],["114975",{"2":{"147":1}}],["11501",{"2":{"244":1}}],["115",{"2":{"196":1}}],["11515346",{"2":{"113":1}}],["11515345",{"2":{"113":1}}],["11001",{"2":{"244":1}}],["11007148",{"2":{"224":1}}],["11023622",{"2":{"224":2}}],["11023762",{"2":{"179":1}}],["110",{"2":{"213":6}}],["11054",{"2":{"187":1}}],["11111",{"2":{"212":1}}],["11153",{"2":{"187":1}}],["111552626",{"2":{"113":1}}],["11182",{"2":{"187":1}}],["119",{"2":{"210":1}}],["11923",{"2":{"187":1}}],["11984776",{"2":{"77":1}}],["1166653290328563e",{"2":{"258":1}}],["11621",{"2":{"187":1}}],["11688",{"2":{"187":1}}],["116989",{"2":{"171":1}}],["116796836",{"2":{"113":1}}],["118262501665159e",{"2":{"258":1}}],["118064f",{"2":{"256":1}}],["1181102",{"2":{"224":2}}],["118",{"2":{"196":1}}],["11895",{"2":{"187":1}}],["1188200246206075",{"2":{"153":2}}],["1187928",{"2":{"113":2}}],["112679698301585e",{"2":{"258":1}}],["112685f",{"2":{"256":1}}],["1126356",{"2":{"148":1}}],["1121",{"2":{"249":1}}],["112",{"2":{"196":3}}],["11270",{"2":{"187":1}}],["1124609",{"2":{"113":1}}],["113931f",{"2":{"256":1}}],["113",{"2":{"196":2}}],["11300",{"2":{"187":1}}],["1137304",{"2":{"147":1}}],["11365668",{"2":{"113":2}}],["117236",{"2":{"224":1}}],["117264e",{"2":{"219":1}}],["11755",{"2":{"187":1}}],["1175871f",{"2":{"113":1}}],["1173706",{"2":{"147":1}}],["11",{"2":{"145":2,"146":2,"147":2,"148":1,"180":2,"187":14,"189":2,"196":1,"214":2,"221":2,"228":1,"229":2,"236":3,"237":2,"246":2,"249":3,"258":3}}],["146655873584421e",{"2":{"258":1}}],["14669",{"2":{"187":1}}],["1465417f",{"2":{"256":1}}],["1406",{"2":{"249":2}}],["1405",{"2":{"249":1}}],["14001",{"2":{"244":1}}],["149736059138837e",{"2":{"258":1}}],["1490583665283875e",{"2":{"258":1}}],["1490868",{"2":{"227":1}}],["149483f",{"2":{"256":1}}],["14941669",{"2":{"77":1}}],["149139f",{"2":{"256":1}}],["1496063",{"2":{"224":2}}],["147919181698136e",{"2":{"258":1}}],["1478852f",{"2":{"256":1}}],["14785",{"2":{"187":1}}],["147705370924899",{"2":{"153":1}}],["1477053709248992",{"2":{"153":1}}],["1439",{"2":{"249":1}}],["1437841",{"2":{"179":1}}],["14340512",{"2":{"114":1}}],["14528002394406e",{"2":{"258":1}}],["145296",{"2":{"168":1}}],["145139f",{"2":{"256":1}}],["1458",{"2":{"249":1}}],["14501",{"2":{"244":1}}],["14568081",{"2":{"113":1}}],["1426558477441617e",{"2":{"258":1}}],["1426142f",{"2":{"256":1}}],["142819044402994e",{"2":{"258":1}}],["1420208011508104e",{"2":{"258":1}}],["142981f",{"2":{"256":1}}],["1423416531041828e",{"2":{"258":1}}],["14234",{"2":{"187":1}}],["142470881033475",{"2":{"153":2}}],["142251",{"2":{"113":1}}],["14815",{"2":{"210":2}}],["14825",{"2":{"171":1}}],["148248",{"2":{"171":2}}],["1489007",{"2":{"147":1}}],["1488175",{"2":{"111":1}}],["14",{"2":{"145":1,"187":14,"210":2,"236":2,"249":7}}],["1442137f",{"2":{"256":1}}],["14466",{"2":{"187":1}}],["14445141",{"2":{"113":1}}],["14488737",{"2":{"113":1}}],["141612458391299e",{"2":{"258":1}}],["1413424046492117e",{"2":{"258":1}}],["14132261",{"2":{"224":1}}],["141721667508057e",{"2":{"258":1}}],["1417763f",{"2":{"256":1}}],["1417101f",{"2":{"256":1}}],["14173229",{"2":{"224":2}}],["1418591f",{"2":{"256":1}}],["14118214",{"2":{"113":1}}],["1415927",{"2":{"53":1}}],["1721462346857146e",{"2":{"258":1}}],["1725780621542454e",{"2":{"258":1}}],["1728937f",{"2":{"256":1}}],["1728017f",{"2":{"256":1}}],["172005f",{"2":{"256":1}}],["172325e",{"2":{"148":1}}],["17239982",{"2":{"77":1}}],["1731468165602006e",{"2":{"258":1}}],["173432254475044e",{"2":{"258":1}}],["1734364f",{"2":{"256":1}}],["17322835",{"2":{"224":2}}],["17928976351775e",{"2":{"258":1}}],["1792914f",{"2":{"256":1}}],["1791",{"2":{"249":1}}],["179584495291061",{"2":{"153":2}}],["175704440602927e",{"2":{"258":1}}],["175707im",{"2":{"168":1}}],["17501",{"2":{"244":1}}],["1715955501843653e",{"2":{"258":1}}],["171135321317918e",{"2":{"258":1}}],["171165f",{"2":{"256":1}}],["17111921",{"2":{"227":1}}],["17173",{"2":{"187":1}}],["1783483755736966e",{"2":{"258":1}}],["17816184",{"2":{"224":1}}],["17815",{"2":{"187":1}}],["17875",{"2":{"187":1}}],["17706361",{"2":{"179":1}}],["1709697858707859e",{"2":{"258":1}}],["1709151f",{"2":{"256":1}}],["170203105380961e",{"2":{"258":1}}],["170262566357397e",{"2":{"258":1}}],["170506816511903e",{"2":{"258":1}}],["1700772f",{"2":{"256":1}}],["17001",{"2":{"244":1}}],["17046632099662e",{"2":{"258":1}}],["1704367f",{"2":{"256":1}}],["170480160349125e",{"2":{"258":1}}],["1704818f",{"2":{"256":1}}],["17048413",{"2":{"113":1}}],["1706837f",{"2":{"256":1}}],["1706",{"2":{"249":1}}],["170",{"2":{"237":1}}],["170342",{"2":{"171":1}}],["176080159640047e",{"2":{"258":1}}],["176085f",{"2":{"256":1}}],["176196f",{"2":{"256":1}}],["1769334916453e",{"2":{"258":1}}],["176932f",{"2":{"256":1}}],["1769385",{"2":{"147":1}}],["1763",{"2":{"249":1}}],["176",{"2":{"219":1}}],["1764085",{"2":{"129":1}}],["17",{"2":{"126":1,"148":1,"187":14,"196":9,"225":1,"236":2,"249":4,"258":14}}],["1742546820506443e",{"2":{"258":1}}],["1740796f",{"2":{"256":1}}],["1741783f",{"2":{"256":1}}],["174312648890671e",{"2":{"258":1}}],["1743093f",{"2":{"256":1}}],["17435724",{"2":{"113":2}}],["1746446304759924e",{"2":{"258":1}}],["1746462f",{"2":{"256":1}}],["1746128",{"2":{"77":1}}],["17441",{"2":{"171":1}}],["17449912",{"2":{"77":1}}],["1th",{"2":{"69":3}}],["136413540088819e",{"2":{"258":1}}],["1363404f",{"2":{"256":1}}],["136356",{"2":{"168":1}}],["132216454980387e",{"2":{"258":1}}],["1322895285109382e",{"2":{"258":1}}],["1325188f",{"2":{"256":1}}],["13475561",{"2":{"224":1}}],["13401",{"2":{"187":1}}],["13",{"2":{"187":14,"210":4,"213":3,"236":5,"249":3}}],["130487270450853e",{"2":{"258":1}}],["130636f",{"2":{"256":1}}],["1306755",{"2":{"148":1}}],["1303",{"2":{"249":1}}],["13001",{"2":{"244":1}}],["13073668",{"2":{"179":1}}],["1302",{"2":{"68":1}}],["13819042",{"2":{"129":1}}],["13864",{"2":{"113":1}}],["13725637",{"2":{"113":1}}],["13725635",{"2":{"113":1}}],["13760868",{"2":{"113":1}}],["13760866",{"2":{"113":1}}],["1377298",{"2":{"113":2}}],["135817e",{"2":{"219":1}}],["13525",{"2":{"187":1}}],["13559",{"2":{"171":1}}],["13501",{"2":{"244":1}}],["1350521",{"2":{"147":1}}],["13504265",{"2":{"113":1}}],["13518013",{"2":{"113":1}}],["13518015",{"2":{"113":1}}],["1390080646152605e",{"2":{"258":1}}],["139398455737204e",{"2":{"258":1}}],["13936",{"2":{"187":1}}],["139766f",{"2":{"256":1}}],["1395766",{"2":{"224":1}}],["139433",{"2":{"148":1}}],["13913931",{"2":{"113":1}}],["13988f",{"2":{"77":1}}],["13343152",{"2":{"113":1}}],["1311886442520993e",{"2":{"258":1}}],["131134f",{"2":{"256":1}}],["1310",{"2":{"249":1}}],["131664",{"2":{"168":1}}],["13168f",{"2":{"77":1}}],["131726",{"2":{"147":1,"148":1}}],["131583631",{"2":{"78":1}}],["13121",{"2":{"187":1}}],["1312",{"2":{"24":1}}],["1c",{"2":{"66":1}}],["1b",{"2":{"66":3}}],["1a",{"2":{"66":3}}],["189516048298042e",{"2":{"258":1}}],["1897146f",{"2":{"256":1}}],["18941",{"2":{"168":1}}],["185245524192443e",{"2":{"258":1}}],["185083f",{"2":{"256":1}}],["18501",{"2":{"244":1}}],["18535946",{"2":{"227":1}}],["18564",{"2":{"224":1}}],["1851469807664616e",{"2":{"258":1}}],["18519",{"2":{"210":2}}],["185124",{"2":{"147":1}}],["182772560002377e",{"2":{"258":1}}],["1826584f",{"2":{"256":1}}],["1828",{"2":{"249":1}}],["1828456",{"2":{"224":1}}],["18294",{"2":{"187":1}}],["1846",{"2":{"249":1}}],["1846486482317626",{"2":{"153":2}}],["1848228f",{"2":{"256":1}}],["18481395",{"2":{"227":1}}],["18488",{"2":{"187":1}}],["18414",{"2":{"187":1}}],["18001",{"2":{"244":1}}],["18056087",{"2":{"179":1}}],["18089005",{"2":{"113":1}}],["1872151894090286e",{"2":{"258":1}}],["1871622",{"2":{"176":4}}],["18794",{"2":{"168":1}}],["187646",{"2":{"168":1}}],["1863119136768887e",{"2":{"258":1}}],["186",{"2":{"256":1}}],["18695377",{"2":{"179":1}}],["18652338",{"2":{"148":1}}],["186451",{"2":{"148":1}}],["1832",{"2":{"249":1}}],["18387",{"2":{"187":1}}],["18347",{"2":{"187":1}}],["18365",{"2":{"168":1}}],["1836515766351254",{"2":{"153":2}}],["183307",{"2":{"147":1}}],["18308182",{"2":{"129":1}}],["1880202f",{"2":{"256":1}}],["18807876",{"2":{"113":2}}],["1887817",{"2":{"224":1}}],["18841726",{"2":{"179":1}}],["18860114",{"2":{"129":1}}],["18811704",{"2":{"77":1}}],["1811024",{"2":{"224":2}}],["18102339",{"2":{"77":1}}],["181208",{"2":{"77":1}}],["18",{"2":{"59":1,"187":14,"196":1,"236":2,"249":5,"258":9}}],["1−z",{"2":{"66":1}}],["1−2∑yy^+α∑y2+∑y^2+α",{"2":{"53":1}}],["1−α",{"2":{"53":2}}],["1−y",{"2":{"53":1}}],["1−yy^",{"2":{"53":2}}],["1−y^+ϵ",{"2":{"53":1}}],["1−y~",{"2":{"53":2}}],["1630862076952195e",{"2":{"258":1}}],["16673f",{"2":{"256":1}}],["168424f",{"2":{"256":1}}],["1652",{"2":{"249":1}}],["16501",{"2":{"244":1}}],["16566901",{"2":{"145":1}}],["1629923f",{"2":{"256":1}}],["16241",{"2":{"213":12}}],["16240",{"2":{"213":12}}],["16251",{"2":{"187":1}}],["1615366175426974e",{"2":{"258":1}}],["16143133890716e",{"2":{"258":1}}],["161465f",{"2":{"256":1}}],["1618821547760237e",{"2":{"258":1}}],["16187939",{"2":{"113":1}}],["1613598f",{"2":{"256":1}}],["1617228180412864",{"2":{"153":2}}],["164670697888798e",{"2":{"258":1}}],["164675f",{"2":{"256":1}}],["16464",{"2":{"187":1}}],["16450",{"2":{"213":6}}],["16418",{"2":{"187":1}}],["1641532f",{"2":{"113":1}}],["164786",{"2":{"171":1}}],["164379",{"2":{"168":1}}],["1642133",{"2":{"147":1}}],["16407",{"2":{"113":1}}],["16409892",{"2":{"113":1}}],["1698948f",{"2":{"256":1}}],["16946f",{"2":{"77":1}}],["16909766",{"2":{"77":1}}],["16001",{"2":{"244":1}}],["160876",{"2":{"168":1}}],["16083185f0",{"2":{"53":1}}],["160832f0",{"2":{"53":1}}],["16094846",{"2":{"145":1}}],["1607",{"2":{"19":2,"69":1}}],["16",{"2":{"39":1,"59":3,"109":1,"125":13,"126":14,"147":1,"148":1,"171":1,"187":14,"189":2,"193":3,"225":4,"228":2,"236":4,"243":1,"244":8,"249":4,"251":4,"258":7,"260":4}}],["104083861456283e",{"2":{"258":1}}],["10458f",{"2":{"77":1}}],["10f",{"2":{"257":1}}],["10330341896618e",{"2":{"258":1}}],["10334256722243e",{"2":{"258":1}}],["1038278f",{"2":{"256":1}}],["1030503f",{"2":{"256":1}}],["103716f",{"2":{"256":1}}],["103541f",{"2":{"256":1}}],["1032465",{"2":{"113":1}}],["10160033287437e",{"2":{"258":1}}],["101596f",{"2":{"256":1}}],["101",{"2":{"213":6,"219":1,"228":1}}],["10140238162746013",{"2":{"153":2}}],["10862370290679e",{"2":{"258":1}}],["108145",{"2":{"224":1}}],["108",{"2":{"196":1}}],["10806",{"2":{"187":1}}],["105156f",{"2":{"256":1}}],["1050467878194525e",{"2":{"258":1}}],["105098f",{"2":{"256":1}}],["10501",{"2":{"244":1}}],["1058",{"2":{"249":1}}],["10579",{"2":{"187":1}}],["10552457",{"2":{"113":1}}],["105524555",{"2":{"113":1}}],["1072311825316805e",{"2":{"258":1}}],["107114242346946e",{"2":{"258":1}}],["107852242813476e",{"2":{"258":1}}],["107888",{"2":{"224":1}}],["1073043f",{"2":{"256":1}}],["107f",{"2":{"256":1}}],["1079664f",{"2":{"256":1}}],["1079326",{"2":{"147":1}}],["10754459",{"2":{"113":1}}],["1028568257729236e",{"2":{"258":1}}],["1025545f",{"2":{"256":1}}],["102430617361763e",{"2":{"258":1}}],["1024",{"2":{"153":7}}],["102",{"2":{"125":1}}],["109614687845041e",{"2":{"258":1}}],["1094975f",{"2":{"256":1}}],["109576075079418e",{"2":{"258":1}}],["109525f",{"2":{"256":1}}],["1095082",{"2":{"113":1}}],["10950818",{"2":{"113":1}}],["1090526f",{"2":{"256":1}}],["1090",{"2":{"254":2}}],["10917f",{"2":{"256":1}}],["1091",{"2":{"249":1}}],["109215117091378e",{"2":{"258":1}}],["109261915",{"2":{"129":1}}],["109203495",{"2":{"113":1}}],["106",{"2":{"196":2}}],["106069",{"2":{"145":1}}],["10688411",{"2":{"113":1}}],["106884085",{"2":{"113":1}}],["1069",{"2":{"113":1}}],["10",{"2":{"34":2,"39":2,"49":1,"62":1,"69":12,"74":2,"76":1,"77":5,"78":1,"111":2,"112":1,"113":5,"145":2,"146":2,"148":2,"171":4,"174":2,"179":3,"180":5,"187":14,"189":5,"193":5,"195":1,"196":22,"197":2,"208":5,"210":1,"213":30,"214":5,"221":5,"229":5,"234":1,"236":2,"237":5,"246":5,"249":4,"250":1,"251":2,"254":2,"258":8,"260":2}}],["10052323654917e",{"2":{"258":1}}],["1009142367080704e",{"2":{"258":1}}],["1007763f",{"2":{"256":1}}],["100778f",{"2":{"256":1}}],["10077",{"2":{"187":1}}],["1001",{"2":{"179":1,"244":1}}],["1003911",{"2":{"142":1}}],["10001",{"2":{"244":1}}],["10000",{"2":{"179":2,"244":1}}],["1000",{"2":{"59":1,"78":3,"114":14,"179":1}}],["100",{"2":{"24":1,"49":2,"63":6,"78":1,"114":2,"180":2,"189":2,"195":2,"197":1,"210":2,"213":6,"214":2,"221":2,"229":2,"236":34,"237":2,"246":2,"251":1,"255":2,"260":1}}],["121142395241432e",{"2":{"258":1}}],["121437638982065e",{"2":{"258":1}}],["121483363343764e",{"2":{"258":1}}],["121403f",{"2":{"256":1}}],["121903193452253e",{"2":{"258":1}}],["121937f",{"2":{"256":1}}],["121518f",{"2":{"256":1}}],["12s",{"2":{"236":2}}],["12001",{"2":{"244":1}}],["12096125",{"2":{"227":1}}],["1204217935313214",{"2":{"153":2}}],["1265",{"2":{"249":1}}],["126",{"2":{"219":1}}],["12679",{"2":{"187":1}}],["12610",{"2":{"187":1}}],["1261990389976131",{"2":{"174":1}}],["12abac4f24f6",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["12501",{"2":{"244":1}}],["12589",{"2":{"179":1}}],["12556516",{"2":{"113":2}}],["124753790103359e",{"2":{"258":1}}],["12477568",{"2":{"179":1}}],["124871f",{"2":{"256":1}}],["12442",{"2":{"168":1}}],["1245008",{"2":{"147":1}}],["12902719",{"2":{"113":2}}],["1293236",{"2":{"113":1}}],["12992674",{"2":{"113":1}}],["129",{"2":{"59":1,"69":1}}],["1277556f0",{"2":{"53":1}}],["1289227206331026e",{"2":{"258":1}}],["128685f",{"2":{"256":1}}],["1286439",{"2":{"224":1}}],["1284488f",{"2":{"256":1}}],["1285985f",{"2":{"256":1}}],["12827216",{"2":{"113":1}}],["128",{"2":{"39":2,"59":12,"69":3,"77":4,"193":6,"195":1,"210":1,"224":4,"251":1,"260":1}}],["12",{"2":{"34":2,"140":1,"147":6,"148":7,"152":9,"171":2,"180":6,"187":14,"189":6,"197":1,"210":1,"214":6,"221":6,"229":6,"236":10,"237":6,"246":6,"249":5,"251":1,"254":1,"260":1}}],["1234",{"2":{"248":1}}],["12345",{"2":{"224":1}}],["1239749674027375",{"2":{"153":2}}],["123",{"2":{"24":3,"62":1,"153":1}}],["1=dense",{"2":{"32":1}}],["1d",{"2":{"24":1,"66":1}}],["1f0",{"2":{"19":3,"53":2,"59":1,"69":2,"78":1,"224":1}}],["1977196550441838e",{"2":{"258":1}}],["197095318178782e",{"2":{"258":1}}],["197045",{"2":{"171":1}}],["197203f",{"2":{"256":1}}],["197501f",{"2":{"256":1}}],["1988",{"2":{"254":2}}],["1984668",{"2":{"145":1}}],["1943",{"2":{"249":1}}],["1969775f",{"2":{"256":1}}],["1968s\\ttraining",{"2":{"210":1}}],["19616",{"2":{"187":1}}],["19501",{"2":{"244":1}}],["195746",{"2":{"224":1}}],["1953009",{"2":{"177":1,"178":1}}],["19597391412112541",{"2":{"174":1}}],["1958431",{"2":{"179":1}}],["1958",{"2":{"17":1,"249":1}}],["1914",{"2":{"249":1}}],["191956",{"2":{"172":1}}],["19124654",{"2":{"145":1}}],["193239426564024e",{"2":{"258":1}}],["193291",{"2":{"171":1}}],["1930511729973555e",{"2":{"258":1}}],["1931882f",{"2":{"256":1}}],["19397983",{"2":{"179":1}}],["1936812",{"2":{"145":1}}],["19001",{"2":{"244":1}}],["1904755",{"2":{"148":1}}],["19084926",{"2":{"113":1}}],["1990",{"2":{"149":1}}],["199387",{"2":{"145":1}}],["19975941",{"2":{"77":1}}],["192574642990644e",{"2":{"258":1}}],["192573f",{"2":{"256":1}}],["192836",{"2":{"168":1}}],["1921258",{"2":{"147":1}}],["19209f",{"2":{"113":2}}],["1929572f",{"2":{"256":1}}],["1929",{"2":{"17":1}}],["19",{"2":{"110":1,"187":14,"196":1,"236":3,"249":5,"258":2}}],["153587963416006e",{"2":{"258":1}}],["1536685f",{"2":{"256":1}}],["159042358",{"2":{"244":2}}],["15941",{"2":{"187":1}}],["156017242074563e",{"2":{"258":1}}],["15604",{"2":{"187":1}}],["156197255254455e",{"2":{"258":1}}],["1563144f",{"2":{"256":1}}],["1565",{"2":{"249":1}}],["15681",{"2":{"213":6}}],["15680",{"2":{"213":6}}],["15686738",{"2":{"113":1}}],["156",{"2":{"193":2}}],["1550",{"2":{"249":2}}],["15501",{"2":{"244":1}}],["15557",{"2":{"187":1}}],["1557574",{"2":{"148":1}}],["15544322",{"2":{"113":1}}],["15542f",{"2":{"77":1}}],["15701",{"2":{"213":6}}],["15700",{"2":{"213":12}}],["15707001",{"2":{"147":1}}],["1577715",{"2":{"77":1}}],["15276335",{"2":{"140":1}}],["1516021650309755e",{"2":{"258":1}}],["1514736f",{"2":{"256":1}}],["1511",{"2":{"249":1}}],["151",{"2":{"219":1,"228":1}}],["15106",{"2":{"187":1}}],["15107603",{"2":{"113":1}}],["15107606",{"2":{"113":1}}],["15133555",{"2":{"113":1}}],["15850",{"2":{"187":1}}],["1585735",{"2":{"113":1}}],["1586047939092094",{"2":{"153":2}}],["15802455",{"2":{"113":1}}],["154041",{"2":{"171":1}}],["1545162",{"2":{"148":1}}],["15451166",{"2":{"77":1}}],["15493166",{"2":{"113":1}}],["1549292",{"2":{"113":1}}],["154",{"2":{"110":1,"193":2}}],["1501",{"2":{"244":1}}],["15001",{"2":{"244":1}}],["1500",{"2":{"206":2,"250":1}}],["150",{"2":{"69":1}}],["15",{"2":{"17":1,"53":1,"147":1,"148":3,"171":4,"180":3,"187":14,"189":5,"197":1,"214":3,"221":3,"229":3,"236":2,"237":3,"246":3,"249":5,"251":1,"260":1}}],["1",{"2":{"2":1,"4":1,"5":2,"7":1,"11":4,"17":8,"19":10,"24":48,"32":6,"39":5,"48":6,"49":1,"52":1,"53":110,"54":1,"59":24,"62":27,"63":9,"64":1,"65":24,"67":7,"68":12,"69":13,"70":3,"77":57,"78":13,"88":1,"97":1,"102":2,"109":6,"111":1,"112":2,"113":36,"114":5,"125":35,"126":47,"129":4,"130":2,"131":2,"132":9,"134":2,"140":3,"141":11,"142":1,"145":13,"147":23,"148":19,"150":3,"151":3,"152":3,"153":88,"168":5,"171":45,"173":4,"174":5,"176":4,"177":6,"178":1,"179":6,"180":4,"183":11,"185":1,"186":1,"187":116,"189":4,"192":5,"193":8,"194":1,"195":5,"196":2,"197":1,"206":5,"207":3,"209":1,"210":6,"211":1,"212":1,"213":118,"214":4,"217":12,"219":18,"220":7,"221":4,"224":90,"225":5,"226":1,"227":4,"228":17,"229":4,"232":4,"233":1,"234":1,"235":1,"236":7,"237":4,"241":1,"242":6,"243":3,"244":6,"245":5,"246":4,"248":6,"249":69,"250":9,"251":1,"254":37,"255":7,"256":107,"257":2,"258":112,"259":5,"260":1}}],["e^2",{"2":{"255":1}}],["err",{"2":{"245":3}}],["errs",{"2":{"245":3}}],["errored",{"2":{"124":1}}],["errors",{"2":{"33":3,"127":1,"219":1}}],["error",{"2":{"2":3,"3":1,"31":1,"33":6,"50":2,"52":1,"53":3,"55":1,"57":2,"60":1,"69":1,"90":2,"97":1,"125":3,"145":1,"179":1,"245":1,"249":2}}],["ess",{"2":{"249":3}}],["essentially",{"2":{"59":1,"62":1,"141":1,"166":1,"228":1}}],["estimated",{"2":{"149":1}}],["estimate",{"2":{"149":1,"152":1}}],["estimation",{"0":{"149":1},"1":{"150":1,"151":1,"152":1},"2":{"149":1,"219":4}}],["established",{"2":{"81":1,"174":1}}],["especially",{"2":{"104":1,"124":1}}],["epyc",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["epochs",{"2":{"219":2,"228":3}}],["epoch",{"2":{"59":1,"187":353,"195":2,"210":2,"228":11,"236":2}}],["eps",{"2":{"19":8,"53":1}}],["epsilon=1f",{"2":{"69":4}}],["epsilon=0",{"2":{"53":2}}],["epsilon=nothing",{"2":{"53":1}}],["epsilon",{"2":{"19":9,"53":9,"69":4}}],["emp",{"2":{"145":2,"146":2}}],["empting",{"2":{"63":1}}],["empty",{"2":{"7":1,"8":2,"52":2,"53":1,"63":2,"65":9,"67":4,"68":5,"69":5,"70":1,"140":1,"179":1,"256":1}}],["embeddings",{"2":{"67":2}}],["embedding",{"2":{"67":2,"99":1,"153":1,"234":1}}],["embed",{"2":{"59":8,"78":8,"153":1}}],["either",{"2":{"53":1,"63":4,"65":6,"254":1}}],["eagerly",{"2":{"160":1}}],["easily",{"2":{"82":1,"145":1,"157":1}}],["easier",{"2":{"52":1,"68":1,"250":1}}],["easy",{"2":{"62":1,"71":1,"83":1,"124":1,"155":1}}],["eachindex",{"2":{"249":1}}],["eachslice",{"2":{"54":2,"184":1,"185":1}}],["each",{"2":{"5":1,"19":2,"24":1,"34":4,"62":15,"63":8,"65":12,"66":4,"67":2,"68":4,"69":2,"146":3,"171":2,"218":1,"249":1,"255":1}}],["evolved",{"2":{"250":1}}],["eval=32",{"2":{"232":1}}],["evalpoly",{"2":{"224":2,"228":1}}],["eval",{"2":{"153":4,"232":5}}],["evaluate",{"2":{"50":1}}],["eventually",{"2":{"153":1}}],["even",{"2":{"3":1,"7":1,"8":1,"55":1,"82":1,"83":1,"84":1,"124":1,"126":1,"156":1,"171":1,"175":1,"196":1}}],["everystep",{"2":{"213":13}}],["everystep=false",{"2":{"208":1}}],["everything",{"2":{"83":2,"134":1}}],["every",{"2":{"48":1,"64":1,"107":1,"108":1,"160":1,"171":1}}],["ever",{"2":{"3":1,"83":1}}],["ecosystem",{"2":{"37":1,"78":1,"101":1}}],["eccv",{"2":{"19":1}}],["edges",{"2":{"144":1}}],["edge",{"2":{"30":1,"83":1,"104":1,"105":1,"127":1,"153":1}}],["effort",{"2":{"113":1}}],["efficient",{"2":{"53":1,"55":1,"74":1,"100":1,"143":1,"145":1,"146":1,"175":2,"240":1}}],["efficiently",{"2":{"27":2,"53":1}}],["effectively",{"2":{"219":2}}],["effect",{"2":{"1":1,"60":1,"70":1}}],["european",{"2":{"19":1}}],["equilibrium",{"2":{"83":1}}],["equivalent",{"2":{"8":1,"39":1,"53":2,"55":4,"59":1,"68":1,"91":1,"171":1}}],["equations",{"2":{"74":1,"257":1}}],["equals",{"2":{"68":1}}],["equal",{"2":{"24":1,"34":1,"53":1,"63":2,"65":3}}],["equally",{"2":{"19":1,"54":1}}],["et",{"2":{"17":2,"24":2,"53":2,"252":1}}],["etc",{"2":{"3":2,"7":1,"20":1,"83":1,"133":1,"134":1,"136":1,"140":1,"143":1,"145":2,"174":1,"215":1}}],["elem",{"2":{"243":2,"245":2}}],["element",{"0":{"57":1},"2":{"17":2,"24":1,"34":1,"53":1,"55":1,"57":10,"59":2,"62":1,"66":6,"69":1,"153":4,"171":4,"176":1,"177":1,"179":1,"184":1,"188":1}}],["elementwise",{"2":{"15":1,"19":1,"68":2,"69":5}}],["elements",{"2":{"8":1,"24":9,"32":1,"63":2,"65":3,"67":1,"81":1,"171":6,"184":1}}],["elman",{"2":{"66":1}}],["eltypes",{"2":{"155":1,"165":1}}],["eltype",{"0":{"165":1},"2":{"19":9,"55":6,"56":3,"57":3,"109":1,"155":5,"165":2,"173":1}}],["elseif",{"2":{"117":1,"142":1,"254":1}}],["else",{"2":{"8":1,"17":1,"28":1,"37":1,"50":1,"52":1,"54":1,"55":1,"62":1,"64":3,"66":1,"68":1,"117":1,"254":3}}],["eg",{"2":{"8":1,"63":2,"65":3}}],["energy",{"2":{"249":2}}],["environment",{"2":{"180":2,"189":2,"197":1,"214":2,"221":2,"229":2,"237":2,"246":2,"251":1,"260":1}}],["engine",{"2":{"173":1}}],["enforce",{"2":{"173":1}}],["enough",{"2":{"133":1,"160":1,"219":1}}],["encountered",{"2":{"126":1}}],["encounter",{"2":{"105":1,"113":1,"144":1}}],["enhance",{"2":{"104":1}}],["entries",{"2":{"146":1}}],["entry",{"2":{"128":1}}],["entropy",{"2":{"53":3}}],["enter",{"2":{"76":1}}],["entire",{"2":{"64":2,"66":5,"69":1,"108":1,"219":1}}],["entirely",{"2":{"6":1,"63":2,"67":3,"211":1,"213":1}}],["enzymemlir",{"2":{"113":1}}],["enzyme",{"2":{"49":3,"52":1,"83":1,"88":2,"102":1,"103":4,"105":1,"113":10,"144":1,"153":1,"173":1,"175":1}}],["enable",{"2":{"157":1}}],["enables",{"2":{"18":1,"83":1,"247":1}}],["enabled",{"2":{"7":1,"33":2,"97":1,"247":1}}],["ensuring",{"2":{"17":1}}],["ensures",{"2":{"119":1}}],["ensure",{"2":{"2":1,"8":1,"24":1,"83":1,"105":1,"119":1,"149":1,"184":1,"227":1}}],["endpoints",{"2":{"254":2}}],["end",{"2":{"5":2,"11":1,"24":2,"32":2,"59":14,"62":4,"63":2,"65":3,"77":1,"78":7,"109":3,"110":1,"111":3,"113":2,"114":4,"117":1,"125":2,"126":4,"129":1,"130":2,"131":2,"134":3,"140":4,"141":2,"142":3,"145":1,"146":1,"147":1,"148":1,"150":1,"151":1,"152":1,"153":1,"160":2,"172":1,"174":2,"179":3,"180":3,"181":1,"183":3,"184":4,"185":3,"186":1,"187":4,"189":3,"192":1,"194":2,"195":3,"197":3,"206":1,"207":7,"208":1,"209":2,"210":3,"211":3,"214":3,"217":2,"218":1,"219":4,"220":1,"221":3,"224":2,"228":4,"229":3,"232":2,"233":3,"234":1,"235":2,"236":4,"237":3,"241":3,"242":3,"243":1,"244":3,"245":2,"246":3,"248":1,"249":4,"250":3,"251":3,"254":26,"255":2,"256":2,"257":2,"259":2,"260":3}}],["enumerate",{"2":{"5":2}}],["execution",{"2":{"174":1}}],["executables",{"2":{"113":1}}],["exhaustive",{"2":{"161":1}}],["existent",{"2":{"122":1}}],["exists",{"2":{"121":1,"207":1}}],["exist",{"2":{"59":2}}],["external",{"2":{"249":1}}],["extensively",{"2":{"83":1,"104":2,"105":1,"175":1}}],["extensive",{"2":{"82":1,"83":1}}],["extensible",{"2":{"82":1}}],["extensions",{"0":{"50":1}}],["extending",{"2":{"173":1,"184":1}}],["extended",{"2":{"31":1,"32":1,"33":1,"53":2,"57":1,"59":1,"62":6,"63":2,"65":3,"66":2,"68":1,"69":4,"70":1}}],["extend",{"2":{"7":1,"31":1,"83":1}}],["ext",{"2":{"110":2}}],["extrema",{"2":{"243":2}}],["extremely",{"2":{"33":1,"52":1,"115":1,"134":1}}],["extract",{"2":{"249":2,"250":1}}],["extra",{"2":{"24":1}}],["exact",{"2":{"24":1,"141":1,"187":1}}],["exactly",{"2":{"16":1,"54":1,"70":1,"91":1,"136":1,"140":1,"141":1}}],["examplex",{"2":{"116":1}}],["examples",{"0":{"169":1},"2":{"5":1,"24":2,"53":2,"59":4,"84":1,"169":1,"202":1}}],["example",{"0":{"108":1},"1":{"109":1,"110":1,"111":1,"112":1},"2":{"2":1,"3":2,"4":1,"8":1,"19":1,"24":1,"28":1,"31":3,"32":2,"34":3,"37":1,"39":1,"48":1,"49":1,"52":1,"53":14,"58":1,"62":3,"68":5,"69":3,"84":1,"91":1,"94":1,"116":3,"118":2,"124":1,"129":1,"130":1,"133":1,"134":1,"142":1,"143":1,"146":4,"147":1,"148":1,"155":1,"166":1,"176":1,"177":1,"256":1}}],["excellent",{"2":{"190":1}}],["except",{"2":{"7":1,"66":2,"68":1,"156":1}}],["exceptions",{"2":{"24":1}}],["exception",{"2":{"3":2,"50":1}}],["exciting",{"2":{"85":1}}],["exclusively",{"2":{"32":1,"47":1}}],["excluding",{"2":{"31":1,"39":1,"68":1,"69":1}}],["exclude",{"2":{"10":2,"87":1}}],["exclude=internal",{"2":{"10":1}}],["exp",{"2":{"243":1}}],["exposing",{"2":{"213":1}}],["exported",{"2":{"3":1,"6":1,"30":1,"172":1}}],["exploiting",{"2":{"160":1}}],["explore",{"2":{"144":2}}],["explicit",{"2":{"74":1,"83":1,"168":2,"247":1}}],["explicitly",{"2":{"7":1,"59":2}}],["express",{"2":{"249":1}}],["expressed",{"2":{"114":1}}],["expression",{"2":{"48":1,"59":1}}],["expr",{"2":{"50":4,"59":1}}],["expected",{"2":{"53":4,"62":1,"63":2,"67":1,"83":1,"122":1,"126":1,"174":1}}],["expect",{"2":{"30":1,"83":1,"113":1,"122":1,"153":1,"247":1}}],["expects",{"2":{"28":1,"39":1,"48":1,"63":1,"65":3,"70":1,"142":1}}],["experimental",{"0":{"30":1},"1":{"31":1,"32":1,"33":1,"34":1},"2":{"2":1,"4":2,"7":1,"30":2,"31":10,"32":2,"33":6,"34":2,"97":5,"98":5,"113":2,"115":1,"123":1,"124":1,"125":2,"126":2,"127":1,"128":1,"129":3,"130":2,"131":2,"132":1,"153":2,"155":1}}],["e",{"2":{"2":1,"11":1,"19":1,"24":1,"31":1,"37":1,"39":1,"53":3,"57":1,"58":1,"63":2,"64":2,"65":9,"69":3,"90":2,"110":2,"113":1,"119":1,"125":4,"126":4,"143":1,"149":1,"254":4,"255":6,"256":3}}],["gw",{"2":{"255":1}}],["gc",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["gnu",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["guess",{"2":{"258":1}}],["guide",{"0":{"119":1,"120":1},"1":{"121":1,"122":1},"2":{"120":1,"140":1}}],["guarantee",{"2":{"98":1,"166":1}}],["guarantees",{"2":{"30":1}}],["guaranteed",{"2":{"16":1,"18":1,"145":2}}],["gdev",{"2":{"95":1,"116":1,"117":4,"153":2,"160":6,"216":1,"218":3,"219":3,"220":1,"239":1,"244":3}}],["gif",{"2":{"245":1,"250":2}}],["gib",{"2":{"180":2,"189":4,"214":2,"221":2,"229":2,"237":2,"246":2}}],["gigantic",{"2":{"124":1}}],["github",{"2":{"66":1,"71":2,"84":2,"127":1,"144":1,"153":1}}],["give",{"2":{"183":1,"258":2}}],["gives",{"2":{"54":1,"59":1,"140":1}}],["given",{"2":{"2":1,"4":2,"19":1,"20":1,"24":6,"25":24,"37":1,"42":6,"43":2,"44":5,"53":3,"62":2,"67":3,"69":5,"82":1,"83":1,"219":1}}],["g=tanh",{"2":{"66":1}}],["gs",{"2":{"59":2,"77":3,"195":1}}],["globals",{"2":{"256":1}}],["globally",{"2":{"247":1}}],["globallppool",{"2":{"65":1,"100":1}}],["globalmeanpool",{"2":{"65":1}}],["globalmaxpool",{"2":{"65":1}}],["global",{"2":{"48":1,"65":3,"153":1,"155":1,"218":1,"247":1}}],["glorot",{"2":{"24":4,"140":2}}],["gaussian",{"2":{"249":1}}],["gaussadjoint",{"2":{"210":1}}],["gated",{"2":{"66":1}}],["gamma=0",{"2":{"53":1}}],["gamma",{"2":{"53":2}}],["ganguli",{"2":{"24":1}}],["gain=1",{"2":{"24":1,"168":2}}],["gain",{"2":{"24":15,"63":4,"67":2,"99":2}}],["grid",{"2":{"243":5,"245":8}}],["green",{"2":{"228":1}}],["great",{"2":{"215":1}}],["ground",{"2":{"179":3}}],["group",{"2":{"19":3,"69":1,"249":1}}],["groups=1",{"2":{"63":2}}],["groups",{"2":{"19":4,"63":8,"69":4}}],["groupnorm",{"2":{"19":1,"69":7,"136":1}}],["gravitational",{"0":{"252":1},"1":{"253":1,"254":1,"255":1,"256":1,"257":1,"258":1,"259":1,"260":1}}],["gravitate",{"2":{"55":1}}],["graph",{"2":{"248":1,"250":1}}],["grads",{"2":{"52":11,"114":1,"179":1}}],["gradient|jacobian",{"2":{"144":2}}],["gradient",{"0":{"49":1,"147":1},"2":{"27":2,"47":1,"49":1,"52":1,"113":8,"126":4,"133":2,"134":2,"145":6,"146":3,"147":6,"148":6,"152":3,"176":9,"179":1,"215":1,"242":3}}],["gradients",{"0":{"176":1},"2":{"27":2,"45":1,"49":10,"52":29,"53":2,"54":1,"62":1,"77":6,"121":1,"144":1,"145":1,"152":1,"176":1,"195":1,"240":1}}],["grucell",{"2":{"66":6,"99":1}}],["gru",{"2":{"7":1,"66":1}}],["günter",{"2":{"17":1}}],["gt",{"2":{"5":1,"11":1,"24":1,"53":1,"54":1,"59":2,"63":2,"65":3,"68":2,"69":2,"70":3,"79":1,"90":2,"95":1,"116":2,"141":2,"144":12,"184":1}}],["geared",{"2":{"215":1}}],["gelu",{"2":{"113":6,"114":2,"155":1}}],["geoffrey",{"2":{"19":1}}],["genericlossfunction",{"2":{"53":2}}],["genericbroadcastop",{"2":{"20":1}}],["generic",{"2":{"13":1,"16":2,"18":2,"78":1,"97":1,"113":1,"126":1,"150":1,"151":1,"152":1,"153":1,"183":1,"185":1,"186":1,"192":1,"194":1,"195":1,"206":1,"207":2,"208":1,"209":1,"216":1,"224":1,"232":1,"233":1,"234":1,"235":1,"239":1,"242":2,"249":2,"250":1,"254":5,"256":1,"257":2}}],["generating",{"0":{"248":1},"2":{"70":1}}],["generation",{"2":{"66":3}}],["generator=lux",{"2":{"233":1}}],["generator",{"2":{"17":4,"24":3,"64":3,"140":1,"170":1,"174":2,"224":1,"233":4,"234":2}}],["generates",{"2":{"248":1}}],["generated",{"2":{"17":1,"24":1,"59":1,"64":1,"144":1,"180":1,"189":1,"197":1,"214":1,"221":1,"222":1,"229":1,"237":1,"246":1,"250":1,"251":1,"260":1}}],["generate",{"0":{"217":1,"243":1},"2":{"3":1,"9":1,"10":1,"59":1,"66":1,"143":1,"168":2,"179":2,"183":1,"224":4,"233":1,"243":1,"248":2}}],["generalization",{"2":{"95":1}}],["generalized",{"2":{"5":1}}],["general",{"0":{"8":1},"2":{"62":1,"71":1,"79":1,"154":1,"256":1}}],["generally",{"2":{"5":1}}],["getaxes",{"2":{"233":1}}],["getindex",{"2":{"218":1}}],["getproperty",{"2":{"54":3,"142":2,"213":3}}],["getting",{"0":{"75":1},"1":{"76":1,"77":1,"78":1,"79":1,"80":1},"2":{"8":1}}],["getfield",{"2":{"7":1,"109":3,"142":3}}],["get",{"0":{"84":1},"2":{"3":5,"13":1,"14":1,"20":1,"41":2,"42":2,"43":2,"54":1,"77":1,"119":2,"133":1,"142":1,"149":2,"153":2,"165":1,"169":1,"171":2,"174":2,"183":3,"184":1,"187":2,"203":1,"249":2,"254":1}}],["g",{"2":{"2":1,"62":4,"64":2,"69":4,"113":1,"254":1}}],["goal",{"2":{"248":1}}],["goodies",{"2":{"177":1}}],["good",{"2":{"138":1,"145":1,"219":1,"249":1,"258":2}}],["goodfellow",{"2":{"68":1}}],["going",{"2":{"37":1,"147":1}}],["go",{"2":{"2":1,"84":2,"108":1,"126":1,"128":1,"141":1,"142":1,"154":1,"181":1,"238":1}}],["gpuci",{"2":{"110":3,"125":1,"145":2,"213":3,"244":4}}],["gpuarray",{"2":{"54":1}}],["gpuarrayscore",{"2":{"156":2}}],["gpuarrays",{"2":{"22":7,"54":1}}],["gpubroadcastop",{"2":{"20":1}}],["gpusintel",{"2":{"72":2}}],["gpusmetal",{"2":{"72":2}}],["gpusamd",{"2":{"72":2}}],["gpus",{"2":{"13":1,"42":1,"72":2,"115":1,"155":1,"156":1,"160":1}}],["gpu",{"0":{"4":1,"72":1,"80":1,"115":1,"153":1,"156":1,"163":1,"164":1},"1":{"116":1,"117":1},"2":{"1":8,"2":7,"3":10,"5":2,"16":1,"20":1,"49":1,"65":3,"72":4,"73":1,"77":2,"78":2,"80":1,"98":2,"102":1,"103":3,"109":1,"113":2,"115":4,"116":11,"117":5,"122":4,"134":1,"153":15,"160":4,"164":3,"168":1,"172":3,"187":1,"210":3,"213":1,"216":1,"218":3,"227":3,"228":2,"236":1,"239":1}}],["nparameters",{"2":{"249":3}}],["nvml",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["nvidia",{"2":{"3":1,"5":1,"72":2,"180":4,"189":3,"197":2,"214":4,"221":4,"229":4,"237":4,"246":4}}],["ndrange=length",{"2":{"153":2}}],["ndims",{"2":{"11":1,"28":4,"63":4,"65":9,"68":4,"69":2,"70":2,"109":2,"150":2,"151":2}}],["nicely",{"2":{"145":1}}],["nilarray",{"2":{"90":1}}],["nitish",{"2":{"17":1}}],["n=tanh⁡",{"2":{"66":1}}],["nn",{"2":{"63":2,"67":1,"153":7,"249":12,"250":11,"256":14,"257":1,"259":9}}],["nnlib",{"2":{"13":2,"14":2,"63":1,"70":6,"97":3,"133":2,"134":2,"158":3,"228":1}}],["ntuple",{"2":{"62":1,"63":2,"69":2,"109":1,"213":13,"244":1}}],["nlayers",{"2":{"59":2,"78":2}}],["nccl",{"2":{"41":1,"42":4,"121":1}}],["ncclbackend",{"2":{"41":2,"42":2,"119":4}}],["nabla",{"2":{"176":1}}],["native",{"2":{"137":1,"215":1}}],["naming",{"2":{"62":9,"68":2}}],["name>=",{"2":{"161":3}}],["namefreezing",{"2":{"130":1}}],["name=",{"2":{"59":1,"62":1}}],["name=nothing",{"2":{"59":1,"62":11}}],["names",{"2":{"31":1,"59":1,"69":1}}],["named",{"2":{"19":2,"31":2,"53":1,"142":1,"208":2,"210":1,"249":1}}],["namedtuples",{"2":{"142":1}}],["namedtuple",{"2":{"7":4,"8":1,"10":3,"31":5,"32":1,"52":1,"54":1,"55":1,"59":3,"62":10,"63":2,"65":9,"66":2,"67":4,"68":9,"69":5,"70":1,"77":24,"78":1,"90":1,"107":3,"109":3,"110":7,"111":3,"113":7,"125":3,"126":6,"129":3,"132":4,"140":4,"141":3,"143":1,"153":2,"184":2,"213":147,"227":2,"228":1,"249":1,"256":6}}],["name",{"0":{"130":1},"2":{"7":2,"8":5,"31":1,"32":1,"59":3,"68":1,"79":1,"97":1,"109":5,"116":1,"130":5,"131":6,"142":1,"236":4}}],["navab",{"2":{"53":1}}],["nassir",{"2":{"53":1}}],["nans",{"0":{"126":1},"2":{"33":3,"126":7,"127":1}}],["nan",{"2":{"33":5,"126":31,"244":1}}],["nₙ",{"2":{"28":2}}],["n₂",{"2":{"28":2}}],["n₁",{"2":{"28":2}}],["n",{"2":{"19":5,"54":2,"59":5,"62":23,"63":27,"65":54,"67":2,"68":11,"69":11,"70":8,"78":5,"114":1,"179":3,"187":2,"192":3,"195":1,"206":3,"207":5,"210":1,"211":5,"219":1,"228":1,"232":12,"236":2,"244":1,"248":2,"249":3,"250":2,"257":1}}],["numer",{"2":{"255":3,"256":3}}],["numeric",{"2":{"24":2}}],["numerically",{"2":{"186":1}}],["numerical",{"2":{"19":4,"53":1,"69":4,"155":1,"249":1}}],["num",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"250":2,"251":1,"260":1}}],["number=0",{"2":{"24":2}}],["number=1",{"2":{"24":2}}],["numbers",{"2":{"24":6,"25":12,"168":1,"171":3}}],["number",{"2":{"9":1,"10":1,"17":4,"19":1,"24":8,"43":1,"52":1,"53":4,"54":3,"55":1,"59":3,"62":3,"63":10,"64":3,"65":3,"67":7,"68":2,"69":3,"70":3,"140":1,"170":1,"171":1,"174":2,"175":1,"224":1,"248":1,"249":4}}],["nepochs",{"2":{"179":3,"195":3,"210":3,"236":3}}],["nest",{"2":{"145":1}}],["nested",{"0":{"29":1,"144":1,"162":1},"1":{"145":1,"146":1,"147":1,"148":1,"149":1,"150":1,"151":1,"152":1},"2":{"3":1,"29":2,"34":2,"55":5,"58":2,"102":1,"144":1,"147":2,"162":3,"238":1,"240":1,"245":1}}],["next",{"2":{"119":1,"140":1,"249":1,"250":1,"254":1,"256":1,"257":1}}],["nearest",{"2":{"70":7}}],["necessary",{"2":{"65":3,"140":1}}],["negative",{"2":{"53":1,"254":1}}],["net",{"2":{"53":1,"242":11,"249":1,"256":1,"259":2}}],["network",{"0":{"225":1,"247":1,"249":1,"256":1,"257":1,"258":1},"1":{"248":1,"249":1,"250":1,"251":1},"2":{"19":1,"24":1,"78":1,"81":2,"83":1,"108":1,"145":1,"146":2,"153":2,"170":1,"181":2,"225":1,"233":5,"234":3,"248":1,"249":6,"250":4,"256":6}}],["networks",{"0":{"153":1,"241":1},"2":{"17":3,"24":3,"39":1,"53":2,"68":1,"74":1,"83":3,"152":1,"153":1,"190":1,"215":2,"241":2,"249":1}}],["never",{"2":{"30":1,"37":1,"68":1,"256":1}}],["neuralpde",{"2":{"238":2}}],["neuralode",{"2":{"207":7,"210":4,"213":5}}],["neuralodecompact",{"2":{"207":2,"210":1,"213":1}}],["neural",{"0":{"153":1,"204":1,"207":1,"208":1,"212":1,"225":1,"241":1,"247":1,"249":1,"252":1,"256":1,"257":1,"258":1},"1":{"205":1,"206":1,"207":1,"208":1,"209":1,"210":1,"211":1,"212":1,"213":1,"214":1,"248":1,"249":1,"250":1,"251":1,"253":1,"254":1,"255":1,"256":1,"257":1,"258":1,"259":1,"260":1},"2":{"17":4,"24":4,"39":1,"53":1,"58":1,"74":2,"78":1,"81":2,"83":4,"108":3,"145":3,"146":2,"152":1,"153":3,"170":1,"181":2,"190":1,"204":2,"207":1,"208":1,"215":5,"225":1,"248":1,"249":7,"250":2,"256":7,"257":1,"259":2}}],["needed",{"2":{"13":2,"27":2,"28":1,"52":1,"97":1,"121":1,"134":1,"144":1,"168":2}}],["need",{"2":{"6":1,"8":1,"31":1,"34":1,"37":1,"59":2,"68":1,"77":1,"85":1,"97":1,"107":1,"113":3,"114":1,"119":1,"120":2,"125":1,"134":1,"140":3,"141":2,"144":1,"153":1,"166":1,"169":1,"171":1,"183":1,"184":1,"193":2,"207":1,"219":1,"227":1,"234":1,"242":1,"254":1,"256":1}}],["needs",{"2":{"3":1,"7":1,"10":1,"13":2,"63":1,"64":1,"109":1,"120":1,"148":1,"164":1}}],["newtonian",{"2":{"254":2,"256":1,"258":1}}],["new",{"0":{"88":1,"91":1,"95":1,"100":1,"212":1},"2":{"1":1,"32":9,"34":5,"52":1,"59":1,"64":1,"66":4,"68":5,"85":1,"87":1,"98":1,"107":1,"113":1,"115":1,"120":1,"138":1,"140":1,"141":1,"144":1,"153":1,"233":2,"249":3}}],["nom",{"2":{"249":1}}],["noisy",{"2":{"183":2}}],["noise",{"2":{"179":1}}],["now",{"2":{"88":1,"95":1,"98":1,"99":4,"100":2,"113":4,"114":1,"120":1,"122":3,"125":2,"126":2,"134":1,"140":1,"141":1,"145":1,"146":2,"147":1,"148":1,"152":2,"153":2,"155":1,"170":2,"175":1,"179":1,"184":2,"186":1,"193":1,"196":1,"219":1,"228":1,"247":1,"249":2,"250":1,"254":1,"256":2,"257":1,"259":1}}],["norm",{"2":{"69":1,"145":7,"146":7,"147":6,"148":6,"152":12}}],["normally",{"2":{"113":1}}],["normal",{"2":{"22":2,"24":12,"25":6,"168":6,"249":1,"256":3}}],["normalises",{"2":{"19":2,"69":2}}],["normalize",{"2":{"69":2}}],["normalized",{"2":{"19":8,"53":3,"69":7,"245":2}}],["normalization",{"0":{"19":1,"69":1},"2":{"19":12,"24":1,"28":1,"69":11,"146":1}}],["normalizing",{"2":{"17":1}}],["nooplayer",{"2":{"62":6,"64":3,"68":3}}],["nonlinear",{"2":{"24":1}}],["non",{"0":{"112":1},"2":{"16":1,"18":1,"24":2,"31":1,"33":1,"42":2,"52":2,"53":1,"59":9,"67":1,"90":1,"93":1,"122":1,"124":1,"134":2,"203":1,"207":2,"254":1}}],["nonetheless",{"2":{"2":1}}],["none",{"2":{"2":1,"30":1,"31":1,"33":1,"57":1,"126":1}}],["node",{"2":{"3":1}}],["notice",{"2":{"140":1,"141":1,"146":2,"210":1}}],["notion",{"2":{"55":1}}],["notangent",{"2":{"49":1,"126":1}}],["not",{"2":{"2":1,"3":4,"4":2,"6":1,"7":1,"8":1,"15":1,"16":1,"17":1,"19":3,"24":2,"28":1,"33":1,"34":1,"39":3,"41":2,"47":1,"50":1,"52":1,"54":1,"57":1,"58":1,"59":1,"62":1,"66":11,"68":1,"69":1,"77":1,"83":1,"90":2,"97":1,"101":1,"104":1,"105":2,"113":1,"116":1,"119":1,"122":1,"125":1,"126":1,"134":3,"138":1,"144":1,"145":5,"149":1,"152":1,"153":1,"160":1,"167":1,"169":1,"196":2,"203":1,"207":1,"210":2,"212":1,"213":2,"219":1,"225":1,"249":1,"250":1,"254":1}}],["notes",{"2":{"16":1,"18":1,"49":1,"177":1,"204":1}}],["note",{"2":{"2":1,"3":4,"13":2,"24":1,"31":1,"40":1,"52":1,"53":1,"55":2,"58":1,"59":1,"68":1,"74":1,"105":1,"113":1,"114":1,"119":1,"125":1,"137":1,"140":1,"141":1,"144":1,"147":1,"156":1,"173":1,"176":1,"188":1,"207":1,"213":1,"247":1}}],["nothing",{"2":{"2":4,"3":5,"4":1,"8":2,"15":1,"16":1,"17":2,"18":1,"19":15,"31":5,"41":3,"42":1,"49":1,"53":12,"54":1,"55":2,"58":1,"62":4,"63":4,"64":1,"66":11,"67":4,"68":10,"69":5,"77":27,"78":1,"110":4,"113":9,"126":1,"145":2,"147":2,"148":2,"213":117,"217":1,"218":4,"219":2,"228":6,"249":1,"256":1}}],["no",{"2":{"2":2,"4":2,"5":1,"30":1,"31":3,"39":1,"48":1,"52":1,"53":2,"57":1,"60":1,"68":1,"77":1,"83":1,"92":1,"95":1,"97":1,"110":1,"116":2,"117":1,"121":3,"125":1,"126":1,"140":1}}],["u=u",{"2":{"242":1}}],["u0=res",{"2":{"219":1}}],["u0",{"2":{"217":2,"219":2,"220":1,"255":2,"256":2,"257":1,"259":2}}],["utc",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["utility",{"0":{"209":1,"235":1,"254":1}}],["utilities",{"0":{"51":1},"1":{"52":1,"53":1,"54":1,"55":1,"56":1,"57":1,"58":1,"59":1,"60":1},"2":{"47":1,"134":1}}],["utils",{"0":{"40":1},"1":{"41":1,"42":1,"43":1,"44":1,"45":1,"46":1},"2":{"31":2,"55":1,"145":4}}],["url",{"2":{"74":1}}],["url=",{"2":{"71":1}}],["u",{"2":{"27":7,"207":7,"211":2,"217":4,"219":11,"220":6,"241":4,"242":11,"244":4,"245":7,"255":3,"256":4,"258":1,"259":2}}],["ulyanov",{"2":{"19":1,"69":1}}],["upto",{"2":{"240":1}}],["upsampled",{"2":{"70":1}}],["upsample",{"2":{"70":5,"99":1}}],["upsampling",{"0":{"70":1},"2":{"70":2}}],["upscaling",{"2":{"70":1}}],["upscale",{"2":{"70":2}}],["up",{"0":{"257":1},"2":{"54":1,"149":1,"152":1,"203":2,"204":1}}],["updating",{"0":{"56":1,"85":1},"1":{"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"96":1,"97":1,"98":1,"99":1,"100":1},"2":{"19":2,"45":1,"76":1,"179":1}}],["updates",{"2":{"34":1,"52":3,"69":1,"93":1,"119":1}}],["updated",{"2":{"15":1,"17":2,"19":2,"34":1,"52":5,"53":1,"62":6,"64":3,"66":7,"68":1,"69":1,"78":1,"82":1,"83":1,"99":1,"122":1,"140":1,"184":1,"203":1,"227":1}}],["update",{"2":{"10":2,"15":1,"17":2,"52":2,"56":1,"59":1,"64":3,"66":5,"69":3,"76":2,"85":1,"173":1}}],["upon",{"2":{"5":1}}],["untrained",{"2":{"256":2,"259":1}}],["until",{"2":{"64":1}}],["uncertain",{"2":{"250":1}}],["unchanged",{"2":{"62":1}}],["unable",{"2":{"173":1}}],["unnecessary",{"2":{"146":1}}],["unnormalized",{"2":{"69":1}}],["un",{"2":{"97":1}}],["unexpected",{"2":{"83":1}}],["unreleased",{"2":{"71":1}}],["unreasonably",{"2":{"62":1}}],["unrolls",{"2":{"62":1}}],["unroll",{"2":{"13":1}}],["unwrapped",{"2":{"55":1}}],["unwrap",{"2":{"55":2}}],["unwraps",{"2":{"31":1}}],["undone",{"2":{"34":1}}],["undef",{"2":{"174":1}}],["undefined",{"2":{"8":1,"66":1}}],["underlying",{"2":{"207":1}}],["under",{"2":{"134":1}}],["understand",{"2":{"59":1,"138":1,"184":1,"204":1,"207":1}}],["understanding",{"2":{"24":2,"233":1}}],["undesirable",{"2":{"11":1}}],["unfreezes",{"2":{"31":1}}],["unfreeze",{"2":{"31":2}}],["unlike",{"2":{"25":1,"59":1}}],["unless",{"2":{"2":1,"33":1,"233":1}}],["unified",{"2":{"215":1}}],["uniformly",{"2":{"119":1}}],["uniform",{"2":{"24":6,"25":6,"63":5,"66":6,"67":4,"77":1,"140":3}}],["uninitiated",{"0":{"170":1},"1":{"171":1,"172":1,"173":1,"174":1,"175":1,"176":1,"177":1,"178":1,"179":1,"180":1}}],["universal",{"2":{"68":1}}],["unity",{"2":{"254":1}}],["unitrange",{"2":{"173":1}}],["unit",{"2":{"66":1}}],["union",{"2":{"2":3,"8":1,"17":1,"24":2,"33":2,"39":1,"53":3,"66":2,"69":1}}],["unpack",{"2":{"8":1}}],["unsupported",{"2":{"8":1,"22":1}}],["unsafe",{"2":{"5":1}}],["unknown",{"2":{"3":2}}],["unknowndevice",{"2":{"3":2}}],["usr",{"2":{"180":2,"189":2,"197":2,"214":2,"221":2,"229":2,"237":2,"246":2}}],["usacases",{"2":{"103":2}}],["usage",{"2":{"31":1,"84":1}}],["usual",{"2":{"69":3,"148":1,"153":1}}],["usually",{"2":{"53":2,"59":1,"70":1,"171":1,"219":1}}],["us",{"2":{"27":2,"30":1,"124":1,"125":1,"126":6,"134":1,"141":2,"142":3,"144":1,"170":1,"174":1,"177":1,"178":1,"179":3,"183":1,"212":1,"256":1,"257":1,"259":2}}],["usecases",{"2":{"55":1,"58":1,"153":1,"238":1}}],["uses",{"2":{"16":1,"18":2,"37":1,"55":4,"56":1,"58":1,"69":1,"90":1,"144":1,"147":1,"155":1,"158":2,"161":1,"174":1,"215":1,"254":2,"255":1,"256":1,"258":1}}],["userbase",{"2":{"37":1}}],["user",{"2":{"7":2,"8":2,"13":2,"58":1,"62":1,"81":1,"107":1,"134":1,"136":2,"147":1}}],["users",{"2":{"6":1,"7":2,"15":1,"31":1,"41":2,"42":1,"52":1,"55":1,"81":1,"83":1,"90":1,"93":1,"155":1,"173":1,"204":2,"207":1,"213":1}}],["useful",{"2":{"3":1,"20":1,"24":3,"33":2,"53":1,"54":1,"57":1,"59":2,"74":1,"124":1,"125":1}}],["use",{"0":{"83":1,"137":1},"2":{"2":1,"4":2,"5":1,"13":3,"15":1,"17":1,"18":2,"20":1,"24":1,"27":2,"28":1,"30":1,"31":2,"33":1,"41":4,"47":2,"52":4,"59":1,"63":11,"66":18,"67":16,"69":3,"71":1,"74":1,"77":2,"78":1,"83":1,"84":2,"93":1,"97":2,"98":4,"99":1,"100":1,"103":3,"105":1,"113":3,"114":2,"116":1,"119":2,"123":1,"124":1,"125":1,"129":1,"137":1,"144":3,"145":1,"146":1,"147":2,"149":2,"153":4,"155":2,"158":1,"159":1,"163":1,"164":2,"167":2,"169":1,"170":1,"171":1,"174":1,"175":1,"176":1,"177":2,"179":3,"183":2,"184":3,"186":2,"190":2,"192":1,"204":1,"206":1,"207":1,"208":2,"210":2,"226":1,"227":1,"228":1,"238":1,"242":1,"244":4,"247":1,"248":1,"249":5,"250":1,"254":1,"256":5}}],["used",{"2":{"2":2,"3":6,"8":2,"17":3,"24":1,"33":2,"34":2,"37":1,"39":2,"46":1,"52":2,"53":5,"55":1,"58":1,"59":11,"63":3,"64":3,"66":1,"67":1,"68":1,"69":7,"70":1,"90":1,"94":1,"97":1,"98":1,"100":1,"113":1,"115":1,"116":2,"122":1,"144":1,"145":2,"155":1,"166":1,"167":1,"169":1,"171":1,"211":1,"252":1}}],["using",{"0":{"38":1,"48":1,"112":1,"113":1,"114":1,"146":1,"150":1,"151":1,"152":1,"185":1,"204":1,"211":1,"215":1,"222":1},"1":{"39":1,"114":1,"205":1,"206":1,"207":1,"208":1,"209":1,"210":1,"211":1,"212":1,"213":1,"214":1,"216":1,"217":1,"218":1,"219":1,"220":1,"221":1,"223":1,"224":1,"225":1,"226":1,"227":1,"228":1,"229":1},"2":{"2":1,"3":1,"4":2,"5":2,"7":2,"20":3,"24":2,"27":2,"31":1,"32":1,"37":3,"39":4,"44":1,"45":1,"46":1,"48":2,"49":1,"52":7,"53":4,"55":1,"59":9,"62":11,"66":6,"67":1,"68":2,"69":1,"71":2,"76":1,"77":3,"78":4,"81":1,"82":1,"83":2,"90":1,"95":1,"100":1,"113":8,"114":2,"115":3,"117":2,"118":1,"122":1,"125":1,"133":2,"136":1,"137":1,"138":2,"142":2,"144":4,"145":6,"146":1,"147":1,"148":2,"149":5,"152":14,"153":3,"155":1,"156":1,"163":1,"170":1,"171":2,"174":1,"177":2,"178":1,"179":1,"180":1,"181":2,"183":1,"185":1,"188":1,"189":1,"190":1,"191":2,"196":1,"197":1,"205":2,"207":1,"211":1,"213":2,"214":1,"215":1,"216":1,"219":1,"221":1,"223":1,"225":1,"229":1,"237":1,"238":3,"239":1,"240":1,"241":1,"242":1,"246":1,"247":2,"249":1,"250":1,"251":1,"253":1,"255":1,"256":1,"260":1}}],["w=w",{"2":{"242":1}}],["w=gv∥v∥weight",{"2":{"69":1}}],["w=",{"2":{"59":1}}],["w=rand",{"2":{"59":1}}],["w=ones",{"2":{"59":3}}],["w3",{"2":{"59":3,"78":3}}],["w3=dense",{"2":{"59":1,"78":1}}],["w2",{"2":{"59":3,"78":3}}],["w2=",{"2":{"59":1,"78":1}}],["w1",{"2":{"59":3,"78":3}}],["w1=dense",{"2":{"59":1,"78":1}}],["w",{"2":{"59":21,"65":6,"67":1,"70":4,"78":4,"142":2,"158":1,"171":1,"179":5,"192":1,"206":1,"241":4,"242":10}}],["write",{"2":{"171":2,"173":1,"179":1,"233":1}}],["writing",{"0":{"111":1},"2":{"97":1,"112":1,"138":1}}],["written",{"2":{"37":1}}],["wrote",{"0":{"81":1},"1":{"82":1,"83":1},"2":{"203":1}}],["wrapping",{"2":{"90":1}}],["wrappers",{"0":{"27":1}}],["wrapper",{"2":{"14":1,"27":2,"33":1,"58":1,"66":1,"141":2,"148":1,"228":1,"241":1}}],["wrappedlayer",{"2":{"64":1}}],["wrappedfunction",{"2":{"63":1,"68":2,"126":3,"213":9,"256":1}}],["wrapped",{"2":{"7":3,"33":1,"62":8,"68":2,"141":1}}],["wrap",{"2":{"45":1,"119":1,"124":1,"141":1,"218":1}}],["wraps",{"2":{"39":1,"42":2,"66":2,"68":1}}],["wrt",{"2":{"27":2,"49":1,"52":3,"53":2,"54":1,"120":1,"148":2,"242":1}}],["wu",{"2":{"19":1}}],["wide",{"2":{"175":1}}],["wider",{"2":{"83":1,"88":1,"92":1,"177":1}}],["width",{"2":{"63":1}}],["wio",{"2":{"66":1}}],["wio×x+who×hprev+bo",{"2":{"66":1}}],["wig",{"2":{"66":1}}],["wig×x+whg×hprev+bg",{"2":{"66":1}}],["wif",{"2":{"66":1}}],["wif×x+whf×hprev+bf",{"2":{"66":1}}],["wii",{"2":{"66":1}}],["wii×x+whi×hprev+bi",{"2":{"66":1}}],["wiz",{"2":{"66":1}}],["wiz×x+biz+whz×hprev+bhz",{"2":{"66":1}}],["wir",{"2":{"66":1}}],["wir×x+bir+whr×hprev+bhr",{"2":{"66":1}}],["win",{"2":{"66":1}}],["win×x+bin+r⋅",{"2":{"66":1}}],["window",{"2":{"65":18}}],["will",{"2":{"3":2,"5":1,"11":1,"19":1,"24":3,"28":4,"30":1,"33":2,"34":3,"37":4,"39":1,"44":2,"48":2,"49":1,"50":4,"52":1,"55":4,"57":4,"58":1,"59":8,"62":5,"64":2,"66":3,"68":1,"69":3,"71":1,"77":1,"78":1,"90":1,"108":1,"113":5,"115":1,"124":1,"125":1,"126":2,"128":1,"133":1,"134":2,"138":1,"141":1,"144":2,"145":3,"147":1,"149":2,"150":1,"153":8,"155":2,"157":1,"167":1,"169":1,"171":1,"172":1,"173":1,"174":2,"175":4,"176":1,"177":1,"179":2,"181":2,"183":3,"184":6,"186":1,"190":2,"196":2,"203":1,"207":1,"210":1,"215":2,"218":4,"219":1,"222":1,"226":1,"227":1,"228":2,"238":3,"240":1,"241":1,"242":2,"243":3,"247":2,"249":4,"256":1}}],["withgradient",{"2":{"59":1}}],["within",{"2":{"17":2,"19":2,"59":1,"145":2}}],["without",{"2":{"2":1,"6":1,"59":1,"83":2,"90":2,"113":1,"114":1,"138":1,"145":2,"173":1,"184":1,"219":2}}],["with",{"0":{"190":1},"1":{"191":1,"192":1,"193":1,"194":1,"195":1,"196":1,"197":1},"2":{"1":1,"2":1,"3":1,"5":2,"6":1,"7":2,"8":1,"10":2,"11":1,"13":7,"15":1,"16":2,"18":1,"20":1,"24":5,"28":2,"31":5,"32":2,"33":3,"34":1,"37":1,"39":1,"42":2,"45":1,"46":2,"48":2,"49":1,"52":2,"53":6,"54":2,"55":2,"56":3,"57":1,"59":3,"62":14,"63":11,"64":6,"65":12,"66":10,"67":12,"68":5,"69":3,"70":5,"78":3,"81":1,"83":7,"87":1,"88":1,"90":2,"97":3,"99":1,"100":1,"101":2,"103":1,"104":2,"105":2,"112":2,"113":2,"114":1,"116":1,"119":2,"121":2,"122":1,"123":1,"124":3,"125":1,"126":1,"133":1,"138":1,"140":1,"141":1,"142":6,"144":3,"145":1,"146":4,"147":1,"150":1,"151":1,"152":1,"153":5,"155":1,"157":1,"158":6,"163":1,"167":2,"168":2,"169":2,"170":1,"171":5,"172":2,"173":1,"174":2,"175":1,"177":2,"179":4,"181":1,"183":1,"185":1,"186":1,"187":1,"192":1,"194":1,"195":1,"203":1,"206":1,"207":3,"208":1,"209":1,"215":2,"216":1,"219":1,"224":1,"232":1,"233":2,"234":1,"235":1,"239":1,"240":1,"242":2,"247":2,"248":1,"249":6,"250":2,"254":5,"256":2,"257":2}}],["what",{"2":{"125":1,"126":1,"136":1,"140":1,"142":1,"148":1,"165":1,"171":2}}],["whatever",{"2":{"52":1,"68":1}}],["why",{"0":{"81":1,"83":1},"1":{"82":1,"83":1},"2":{"140":1}}],["whole",{"2":{"69":2}}],["whose",{"2":{"67":1,"69":1}}],["who",{"2":{"66":1}}],["whg",{"2":{"66":1}}],["whf",{"2":{"66":1}}],["whn",{"2":{"66":1}}],["whn×hprev+bhn",{"2":{"66":1}}],["whz",{"2":{"66":1}}],["whr",{"2":{"66":1}}],["whcn",{"2":{"63":1,"64":2,"69":3}}],["whi",{"2":{"66":1}}],["while",{"2":{"3":1,"32":1,"39":1,"58":1,"62":1,"70":1,"83":1,"114":1,"131":1,"138":1,"140":1,"155":1,"177":1}}],["which",{"0":{"107":1},"2":{"2":1,"3":1,"7":1,"19":1,"24":1,"30":1,"31":14,"34":1,"52":1,"53":5,"58":1,"59":5,"62":3,"63":1,"65":3,"66":1,"68":3,"69":4,"83":2,"84":1,"99":1,"100":1,"124":2,"136":1,"138":1,"140":1,"141":2,"142":1,"149":1,"155":1,"170":1,"171":2,"173":1,"179":1,"185":1,"207":1,"211":1,"219":1,"228":1,"247":1,"249":1,"252":1,"255":1,"256":1}}],["whether",{"2":{"33":2,"39":1,"64":1,"183":1}}],["whereas",{"2":{"63":1}}],["where",{"2":{"3":1,"13":2,"16":1,"18":1,"19":1,"20":1,"24":7,"32":1,"33":1,"53":4,"58":1,"63":5,"65":6,"66":6,"67":4,"68":3,"69":3,"70":1,"105":1,"126":2,"134":1,"159":1,"176":1,"184":1,"185":1,"232":1,"249":2,"250":2,"254":3}}],["when",{"2":{"3":2,"16":1,"24":2,"39":2,"48":1,"53":2,"54":1,"59":2,"63":1,"67":1,"68":1,"70":1,"104":1,"121":1,"130":1,"140":2,"144":1,"156":1,"165":1,"175":2,"184":1,"196":1,"207":1,"254":1,"257":1}}],["world",{"2":{"219":1}}],["worthwhile",{"2":{"83":1}}],["word",{"2":{"67":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["words",{"2":{"63":1}}],["workaround",{"2":{"153":1}}],["worker",{"2":{"160":1}}],["workers",{"2":{"43":3,"44":5}}],["worked",{"2":{"88":1,"147":1}}],["working",{"2":{"33":1,"101":1,"103":2,"105":1,"113":1,"116":1,"122":1,"123":1,"169":1,"248":1}}],["work",{"2":{"2":1,"5":1,"31":1,"68":1,"70":1,"74":1,"104":1,"105":1,"107":1,"119":1,"122":1,"127":1,"134":1,"138":1,"144":1,"167":1,"171":2,"176":1}}],["works",{"2":{"2":1,"33":1,"37":1,"55":1,"58":1,"70":2,"83":1,"95":1,"105":1,"112":1,"121":1,"140":2,"142":1,"144":1,"145":1,"153":1,"160":1,"171":1,"207":1}}],["would",{"2":{"7":2,"8":1,"63":2,"68":3,"81":1,"83":1,"90":1,"113":2,"125":1,"130":1,"134":1}}],["wondered",{"2":{"83":1}}],["won",{"2":{"2":1,"8":1,"59":1,"93":1,"108":1,"184":1,"215":1}}],["waveform",{"2":{"254":5,"255":7,"256":9,"257":4,"259":12}}],["waveforms",{"0":{"252":1},"1":{"253":1,"254":1,"255":1,"256":1,"257":1,"258":1,"259":1,"260":1}}],["wall",{"2":{"249":1}}],["wan",{"2":{"144":1}}],["wants",{"2":{"136":1}}],["wanted",{"2":{"83":1}}],["want",{"0":{"72":1,"73":1},"2":{"8":2,"52":2,"71":1,"78":1,"108":1,"114":1,"130":1,"138":1,"145":1,"148":1,"171":1,"177":1,"215":1,"218":1,"243":1}}],["warmup",{"2":{"195":1,"257":1}}],["warde",{"2":{"68":1}}],["warntype",{"2":{"213":3}}],["warn",{"2":{"57":3,"60":1}}],["warning",{"2":{"2":3,"3":1,"4":2,"8":1,"16":1,"27":2,"37":3,"39":2,"47":1,"52":1,"53":1,"57":5,"58":1,"63":1,"69":1,"116":1,"128":1,"144":1,"145":2,"153":1,"202":1,"203":1,"244":4}}],["way",{"2":{"17":2,"37":3,"39":2,"62":1,"83":1,"124":1,"138":2,"150":1,"161":1,"185":2,"249":1}}],["wasteful",{"2":{"140":1}}],["was",{"2":{"2":1,"5":3,"7":1,"11":1,"24":1,"34":1,"37":1,"63":1,"90":3,"92":1,"93":1,"99":1,"113":1,"121":2,"155":2,"180":1,"189":1,"197":1,"207":1,"214":1,"219":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["welcome",{"2":{"144":1}}],["well",{"2":{"39":1,"53":1,"81":1,"101":1,"103":1,"113":1,"145":1,"146":1,"170":1}}],["weird",{"2":{"140":1,"142":2}}],["weightnorm",{"2":{"69":4,"83":1,"140":1}}],["weightih×x+biasih+weighthh×hprev+biashh",{"2":{"66":1}}],["weighting",{"2":{"53":1}}],["weightinitializers",{"0":{"21":1,"92":1},"1":{"22":1,"23":1,"24":1,"25":1},"2":{"3":1,"24":8,"25":24,"140":3,"168":2,"256":1}}],["weight=truncated",{"2":{"256":3}}],["weight=l",{"2":{"140":1}}],["weight=randn32",{"2":{"99":1}}],["weight=rand32",{"2":{"67":1,"99":1}}],["weight=ones32",{"2":{"67":1}}],["weight=glorot",{"2":{"63":1,"140":1}}],["weight=nothing",{"2":{"63":1,"66":3,"67":3}}],["weight=ps",{"2":{"59":1}}],["weight=zero",{"2":{"32":1}}],["weights",{"0":{"168":1},"1":{"169":1},"2":{"53":1,"66":4,"168":10,"169":5,"233":1,"249":2,"250":3}}],["weight",{"2":{"16":4,"18":4,"21":1,"24":3,"31":3,"32":4,"34":4,"63":6,"66":12,"67":24,"69":5,"77":15,"110":2,"113":12,"126":4,"129":4,"130":2,"131":4,"140":6,"142":4,"145":2,"147":4,"148":4,"168":1,"179":1,"213":30,"227":2,"233":5,"234":2,"249":1,"256":3,"258":3}}],["weak",{"2":{"47":1}}],["weren",{"2":{"97":1}}],["were",{"2":{"11":1,"85":1,"92":1,"97":2,"144":1}}],["we",{"0":{"81":1,"137":1},"1":{"82":1,"83":1},"2":{"2":4,"3":3,"7":2,"8":4,"13":2,"16":2,"18":3,"30":2,"37":1,"42":1,"47":1,"52":2,"53":2,"55":5,"57":1,"59":3,"62":3,"63":4,"66":6,"67":4,"77":4,"78":2,"83":4,"85":2,"90":1,"92":1,"93":2,"97":1,"98":1,"99":1,"101":1,"103":2,"104":3,"105":3,"107":1,"108":3,"112":1,"113":13,"114":2,"120":1,"122":3,"123":2,"125":3,"126":6,"127":2,"128":1,"129":1,"131":1,"133":2,"134":2,"137":1,"138":1,"140":5,"141":4,"142":4,"143":1,"144":3,"145":2,"146":3,"147":3,"148":3,"149":3,"152":2,"153":11,"155":3,"159":1,"160":1,"170":1,"171":11,"173":4,"174":9,"175":6,"177":2,"179":3,"181":1,"183":3,"184":11,"185":2,"186":1,"187":1,"188":3,"190":2,"193":2,"196":3,"203":1,"204":1,"207":3,"210":1,"212":1,"213":2,"215":4,"218":4,"219":5,"222":1,"226":1,"227":2,"228":2,"233":2,"238":3,"240":2,"241":2,"242":3,"243":3,"247":3,"248":1,"249":8,"250":7,"254":3,"256":9,"257":1}}],[">randn32",{"2":{"59":2}}],[">",{"2":{"2":3,"3":8,"8":2,"24":8,"25":24,"53":3,"59":2,"66":1,"109":1,"113":1,"126":2,"133":2,"134":4,"145":2,"146":2,"147":2,"148":2,"152":1,"186":1,"224":1,"228":1,"244":2,"254":1,"258":1}}],["cycle",{"2":{"145":2,"244":2}}],["cdev",{"2":{"116":2,"117":1,"216":1,"220":1,"239":1,"244":2}}],["cdims",{"2":{"16":3}}],["circle",{"2":{"255":1,"256":2,"259":4}}],["circumvented",{"2":{"117":1}}],["circular",{"2":{"24":1,"63":1}}],["ci",{"2":{"83":1,"202":1}}],["cite",{"2":{"74":2}}],["citation",{"0":{"74":1}}],["cnew",{"2":{"66":2}}],["cnew=f⋅cprev+i⋅ghnew=o⋅tanh",{"2":{"66":1}}],["cvpr",{"2":{"53":1}}],["cluster",{"2":{"250":1}}],["clockwise",{"2":{"181":1,"183":4}}],["closest",{"2":{"110":1}}],["closures",{"2":{"59":1}}],["cl",{"2":{"141":3,"168":4}}],["classifying",{"2":{"250":1}}],["classify",{"2":{"181":1,"248":1}}],["classifier=st",{"2":{"184":1}}],["classifier",{"0":{"184":1},"2":{"184":11,"185":3,"249":1}}],["classifiers",{"2":{"53":2}}],["classified",{"2":{"53":1}}],["classification",{"0":{"190":1,"204":1},"1":{"191":1,"192":1,"193":1,"194":1,"195":1,"196":1,"197":1,"205":1,"206":1,"207":1,"208":1,"209":1,"210":1,"211":1,"212":1,"213":1,"214":1},"2":{"24":2,"53":2,"247":1}}],["classes",{"2":{"53":1}}],["class",{"0":{"104":1},"2":{"53":1,"102":1,"105":1,"194":5,"209":5,"235":5,"247":1}}],["clear",{"2":{"34":1,"126":1}}],["c",{"2":{"32":3,"63":4,"65":21,"66":1,"70":5,"184":2,"192":1,"206":1,"213":9,"250":2,"254":4}}],["cell=st",{"2":{"184":1}}],["cell`",{"2":{"184":1}}],["cells",{"2":{"66":1,"99":1}}],["cell",{"2":{"66":45,"184":10,"185":4}}],["central",{"2":{"24":1,"213":13}}],["certain",{"0":{"135":1},"1":{"136":1},"2":{"7":1,"8":2,"13":1,"54":1,"64":2,"81":1,"90":1,"97":1,"113":1,"119":1,"123":1,"128":1,"155":1,"167":1,"207":1}}],["ca",{"2":{"219":2,"233":3}}],["cairomakie",{"2":{"216":1,"217":1,"220":1,"223":1,"224":1,"228":1,"239":1,"245":2,"247":1,"248":1,"253":1,"255":1,"256":1,"259":2}}],["capabilities",{"2":{"172":1,"238":1}}],["capture",{"2":{"144":1}}],["causing",{"2":{"155":1}}],["causes",{"2":{"123":1}}],["cause",{"2":{"8":1,"13":1,"34":1,"155":1}}],["cat",{"2":{"109":1,"183":1}}],["catch",{"0":{"154":1},"1":{"155":1,"156":1,"157":1,"158":1,"159":1,"160":1},"2":{"52":1,"110":1,"125":2,"126":2,"157":2}}],["care",{"2":{"174":1}}],["cartesian",{"2":{"67":1}}],["carry",{"2":{"66":4,"184":3,"185":3}}],["caching",{"2":{"52":1}}],["cached",{"2":{"52":2}}],["cache",{"2":{"52":2,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["case",{"2":{"31":1,"57":1,"66":19,"121":1,"137":1,"140":1,"145":1,"179":1,"219":1,"233":1,"250":1,"256":1}}],["cases",{"2":{"8":3,"24":1,"30":1,"37":1,"52":2,"55":6,"57":1,"58":1,"59":1,"71":1,"83":1,"104":1,"105":1,"127":2,"133":1,"146":1,"153":1,"159":1,"173":1}}],["caveats",{"2":{"24":1}}],["calculation",{"2":{"145":1,"146":3}}],["calculations",{"2":{"39":1}}],["calculates",{"2":{"65":3}}],["calculate",{"2":{"63":4,"65":3,"67":1}}],["calculated",{"2":{"7":2,"17":1,"53":7}}],["caller",{"2":{"244":4}}],["called",{"2":{"3":1,"17":2,"19":2,"42":1,"62":2,"64":3,"130":1,"134":2,"136":1,"140":1,"169":1,"171":2,"184":1}}],["callback",{"2":{"219":4,"257":3,"258":1}}],["callable",{"2":{"62":2}}],["calls",{"2":{"7":1,"8":2,"144":2}}],["call",{"2":{"7":1,"8":1,"17":1,"32":1,"48":6,"58":1,"64":5,"69":3,"77":1,"83":1,"144":1,"145":2,"153":1,"168":4,"174":2,"184":1}}],["calling",{"2":{"5":1,"7":1,"8":1,"42":1,"48":1,"114":1,"119":1,"122":1,"249":1}}],["candidates",{"2":{"110":1}}],["cannot",{"2":{"24":1,"59":1,"82":1,"134":1,"140":1,"141":1,"153":1,"202":1}}],["can",{"0":{"137":1},"2":{"2":2,"3":4,"4":2,"7":3,"8":3,"11":1,"13":1,"15":1,"16":1,"17":2,"18":1,"19":14,"20":1,"31":1,"33":1,"42":3,"48":1,"49":1,"52":1,"53":2,"55":1,"58":1,"59":5,"60":1,"62":6,"63":6,"65":3,"66":7,"67":3,"68":3,"71":2,"76":2,"77":3,"78":1,"79":1,"98":1,"112":1,"113":2,"115":1,"117":1,"119":1,"124":2,"125":1,"126":2,"129":1,"131":1,"134":1,"136":1,"137":1,"141":1,"142":3,"144":2,"145":2,"146":3,"148":1,"149":2,"153":1,"155":2,"156":1,"157":1,"160":1,"163":1,"166":1,"167":1,"168":1,"169":1,"171":11,"172":2,"174":1,"176":1,"179":1,"184":1,"185":1,"187":1,"188":1,"207":2,"210":1,"211":1,"219":1,"234":1,"240":1,"241":1,"249":2,"250":3,"254":1,"256":1}}],["coordinates",{"2":{"250":1}}],["cos",{"2":{"147":1,"243":1,"254":2,"255":3,"256":8}}],["cover",{"2":{"133":1}}],["covered",{"2":{"127":1}}],["covariate",{"2":{"19":1}}],["could",{"2":{"140":1,"141":1,"249":1}}],["course",{"2":{"112":1,"145":1}}],["courville",{"2":{"68":1}}],["coupled",{"2":{"81":1,"167":1}}],["counterpart",{"2":{"137":1}}],["count",{"2":{"59":1}}],["colormap=",{"2":{"250":3}}],["colorbar",{"2":{"245":1}}],["color=",{"2":{"217":2,"220":4,"224":2,"228":2,"248":2}}],["columns",{"2":{"171":1}}],["column",{"2":{"67":1,"171":4}}],["collects",{"2":{"62":1}}],["collect",{"2":{"59":1,"78":1,"183":2,"192":2,"206":2,"224":1,"243":4,"245":1,"250":4}}],["cols",{"2":{"24":1}}],["coefficient",{"2":{"53":2}}],["corner",{"2":{"70":1}}],["corners",{"2":{"70":1,"99":1}}],["corners=false",{"2":{"70":1}}],["cores",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["core",{"2":{"37":1,"48":3,"83":1,"133":1,"173":1,"180":1,"189":1,"197":1,"213":2,"214":1,"221":1,"229":1,"233":5,"234":3,"237":1,"244":4,"246":1,"251":1,"260":1}}],["correlation=true",{"2":{"63":2,"98":1,"100":1}}],["correlation=false",{"2":{"63":2}}],["correlation",{"2":{"63":7}}],["corresponding",{"2":{"4":3,"32":2,"34":2,"53":3,"67":1,"70":2,"94":1,"97":1,"116":1,"146":1}}],["corresponds",{"2":{"2":1,"219":1}}],["corrections",{"2":{"112":1}}],["correctness",{"0":{"49":1},"2":{"47":1,"55":1}}],["correct",{"0":{"111":1},"2":{"3":2,"49":1,"155":2,"194":3,"209":3,"235":3}}],["correctly",{"2":{"2":1,"33":1,"119":1,"127":1}}],["codebases",{"2":{"58":1}}],["code",{"0":{"119":1},"2":{"30":2,"37":1,"39":1,"55":4,"59":4,"78":1,"85":1,"103":1,"113":1,"115":1,"119":1,"136":1,"137":1,"143":1,"145":2,"155":1,"156":1,"157":1,"161":1,"170":1,"185":1,"187":1,"213":3,"248":1,"252":2}}],["combination",{"2":{"144":1}}],["combined",{"2":{"66":2,"77":1}}],["combines",{"2":{"62":1}}],["come",{"2":{"125":1,"155":1,"177":1}}],["comes",{"2":{"62":1,"81":1,"83":2,"145":1,"147":1}}],["coming",{"2":{"78":1,"140":1,"155":1}}],["com",{"2":{"66":1,"71":1}}],["community",{"2":{"203":1}}],["communication",{"0":{"44":1},"2":{"121":1,"122":1}}],["communications",{"2":{"42":2}}],["commit",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["command",{"2":{"71":2,"161":2}}],["comm",{"2":{"41":2}}],["common",{"2":{"21":1,"34":1,"55":4,"141":1,"160":1,"166":1,"168":1}}],["comprises",{"2":{"141":1}}],["compilable",{"2":{"113":1}}],["compilation",{"2":{"113":1}}],["compiling",{"0":{"113":1},"1":{"114":1},"2":{"83":1}}],["compiled",{"2":{"103":1,"113":7}}],["compiler",{"2":{"81":2,"113":1}}],["compile=true",{"2":{"52":1}}],["compile",{"2":{"3":1,"48":1,"52":1,"62":1,"113":8}}],["completeness",{"2":{"152":1,"210":1}}],["completely",{"2":{"66":1,"81":1,"97":1}}],["complete",{"2":{"65":3,"66":1,"168":1}}],["complexity",{"2":{"84":1,"175":1}}],["complexf64",{"2":{"25":8}}],["complexf32",{"2":{"25":8,"168":2}}],["complexf16",{"2":{"25":8}}],["complex",{"2":{"5":1,"52":1,"59":1,"168":1}}],["compare",{"2":{"120":1,"152":1}}],["comparison",{"2":{"62":1}}],["compactmacroimpl",{"2":{"213":3}}],["compactluxlayer",{"2":{"59":2,"213":3,"233":2}}],["compact",{"0":{"59":1,"185":1},"2":{"58":1,"59":20,"78":3,"98":2,"138":2,"144":2,"185":2,"187":1,"207":4,"211":1,"213":7,"233":1}}],["compatibility",{"2":{"37":1,"105":1,"138":1}}],["compatible",{"2":{"6":1,"16":1,"18":1,"33":2,"45":1,"46":2,"53":2,"138":1,"144":1,"153":2,"210":1}}],["components",{"2":{"254":4}}],["component",{"2":{"254":7}}],["componentvector",{"2":{"179":1,"213":6,"258":1}}],["componentarray",{"2":{"34":1,"145":2,"146":2,"147":2,"148":3,"152":4,"179":1,"208":1,"210":1,"219":2,"233":2,"256":1}}],["componentarrays",{"2":{"34":2,"142":1,"144":1,"175":1,"205":1,"213":12,"216":1,"231":1,"249":1,"253":1}}],["composability",{"2":{"247":1}}],["composes",{"2":{"101":1}}],["composedlinear",{"2":{"141":3}}],["composed",{"2":{"52":1,"66":1}}],["compose",{"2":{"39":1,"249":1}}],["composition",{"2":{"19":1,"141":1}}],["computing",{"0":{"148":1,"150":1,"151":1,"152":1},"2":{"27":2,"28":1,"146":1,"150":1,"176":1}}],["computed",{"2":{"17":1,"19":1,"52":3,"53":3,"62":4,"63":2,"67":1,"68":1,"69":2,"176":4,"227":1}}],["computes",{"2":{"14":1,"16":1,"19":3,"24":1,"28":1,"52":2,"69":4,"134":1,"149":1}}],["compute",{"2":{"13":2,"18":1,"27":6,"28":1,"52":10,"53":1,"77":3,"90":1,"99":2,"113":1,"126":1,"148":3,"149":5,"152":1,"175":1,"176":1,"177":1,"178":1,"186":1,"195":1,"219":1,"240":1,"242":2,"249":1,"254":4,"255":1,"256":1,"257":1,"259":1}}],["computer",{"2":{"5":1,"19":1,"24":2,"53":4}}],["computationally",{"2":{"175":1}}],["computational",{"2":{"175":1}}],["computation",{"0":{"145":1,"147":1},"1":{"146":1},"2":{"3":1,"13":1,"49":1,"53":1,"62":2,"69":2,"90":1,"160":2}}],["copying",{"2":{"184":1}}],["copyto",{"2":{"55":3}}],["copy",{"2":{"8":1,"52":2,"55":1,"134":2,"173":5}}],["copied",{"2":{"5":1,"66":4}}],["concise",{"2":{"138":1,"185":1}}],["conclusion",{"0":{"127":1}}],["concatenate",{"2":{"109":1}}],["concatenated",{"2":{"66":7}}],["concrete",{"0":{"108":1},"1":{"109":1,"110":1,"111":1,"112":1},"2":{"85":1,"134":1,"142":1}}],["conjunction",{"2":{"83":1}}],["connection",{"2":{"62":26,"66":4}}],["connected",{"0":{"18":1},"2":{"24":1,"67":3}}],["confusing",{"2":{"219":1}}],["confusion",{"2":{"90":1}}],["conform",{"2":{"62":1}}],["conference",{"2":{"19":2,"24":6,"53":4}}],["convtranspose",{"2":{"63":1,"99":1,"100":2}}],["convolutions",{"2":{"63":5}}],["convolution",{"2":{"24":1,"63":9}}],["convolutional",{"0":{"16":1,"63":1},"2":{"24":2,"53":1,"63":4}}],["convdims",{"2":{"16":2}}],["conv",{"2":{"16":3,"39":2,"63":4,"98":1,"99":1,"133":1,"158":2,"193":6}}],["convention",{"2":{"173":1}}],["conveniently",{"2":{"171":1}}],["convenience",{"0":{"25":1},"2":{"7":1,"58":1,"101":1,"228":1}}],["conversely",{"2":{"175":1}}],["converse",{"2":{"63":1}}],["conversions",{"2":{"57":2}}],["conversion",{"0":{"165":1},"2":{"5":1}}],["converts",{"2":{"56":3,"70":1}}],["converted",{"2":{"39":2,"57":1}}],["converting",{"2":{"34":1,"39":3}}],["convert",{"2":{"5":1,"8":1,"37":2,"39":4,"57":3,"134":1,"137":1,"153":1,"193":1,"207":1,"219":1,"220":1}}],["cond",{"2":{"8":3}}],["conditions",{"2":{"196":1,"242":1,"255":1,"256":1}}],["condition",{"2":{"8":2,"24":1}}],["continua",{"2":{"254":1}}],["continue",{"2":{"122":1}}],["contour",{"2":{"245":1,"250":6}}],["contrib",{"2":{"125":1}}],["control",{"2":{"70":2,"113":2,"155":1,"170":1}}],["controlled",{"2":{"57":1,"82":1,"100":1}}],["controlling",{"2":{"57":1,"165":1,"166":1}}],["controls",{"2":{"24":1,"53":1,"63":4,"66":3,"69":8}}],["contrastive",{"2":{"53":1}}],["contrast",{"2":{"2":1}}],["context",{"2":{"17":1,"19":2,"54":1}}],["context`",{"2":{"17":1}}],["contained",{"2":{"62":1}}],["containerlayer",{"2":{"207":1}}],["containers",{"0":{"62":1},"2":{"90":2,"213":3}}],["container",{"0":{"141":1},"2":{"7":2,"8":1,"33":1,"46":1,"91":1,"119":1,"141":2,"184":2}}],["contains",{"0":{"147":1},"2":{"8":1,"28":1,"54":2,"64":1,"68":1}}],["contain",{"2":{"7":1,"57":1,"59":1,"83":1,"140":2,"184":1}}],["containing",{"0":{"145":1},"1":{"146":1},"2":{"3":1,"7":3,"19":2,"24":4,"25":24,"52":2,"53":2,"66":14,"67":1,"82":1}}],["consensus",{"2":{"147":1}}],["consecutive",{"2":{"62":1}}],["consequence",{"2":{"32":1}}],["consult",{"2":{"29":1}}],["considering",{"2":{"175":1}}],["consider",{"2":{"108":1,"140":1,"142":1,"155":1,"176":1,"179":1}}],["considered",{"2":{"3":1,"4":2,"49":1,"52":1,"115":1,"128":1}}],["consistent",{"2":{"66":1}}],["consistency",{"2":{"24":1}}],["consists",{"2":{"62":1,"146":1}}],["constrained",{"2":{"143":1}}],["constructured",{"2":{"134":1}}],["constructing",{"2":{"52":1,"119":1}}],["construction",{"2":{"7":1,"70":1,"97":1}}],["constructor",{"2":{"31":1}}],["construct",{"2":{"24":1,"31":1,"33":2,"59":2,"77":2,"82":1,"114":1,"124":1,"141":2,"208":1,"219":1,"249":2}}],["constructed",{"2":{"17":1,"59":1,"140":1}}],["constructs",{"2":{"7":1,"24":2,"31":1}}],["const",{"2":{"72":4,"73":3,"113":5,"126":1,"213":2,"216":2,"217":2,"227":2,"239":2,"254":6,"255":1,"256":2}}],["constants",{"2":{"17":1,"255":1,"256":1}}],["constant",{"2":{"3":1}}],["cupti",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["cusparse",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["cusolver",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["customparamtype",{"2":{"31":2}}],["customabstractluxlayer",{"2":{"7":4}}],["customize",{"2":{"3":1}}],["custom",{"0":{"78":1,"106":1,"134":1},"1":{"107":1,"108":1,"109":1,"110":1,"111":1,"112":1},"2":{"3":1,"7":2,"8":1,"11":1,"20":1,"31":1,"59":1,"78":1,"83":1,"111":1,"126":2,"138":1,"142":1,"144":1,"163":1,"173":1,"181":1,"184":1,"185":1,"207":1,"238":1,"242":1}}],["cufft",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["curand",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["currently",{"2":{"4":4,"18":2,"20":1,"33":1,"65":3,"70":1,"104":2,"105":1,"113":1,"114":1,"115":1,"123":1,"144":1,"153":2,"177":1}}],["current",{"2":{"2":1,"5":1,"7":1,"31":2,"52":1,"64":1,"101":1,"108":1,"173":1,"249":1,"250":1}}],["cublas",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["cublaslt",{"2":{"18":1}}],["cu",{"2":{"172":4}}],["cuarray",{"2":{"5":3,"22":3,"77":18,"153":2,"168":2,"172":1,"213":18}}],["cuiterator",{"2":{"5":2,"95":1,"160":1}}],["cudevice",{"2":{"4":1}}],["cudnn",{"2":{"2":2,"3":1,"16":1,"72":1}}],["cudadevice",{"2":{"2":2,"4":2,"5":1,"78":1,"94":1,"117":2,"122":1,"180":1,"189":1,"197":1,"214":1,"218":2,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["cuda",{"0":{"172":1},"2":{"2":6,"3":2,"4":1,"5":5,"16":1,"18":1,"22":1,"42":7,"72":1,"77":19,"78":1,"80":1,"88":2,"95":1,"115":1,"121":1,"122":1,"123":1,"153":2,"160":1,"163":3,"164":1,"168":5,"172":7,"180":10,"189":10,"197":3,"205":1,"213":36,"214":10,"221":10,"229":10,"231":1,"237":10,"239":1,"246":10,"251":3,"260":3}}],["ch",{"2":{"249":2,"250":1}}],["cheat",{"2":{"147":1}}],["checking",{"2":{"140":1,"213":1}}],["check=",{"2":{"126":2}}],["check",{"2":{"8":4,"33":11,"42":1,"49":1,"59":1,"64":3,"69":3,"113":1,"126":3,"152":1,"157":2,"166":3}}],["checked",{"2":{"3":1}}],["checks",{"2":{"3":2,"31":2,"33":1,"59":2}}],["chs",{"2":{"63":17,"69":19}}],["chunks",{"2":{"54":1}}],["choice",{"2":{"188":1}}],["chosen",{"2":{"169":1}}],["chopra",{"2":{"53":1}}],["choose",{"2":{"2":1}}],["christian",{"2":{"19":1}}],["chains",{"0":{"39":1},"2":{"39":4,"193":1,"196":1,"249":2}}],["chain=chain",{"2":{"32":1}}],["chain",{"0":{"109":1,"132":1},"2":{"32":10,"34":3,"37":1,"39":2,"59":1,"62":7,"66":2,"68":4,"69":6,"77":9,"97":1,"108":1,"109":2,"112":3,"113":2,"114":1,"125":8,"126":6,"129":2,"130":1,"132":2,"133":2,"145":1,"146":1,"147":1,"148":1,"152":1,"153":1,"193":6,"208":2,"213":18,"219":1,"225":2,"228":1,"234":2,"241":1,"249":5,"250":2,"256":2}}],["chainrulescore",{"2":{"126":2}}],["chainrules",{"2":{"16":1,"18":1,"33":2,"53":1,"102":1,"105":1,"144":1}}],["channel",{"2":{"65":3,"69":12,"70":3}}],["channels",{"2":{"19":1,"63":6,"64":2,"69":1,"70":1}}],["changed",{"2":{"87":1,"120":1,"136":1}}],["changes",{"0":{"87":1,"90":1,"94":1,"97":1,"98":1,"99":2},"2":{"7":1,"11":1,"60":1,"62":9,"68":2,"81":1,"85":1,"90":1,"92":1,"120":1,"125":1,"133":1,"144":1}}],["change",{"2":{"1":1,"2":1,"58":1,"90":1,"93":1,"119":1,"140":1,"210":1,"254":1}}],["crude",{"2":{"254":1}}],["crc",{"2":{"126":2}}],["critical",{"2":{"104":1,"115":1}}],["criteria",{"2":{"2":1,"33":1}}],["creating",{"0":{"184":1},"2":{"59":1,"207":1}}],["created",{"2":{"59":1}}],["create",{"0":{"208":1,"234":1},"2":{"2":1,"5":1,"37":1,"41":2,"52":1,"55":2,"59":1,"62":2,"67":3,"111":1,"113":2,"114":1,"126":1,"171":1,"174":1,"181":1,"183":3,"184":2,"187":1,"208":2,"210":1,"213":3,"228":1,"234":2,"236":1,"241":4,"249":2}}],["creates",{"2":{"1":1,"8":1,"24":1,"59":1,"66":5,"174":1,"249":1}}],["crosscor",{"2":{"63":1,"98":1}}],["crossentropyloss",{"2":{"53":6,"194":1,"209":1,"235":1}}],["cross",{"2":{"53":3,"63":11,"98":1,"100":1,"138":1}}],["cpu=true",{"2":{"210":2}}],["cpu`",{"2":{"116":1}}],["cpus",{"2":{"13":1,"14":2,"39":1,"155":1,"159":1}}],["cpudevice",{"2":{"2":4,"4":2,"116":2,"117":1,"216":1,"239":1}}],["cpu",{"2":{"2":4,"5":1,"18":1,"20":1,"49":1,"65":3,"73":2,"83":1,"98":2,"102":1,"103":3,"105":1,"113":1,"115":1,"116":5,"117":7,"134":1,"153":3,"167":1,"180":2,"187":1,"188":1,"189":2,"196":1,"197":2,"210":4,"214":2,"216":1,"221":2,"227":2,"228":1,"229":2,"237":2,"239":1,"246":2,"251":2,"260":2}}],["rk4",{"2":{"255":1,"256":1,"257":1,"259":1}}],["r₂",{"2":{"254":2}}],["r₁",{"2":{"254":2}}],["r2",{"2":{"254":1}}],["r1",{"2":{"254":1}}],["r=r1−r2",{"2":{"254":1}}],["r=σ",{"2":{"66":1}}],["rhat",{"2":{"249":1}}],["rtx",{"2":{"189":2}}],["rrule",{"2":{"126":1}}],["rrules",{"2":{"105":1}}],["risk",{"2":{"123":1}}],["right",{"2":{"68":1}}],["rᴰ",{"2":{"70":1}}],["r²",{"2":{"70":1}}],["rgb",{"2":{"63":1}}],["r",{"2":{"59":9,"70":9,"254":3}}],["rnns",{"2":{"66":1}}],["rnncell",{"2":{"66":9,"99":1,"100":1}}],["rnn",{"2":{"54":1,"66":3}}],["rng=xoshiro",{"2":{"195":1}}],["rngs",{"2":{"82":1}}],["rng",{"0":{"22":1},"2":{"3":3,"7":2,"8":6,"9":1,"10":1,"11":2,"17":6,"22":10,"24":11,"25":24,"32":3,"37":1,"39":1,"59":5,"62":4,"64":6,"66":3,"67":4,"68":18,"77":7,"78":3,"92":2,"97":1,"110":2,"112":1,"113":1,"114":1,"125":3,"126":2,"129":4,"132":6,"133":7,"134":9,"140":9,"141":2,"142":5,"155":4,"168":13,"169":6,"170":2,"171":1,"174":5,"176":1,"177":1,"179":8,"187":2,"195":2,"208":4,"218":1,"219":1,"224":4,"227":1,"233":3,"236":2,"244":4,"248":11,"249":1,"256":1}}],["row",{"2":{"171":3,"250":1}}],["rows",{"2":{"24":1,"171":1}}],["routines",{"2":{"144":1}}],["route",{"2":{"141":1}}],["rough",{"2":{"144":1}}],["rounded",{"2":{"63":2,"65":3}}],["round",{"2":{"42":1,"236":4,"248":1}}],["root",{"2":{"44":7,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["robin",{"2":{"42":1}}],["rocarray",{"2":{"22":4}}],["rocrand",{"2":{"22":1}}],["rocm",{"2":{"3":1,"72":2,"122":1,"123":1,"163":3,"164":1}}],["ryan",{"2":{"19":1}}],["raw",{"2":{"192":2,"206":2}}],["rademacher",{"2":{"152":1}}],["ra",{"2":{"113":18,"114":9}}],["ratio≥0",{"2":{"254":1}}],["ratio≤1",{"2":{"254":1}}],["ratio",{"2":{"254":6,"255":2,"256":1,"257":1,"259":1}}],["rationale",{"2":{"90":1}}],["rate",{"2":{"179":1,"249":1}}],["rather",{"2":{"3":1,"16":1,"66":1,"82":1,"184":1}}],["raia",{"2":{"53":1}}],["ran",{"2":{"125":1}}],["randc64",{"2":{"25":1}}],["randc32",{"2":{"25":1}}],["randc16",{"2":{"25":1}}],["rand64",{"2":{"25":1}}],["rand32",{"2":{"25":1}}],["rand16",{"2":{"25":1}}],["randnc64",{"2":{"25":1}}],["randnc32",{"2":{"25":1}}],["randnc16",{"2":{"25":1}}],["randn64",{"2":{"25":1}}],["randn32",{"2":{"25":1}}],["randn16",{"2":{"25":1}}],["randn",{"2":{"24":1,"37":1,"39":1,"59":1,"62":2,"68":2,"110":1,"113":1,"114":1,"116":1,"117":1,"125":1,"129":1,"132":1,"133":2,"134":6,"140":1,"141":1,"142":1,"145":2,"146":2,"171":2,"174":1,"176":1,"177":1,"179":4,"195":1,"224":1}}],["randomness",{"0":{"174":1},"2":{"66":3,"77":1,"82":1,"149":1,"170":1,"174":1}}],["randomly",{"2":{"64":2}}],["random",{"2":{"17":4,"22":1,"24":8,"25":12,"32":2,"37":2,"39":2,"59":3,"62":2,"64":3,"68":8,"77":4,"78":3,"109":1,"113":3,"114":1,"125":1,"129":2,"132":4,"133":4,"134":4,"140":4,"142":3,"144":1,"149":1,"153":1,"155":2,"168":3,"170":5,"171":1,"174":8,"179":4,"182":1,"191":1,"205":1,"208":2,"216":1,"218":1,"219":1,"223":1,"224":2,"231":1,"233":1,"239":1,"243":1,"244":2,"247":1,"248":2,"253":1,"256":1}}],["rand",{"2":{"5":1,"59":1,"77":3,"78":1,"147":1,"148":1,"152":2,"153":1,"155":2,"171":5,"172":1,"174":3,"248":8}}],["rank",{"2":{"4":3,"43":3,"119":1,"120":1}}],["ranges",{"2":{"62":1}}],["range",{"2":{"3":2,"92":1,"177":1,"217":1,"224":1,"243":4,"250":23,"255":1}}],["rule",{"2":{"70":1,"228":2}}],["rules",{"0":{"111":1},"2":{"0":1,"55":1,"104":1}}],["runtime",{"2":{"49":2,"180":2,"189":2,"214":2,"221":2,"229":2,"237":2,"246":2}}],["running",{"0":{"110":1},"2":{"17":2,"19":18,"69":16,"90":1,"125":5,"126":11,"129":2,"132":2,"136":1,"156":1,"184":1}}],["run",{"2":{"2":1,"3":1,"5":1,"48":1,"64":1,"71":2,"72":1,"73":1,"77":1,"97":1,"111":1,"113":3,"123":1,"126":3,"134":1,"140":1,"153":3,"155":1,"161":3,"174":1,"184":1,"202":1,"250":1}}],["red",{"2":{"217":1,"220":2,"248":1}}],["reduction",{"2":{"53":1,"65":3}}],["reduce",{"2":{"44":3,"47":1,"68":1,"249":1}}],["reducing",{"2":{"19":1,"62":1}}],["refresher",{"2":{"140":1}}],["referred",{"2":{"171":1}}],["refer",{"2":{"78":1,"203":1,"215":1,"238":1}}],["reference",{"0":{"23":1},"1":{"24":1,"25":1},"2":{"190":1}}],["references",{"2":{"17":2,"19":4,"24":6,"53":4,"68":1,"69":1}}],["reiterate",{"2":{"134":1}}],["reexport",{"2":{"97":2}}],["renamed",{"2":{"90":2,"93":1,"94":2}}],["renormalize",{"2":{"69":2}}],["request",{"2":{"84":1,"90":1}}],["requisites",{"2":{"77":1}}],["requirements",{"2":{"62":1,"228":1}}],["require",{"2":{"19":1,"37":1,"39":1,"59":1,"122":1,"219":1}}],["requires",{"2":{"8":1,"10":1,"42":4,"54":1,"80":1,"107":1,"219":1,"233":1}}],["rev=true",{"2":{"244":4}}],["revising",{"2":{"83":1}}],["reverses",{"2":{"68":1}}],["reversesequence",{"2":{"68":3}}],["reversed",{"2":{"68":1}}],["reversediffadjoint",{"2":{"207":1}}],["reversediff",{"2":{"8":2,"16":1,"18":1,"20":1,"49":1,"52":1,"55":1,"102":1,"103":1,"110":1,"210":1}}],["reverse",{"2":{"27":2,"33":2,"49":1,"59":1,"68":2,"102":6,"113":1,"126":1,"175":2,"176":2}}],["retcode",{"2":{"258":1}}],["retrieve",{"2":{"67":1}}],["retained",{"2":{"64":1}}],["retuened",{"2":{"3":2}}],["returned",{"2":{"17":1,"19":1,"22":1,"24":1,"34":1,"37":1,"39":1,"46":1,"52":6,"54":1,"64":4,"66":3,"67":1,"68":1}}],["returning",{"2":{"8":1,"140":1}}],["returns",{"2":{"3":3,"7":2,"8":3,"13":2,"17":2,"19":4,"20":1,"24":6,"27":2,"28":1,"34":1,"50":1,"52":2,"53":6,"54":2,"57":1,"62":7,"63":2,"64":3,"65":9,"66":8,"67":5,"68":6,"69":5,"70":2,"95":1,"116":3,"146":1,"147":1,"148":1,"213":6,"219":1,"256":1}}],["return",{"2":{"2":3,"3":5,"7":1,"9":1,"10":1,"11":2,"24":6,"25":24,"31":1,"32":2,"52":4,"53":9,"54":2,"55":2,"59":19,"62":3,"66":4,"68":1,"78":3,"82":1,"90":1,"109":1,"111":2,"113":2,"114":1,"126":2,"129":1,"130":3,"131":4,"134":1,"140":5,"141":2,"142":3,"145":1,"146":1,"147":1,"148":1,"150":1,"151":1,"152":1,"169":1,"179":1,"183":1,"184":2,"185":2,"186":1,"187":1,"192":1,"194":1,"195":1,"206":1,"207":5,"208":1,"209":1,"211":2,"213":3,"217":1,"219":3,"224":1,"227":1,"228":1,"232":2,"233":3,"234":1,"235":1,"236":1,"241":2,"242":3,"244":1,"245":1,"248":1,"249":2,"250":2,"254":11,"255":1,"256":1,"257":2}}],["remove",{"2":{"174":1}}],["removed",{"0":{"97":1,"121":1},"2":{"63":1,"87":1,"90":2,"94":1,"97":10,"98":4,"113":1,"115":1,"121":1,"145":2,"146":1}}],["remake",{"2":{"219":1}}],["remark",{"2":{"146":1}}],["remains",{"2":{"17":1}}],["remember",{"2":{"114":1,"124":1,"127":1,"140":1,"144":1,"153":1,"184":1,"210":1}}],["regions",{"2":{"250":1}}],["registry",{"2":{"71":1,"79":1}}],["registered",{"2":{"59":1,"71":1}}],["regression",{"0":{"179":1},"2":{"155":1,"179":1}}],["regressions",{"2":{"8":1,"115":1,"196":1}}],["reg",{"2":{"145":2,"146":2}}],["regarding",{"2":{"134":1,"175":1}}],["regularization",{"2":{"145":1,"152":1,"249":1}}],["regular",{"2":{"39":2,"59":2,"153":1}}],["reuse",{"2":{"16":1,"18":1}}],["reusing",{"2":{"16":1,"18":1}}],["reltol",{"2":{"213":13}}],["reltol=1",{"2":{"208":1}}],["reliance",{"2":{"145":2}}],["reliable",{"2":{"103":2}}],["reliability",{"2":{"83":1}}],["relies",{"2":{"134":2,"161":1,"174":1}}],["relevant",{"2":{"113":1,"247":1,"254":1}}],["release",{"2":{"85":2,"92":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["released",{"2":{"71":1}}],["relativisticorbitmodel",{"2":{"255":3}}],["relatively",{"2":{"144":1,"153":1}}],["relation",{"2":{"66":1}}],["related",{"2":{"84":1}}],["relu",{"2":{"16":1,"37":1,"39":4,"59":3,"62":4,"66":1,"68":3,"69":8,"78":1,"125":5,"126":5,"133":2,"153":1,"193":12,"225":2,"228":2,"234":2}}],["rely",{"2":{"15":1,"59":1,"90":1,"174":1}}],["readme",{"2":{"113":1}}],["read",{"2":{"84":1,"173":1}}],["reactant",{"0":{"113":1},"1":{"114":1},"2":{"73":7,"83":1,"113":9,"114":1}}],["reason",{"2":{"103":1,"155":1}}],["reasonable",{"2":{"62":1}}],["reasons",{"2":{"8":1,"207":1}}],["really",{"2":{"39":1,"59":1,"105":1,"140":1,"171":1}}],["reallocations",{"2":{"16":1,"18":1}}],["real",{"2":{"24":1,"53":4,"64":1,"111":1,"245":2}}],["real=eps",{"2":{"19":1}}],["rewrite",{"2":{"13":1,"37":1,"240":1}}],["receives",{"2":{"68":1}}],["reconstruction",{"2":{"140":1}}],["recognition",{"2":{"53":1}}],["record",{"2":{"50":1,"245":1,"250":1}}],["recorded",{"2":{"49":1,"50":4}}],["recomputing",{"2":{"17":1}}],["recommendations",{"0":{"103":1},"2":{"154":1,"155":1}}],["recommendation",{"2":{"83":1}}],["recommend",{"2":{"7":1,"83":1,"122":1,"138":1,"140":1,"173":1,"177":1,"185":1,"188":1,"204":1,"207":1,"213":1,"233":1}}],["recommended",{"0":{"116":1},"2":{"3":1,"7":2,"8":1,"15":1,"31":1,"37":1,"47":1,"55":1,"59":2,"83":1,"134":1,"138":1,"140":2,"144":1,"145":2,"150":1,"152":1,"153":1,"156":1,"164":1,"186":1,"256":1}}],["recvbuf",{"2":{"44":6}}],["rectifiers",{"2":{"24":2}}],["recur",{"2":{"66":3}}],["recurrence",{"2":{"66":4,"184":1}}],["recurrent",{"0":{"66":1},"2":{"24":1,"66":10,"99":1,"181":2}}],["recurse",{"2":{"55":3}}],["recurses",{"2":{"33":1,"56":3}}],["recursion",{"2":{"55":1}}],["recursive",{"0":{"55":1},"2":{"55":9,"153":2,"155":1}}],["recursively",{"2":{"10":1,"55":5}}],["repository",{"2":{"144":1}}],["report",{"2":{"30":1,"84":1,"105":1}}],["reproducer",{"2":{"123":1}}],["represents",{"2":{"249":1}}],["representing",{"2":{"70":1}}],["representation",{"2":{"59":1}}],["represent",{"2":{"24":1}}],["reparameterized",{"2":{"69":2}}],["reparameterization",{"2":{"69":1}}],["repack",{"2":{"8":1}}],["repeat",{"2":{"183":2}}],["repeatedly",{"2":{"62":1}}],["repeatedlayer",{"2":{"62":1}}],["repeats",{"2":{"62":6,"66":5}}],["replacing",{"2":{"133":1,"171":1}}],["replacement",{"2":{"90":1}}],["replaces",{"2":{"33":1,"65":3}}],["replaced",{"2":{"13":1}}],["replace",{"2":{"13":2,"112":1,"158":5}}],["repl",{"2":{"48":1,"71":1,"76":1,"156":2,"161":1}}],["replicated",{"2":{"174":1}}],["replicate",{"2":{"7":1,"8":1,"62":1,"174":3}}],["resolve",{"2":{"148":1}}],["resolution",{"2":{"70":1}}],["resources",{"0":{"84":1}}],["rescale",{"2":{"69":4}}],["resnet",{"2":{"62":1}}],["res",{"2":{"59":2,"62":4,"219":5,"258":1,"259":1}}],["respective",{"2":{"81":1,"119":2,"134":1,"173":1}}],["respect",{"2":{"28":2,"49":1,"146":2}}],["responsibility",{"2":{"8":1,"142":1}}],["reshapes",{"2":{"68":1}}],["reshapelayer",{"2":{"68":3}}],["reshape",{"2":{"53":4,"78":1,"150":2,"151":2,"173":2,"183":2,"192":1,"206":1,"207":4,"224":1,"232":2,"243":2,"245":2,"249":1}}],["reshaped",{"2":{"16":1,"68":1}}],["reshaping",{"2":{"24":1}}],["restricted",{"2":{"55":1}}],["rest",{"2":{"24":1,"184":2,"185":2}}],["restarted",{"2":{"1":1,"60":1}}],["reserved",{"2":{"59":1}}],["research",{"2":{"17":1}}],["resets",{"2":{"3":1}}],["reset",{"2":{"3":1}}],["results",{"0":{"220":1,"245":1,"259":1},"2":{"113":1,"152":2,"228":1,"250":2,"255":1,"256":1,"258":1,"259":1}}],["result",{"2":{"15":1,"24":1,"28":2,"44":4,"50":4,"69":1,"82":1,"142":4}}],["mtensor",{"2":{"254":4}}],["mtlarray",{"2":{"22":3}}],["mcse",{"2":{"249":1}}],["mcmcchains",{"2":{"249":1}}],["mcmc",{"2":{"249":1,"250":1}}],["mcclelland",{"2":{"24":1}}],["mvnormal",{"2":{"249":1}}],["md",{"2":{"244":8}}],["mnist\\ttraining",{"2":{"236":1}}],["mnist\\ttime",{"2":{"236":50}}],["mnist",{"0":{"190":1,"192":1,"204":1,"206":1,"230":1},"1":{"191":1,"192":1,"193":1,"194":1,"195":1,"196":1,"197":1,"205":1,"206":1,"207":1,"208":1,"209":1,"210":1,"211":1,"212":1,"213":1,"214":1,"231":1,"232":1,"233":1,"234":1,"235":1,"236":1,"237":1},"2":{"191":1,"192":2,"205":1,"206":2,"232":1,"236":2}}],["my",{"2":{"196":1}}],["mybias",{"2":{"142":3}}],["myinputtype",{"2":{"107":3}}],["myfancychain",{"2":{"62":2}}],["myweight",{"2":{"31":1,"142":4}}],["mse",{"2":{"242":3}}],["mseloss",{"2":{"53":4,"77":2,"78":1,"113":1,"114":1,"179":1,"219":1,"227":1,"242":1,"257":3}}],["msleloss",{"2":{"53":2}}],["mpi",{"0":{"163":1},"2":{"41":2,"42":8,"122":2,"123":1,"163":5}}],["mpibackend",{"2":{"41":2,"42":2}}],["m2",{"2":{"37":3}}],["mₘ",{"2":{"28":2}}],["m₂",{"2":{"28":2,"254":7}}],["m₁",{"2":{"28":2,"254":6}}],["m",{"2":{"19":2,"37":3,"56":6,"62":2,"72":2,"207":2,"211":2,"248":15,"254":4,"255":5,"256":3}}],["mkl",{"2":{"18":1}}],["mldatasets",{"2":{"191":1,"205":1,"231":1}}],["mldatadevices",{"0":{"0":1,"93":1},"1":{"1":1,"2":1,"3":1,"4":1,"5":1,"94":1,"95":1},"2":{"0":1,"1":1,"2":3,"3":12,"4":1,"5":2,"93":2,"117":2,"164":2,"180":3,"189":3,"197":3,"214":3,"216":1,"218":3,"221":3,"229":3,"237":3,"239":1,"246":3,"251":3,"260":3}}],["ml",{"2":{"171":1,"219":2}}],["mlir",{"2":{"113":1}}],["mlp",{"0":{"222":1},"1":{"223":1,"224":1,"225":1,"226":1,"227":1,"228":1,"229":1},"2":{"59":1,"78":1,"113":1,"222":1,"234":1,"241":4}}],["mlutils",{"0":{"46":1},"2":{"5":3,"46":4,"95":1,"119":1,"160":2,"182":1,"183":3,"191":1,"205":1,"216":1,"218":1,"231":1,"239":1}}],["motion",{"2":{"254":1,"255":1,"256":1}}],["motivating",{"2":{"8":1,"58":1}}],["moment",{"2":{"147":1,"254":1}}],["momentum=0",{"2":{"69":2}}],["momentum",{"2":{"19":6,"69":2}}],["mooncake",{"2":{"102":1}}],["monolithic",{"2":{"83":1}}],["month",{"2":{"74":1}}],["mouthful",{"2":{"34":1}}],["moved",{"0":{"98":1},"2":{"90":1,"98":2,"113":1}}],["move",{"2":{"30":1,"113":1,"114":2,"172":1,"173":1,"218":3}}],["movement",{"2":{"3":2}}],["modivations",{"2":{"97":1}}],["modify",{"2":{"69":1}}],["modified",{"2":{"55":2,"109":1}}],["modulating",{"2":{"53":1}}],["modules=",{"2":{"48":2}}],["modules",{"2":{"48":8}}],["module",{"0":{"54":1},"2":{"30":1,"40":1,"48":1,"54":1,"97":1,"98":1}}],["modes",{"2":{"20":1,"60":1,"70":1}}],["mode",{"0":{"136":1},"2":{"17":2,"19":2,"20":5,"27":2,"33":7,"49":1,"60":2,"64":6,"66":2,"69":3,"70":5,"98":1,"102":1,"103":1,"124":3,"125":2,"126":2,"136":4,"145":2,"155":1,"156":1,"161":1,"175":1,"176":4,"177":2,"254":1}}],["model`",{"2":{"207":1}}],["models",{"0":{"37":2,"39":1,"112":1,"113":1,"124":1,"202":1,"215":1},"1":{"114":1,"125":1,"126":1,"127":1,"216":1,"217":1,"218":1,"219":1,"220":1,"221":1},"2":{"8":1,"21":1,"37":2,"39":2,"47":1,"52":2,"59":2,"77":1,"83":6,"108":1,"113":1,"124":2,"127":1,"153":1,"168":1,"171":1,"177":1,"181":1,"185":1,"202":2,"215":1}}],["model",{"0":{"125":1,"128":1,"187":1,"188":1,"193":1,"196":1,"219":1,"252":1,"255":1,"256":1},"1":{"129":1,"130":1,"131":1,"132":1,"253":1,"254":1,"255":1,"256":1,"257":1,"258":1,"259":1,"260":1},"2":{"8":8,"32":1,"33":2,"34":2,"37":6,"39":11,"52":5,"53":26,"58":3,"59":14,"62":16,"66":3,"68":12,"69":4,"77":6,"78":10,"81":1,"108":1,"109":1,"110":2,"111":2,"112":2,"113":18,"114":8,"119":2,"124":3,"125":17,"126":25,"127":1,"128":1,"129":6,"132":7,"133":9,"134":11,"136":1,"137":1,"140":1,"141":5,"145":10,"146":7,"147":7,"148":7,"150":2,"151":2,"152":9,"153":4,"155":6,"179":11,"184":2,"185":1,"186":2,"187":10,"188":6,"190":1,"193":4,"194":2,"195":7,"196":4,"202":1,"207":11,"208":8,"209":2,"210":10,"211":8,"213":17,"219":9,"220":2,"227":2,"228":3,"234":4,"235":2,"236":9,"242":4,"243":1,"244":7,"249":7,"250":1,"254":7,"255":4,"256":11,"257":1,"258":1,"259":2}}],["mostly",{"2":{"14":1,"83":1,"85":1,"97":1,"123":1,"207":1}}],["most",{"2":{"7":1,"8":1,"20":1,"24":1,"33":1,"52":2,"55":1,"71":1,"83":1,"93":1,"101":1,"103":2,"114":1,"133":1,"138":1,"148":1,"150":1,"153":1,"203":1,"256":1}}],["more",{"2":{"5":1,"7":1,"8":1,"11":1,"14":1,"24":2,"37":1,"39":2,"49":1,"54":1,"55":1,"58":1,"59":3,"62":1,"70":1,"83":1,"84":1,"87":1,"90":1,"92":1,"95":1,"97":1,"99":2,"122":1,"145":1,"146":1,"155":1,"157":1,"162":1,"165":1,"166":1,"171":3,"175":1,"184":1,"185":1,"186":1,"215":1,"250":1}}],["mechanics",{"2":{"254":1}}],["mechanism",{"2":{"83":1}}],["message",{"2":{"144":1}}],["mersennetwister",{"2":{"110":1,"168":2,"224":1}}],["merged",{"2":{"66":1}}],["merge",{"2":{"31":1,"32":1,"66":2,"109":1,"184":1}}],["mentioned",{"2":{"79":1,"140":1}}],["measure",{"2":{"53":1}}],["meanpool",{"2":{"65":1}}],["meant",{"2":{"33":1,"52":1,"58":1,"169":1}}],["means",{"2":{"24":1,"30":1,"59":1,"112":1,"140":1,"142":1,"155":1,"171":1,"173":1,"219":2}}],["meaningless",{"2":{"17":1}}],["mean",{"2":{"17":2,"19":13,"24":2,"53":17,"65":7,"69":13,"125":1,"126":2,"129":1,"132":1,"142":1,"179":1,"242":3,"244":12,"249":1,"250":1}}],["medical",{"2":{"53":1}}],["medium",{"2":{"18":1}}],["met",{"2":{"24":1,"33":1}}],["methodinstance",{"2":{"213":3}}],["methoderror",{"2":{"110":1}}],["methods",{"2":{"70":1,"78":1,"149":1,"153":1,"169":2,"207":1,"208":1,"215":2,"216":1,"219":1,"232":1,"239":1,"249":1,"254":2}}],["method",{"2":{"24":3,"107":1,"110":1,"113":1,"126":1,"150":1,"151":1,"152":1,"183":1,"185":1,"186":1,"192":1,"194":1,"195":1,"206":1,"207":1,"209":1,"224":1,"233":1,"234":1,"235":1,"242":2,"249":1,"250":2,"254":3,"256":1,"257":2}}],["metaldevice",{"2":{"4":2}}],["metal",{"2":{"2":1,"3":2,"22":1,"72":2,"77":1,"78":1,"80":2,"115":4,"164":1}}],["memory=false",{"2":{"66":1}}],["memory=zeros32",{"2":{"66":1}}],["memory",{"2":{"5":1,"16":1,"18":1,"66":20,"180":2,"184":1,"189":2,"197":1,"214":2,"221":2,"229":2,"237":2,"246":2,"251":1,"260":1}}],["mutability",{"0":{"173":1}}],["mutables",{"2":{"134":1}}],["mutable",{"2":{"134":1,"140":1}}],["mutations",{"2":{"81":1,"83":2,"103":1}}],["mutation",{"2":{"16":1,"18":1,"173":2}}],["mutating",{"2":{"16":1,"18":1}}],["mutate",{"2":{"173":1}}],["mutated",{"2":{"15":1,"55":1,"173":2,"174":1}}],["mutates",{"2":{"8":1}}],["much",{"2":{"53":2,"83":1,"120":1,"250":1}}],["mul",{"2":{"14":2,"158":1}}],["multilayer",{"2":{"222":1}}],["multigate",{"2":{"54":1}}],["multiply",{"2":{"171":1}}],["multiplied",{"2":{"17":1}}],["multiplication",{"2":{"14":3}}],["multiple",{"0":{"146":1},"2":{"16":1,"18":1,"62":1,"66":1,"69":1,"115":1,"153":2,"250":1}}],["multi",{"0":{"4":1},"2":{"53":1,"67":1}}],["must",{"2":{"1":1,"3":2,"4":1,"7":1,"19":1,"24":4,"28":2,"32":2,"34":2,"37":1,"39":2,"42":1,"46":2,"52":3,"60":1,"62":3,"63":2,"64":3,"66":7,"67":4,"69":1,"70":1,"82":4,"83":1,"119":1,"140":1,"143":1,"227":1,"254":4}}],["major",{"0":{"88":1,"91":1,"95":1},"2":{"85":1,"92":1}}],["masses",{"2":{"254":1}}],["mass2",{"2":{"254":5}}],["mass1",{"2":{"254":6}}],["mass",{"2":{"254":14,"255":2,"256":1,"257":1,"259":1}}],["mass=1",{"2":{"254":3}}],["massachusetts",{"2":{"74":1}}],["master",{"2":{"119":1}}],["mask",{"2":{"17":9,"64":10}}],["magnitude",{"2":{"69":2}}],["maeloss",{"2":{"53":2}}],["made",{"2":{"52":1,"85":1,"90":1,"93":1,"140":1,"144":1}}],["making",{"2":{"52":1,"81":1,"83":1,"93":1,"113":1,"153":1}}],["makes",{"2":{"32":1,"53":1,"66":1,"83":1,"100":1,"138":1}}],["make",{"2":{"10":2,"34":1,"52":1,"55":6,"66":1,"81":2,"83":1,"120":1,"125":1,"133":1,"140":1,"142":1,"145":1,"146":1,"153":1,"161":1,"171":1,"175":1,"183":1,"249":1,"256":2}}],["macro",{"2":{"48":1,"49":1,"59":4,"78":2,"113":1,"138":2,"185":1,"207":2}}],["machines",{"2":{"53":2}}],["machine",{"2":{"17":1,"19":1,"24":1,"149":1,"171":1,"196":1,"254":1}}],["maxiters",{"2":{"244":4}}],["maxiters=1000",{"2":{"258":1}}],["maxiters=500",{"2":{"219":1}}],["maxiters=epochs",{"2":{"219":1}}],["maximum",{"2":{"16":1,"18":1,"68":1,"243":2,"245":1}}],["maxout",{"2":{"68":5}}],["max",{"2":{"53":2,"65":4,"68":1,"243":8,"245":1,"250":1}}],["maxpool",{"2":{"39":2,"65":1,"193":6}}],["margin=2",{"2":{"53":1}}],["margin−y^",{"2":{"53":1}}],["margin",{"2":{"53":2}}],["marker=",{"2":{"255":1,"256":2,"259":4}}],["markersize=16",{"2":{"248":2}}],["markersize=12",{"2":{"224":1,"228":2,"255":1,"256":2,"259":4}}],["marked",{"2":{"5":1,"56":3,"59":1}}],["mark",{"2":{"59":2,"256":1}}],["marks",{"2":{"48":2,"93":1}}],["martens",{"2":{"24":1}}],["main",{"0":{"24":1},"2":{"47":1,"111":1,"112":1,"140":1,"160":1,"184":1,"187":3,"207":1,"213":18,"218":2,"228":2,"241":1}}],["maintaining",{"2":{"19":1}}],["matches",{"2":{"186":2}}],["matched",{"2":{"110":5}}],["matching",{"0":{"57":1},"2":{"110":1}}],["match",{"2":{"32":1,"57":4,"66":5,"143":2,"155":1,"165":1}}],["matrices",{"2":{"18":1,"67":1}}],["matrix",{"2":{"5":3,"14":3,"15":1,"18":2,"24":13,"53":6,"59":4,"67":6,"68":1,"78":1,"110":3,"111":1,"112":1,"113":2,"125":5,"126":13,"146":1,"147":1,"148":1,"149":5,"153":1,"168":4,"171":13,"175":3,"218":2}}],["matmul",{"2":{"14":2,"150":1,"151":1,"158":1}}],["maps",{"2":{"24":2,"53":1,"65":3,"66":2}}],["mapping",{"2":{"24":7,"53":1}}],["map",{"0":{"32":1},"2":{"7":1,"32":4,"55":2,"66":4,"97":2,"98":1,"129":2,"130":1,"153":2,"250":1}}],["managing",{"0":{"174":1},"2":{"174":1}}],["management",{"0":{"115":1,"116":1,"117":1},"1":{"116":1,"117":1},"2":{"93":1,"115":1,"116":4}}],["manager",{"2":{"76":1}}],["manage",{"2":{"59":1}}],["many",{"2":{"146":1,"171":1,"175":1}}],["mandatorily",{"2":{"140":1}}],["manual",{"0":{"117":1},"2":{"8":1,"29":1,"31":1,"58":1,"127":1,"128":1,"144":1,"162":1,"172":1}}],["manually",{"2":{"2":1,"37":1,"39":1,"119":1,"138":1,"172":1}}],["manipulation",{"2":{"7":2,"83":1}}],["maybe",{"2":{"57":1,"175":1}}],["may",{"2":{"3":1,"59":3,"70":2,"196":1,"203":1}}],["min",{"2":{"243":10,"245":2}}],["minibatching",{"2":{"215":1,"219":1}}],["minibatch",{"2":{"183":1,"192":1,"206":1}}],["mini",{"2":{"177":1}}],["minimum",{"2":{"243":4,"245":2}}],["minimally",{"2":{"252":1}}],["minimal",{"2":{"123":1}}],["minimized",{"2":{"257":1}}],["minimize",{"2":{"18":1}}],["minimizes",{"2":{"16":1,"179":1}}],["minor",{"2":{"144":1,"153":1}}],["mig",{"2":{"180":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["migrating",{"0":{"133":1},"1":{"134":1,"135":1,"136":1,"137":1}}],["migration",{"0":{"120":1},"1":{"121":1,"122":1},"2":{"140":1}}],["might",{"2":{"2":1,"8":1,"13":1,"15":1,"37":1,"39":1,"52":3,"58":2,"59":1,"62":1,"68":1,"105":1,"113":1,"114":1,"115":1,"127":1,"140":2,"144":1,"145":2,"155":1,"159":1,"167":2,"171":1,"173":1,"196":1,"212":1,"219":1}}],["miopen",{"2":{"100":1}}],["mirza",{"2":{"68":1}}],["milletari",{"2":{"53":1}}],["mixing",{"2":{"28":1}}],["mixed",{"2":{"16":1,"27":2}}],["mistakes",{"2":{"83":1}}],["misc",{"0":{"68":1}}],["miscellaneous",{"0":{"3":1,"60":1},"2":{"62":1}}],["mismatch",{"0":{"125":1},"2":{"57":3,"122":1,"155":1,"165":1}}],["missing",{"2":{"19":1,"42":1,"69":1}}],["s3",{"2":{"259":2}}],["s0025",{"2":{"254":2}}],["s2",{"2":{"228":2,"256":2,"259":2}}],["s1",{"2":{"228":2,"256":2,"259":2}}],["sgd",{"2":{"179":1}}],["src",{"2":{"110":1,"125":1,"145":2,"213":3,"244":4}}],["srivastava",{"2":{"17":1}}],["sz",{"2":{"109":2}}],["szegedy",{"2":{"19":1}}],["switch",{"2":{"64":3,"93":1,"144":1,"175":1}}],["switching",{"0":{"36":1},"1":{"37":1},"2":{"144":4,"162":2}}],["square",{"2":{"171":2,"243":1}}],["squaredhingeloss",{"2":{"53":2}}],["squared",{"2":{"53":3,"179":1}}],["sqrt",{"2":{"24":4,"63":2,"66":6,"67":3,"249":1,"255":2}}],["sm",{"2":{"180":1,"189":2,"214":1,"221":1,"229":1,"237":1,"246":1}}],["smarter",{"2":{"243":1}}],["smatrix",{"2":{"153":4}}],["smaller",{"2":{"83":1}}],["small",{"2":{"18":1,"39":1,"83":1,"113":1,"155":1,"171":1,"190":1,"219":1}}],["smodel",{"2":{"145":3,"146":4,"147":2,"148":2,"150":2,"151":2,"152":2,"219":3}}],["smooth",{"2":{"53":2}}],["smoothing=0",{"2":{"53":3}}],["smoothing",{"2":{"53":16}}],["skipped",{"2":{"62":1,"254":1}}],["skipconnection",{"2":{"62":4}}],["skip",{"2":{"49":3,"62":1,"113":1,"243":1}}],["speedup",{"2":{"196":2}}],["spectralnorm",{"2":{"83":1}}],["specify",{"2":{"53":1,"59":1,"64":2,"70":1,"131":1,"249":1}}],["specifying",{"2":{"24":1,"48":1,"59":1,"63":2,"65":3,"69":2}}],["specifies",{"2":{"63":4,"65":3,"68":1,"177":1}}],["specified",{"2":{"2":1,"24":2,"49":1,"62":8,"67":1,"68":3,"70":1,"116":1,"169":1}}],["specifically",{"2":{"136":1,"171":1}}],["specifications",{"2":{"127":1}}],["specification",{"0":{"125":1},"2":{"249":1}}],["specific",{"2":{"4":2,"8":1,"55":1,"67":1,"104":1,"164":1}}],["specialized",{"2":{"13":1,"20":1,"59":1,"153":1,"173":1}}],["special",{"2":{"3":2,"18":2,"44":2,"53":1,"59":1,"66":1,"104":1,"213":3}}],["spiralclassifiercompact",{"2":{"185":2,"187":1}}],["spiralclassifier",{"2":{"184":5,"187":1}}],["spiral",{"2":{"183":1}}],["spirals",{"2":{"181":1,"183":6}}],["spiritual",{"2":{"118":1}}],["spurious",{"0":{"155":1}}],["space",{"2":{"66":6}}],["spatial",{"2":{"63":5,"65":6,"243":1}}],["sparsity=0",{"2":{"24":1}}],["sparsity",{"2":{"24":4}}],["sparsely",{"2":{"24":2,"67":1}}],["sparse",{"2":{"24":2}}],["spliced",{"2":{"66":2}}],["split=",{"2":{"192":1,"206":1}}],["splitobs",{"2":{"183":1,"192":1,"205":1,"206":1}}],["split",{"2":{"54":1,"119":2,"183":1,"184":1,"192":2,"206":2}}],["splatted",{"2":{"59":1}}],["splatting",{"2":{"59":1}}],["scientific",{"2":{"254":1}}],["scientificmachinelearning",{"2":{"252":1}}],["scimlsensitivity",{"2":{"205":1,"213":26,"216":1,"253":1}}],["sciml",{"2":{"58":1,"59":1,"78":1,"83":2,"177":1}}],["scatter",{"2":{"224":1,"228":2,"248":2,"255":1,"256":2,"259":4}}],["scalable",{"2":{"150":1}}],["scalar",{"0":{"156":1},"2":{"3":2,"20":1,"114":1,"156":1,"176":1,"241":1}}],["scale=ones32",{"2":{"69":4}}],["scaled",{"2":{"24":3}}],["scale",{"2":{"19":15,"67":2,"69":20,"70":6,"126":1,"132":1,"145":1}}],["scaling",{"2":{"17":2,"24":2,"254":6}}],["scratch",{"2":{"179":1,"184":1,"204":1}}],["schwarzschild",{"2":{"255":1}}],["school",{"2":{"74":1}}],["schemes",{"2":{"21":1,"168":1}}],["score",{"2":{"53":1}}],["slow",{"2":{"145":2}}],["slower",{"2":{"124":1}}],["slices",{"2":{"54":1}}],["slice",{"2":{"19":2,"24":1,"66":2,"69":2}}],["slightly",{"2":{"62":1}}],["slight",{"2":{"13":1,"175":1}}],["sleefpirates",{"2":{"13":2}}],["s",{"2":{"10":1,"20":1,"57":3,"58":1,"59":1,"62":1,"64":2,"67":1,"69":3,"70":1,"72":1,"77":1,"83":1,"113":2,"114":1,"120":2,"125":1,"126":1,"129":1,"134":1,"140":1,"141":1,"144":2,"145":3,"147":1,"148":1,"149":1,"152":3,"153":1,"155":1,"170":4,"171":5,"176":1,"179":2,"184":5,"186":1,"188":1,"210":1,"215":1,"219":2,"224":3,"225":1,"228":1,"249":2,"255":3}}],["syntax",{"2":{"59":1,"62":1,"171":2,"172":1}}],["synchronized",{"2":{"119":2}}],["synchronize",{"2":{"44":2,"119":6,"120":2,"122":2,"153":2}}],["symbol",{"2":{"10":1,"33":1,"59":1,"69":1,"113":1,"142":1,"188":1,"213":29,"249":2}}],["systems",{"2":{"17":1,"77":1,"83":2,"167":1}}],["system",{"2":{"2":1,"3":1,"113":1,"115":2,"142":1,"175":1,"238":1,"255":1,"256":1}}],["safely",{"2":{"256":1}}],["saveat=tsteps",{"2":{"255":1,"256":1,"257":1,"259":1}}],["saveat=t",{"2":{"217":1,"219":1,"220":1}}],["save",{"2":{"188":4,"208":2,"213":26}}],["saving",{"0":{"188":1},"2":{"188":1}}],["sake",{"2":{"184":1,"186":1,"243":1}}],["sarray",{"2":{"153":7}}],["sarrays",{"2":{"153":1}}],["sanity",{"2":{"152":1}}],["sampling",{"2":{"243":1,"247":1}}],["sampler",{"2":{"249":1}}],["sampled",{"2":{"249":2}}],["samples",{"2":{"179":15,"249":2,"250":2}}],["sample",{"2":{"149":3,"152":1,"249":3,"250":1}}],["samepad",{"2":{"63":2,"65":3}}],["same",{"0":{"112":1},"2":{"3":1,"5":2,"7":3,"13":2,"15":1,"17":1,"19":3,"24":1,"27":2,"32":1,"33":1,"34":1,"52":2,"54":2,"57":2,"62":1,"63":2,"65":3,"66":3,"68":2,"69":1,"71":1,"78":1,"82":2,"113":1,"119":1,"141":1,"146":1,"152":2,"153":1,"172":1,"174":1,"178":1,"187":1,"190":1,"207":1}}],["saw",{"2":{"114":1}}],["say",{"2":{"83":1,"129":1}}],["satisfactory",{"2":{"250":1}}],["satisfying",{"2":{"63":2,"65":6,"140":1}}],["satisfies",{"2":{"39":2,"68":1}}],["satisfied",{"2":{"8":1,"227":1}}],["said",{"2":{"30":1}}],["saxe",{"2":{"24":1}}],["sorted",{"2":{"84":1}}],["soln",{"2":{"254":13,"255":2,"256":2,"259":2}}],["soln2orbit",{"2":{"254":3}}],["solution",{"2":{"243":5,"245":1}}],["solutions",{"2":{"24":1}}],["sol",{"2":{"220":2}}],["solves",{"2":{"219":1}}],["solve",{"2":{"207":2,"211":1,"217":1,"219":4,"220":1,"238":1,"255":1,"256":1,"257":1,"258":1,"259":1}}],["solver",{"2":{"207":6,"211":3,"213":7}}],["solver=tsit5",{"2":{"207":2,"211":1}}],["solvers",{"2":{"83":1}}],["society",{"2":{"53":1}}],["software",{"2":{"74":2}}],["softmax",{"2":{"53":5}}],["softfail",{"2":{"50":2}}],["soft",{"2":{"49":4}}],["sooner",{"2":{"30":1}}],["so",{"2":{"13":1,"77":1,"134":1,"144":3,"145":1,"146":1,"207":2,"211":2,"218":1,"227":1,"240":1,"241":1}}],["sometimes",{"2":{"171":2}}],["somewhere",{"2":{"37":1,"39":1}}],["some",{"0":{"217":1,"254":1},"2":{"8":1,"33":1,"37":2,"59":1,"66":1,"68":1,"83":1,"85":1,"97":1,"101":1,"103":1,"104":1,"105":1,"118":1,"122":1,"124":1,"126":1,"131":1,"134":1,"141":1,"144":7,"145":1,"155":1,"158":1,"160":2,"171":1,"210":1,"233":1,"243":1}}],["source",{"2":{"1":1,"2":3,"3":8,"4":2,"5":1,"7":3,"8":7,"9":2,"10":5,"11":1,"13":2,"14":1,"15":2,"16":1,"17":2,"18":1,"19":4,"20":1,"24":8,"25":24,"27":2,"28":1,"31":5,"32":1,"33":2,"34":1,"37":3,"39":3,"41":2,"42":3,"43":2,"44":4,"45":1,"46":1,"48":2,"49":2,"50":1,"52":6,"53":15,"54":8,"55":6,"56":3,"57":1,"58":1,"59":3,"60":1,"62":6,"63":2,"64":3,"65":9,"66":6,"67":4,"68":7,"69":5,"70":2,"90":1,"170":2}}],["situations",{"2":{"123":1}}],["si+1",{"2":{"63":1,"65":3}}],["siamese",{"2":{"53":1}}],["siamesecontrastiveloss",{"2":{"53":3}}],["sig",{"2":{"249":2}}],["sigmoid",{"2":{"53":3,"184":1,"185":1,"249":2}}],["signify",{"2":{"85":1,"92":1}}],["significantly",{"2":{"138":1,"210":1}}],["significant",{"2":{"8":1,"196":1,"212":1}}],["signature",{"2":{"17":1,"32":1}}],["silently",{"2":{"34":1}}],["sided",{"2":{"254":2}}],["side",{"2":{"16":1,"59":1}}],["size=1000",{"2":{"183":1}}],["sizes",{"2":{"18":1,"24":2,"90":1}}],["sized",{"2":{"18":1,"19":1,"54":1}}],["size",{"0":{"11":1},"2":{"11":2,"13":2,"19":3,"24":24,"25":72,"28":2,"37":1,"39":1,"59":6,"62":1,"63":16,"65":48,"66":11,"67":16,"68":8,"69":7,"70":8,"100":1,"109":1,"150":2,"151":2,"153":2,"171":1,"179":2,"180":1,"183":7,"189":1,"192":3,"197":1,"206":3,"207":2,"210":1,"214":1,"221":1,"229":1,"237":1,"246":1,"249":4,"250":1,"251":1,"254":4,"260":1}}],["sin",{"2":{"254":1}}],["singular",{"0":{"140":1},"2":{"140":1,"141":2}}],["singleton",{"2":{"7":3,"63":2,"65":3,"90":2,"91":1}}],["single",{"2":{"7":2,"8":1,"15":1,"16":1,"52":5,"53":1,"59":1,"63":6,"65":9,"66":13,"77":2,"78":1,"90":1,"114":3,"134":1,"141":1,"146":1,"149":1,"153":4,"171":1,"179":1,"187":1,"195":1,"210":1,"228":1,"236":1,"244":1,"249":1}}],["since",{"2":{"8":1,"24":1,"32":1,"59":1,"71":1,"83":1,"90":1,"107":1,"114":1,"119":1,"142":1,"177":1,"184":1,"186":1,"219":2,"240":1}}],["simultaneously",{"2":{"142":1}}],["simulate",{"2":{"126":1,"254":1,"255":1,"256":2}}],["simulating",{"0":{"255":1},"2":{"24":1}}],["simd",{"2":{"20":1}}],["simplicity",{"2":{"149":1,"186":1,"243":1}}],["simplified",{"2":{"140":1}}],["simplest",{"2":{"62":1}}],["simplechainslayer",{"2":{"39":2,"193":1}}],["simplechains",{"0":{"190":1},"1":{"191":1,"192":1,"193":1,"194":1,"195":1,"196":1,"197":1},"2":{"39":14,"83":1,"190":3,"191":2,"193":1,"196":2}}],["simple",{"0":{"39":1,"181":1},"1":{"182":1,"183":1,"184":1,"185":1,"186":1,"187":1,"188":1,"189":1},"2":{"17":2,"20":1,"39":4,"52":1,"59":1,"66":1,"113":1,"116":2,"134":1,"136":1,"170":1,"176":1,"193":1,"196":1,"215":1}}],["simply",{"2":{"8":1,"13":1,"52":1,"56":1,"57":1,"59":1,"71":1,"112":1,"114":1,"124":1,"131":1,"142":1,"233":1,"249":1}}],["similarly",{"2":{"141":1}}],["similarity",{"2":{"5":1}}],["similar",{"2":{"2":1,"3":1,"7":1,"19":1,"53":1,"54":1,"55":1,"66":1,"67":1,"113":1,"114":1,"133":1,"142":1,"160":1,"175":1,"256":1}}],["ship",{"2":{"124":1}}],["shifted",{"2":{"24":1}}],["shift",{"2":{"19":1,"24":4,"69":4}}],["shuffle=true",{"2":{"183":2,"192":1,"206":1,"232":1,"244":2}}],["shuffle=false",{"2":{"5":1,"183":1,"192":1,"206":1,"232":1}}],["shuffle",{"2":{"70":1,"183":2,"192":2,"206":2}}],["shuffling",{"2":{"70":1}}],["shapedaxis",{"2":{"213":30}}],["shaped",{"2":{"65":9}}],["shape",{"2":{"63":1,"66":16,"68":1,"69":17,"125":4,"171":1,"179":4}}],["shate",{"2":{"34":1}}],["sharing",{"2":{"34":9}}],["share",{"2":{"34":4}}],["shared",{"2":{"19":2,"34":1,"93":1}}],["shooting",{"2":{"219":1}}],["shortcomings",{"0":{"123":1}}],["shortcut",{"2":{"8":1,"62":1}}],["short",{"2":{"66":1,"175":1}}],["shorthand",{"2":{"8":1}}],["shown",{"2":{"249":1}}],["showcasing",{"2":{"203":1}}],["showing",{"2":{"152":1}}],["shows",{"2":{"142":1,"148":1,"149":1,"152":1,"250":1}}],["showerror",{"2":{"110":1}}],["show",{"2":{"5":2,"77":1,"145":1,"172":1,"215":1,"247":1}}],["shouldn",{"2":{"52":1,"90":1,"142":1,"147":1}}],["should",{"0":{"107":1},"2":{"4":2,"15":1,"20":1,"31":1,"34":1,"39":1,"41":2,"52":2,"53":1,"55":1,"59":1,"63":5,"65":6,"66":1,"69":1,"70":1,"93":1,"94":1,"115":1,"128":1,"133":1,"134":2,"140":2,"141":2,"142":1,"155":1,"173":1,"174":1,"204":1,"225":1,"256":1}}],["stencils",{"2":{"254":2}}],["stepnorm=0",{"2":{"258":1}}],["steprangelen",{"2":{"218":2}}],["steps",{"2":{"52":1,"77":1,"114":1,"249":1}}],["step",{"2":{"52":10,"77":1,"78":1,"114":3,"179":1,"187":1,"195":1,"210":1,"228":2,"236":1,"244":1,"249":3}}],["stime",{"2":{"195":2,"210":2,"236":2}}],["stick",{"2":{"175":1}}],["still",{"0":{"137":1},"2":{"2":1,"8":1,"39":1,"112":1,"115":1,"125":1,"140":1,"141":1,"184":1,"213":1,"225":1,"250":1}}],["stop=6",{"2":{"250":4}}],["stochastic",{"2":{"82":1,"83":1,"179":1}}],["stores",{"2":{"58":1,"64":1,"67":1,"122":1,"134":1,"171":1,"207":1}}],["stored",{"2":{"52":3,"63":1}}],["store",{"2":{"44":2,"67":1,"82":2,"134":1,"219":1,"248":1,"256":1,"257":1}}],["storing",{"2":{"19":1,"111":1,"134":1}}],["std=1e",{"2":{"256":3}}],["std=0",{"2":{"24":1}}],["stdlib",{"2":{"174":1}}],["stdout",{"2":{"110":1}}],["std",{"2":{"19":1,"24":5,"249":1}}],["stylization",{"2":{"19":1,"69":1}}],["stage",{"2":{"144":1}}],["start=false",{"2":{"208":1}}],["start",{"2":{"113":1,"170":1,"213":13,"247":1}}],["starting",{"2":{"88":1,"115":1,"171":1,"211":1}}],["started",{"0":{"75":1,"84":1},"1":{"76":1,"77":1,"78":1,"79":1,"80":1},"2":{"133":1}}],["stacktraces",{"2":{"124":1}}],["stacktrace",{"2":{"97":2,"125":1}}],["stack",{"2":{"66":2,"243":6,"245":2}}],["stackedrnncells",{"2":{"66":1}}],["standard",{"2":{"24":3,"25":6,"63":2,"69":1,"77":1,"145":1,"256":1}}],["stabilities",{"2":{"212":1}}],["stability",{"0":{"213":1},"2":{"8":1,"19":4,"53":1,"59":1,"69":4,"85":1,"92":1,"166":1}}],["stablerng",{"2":{"145":3,"146":3,"147":2,"148":2,"152":3}}],["stablerngs",{"2":{"22":1,"144":1}}],["stable",{"2":{"52":1,"55":5,"59":2,"166":1,"186":1,"207":1,"213":1}}],["stats=false",{"2":{"69":5}}],["stats=true",{"2":{"62":2,"69":7,"125":1,"126":2}}],["stats",{"2":{"52":2,"77":2,"114":1,"244":7}}],["staticint",{"2":{"193":2}}],["staticarrayscore",{"2":{"153":4}}],["staticarrays",{"2":{"153":1}}],["staticsymbol",{"2":{"33":1,"54":2}}],["static",{"2":{"20":1,"39":1,"54":1,"58":1,"77":8,"110":2,"113":3,"153":7,"193":4,"213":58,"228":2}}],["staticbool",{"2":{"17":1,"33":1,"54":1}}],["statistics",{"2":{"19":2,"24":2,"52":2,"69":7,"100":1,"182":1,"191":1,"205":1,"223":1,"227":1,"231":1,"239":1,"249":1}}],["state=false",{"2":{"66":4}}],["state=zeros32",{"2":{"66":3}}],["statements",{"2":{"59":1}}],["statefulneuralode",{"2":{"211":4,"212":1,"213":5}}],["statefulrecurrentcell",{"2":{"66":2}}],["statefulluxlayers",{"2":{"144":1}}],["statefulluxlayer",{"2":{"58":1,"98":4,"144":7,"145":1,"146":1,"147":1,"148":1,"150":1,"151":1,"152":1,"211":2,"219":2,"242":7,"244":2,"249":2,"256":2}}],["stateful",{"0":{"58":1,"211":1,"212":1},"2":{"66":2,"145":1,"146":1,"148":2,"213":6}}],["stateless",{"2":{"8":1,"68":1}}],["statelength",{"2":{"7":1,"10":1,"140":4,"141":1}}],["state",{"0":{"143":1},"2":{"7":1,"8":3,"10":5,"17":2,"19":1,"31":1,"37":1,"52":7,"58":4,"59":7,"62":6,"64":4,"66":64,"68":1,"69":4,"77":8,"78":4,"82":3,"83":3,"114":4,"119":5,"134":1,"140":5,"141":3,"143":4,"184":3,"187":7,"195":8,"219":6,"227":1,"236":11,"244":6,"249":2,"256":1}}],["states",{"0":{"10":1},"2":{"3":1,"7":4,"8":1,"10":2,"31":4,"32":6,"33":1,"34":1,"37":1,"39":1,"52":2,"53":2,"56":2,"57":4,"58":1,"59":5,"62":16,"64":3,"66":5,"68":2,"69":7,"77":2,"78":2,"90":2,"109":1,"114":1,"119":2,"125":2,"126":1,"129":3,"132":1,"134":3,"138":1,"140":5,"141":3,"143":1,"179":2,"184":2,"187":2,"188":1,"193":2,"195":2,"207":1,"210":2,"225":1,"227":1,"228":4,"236":4,"244":1,"249":1,"256":1}}],["st",{"2":{"7":2,"8":4,"10":6,"31":2,"32":6,"34":1,"37":4,"39":2,"52":1,"53":2,"54":2,"57":1,"58":4,"59":19,"62":6,"66":1,"68":14,"77":4,"78":6,"98":2,"107":3,"109":7,"110":2,"111":10,"112":2,"113":14,"114":6,"119":2,"125":5,"126":7,"129":9,"130":7,"131":6,"132":2,"133":3,"134":6,"140":7,"141":11,"142":3,"143":2,"145":7,"146":7,"147":6,"148":6,"150":2,"151":2,"152":9,"153":8,"155":5,"179":6,"184":10,"186":4,"187":7,"188":3,"194":4,"195":2,"207":4,"208":4,"209":4,"210":2,"211":7,"213":16,"219":5,"227":1,"228":1,"235":4,"236":2,"242":7,"244":3,"249":2,"256":2}}],["strain",{"2":{"254":5}}],["strokewidth=2",{"2":{"224":1,"228":2,"248":2,"256":2,"259":4}}],["strokecolor=",{"2":{"224":1,"228":2,"248":2}}],["strongly",{"2":{"173":1}}],["struct",{"2":{"109":1,"134":3,"138":1,"140":1,"188":1,"218":1}}],["structs",{"2":{"56":3}}],["structured",{"2":{"66":3,"142":1,"233":1}}],["structures",{"2":{"55":2,"83":1,"155":1}}],["structure",{"2":{"3":5,"7":2,"8":3,"27":2,"32":4,"34":1,"44":1,"55":3,"67":1,"125":5,"126":13,"134":1,"140":2,"141":2,"143":1,"210":1}}],["strength",{"2":{"53":1}}],["stride=window",{"2":{"65":3}}],["stride=1",{"2":{"63":2}}],["stride",{"2":{"63":5,"65":6}}],["stridearray",{"2":{"39":1}}],["stridearrayscore",{"2":{"39":1}}],["strings",{"2":{"98":1}}],["string=",{"2":{"60":2}}],["string",{"2":{"1":2,"3":1,"48":1,"60":1}}],["surprise",{"2":{"155":1}}],["surpassing",{"2":{"24":2}}],["sure",{"2":{"142":1,"256":1}}],["super",{"2":{"254":1}}],["supertype",{"2":{"141":1}}],["suppose",{"2":{"250":1}}],["supposed",{"2":{"83":1,"97":1,"166":1}}],["supporting",{"2":{"103":1}}],["support",{"0":{"4":1,"72":1,"73":1,"80":1,"104":1,"163":1},"2":{"3":4,"4":4,"7":2,"16":2,"18":2,"31":1,"53":2,"55":1,"58":1,"65":3,"77":2,"78":2,"80":5,"83":3,"88":2,"92":1,"101":1,"102":1,"103":1,"105":1,"115":2,"123":1,"136":1,"142":1}}],["supports",{"2":{"3":1,"59":1,"100":1,"136":1,"163":1,"171":1,"172":1,"240":1}}],["supported",{"0":{"22":1},"2":{"2":1,"3":2,"20":1,"27":2,"28":1,"37":1,"52":6,"57":1,"65":3,"70":1,"77":1,"82":2,"92":1,"104":2,"105":1,"115":2,"160":1,"168":2}}],["supplied",{"2":{"42":1,"62":1}}],["supply",{"2":{"42":1}}],["suggests",{"2":{"68":1}}],["subtracts",{"2":{"171":1}}],["subtract",{"2":{"171":1}}],["subtyping",{"2":{"141":1}}],["subtype",{"2":{"140":1,"141":2}}],["subarray",{"2":{"54":1}}],["suboptimal",{"2":{"52":1,"153":1}}],["sumit",{"2":{"53":1}}],["sum",{"2":{"48":3,"49":2,"59":5,"126":2,"133":2,"134":2,"145":1,"146":1,"147":2,"148":1,"150":1,"151":1,"186":1,"194":1,"209":1,"235":1,"242":3,"254":1}}],["summary",{"2":{"5":8,"134":1,"249":1}}],["success",{"2":{"258":1}}],["successor",{"2":{"118":1}}],["successfully",{"2":{"1":1}}],["such",{"2":{"4":2,"6":1,"8":1,"59":1,"63":2,"65":6,"83":1,"113":1,"127":1,"169":1,"185":1,"233":1}}],["seaborn",{"2":{"250":3}}],["seamlessly",{"2":{"52":1}}],["seq",{"2":{"183":1}}],["sequentially",{"2":{"62":2,"66":5}}],["sequences",{"2":{"183":1}}],["sequence=true",{"2":{"66":2}}],["sequence",{"2":{"62":1,"66":9,"183":7,"184":3}}],["separately",{"2":{"172":1}}],["separation",{"2":{"83":1}}],["separating",{"2":{"83":1}}],["several",{"2":{"161":1,"175":1}}],["sensealg=reversediffadjoint",{"2":{"210":1}}],["sensealg=gaussadjoint",{"2":{"210":1}}],["sensealg=interpolatingadjoint",{"2":{"208":1,"210":1}}],["sensealg",{"2":{"208":1,"210":1,"213":13}}],["sensitivities",{"2":{"207":1,"210":1}}],["sensible",{"2":{"83":1}}],["sensibly",{"2":{"54":1}}],["sensical",{"2":{"59":1}}],["send",{"2":{"84":1}}],["sendbuf",{"2":{"44":6}}],["sendrecvbuf",{"2":{"44":6}}],["seyed",{"2":{"53":1}}],["segmentation",{"2":{"53":2}}],["sec",{"2":{"249":1}}],["section",{"2":{"39":1,"62":2,"76":1,"127":1,"146":1,"162":1,"172":1,"254":1}}],["seconds",{"2":{"249":2}}],["second",{"2":{"17":1,"62":1,"171":1,"177":1,"254":2}}],["server",{"2":{"180":1,"189":1,"196":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["serves",{"2":{"37":1}}],["serious",{"2":{"238":1}}],["seriously",{"2":{"77":1}}],["serializes",{"2":{"119":1}}],["serialization",{"2":{"119":1,"188":1}}],["series",{"2":{"72":2}}],["sergey",{"2":{"19":1}}],["semvar",{"2":{"98":1}}],["semver",{"2":{"30":1}}],["semantic",{"2":{"145":2}}],["semantically",{"2":{"62":1}}],["semantics",{"2":{"5":2,"155":1}}],["semi",{"2":{"24":2}}],["self",{"2":{"17":1}}],["selu",{"2":{"17":1}}],["selecting",{"2":{"154":1}}],["selection",{"0":{"164":1},"2":{"2":1,"3":1,"116":1,"117":1,"164":1}}],["selectdim",{"2":{"68":1}}],["select",{"2":{"2":4}}],["selected",{"0":{"203":1},"2":{"2":3,"3":1,"97":1}}],["selects",{"2":{"2":1}}],["seems",{"2":{"258":2}}],["seeding",{"2":{"77":1}}],["seed",{"2":{"62":1,"68":4,"77":1,"78":1,"83":1,"132":1,"140":1,"142":1,"170":1,"174":2,"179":1,"208":1,"224":1,"244":3,"248":1}}],["see",{"2":{"3":1,"7":3,"8":3,"11":1,"14":1,"15":2,"17":2,"19":4,"31":1,"33":2,"34":1,"37":1,"39":2,"49":1,"52":1,"53":1,"55":2,"57":1,"58":2,"59":2,"60":1,"62":4,"64":3,"66":5,"68":2,"69":4,"70":1,"76":1,"83":2,"87":1,"90":3,"92":1,"97":2,"99":2,"113":1,"114":1,"118":1,"122":1,"124":1,"125":3,"126":2,"141":1,"155":2,"159":1,"162":1,"165":1,"166":1,"168":1,"171":2,"172":1,"184":1,"196":1,"212":1,"250":2,"254":2}}],["session",{"2":{"1":1,"60":1}}],["setprogress",{"2":{"247":1}}],["sets",{"2":{"48":1,"166":2}}],["setindexing",{"2":{"16":1,"18":1}}],["setups",{"2":{"148":1}}],["setup",{"2":{"8":1,"32":1,"34":1,"37":1,"39":1,"59":6,"62":1,"68":4,"77":1,"78":1,"110":1,"112":1,"113":1,"114":1,"119":1,"125":2,"126":2,"129":1,"132":1,"133":1,"134":1,"140":2,"141":1,"142":1,"145":1,"146":1,"147":1,"148":1,"152":1,"153":1,"155":1,"179":1,"187":1,"195":1,"208":1,"219":1,"227":1,"236":1,"244":1,"249":1,"256":1}}],["setfield",{"2":{"7":1,"90":1,"231":1}}],["setting",{"0":{"257":1},"2":{"4":2,"63":2,"66":4,"67":3,"126":1,"144":1,"157":1,"166":2,"167":1}}],["set",{"2":{"1":2,"2":1,"4":6,"17":4,"19":4,"20":1,"24":1,"31":2,"34":1,"37":2,"39":1,"42":2,"48":1,"49":1,"53":2,"55":1,"58":1,"59":3,"60":5,"63":2,"64":1,"66":18,"70":2,"73":3,"85":1,"116":1,"122":1,"126":2,"144":1,"145":4,"157":2,"161":2,"162":1,"163":3,"164":3,"166":2,"179":3,"247":1}}],["os",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["oops",{"2":{"155":1}}],["ok",{"2":{"147":1}}],["oh",{"2":{"126":1}}],["own",{"2":{"123":1,"142":1,"171":1}}],["our",{"2":{"77":1,"83":1,"104":1,"126":3,"136":1,"145":1,"149":1,"155":2,"170":1,"171":1,"173":1,"174":1,"176":1,"179":2,"183":1,"184":1,"215":1,"219":3,"227":1,"228":1,"238":1,"248":1,"249":3,"250":4}}],["outperforms",{"2":{"105":1}}],["outpad",{"2":{"63":3,"100":1}}],["outpad=0",{"2":{"63":1}}],["outputs",{"2":{"11":1,"33":1,"39":1,"58":1,"62":2,"66":6,"68":2,"82":1,"114":1,"146":1,"147":1,"174":1,"176":1,"256":1}}],["outputsize",{"2":{"11":3,"90":1}}],["output",{"2":{"11":1,"13":2,"16":1,"17":3,"18":1,"24":6,"33":1,"39":2,"53":6,"58":1,"59":2,"62":7,"63":8,"65":33,"66":13,"67":7,"68":4,"69":1,"70":4,"78":1,"100":1,"113":2,"125":4,"126":14,"140":1,"143":2,"153":13,"155":1,"174":1,"184":1,"207":1,"241":1,"249":2}}],["outside",{"2":{"55":1,"97":2}}],["out",{"2":{"17":2,"24":2,"30":1,"55":1,"59":10,"62":1,"63":8,"64":2,"65":3,"66":15,"67":19,"78":6,"85":2,"124":1,"126":1,"138":1,"140":8,"143":1,"157":1,"184":3,"185":2,"210":1,"247":1}}],["o=σ",{"2":{"66":1}}],["oi=",{"2":{"63":1,"65":3}}],["o",{"2":{"63":4,"65":6}}],["odefunction",{"2":{"207":2,"211":1}}],["odeproblem",{"2":{"207":2,"211":1,"217":1,"219":1,"220":1,"255":1,"256":1,"259":1}}],["odesolution",{"2":{"207":1}}],["odes",{"0":{"204":1},"1":{"205":1,"206":1,"207":1,"208":1,"209":1,"210":1,"211":1,"212":1,"213":1,"214":1},"2":{"83":1,"108":1,"204":2,"255":1,"256":1}}],["ode",{"0":{"207":1,"208":1,"212":1,"252":1},"1":{"253":1,"254":1,"255":1,"256":1,"257":1,"258":1,"259":1,"260":1},"2":{"58":1,"108":1,"207":2,"208":1,"215":3,"217":3,"218":1,"219":2,"220":2,"255":3,"256":6,"257":1,"259":2}}],["odd",{"2":{"24":1}}],["old",{"2":{"52":1,"87":1,"91":2,"115":2}}],["older",{"0":{"36":1},"1":{"37":1},"2":{"97":1,"122":1}}],["observe",{"2":{"249":1}}],["observations",{"2":{"63":1}}],["obviously",{"2":{"124":1}}],["obtain",{"2":{"119":1}}],["obtained",{"2":{"20":1}}],["obj",{"2":{"52":2,"141":2,"142":1}}],["objects",{"2":{"53":1,"94":3,"113":1,"117":1,"155":1,"218":1}}],["objective",{"2":{"52":8,"257":1}}],["object",{"2":{"2":3,"3":4,"16":1,"27":2,"52":6,"53":2,"116":3,"119":1}}],["occurs",{"2":{"126":1}}],["occurred",{"2":{"126":3}}],["occurrences",{"2":{"10":3}}],["octavian",{"0":{"167":1},"2":{"18":2,"159":1,"167":1}}],["other",{"0":{"25":1,"35":1},"1":{"36":1,"37":1,"38":1,"39":1},"2":{"5":1,"8":1,"16":1,"24":1,"25":1,"39":1,"44":2,"49":1,"53":1,"55":2,"62":1,"63":1,"68":2,"70":1,"77":1,"78":1,"88":1,"97":1,"105":1,"114":1,"138":1,"140":1,"141":1,"171":1,"175":1,"188":1,"215":1}}],["otherwisewhere",{"2":{"53":1}}],["otherwise",{"2":{"1":1,"2":2,"3":1,"60":1,"67":1}}],["opening",{"2":{"144":1}}],["open",{"2":{"103":1,"113":1,"123":1,"127":1,"153":1,"202":1,"203":2}}],["operating",{"2":{"66":1}}],["operation",{"2":{"16":2,"18":1,"20":4,"44":4,"65":3,"70":1,"175":1}}],["operations",{"0":{"14":1,"55":1},"2":{"2":1,"16":3,"18":1,"28":1,"39":1,"54":2,"55":1,"88":1,"144":2,"153":2,"167":1,"172":1}}],["operates",{"2":{"113":1}}],["operate",{"2":{"66":1,"134":1}}],["operators",{"2":{"68":1}}],["operator",{"2":{"55":1}}],["optprob",{"2":{"258":2}}],["optf",{"2":{"258":2}}],["opt",{"2":{"48":6,"119":5,"179":2,"219":10,"228":1}}],["optimal",{"2":{"219":1}}],["optim",{"2":{"59":2}}],["optimiser",{"0":{"186":1}}],["optimisers",{"2":{"37":2,"45":1,"52":2,"59":3,"77":10,"78":1,"113":1,"119":1,"134":2,"137":1,"179":2,"181":1,"182":1,"191":1,"205":1,"215":1,"219":2,"223":1,"226":1,"231":1,"239":1,"244":1}}],["optimizer",{"0":{"226":1},"2":{"45":4,"52":4,"119":3,"228":2}}],["optimizers",{"0":{"45":1},"2":{"258":1}}],["optimized",{"2":{"20":1,"159":1,"167":1,"219":1}}],["optimizationproblem",{"2":{"219":2,"258":1}}],["optimizationfunction",{"2":{"219":1,"258":1}}],["optimizationoptimjl",{"2":{"216":1,"253":1}}],["optimizationoptimisers",{"2":{"216":1}}],["optimizations",{"2":{"97":1,"113":1}}],["optimization",{"0":{"215":1},"1":{"216":1,"217":1,"218":1,"219":1,"220":1,"221":1},"2":{"24":1,"77":1,"78":3,"113":1,"215":4,"216":1,"219":8,"253":1,"258":4}}],["options",{"2":{"57":1,"164":1}}],["option",{"2":{"20":1,"57":2,"70":2,"103":2}}],["optional",{"0":{"159":1},"2":{"16":1,"18":1,"24":1,"31":3,"53":1,"58":1,"59":2,"66":1,"90":1,"167":1,"169":1}}],["optionally",{"2":{"7":1,"24":1,"69":1,"140":1,"169":1}}],["op",{"2":{"4":2,"5":1,"19":1,"44":6,"48":1,"54":3,"57":1,"95":1}}],["orbit₂",{"2":{"254":2}}],["orbit₁",{"2":{"254":2}}],["orbits",{"2":{"254":1}}],["orbit2",{"2":{"254":4}}],["orbit2tensor",{"2":{"254":2}}],["orbit1",{"2":{"254":4}}],["orbit",{"2":{"254":17}}],["orange",{"2":{"224":1,"228":1}}],["ordinarydiffeqloworderrk",{"2":{"253":1}}],["ordinarydiffeqcore",{"2":{"213":26}}],["ordinarydiffeq",{"2":{"207":1,"255":1}}],["ordinarydiffeqtsit5",{"2":{"205":1,"213":13,"216":1}}],["ordering",{"2":{"66":6}}],["order",{"0":{"29":1},"2":{"2":1,"31":1,"63":1,"102":1,"145":1,"147":1,"177":1,"240":3,"242":1,"254":2}}],["orcjit",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["originates",{"2":{"33":1}}],["originally",{"2":{"252":1}}],["original",{"2":{"24":1,"31":1,"34":1,"37":1,"113":1,"125":1,"173":2}}],["org",{"2":{"24":1,"68":1,"74":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"254":2,"260":1}}],["orthogonal",{"2":{"22":4,"24":6}}],["or",{"2":{"2":3,"3":2,"4":2,"8":1,"16":2,"17":3,"18":1,"19":2,"20":2,"24":2,"31":1,"33":3,"37":1,"39":2,"44":3,"52":1,"53":5,"54":2,"59":3,"60":1,"62":7,"63":6,"65":9,"66":3,"67":7,"70":4,"72":1,"76":1,"77":1,"83":2,"84":1,"103":1,"114":1,"122":2,"123":1,"126":2,"134":1,"136":1,"140":2,"141":1,"144":1,"147":1,"155":1,"158":2,"163":1,"169":1,"171":4,"172":1,"183":1,"202":1,"203":2,"254":1}}],["overview",{"0":{"102":1}}],["overloaded",{"2":{"97":1}}],["overloading",{"2":{"55":1}}],["overcome",{"2":{"37":1}}],["overridden",{"2":{"18":1}}],["overrides",{"2":{"49":1}}],["override",{"2":{"11":1,"37":1}}],["overfitting",{"2":{"17":2}}],["over",{"0":{"32":1,"83":1},"2":{"2":1,"5":2,"32":1,"33":1,"58":1,"66":1,"68":1,"69":3,"77":1,"128":1,"181":1,"218":1,"228":1,"238":1,"241":1,"257":1,"259":1}}],["onlinestats",{"2":{"239":1,"244":4}}],["online",{"2":{"203":1}}],["only",{"2":{"2":1,"8":1,"33":2,"49":3,"52":1,"53":3,"57":2,"59":1,"63":1,"64":1,"65":3,"66":9,"67":1,"70":1,"113":1,"119":1,"131":1,"141":1,"142":1,"144":2,"147":1,"148":1,"153":2,"176":2,"188":1,"206":1,"242":3}}],["once",{"2":{"11":1,"57":1,"66":2,"126":1,"140":1,"172":1,"173":1,"175":1}}],["onwards",{"2":{"7":1,"97":1}}],["on",{"0":{"106":1,"156":1,"230":1,"238":1},"1":{"107":1,"108":1,"109":1,"110":1,"111":1,"112":1,"231":1,"232":1,"233":1,"234":1,"235":1,"236":1,"237":1,"239":1,"240":1,"241":1,"242":1,"243":1,"244":1,"245":1,"246":1},"2":{"2":2,"3":6,"5":1,"6":2,"7":1,"8":2,"13":2,"14":3,"15":1,"16":3,"18":3,"19":4,"24":11,"29":2,"30":1,"31":1,"32":2,"39":1,"44":2,"48":1,"53":5,"55":3,"58":2,"59":2,"60":1,"62":2,"63":2,"64":2,"65":6,"66":2,"67":1,"71":1,"74":1,"76":1,"77":1,"83":1,"84":2,"88":1,"90":2,"98":1,"99":2,"100":1,"103":2,"105":1,"107":2,"111":1,"113":2,"119":1,"123":1,"127":1,"134":4,"138":2,"140":2,"143":1,"144":4,"145":4,"146":1,"147":2,"153":3,"155":2,"156":1,"157":1,"159":1,"160":2,"161":2,"162":1,"165":1,"166":1,"168":1,"170":1,"171":1,"172":1,"174":3,"177":2,"180":1,"189":1,"196":2,"197":1,"202":1,"210":2,"214":1,"215":1,"218":1,"219":2,"221":1,"222":1,"229":1,"233":1,"237":1,"243":2,"246":1,"249":1,"251":1,"260":1}}],["one2two",{"2":{"254":3}}],["onecold",{"2":{"194":2,"209":2,"235":2}}],["onehotbatch",{"2":{"192":1,"195":1,"206":1,"232":2}}],["onehotarrays",{"2":{"191":1,"205":1,"231":1}}],["onearray",{"2":{"22":3}}],["oneapidevice",{"2":{"4":2}}],["oneapi",{"2":{"2":1,"3":2,"22":1,"72":2,"77":1,"78":1,"80":2,"115":2,"164":1}}],["onesc64",{"2":{"25":1}}],["onesc32",{"2":{"25":1}}],["onesc16",{"2":{"25":1}}],["ones64",{"2":{"25":1}}],["ones32",{"2":{"25":1}}],["ones16",{"2":{"25":1}}],["ones",{"2":{"8":1,"25":7,"59":1,"109":1,"171":2,"177":1,"213":1,"243":2,"248":1,"249":1}}],["one",{"2":{"1":1,"33":1,"53":1,"56":1,"62":2,"66":1,"69":2,"70":2,"119":1,"144":1,"158":2,"169":1,"171":1,"202":1,"203":1,"249":1,"254":4}}],["official",{"2":{"154":1,"180":1,"189":1,"197":1,"203":1,"214":1,"215":1,"221":1,"229":1,"237":1,"246":1,"247":2,"251":1,"260":1}}],["off",{"2":{"149":1}}],["offending",{"2":{"126":9}}],["ofcourse",{"2":{"125":1}}],["often",{"2":{"3":1,"67":1,"104":2,"108":1,"143":1,"149":1,"152":1,"155":1,"158":2,"171":2,"215":1,"249":1}}],["of",{"0":{"129":1,"131":1,"132":1,"148":1},"2":{"1":1,"3":7,"4":3,"6":1,"7":2,"8":17,"9":3,"10":6,"11":4,"14":2,"15":2,"16":1,"17":4,"18":1,"19":8,"24":31,"25":36,"27":6,"28":6,"30":2,"31":6,"32":11,"33":2,"34":9,"37":7,"39":3,"42":2,"43":1,"47":1,"48":1,"49":7,"52":11,"53":13,"54":1,"55":10,"56":4,"57":10,"58":8,"59":16,"62":32,"63":38,"64":3,"65":42,"66":37,"67":32,"68":23,"69":30,"70":13,"71":1,"74":3,"76":1,"78":2,"83":5,"85":3,"90":2,"91":1,"92":2,"93":2,"95":2,"97":6,"99":2,"100":1,"101":2,"105":1,"108":2,"112":1,"113":6,"114":1,"119":4,"122":2,"125":1,"126":6,"129":2,"130":1,"131":3,"134":1,"138":3,"140":3,"141":4,"142":1,"143":3,"145":1,"146":6,"147":1,"148":1,"149":6,"153":1,"155":1,"158":4,"159":1,"161":1,"162":1,"163":1,"166":4,"167":1,"168":1,"171":9,"172":1,"173":1,"175":4,"177":1,"179":3,"181":1,"183":1,"184":3,"185":2,"186":1,"188":1,"196":1,"202":2,"203":2,"204":1,"207":5,"211":1,"212":1,"213":1,"215":1,"228":2,"233":2,"238":3,"240":1,"243":1,"247":2,"248":2,"249":6,"250":3,"254":5,"255":2,"256":3}}],["bfgs",{"2":{"215":1,"219":1,"258":2}}],["bs",{"2":{"192":1,"206":1}}],["bh2",{"2":{"254":1}}],["bh",{"2":{"254":1}}],["bhn",{"2":{"66":2}}],["bhz",{"2":{"66":2}}],["bhr",{"2":{"66":2}}],["bright",{"2":{"250":3}}],["break",{"2":{"244":1}}],["breaking",{"0":{"87":1,"90":1,"94":1,"97":1,"98":1,"99":1},"2":{"92":1}}],["branched",{"2":{"62":1}}],["branchlayer",{"2":{"62":5}}],["broken=true",{"2":{"48":2}}],["broken=false",{"2":{"48":2}}],["broken",{"2":{"30":1,"48":5,"49":4,"50":1}}],["broadcastfunction",{"2":{"113":1}}],["broadcastable",{"2":{"69":1}}],["broadcast",{"2":{"44":1,"64":1,"68":1,"113":1,"249":1}}],["broadcasted",{"2":{"15":1,"16":2,"44":2,"53":1}}],["broadcasting",{"2":{"13":1,"20":1,"171":1}}],["b=f",{"2":{"134":1}}],["b=layer",{"2":{"134":1}}],["b=",{"2":{"59":1}}],["b=zeros",{"2":{"59":1}}],["bc",{"2":{"242":7,"243":21,"244":120}}],["bce",{"2":{"53":5}}],["bcast",{"2":{"44":2}}],["bigger",{"2":{"171":1}}],["bigfloat",{"2":{"171":3}}],["bit",{"2":{"147":1,"219":1}}],["bibtex",{"2":{"74":2}}],["bilinear",{"2":{"67":3,"70":6,"99":1}}],["bidirectional",{"2":{"66":1}}],["bidirectionalrnn",{"2":{"66":1}}],["biz",{"2":{"66":1}}],["bir",{"2":{"66":1}}],["bin",{"2":{"53":7,"66":1}}],["binarycrossentropy",{"2":{"186":2}}],["binarycrossentropyloss",{"2":{"53":7,"186":1}}],["binaryfocalloss",{"2":{"53":3}}],["binary",{"2":{"53":3,"183":1}}],["bias=l",{"2":{"140":1}}],["bias=false",{"2":{"66":6,"67":3}}],["bias=true",{"2":{"63":4,"66":2,"67":6}}],["bias=nothing",{"2":{"63":1,"66":3,"67":3}}],["bias=ps",{"2":{"59":1}}],["bias=zeros32",{"2":{"63":1,"67":1,"69":4,"140":1,"256":3}}],["bias=zero",{"2":{"32":1}}],["biases",{"2":{"24":1,"249":1}}],["bias",{"0":{"15":1},"2":{"15":12,"16":3,"18":3,"19":15,"31":1,"32":4,"34":4,"59":1,"63":12,"66":25,"67":22,"69":20,"77":15,"100":4,"110":2,"113":12,"126":3,"129":4,"130":2,"131":2,"132":1,"140":6,"142":4,"145":3,"147":4,"148":4,"158":5,"166":1,"179":1,"213":30,"227":2,"249":1,"256":3,"258":3}}],["bn=batchnorm",{"2":{"32":1}}],["black",{"2":{"224":1,"228":2,"248":2}}],["blas",{"2":{"8":1,"18":1}}],["blue",{"2":{"217":1,"220":2,"224":1,"248":1}}],["block",{"2":{"59":3,"62":1,"65":3,"184":1}}],["blocks",{"2":{"52":1,"66":1,"184":1}}],["blog",{"2":{"39":1}}],["blisblas",{"2":{"18":1}}],["b",{"2":{"16":4,"17":2,"18":3,"28":3,"59":6,"65":6,"67":4,"116":1,"125":2,"134":9,"142":2,"146":8,"158":2,"179":8,"244":8,"254":4}}],["bulk",{"2":{"249":1}}],["builds",{"2":{"110":3,"125":1,"145":2,"213":3,"244":4}}],["buildkite",{"2":{"110":3,"125":1,"145":2,"180":1,"189":1,"197":1,"213":3,"214":1,"221":1,"229":1,"237":1,"244":4,"246":1,"251":1,"260":1}}],["build",{"2":{"77":1,"163":3,"170":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["building",{"0":{"249":1},"2":{"52":1}}],["built",{"0":{"61":1},"1":{"62":1,"63":1,"64":1,"65":1,"66":1,"67":1,"68":1,"69":1,"70":1},"2":{"81":1,"138":2,"173":1,"196":1}}],["buffer",{"2":{"16":1,"18":1,"44":3}}],["bugs",{"2":{"84":1,"93":1,"142":1}}],["bug",{"2":{"11":1,"59":1,"153":1,"202":1}}],["but",{"2":{"3":2,"7":2,"8":1,"13":1,"14":1,"15":1,"19":1,"24":1,"27":2,"37":1,"39":3,"54":3,"55":5,"57":2,"59":4,"68":1,"70":2,"82":1,"83":2,"90":1,"101":1,"104":3,"105":2,"113":1,"115":1,"118":1,"125":3,"126":2,"140":2,"141":1,"142":1,"145":3,"146":1,"147":1,"152":1,"153":1,"155":2,"160":1,"167":1,"179":1,"184":2,"186":1,"210":1,"212":1,"218":1,"225":1,"243":1,"249":1,"256":1}}],["box",{"2":{"248":1}}],["boxing",{"2":{"58":1,"211":1,"213":1}}],["borrow",{"2":{"247":1}}],["borders",{"2":{"63":2,"65":3}}],["book",{"2":{"177":1}}],["boom",{"2":{"147":1}}],["bool=true",{"2":{"66":1}}],["bool=false",{"2":{"2":2,"37":2,"39":1,"48":1,"66":4,"208":1,"210":1}}],["boolean",{"2":{"8":1,"39":1,"50":1}}],["bool",{"2":{"2":1,"3":5,"8":3,"33":1,"39":1,"53":2,"54":1,"55":1,"213":26}}],["boilerplate",{"2":{"113":1,"114":1,"185":1}}],["boundaries",{"2":{"250":1}}],["boundary",{"2":{"242":1}}],["bound",{"2":{"63":6,"66":18,"67":9}}],["bounds",{"2":{"63":2,"66":6,"67":3}}],["bottom",{"2":{"59":1,"113":1}}],["both",{"2":{"2":1,"33":2,"53":2,"77":1,"81":1,"100":1,"126":3,"134":1,"163":1,"166":1,"203":1,"249":1}}],["body",{"2":{"59":2,"213":3,"254":9}}],["bypasses",{"2":{"59":2}}],["bypass",{"2":{"11":1,"141":1,"164":1}}],["by",{"0":{"130":1},"2":{"2":1,"7":1,"8":2,"11":1,"13":2,"16":1,"18":1,"19":1,"24":5,"39":1,"52":3,"53":2,"54":1,"56":1,"59":2,"62":2,"63":5,"65":3,"66":5,"67":5,"68":1,"69":1,"70":1,"76":1,"77":1,"83":2,"90":1,"97":1,"113":2,"116":1,"117":1,"119":3,"126":1,"130":3,"131":2,"138":1,"144":3,"145":2,"148":1,"149":1,"155":1,"156":1,"157":1,"163":1,"167":1,"171":2,"172":2,"173":1,"175":1,"181":1,"193":1,"203":1,"213":1,"218":1,"227":2,"247":1,"249":1,"250":1}}],["bayes",{"2":{"249":3}}],["bayesian",{"0":{"247":1},"1":{"248":1,"249":1,"250":1,"251":1},"2":{"248":1,"250":1}}],["battery",{"2":{"83":1}}],["batches",{"2":{"192":1,"206":1}}],["batched",{"0":{"14":1,"28":1,"146":1},"2":{"11":1,"14":6,"28":1,"144":1,"146":8,"150":1,"151":1,"158":2}}],["batchsize=32",{"2":{"244":2}}],["batchsize=256",{"2":{"232":1}}],["batchsize=min",{"2":{"232":2}}],["batchsize=8",{"2":{"218":2}}],["batchsize=128",{"2":{"183":2}}],["batchsize=12",{"2":{"160":2}}],["batchsize=13",{"2":{"5":1}}],["batchsize",{"2":{"192":3,"206":3,"232":4}}],["batching",{"2":{"153":3}}],["batchlastindex",{"2":{"54":1,"66":2}}],["batchnorm",{"2":{"7":1,"19":1,"62":4,"69":8,"125":4,"126":4,"129":1,"132":1,"133":2,"136":1,"140":1,"143":1,"145":2,"146":1}}],["batch",{"2":{"5":1,"19":6,"28":3,"39":1,"63":3,"65":3,"66":13,"68":1,"69":6,"70":3,"87":1,"146":1,"153":6,"183":1,"218":1,"219":9,"244":8}}],["basis",{"2":{"63":2,"67":1}}],["basically",{"2":{"141":1}}],["basic",{"2":{"52":2,"170":1}}],["baseline",{"2":{"53":1}}],["base",{"2":{"48":3,"54":3,"64":1,"68":1,"97":1,"110":1,"142":1,"144":3,"147":1,"148":2,"208":1,"213":25,"215":1,"218":2,"256":2}}],["based",{"2":{"2":1,"3":2,"18":1,"19":1,"55":1,"62":1,"84":1,"99":2,"100":1,"145":1,"149":1,"170":1,"215":1}}],["bad",{"2":{"33":1,"155":1,"250":1}}],["ba",{"2":{"19":1}}],["backtracking",{"2":{"258":1}}],["background",{"2":{"140":1,"155":1,"255":1}}],["backward",{"2":{"33":2,"54":1,"66":11,"126":3,"127":1,"173":1}}],["back",{"2":{"2":1,"3":1,"13":1,"142":1}}],["backendtpu",{"2":{"73":1}}],["backendgpu",{"2":{"73":1}}],["backends=",{"2":{"49":2}}],["backends",{"0":{"41":1},"2":{"1":1,"2":4,"3":5,"5":1,"16":3,"18":4,"20":1,"27":6,"28":2,"49":7,"52":5,"82":2,"95":1,"104":3,"115":3,"153":1,"160":1,"162":1,"172":1,"177":1,"210":1}}],["backend",{"0":{"38":1,"116":1,"117":1,"164":1},"1":{"39":1},"2":{"1":17,"2":3,"3":1,"12":1,"27":6,"28":3,"41":5,"42":20,"43":4,"44":11,"45":1,"46":1,"49":1,"52":4,"73":4,"88":1,"116":5,"119":14,"120":2,"122":1,"144":1,"153":6,"164":4,"175":1,"215":1}}],["bernoulli",{"2":{"249":1}}],["became",{"2":{"155":1}}],["because",{"2":{"142":1,"258":1}}],["become",{"2":{"140":1,"181":1}}],["benchmarking",{"2":{"196":1}}],["benefits",{"2":{"113":1}}],["bengio",{"2":{"24":2,"68":1}}],["behind",{"2":{"90":1}}],["behaving",{"2":{"169":1}}],["behaviour",{"2":{"90":1}}],["behavior",{"2":{"3":2,"7":2,"8":1,"11":2,"24":1,"57":3,"66":1,"145":2,"155":1,"184":1}}],["behaves",{"2":{"62":1,"91":1,"160":1}}],["behave",{"2":{"54":1}}],["better",{"2":{"83":1,"84":1}}],["between",{"0":{"35":1},"1":{"36":1,"37":1,"38":1,"39":1},"2":{"24":1,"34":1,"37":1,"53":1,"67":1,"83":1,"113":1,"122":1,"134":3,"250":3}}],["beginner",{"0":{"199":1}}],["begin",{"2":{"63":2,"65":3,"217":1,"220":1,"243":1,"245":1,"255":1,"256":1,"259":1}}],["beyond",{"2":{"62":1}}],["been",{"2":{"37":2,"83":1,"87":2,"90":6,"94":3,"97":10,"98":5,"100":1,"104":1,"121":1,"148":1,"170":1,"252":1}}],["below",{"2":{"32":1,"57":2,"62":1,"74":1,"207":1,"248":1,"249":2,"250":1}}],["beware",{"2":{"25":1,"142":1}}],["being",{"2":{"15":1,"17":2,"19":2,"55":1,"69":4,"88":1,"95":1,"103":2,"123":1,"144":1,"145":2,"155":1,"196":1,"219":1}}],["best",{"2":{"13":2,"16":1,"18":1,"37":1,"59":2,"103":2,"104":1}}],["before",{"2":{"8":2,"24":2,"42":1,"45":1,"46":1,"62":1,"78":1,"114":1,"119":1,"140":1,"174":1,"188":1}}],["be",{"2":{"1":2,"2":1,"3":10,"4":5,"6":1,"7":4,"8":2,"10":1,"13":2,"14":1,"15":3,"16":1,"17":4,"18":1,"19":20,"20":1,"24":8,"28":5,"31":2,"33":3,"34":5,"37":5,"39":5,"42":7,"44":2,"46":2,"48":3,"49":3,"50":4,"52":9,"53":5,"55":3,"58":2,"59":16,"60":2,"62":13,"63":16,"64":4,"65":9,"66":17,"67":8,"68":8,"69":4,"70":3,"71":1,"74":1,"77":1,"81":1,"82":3,"83":2,"84":1,"85":1,"93":1,"94":1,"97":1,"98":1,"109":1,"113":3,"115":2,"117":1,"119":2,"120":1,"124":1,"127":1,"128":1,"130":1,"133":1,"134":6,"136":1,"138":1,"140":1,"142":2,"143":1,"144":2,"145":5,"146":2,"148":1,"150":1,"155":1,"159":1,"164":1,"166":3,"167":2,"169":3,"171":1,"173":1,"174":1,"175":1,"176":1,"181":1,"184":1,"196":2,"202":1,"203":1,"211":1,"219":1,"225":1,"234":1,"238":2,"243":1,"248":1,"249":1,"254":4,"257":1}}],["ixy",{"2":{"254":2}}],["ixx",{"2":{"254":3}}],["iyy",{"2":{"254":3}}],["i∈",{"2":{"179":1}}],["iid",{"2":{"249":1}}],["iii",{"2":{"102":2,"104":1}}],["ii",{"2":{"102":2,"104":1}}],["ii+pi+p",{"2":{"63":1,"65":3}}],["i=σ",{"2":{"66":1}}],["ih",{"2":{"66":6,"100":1}}],["i+n",{"2":{"63":1,"65":3}}],["ignore",{"2":{"233":1,"256":1}}],["ignores",{"2":{"37":1}}],["ignored",{"2":{"2":1,"24":1,"67":3}}],["iclr",{"2":{"24":1}}],["ieee",{"2":{"24":2,"53":5}}],["ioffe",{"2":{"19":1}}],["imgs",{"2":{"192":5,"206":5,"232":4}}],["im",{"0":{"173":1}}],["immutability",{"2":{"174":1}}],["immutable",{"2":{"13":1,"16":1,"18":1,"55":1,"82":1,"83":1,"173":1}}],["immediately",{"2":{"113":1}}],["imbalanced",{"2":{"53":1}}],["images",{"2":{"69":3,"70":2,"192":1,"206":1}}],["image",{"2":{"53":1,"63":2}}],["imagenet",{"2":{"24":2,"118":1}}],["imply",{"2":{"143":1}}],["implements",{"2":{"47":1}}],["implemented",{"2":{"37":1,"83":1,"134":1,"144":1}}],["implementations",{"2":{"13":1,"14":1,"18":1,"20":1,"52":1,"55":1,"122":1,"167":1}}],["implementation",{"0":{"109":1,"135":1,"211":1},"1":{"136":1},"2":{"11":4,"13":3,"16":4,"18":6,"31":1,"52":1,"55":5,"58":2,"62":1,"66":1,"90":1,"122":1,"149":1,"207":1}}],["implement",{"0":{"233":1},"2":{"7":1,"31":1,"134":1,"140":2,"247":1}}],["implementing",{"0":{"134":1},"2":{"7":2,"83":1,"108":1,"204":1,"247":1}}],["improving",{"2":{"105":1}}],["imports",{"0":{"182":1,"191":1,"205":1,"216":1,"223":1,"231":1,"239":1,"253":1}}],["importing",{"2":{"140":1,"170":1,"247":1}}],["important",{"0":{"135":1},"1":{"136":1},"2":{"115":1,"119":2,"134":1,"140":1,"145":1,"146":1}}],["importantly",{"2":{"114":1,"171":1,"250":1}}],["imported",{"2":{"59":1}}],["import",{"2":{"37":1,"39":1,"79":1,"247":1}}],["i",{"2":{"5":10,"11":1,"24":1,"31":1,"37":1,"39":1,"52":2,"53":3,"57":1,"58":1,"59":1,"62":9,"63":6,"65":21,"67":4,"68":8,"70":2,"78":1,"90":2,"102":4,"104":1,"109":3,"119":1,"143":1,"147":1,"153":6,"174":4,"177":1,"179":4,"218":2,"244":3,"245":6,"248":12,"249":7,"250":10}}],["ith",{"2":{"62":1}}],["its",{"2":{"8":1,"65":3,"67":1,"68":1,"69":1,"71":1,"83":1,"250":1}}],["itself",{"2":{"3":1,"68":1,"125":1}}],["iter",{"2":{"78":4,"114":12,"219":2,"244":7,"257":1}}],["iteratively",{"2":{"62":1}}],["iterations",{"2":{"179":12,"249":2}}],["iteration",{"0":{"5":1},"2":{"5":2,"78":12,"108":1,"114":4,"160":1,"174":8,"218":1,"219":26,"244":101,"250":1,"257":1,"259":1}}],["iterate",{"2":{"5":1,"30":1}}],["iterates",{"2":{"5":1}}],["iterators",{"2":{"5":1,"184":1,"185":1,"243":1,"244":2,"245":1}}],["iterator",{"2":{"5":3,"114":1}}],["item",{"2":{"5":1}}],["it",{"2":{"2":1,"3":2,"4":5,"7":3,"8":6,"11":2,"13":3,"15":2,"16":2,"17":1,"24":3,"30":1,"31":1,"32":1,"34":1,"37":3,"47":2,"50":2,"52":1,"53":5,"54":1,"55":3,"57":3,"58":1,"59":5,"62":2,"63":4,"65":3,"66":8,"68":1,"69":7,"70":3,"74":1,"76":1,"78":1,"81":1,"83":4,"90":1,"98":1,"100":1,"101":1,"105":3,"107":1,"113":5,"116":1,"119":2,"120":1,"124":2,"125":1,"126":3,"138":2,"140":2,"141":5,"142":4,"144":3,"145":6,"146":2,"152":1,"153":2,"155":1,"156":2,"157":1,"160":1,"164":1,"167":1,"170":1,"171":2,"172":1,"173":2,"174":2,"177":1,"179":1,"184":4,"186":2,"202":1,"203":1,"207":1,"215":1,"218":2,"219":2,"233":2,"249":2,"254":1,"256":2}}],["inlined",{"2":{"244":4}}],["in2",{"2":{"67":6}}],["in12",{"2":{"67":3}}],["in1",{"2":{"67":8}}],["injection",{"2":{"62":5}}],["independent",{"2":{"146":1}}],["index",{"2":{"62":1,"67":1,"68":2,"153":1,"250":1}}],["indexing",{"0":{"156":1},"2":{"20":1,"62":1,"68":1,"156":1}}],["indexed",{"2":{"2":2,"4":2,"68":1,"84":1}}],["individual",{"2":{"68":1,"219":1}}],["individually",{"2":{"62":1,"70":2,"146":1}}],["indices",{"2":{"67":2}}],["inplace",{"2":{"52":2}}],["input",{"0":{"106":1,"112":1},"1":{"107":1,"108":1,"109":1,"110":1,"111":1,"112":1},"2":{"8":2,"13":2,"15":1,"16":1,"17":3,"18":2,"19":9,"24":4,"27":2,"28":1,"33":2,"39":3,"53":4,"58":1,"59":1,"62":30,"63":7,"64":2,"65":6,"66":20,"67":12,"68":7,"69":14,"70":6,"77":1,"108":1,"113":1,"119":1,"120":1,"122":1,"125":6,"126":14,"140":1,"143":2,"146":3,"148":1,"153":8,"155":2,"165":1,"166":1,"169":1,"184":1,"193":1,"207":1,"241":1,"256":1}}],["inputsize",{"2":{"66":1,"90":1}}],["inputs",{"0":{"146":1},"2":{"8":2,"11":1,"16":3,"18":1,"28":1,"32":1,"33":1,"52":1,"53":4,"55":1,"58":1,"62":9,"63":2,"64":3,"65":9,"66":11,"67":1,"68":6,"69":5,"70":2,"82":1,"98":1,"113":1,"122":1,"144":1,"146":2,"147":1,"148":1,"178":1,"207":2,"227":1,"249":1,"256":1}}],["inner",{"2":{"31":2,"33":1,"130":1}}],["incase",{"2":{"256":1}}],["including",{"2":{"93":1,"113":1}}],["included",{"2":{"24":1,"83":1}}],["include",{"2":{"7":1,"8":1,"24":1}}],["inconvenient",{"2":{"107":1}}],["inconsistent",{"2":{"90":1}}],["incorrectly",{"2":{"155":1}}],["incorrect",{"0":{"125":1},"2":{"28":2,"59":1,"124":1,"127":1}}],["increase",{"2":{"63":1,"100":1}}],["initilly",{"2":{"64":1}}],["initializing",{"0":{"168":1},"1":{"169":1},"2":{"59":1,"119":1}}],["initialize",{"0":{"208":1,"234":1},"2":{"42":5,"59":3,"77":1,"78":1,"119":3,"120":1,"122":1,"153":1,"179":1,"224":1,"249":1}}],["initialized",{"2":{"24":4,"42":2,"69":8}}],["initializers",{"2":{"24":1}}],["initializer",{"2":{"24":1,"59":3,"66":10,"67":7}}],["initializations",{"2":{"99":2}}],["initialization",{"0":{"42":1},"2":{"21":1,"24":2,"39":1,"42":1,"63":4,"99":1,"134":1,"168":1,"184":1,"233":1,"256":1}}],["initial",{"2":{"9":1,"10":1,"59":2,"62":1,"66":11,"83":1,"90":1,"134":1,"184":1,"255":1,"256":1,"258":2}}],["initialstates",{"2":{"7":3,"8":1,"10":1,"134":2,"140":2,"184":1}}],["initialparameters",{"2":{"7":3,"8":1,"9":1,"134":2,"140":2,"184":1,"233":3}}],["init",{"2":{"24":7,"54":6,"59":6,"63":10,"66":26,"67":21,"69":16,"99":2,"100":1,"120":1,"134":4,"140":10,"169":8,"184":2,"185":2,"256":6}}],["ingredient",{"2":{"19":1,"69":1}}],["investigate",{"2":{"212":1}}],["investigated",{"2":{"123":1}}],["inversability",{"2":{"63":1}}],["inverse",{"2":{"17":1}}],["inv",{"2":{"63":2,"66":6,"67":3,"254":1}}],["involving",{"2":{"58":1}}],["invokes",{"2":{"32":1}}],["invoked",{"2":{"2":1,"184":1}}],["invariant",{"2":{"53":1}}],["invp",{"2":{"17":4}}],["informed",{"2":{"242":3}}],["informs",{"2":{"141":1}}],["information",{"2":{"8":1,"11":1,"17":1,"29":1,"33":1,"49":1,"57":1,"82":1,"83":1,"122":1,"157":1,"203":1,"215":1}}],["info",{"2":{"115":1,"117":1,"125":8,"126":20,"180":2,"189":2,"197":2,"214":2,"221":2,"229":2,"237":2,"246":2,"247":2,"251":2,"260":2}}],["inf",{"2":{"53":1,"145":2,"146":2,"147":2,"148":2,"152":4}}],["inference",{"0":{"136":1},"2":{"33":1,"64":3,"69":6,"74":1,"136":1,"145":2,"153":2,"249":2}}],["inferred",{"2":{"19":1}}],["infinity",{"2":{"17":1}}],["int=50000",{"2":{"244":1}}],["int=32",{"2":{"241":1,"244":1}}],["int=0",{"2":{"44":5,"244":1}}],["intro",{"2":{"170":1}}],["introduction",{"2":{"91":1}}],["introductory",{"2":{"84":1}}],["introducing",{"2":{"37":1}}],["introduces",{"2":{"170":1}}],["introduced",{"2":{"24":1}}],["introduce",{"2":{"11":1,"58":1,"126":2}}],["int64",{"2":{"53":3,"77":16,"110":4,"113":6,"171":3,"173":2,"213":99,"218":2,"228":4}}],["int",{"2":{"19":1,"63":2,"66":2,"68":1,"69":1,"70":1,"140":4,"179":1,"207":2,"232":3,"248":1}}],["into",{"0":{"119":1},"2":{"8":1,"16":1,"24":2,"33":1,"39":1,"44":1,"53":1,"54":1,"56":4,"59":2,"62":2,"63":2,"65":3,"66":4,"68":1,"70":1,"77":1,"90":1,"113":1,"138":1,"140":1,"153":2,"171":2,"184":1,"192":1,"206":1}}],["intentionally",{"2":{"133":1}}],["interpolatingadjoint",{"2":{"213":13}}],["intermediate",{"0":{"200":1},"2":{"244":4}}],["interactiveutils",{"2":{"180":2,"189":2,"197":2,"205":1,"214":2,"221":2,"229":2,"237":2,"246":2,"251":2,"260":2}}],["interactive",{"2":{"161":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["interested",{"2":{"146":1,"250":1}}],["interoperability",{"0":{"35":1},"1":{"36":1,"37":1,"38":1,"39":1}}],["inter",{"2":{"28":1}}],["interval",{"2":{"24":2}}],["international",{"2":{"19":1,"24":6,"53":3}}],["internals",{"2":{"233":1,"249":1}}],["internally",{"2":{"37":1,"58":1,"90":1,"144":1,"153":1,"213":1}}],["internal",{"2":{"19":2,"20":3,"31":1,"39":1,"52":1,"58":2,"62":1,"68":2,"81":1,"83":1,"97":1,"119":1}}],["interfacem",{"2":{"39":1}}],["interface",{"0":{"138":1,"139":1,"142":1,"143":1},"1":{"139":1,"140":2,"141":2,"142":1,"143":1},"2":{"7":1,"39":2,"46":2,"138":2,"140":1,"207":1,"215":1,"249":1}}],["integral",{"2":{"53":1}}],["integrating",{"0":{"119":1}}],["integration",{"0":{"45":1,"46":1},"2":{"120":1}}],["integrated",{"2":{"8":1,"157":1}}],["integers",{"2":{"42":1,"63":11,"65":15,"67":5}}],["integer",{"2":{"2":3,"4":3,"24":11,"57":3,"63":12,"65":9,"67":1,"68":1,"69":5}}],["intelligence",{"2":{"24":2}}],["intel",{"2":{"3":1}}],["inside",{"0":{"153":1},"2":{"32":1,"57":1,"59":1,"115":1,"130":1,"134":3,"144":3,"153":3}}],["instructions",{"2":{"76":1}}],["institute",{"2":{"74":1}}],["installation",{"0":{"76":1},"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["install",{"0":{"71":1},"2":{"71":1,"72":1,"73":1,"76":1,"77":1,"79":1}}],["installed",{"2":{"42":4,"46":1,"119":1,"172":1}}],["instability",{"2":{"58":1,"157":1,"166":1}}],["instabilities",{"0":{"157":1},"2":{"37":1,"113":1,"157":2}}],["instance",{"2":{"19":3,"66":1,"69":3,"249":1}}],["instancenorm",{"2":{"19":2,"69":7,"99":1,"100":1}}],["instead",{"2":{"3":2,"4":2,"8":1,"31":2,"37":1,"41":2,"48":1,"52":1,"57":1,"59":1,"63":3,"93":1,"94":1,"95":1,"97":1,"98":4,"99":2,"107":1,"108":1,"119":1,"131":1,"134":2,"138":1,"141":1,"142":1,"147":1,"153":2,"155":1,"158":1,"160":1,"167":1,"171":1,"184":1,"204":1,"244":4,"247":1}}],["inspiration",{"2":{"5":1}}],["in",{"0":{"61":1,"99":1,"107":1},"1":{"62":1,"63":1,"64":1,"65":1,"66":1,"67":1,"68":1,"69":1,"70":1},"2":{"2":2,"3":1,"4":2,"5":2,"7":4,"8":5,"10":3,"13":3,"15":2,"17":3,"19":2,"24":15,"27":2,"30":1,"31":2,"32":3,"33":3,"34":6,"37":5,"39":1,"42":1,"44":2,"45":1,"47":1,"48":1,"52":7,"53":3,"54":4,"55":7,"57":1,"58":4,"59":18,"62":20,"63":22,"64":2,"65":3,"66":23,"67":13,"68":6,"69":10,"71":3,"74":2,"76":1,"78":7,"79":1,"81":2,"82":1,"83":3,"84":2,"85":1,"87":1,"90":1,"99":1,"100":1,"101":2,"103":1,"105":1,"108":1,"109":1,"114":4,"115":2,"116":1,"119":4,"122":2,"123":1,"124":1,"125":1,"126":11,"127":3,"128":2,"129":1,"130":1,"133":2,"134":1,"137":2,"140":10,"143":1,"144":3,"145":3,"146":8,"147":1,"148":1,"149":2,"152":1,"153":5,"155":2,"156":2,"157":1,"160":5,"161":2,"167":1,"168":1,"169":1,"170":2,"171":2,"173":1,"174":3,"175":1,"179":2,"181":1,"183":3,"184":6,"185":3,"187":3,"190":1,"194":1,"195":2,"202":1,"209":1,"210":2,"212":1,"215":2,"218":1,"219":4,"222":1,"228":1,"233":1,"235":1,"236":4,"238":1,"243":1,"244":1,"245":2,"247":1,"248":6,"249":2,"250":13,"255":1,"256":3}}],["idx",{"2":{"235":2,"236":12}}],["ideal",{"2":{"196":1}}],["ideally",{"2":{"20":1,"203":1}}],["identity",{"2":{"16":1,"19":5,"24":13,"62":1,"77":3,"110":2,"113":1,"213":9,"228":1}}],["id",{"2":{"2":7,"4":3}}],["if",{"2":{"1":2,"2":12,"3":9,"4":3,"6":1,"7":1,"8":5,"11":2,"13":4,"15":2,"16":2,"17":7,"18":2,"19":6,"28":2,"31":3,"32":1,"33":5,"34":2,"37":2,"39":1,"42":2,"48":1,"49":2,"50":3,"52":2,"53":8,"54":4,"55":3,"57":1,"58":3,"59":6,"60":1,"62":17,"63":8,"64":10,"66":28,"67":12,"68":5,"69":14,"70":3,"71":1,"74":2,"76":1,"77":1,"78":2,"83":1,"90":2,"97":1,"103":2,"104":1,"113":3,"114":1,"115":1,"116":4,"117":1,"122":1,"123":1,"125":1,"126":1,"127":1,"129":1,"130":1,"136":1,"137":1,"138":1,"140":3,"141":3,"142":3,"144":3,"145":2,"148":1,"153":1,"159":1,"163":3,"167":1,"168":2,"169":2,"172":2,"174":1,"175":1,"179":1,"180":3,"189":3,"197":3,"202":1,"203":2,"214":3,"219":2,"221":3,"228":1,"229":3,"237":3,"244":1,"246":3,"251":3,"254":3,"260":3}}],["isdefined",{"2":{"180":3,"189":3,"197":3,"214":3,"221":3,"229":3,"237":3,"246":3,"251":3,"260":3}}],["isnan",{"2":{"244":1}}],["isn",{"2":{"90":1,"137":1,"254":1}}],["issuing",{"2":{"57":1}}],["issue",{"2":{"57":1,"103":1,"113":1,"123":1,"127":1,"144":1,"145":2,"148":1,"159":1,"202":1,"203":2}}],["issues",{"2":{"52":1,"59":1,"66":1,"83":1,"84":1,"104":2,"105":1,"144":1,"153":1}}],["isbitstype",{"2":{"55":1}}],["istraining",{"2":{"54":4}}],["iszero",{"2":{"32":1}}],["isa",{"2":{"24":1,"32":1,"59":1}}],["isleaf",{"2":{"3":5,"10":1}}],["is",{"2":{"0":1,"1":4,"2":19,"3":18,"4":10,"5":3,"6":1,"7":6,"8":12,"10":2,"11":4,"13":2,"14":1,"15":3,"16":4,"17":6,"18":2,"19":7,"20":4,"21":1,"24":9,"27":4,"31":5,"32":4,"33":6,"37":3,"39":7,"42":2,"46":2,"47":2,"50":2,"52":4,"53":36,"54":5,"55":9,"57":5,"58":3,"59":9,"60":2,"62":23,"63":3,"64":7,"65":3,"66":38,"67":9,"68":10,"69":18,"70":3,"71":1,"76":1,"83":6,"85":1,"88":1,"90":1,"91":1,"93":1,"97":3,"99":1,"100":1,"101":1,"103":2,"105":2,"107":1,"113":4,"115":1,"116":9,"117":1,"118":1,"119":4,"120":1,"121":1,"122":2,"123":2,"124":2,"125":4,"126":5,"127":1,"130":2,"134":6,"136":3,"138":4,"140":3,"141":6,"142":2,"144":3,"145":12,"146":2,"149":1,"150":1,"152":1,"153":3,"155":2,"156":2,"157":1,"158":2,"160":3,"161":1,"163":2,"164":1,"169":3,"170":1,"171":4,"172":3,"173":4,"175":3,"179":1,"183":1,"184":1,"185":1,"186":2,"190":1,"196":2,"207":1,"210":2,"213":1,"215":2,"219":4,"227":1,"228":1,"233":1,"238":1,"244":4,"247":3,"248":1,"249":8,"250":2,"252":1,"254":1,"256":2}}],["fθ",{"2":{"250":1}}],["fw",{"2":{"179":1}}],["fwiw",{"2":{"141":1}}],["fd",{"2":{"145":8,"146":8,"147":8,"148":8}}],["f2",{"2":{"140":2}}],["f=σ",{"2":{"66":1}}],["f=identity",{"2":{"19":1}}],["ft",{"2":{"58":3}}],["f64",{"2":{"56":1,"256":1}}],["f32",{"2":{"56":1}}],["f16",{"2":{"56":1}}],["f1",{"2":{"53":1,"140":2}}],["fn=neuralode",{"2":{"208":1}}],["fn",{"2":{"52":2,"53":2,"59":8,"208":1}}],["fetch",{"2":{"142":1,"224":1}}],["feel",{"2":{"140":1}}],["feedforward",{"2":{"24":2,"249":1}}],["few",{"2":{"81":1,"171":1,"175":1}}],["fed",{"2":{"66":4}}],["features",{"0":{"30":1,"88":1,"91":1,"95":1,"100":1},"1":{"31":1,"32":1,"33":1,"34":1},"2":{"30":3,"47":1,"82":1,"85":1,"97":1,"123":2,"144":1,"192":1,"206":1}}],["feature",{"2":{"2":1,"24":2,"58":1,"63":1,"65":6,"69":3,"105":1,"113":1,"127":1,"144":2,"153":2,"171":1}}],["func",{"2":{"219":3}}],["functor",{"2":{"55":2,"56":3,"134":2}}],["functors",{"2":{"3":1,"5":1,"7":2,"10":3,"32":2,"55":2,"56":3,"90":1,"95":1,"98":1,"113":1,"129":1,"134":1,"247":1}}],["function3",{"2":{"148":4}}],["function2",{"2":{"147":4}}],["function1",{"2":{"145":5}}],["functions",{"0":{"20":1,"24":1,"25":1,"43":1,"53":1,"194":1,"209":1,"235":1,"242":1,"254":1},"2":{"7":1,"13":1,"22":1,"25":1,"37":1,"39":1,"52":1,"53":2,"54":1,"56":1,"62":1,"66":4,"81":1,"82":2,"83":1,"90":1,"97":2,"101":1,"113":1,"114":1,"115":2,"116":1,"122":1,"134":1,"140":3,"144":1,"148":1,"166":1,"167":1,"171":1,"173":1,"177":2,"227":1,"233":1,"254":1}}],["function",{"0":{"107":1,"145":1,"147":1,"148":1,"227":1},"1":{"146":1},"2":{"3":1,"4":4,"8":4,"10":2,"11":3,"13":4,"14":1,"15":2,"16":1,"17":2,"18":1,"19":7,"24":2,"27":4,"28":3,"31":1,"32":4,"39":1,"41":2,"42":1,"48":1,"49":1,"52":15,"53":2,"55":1,"57":3,"58":1,"59":11,"62":2,"63":4,"66":3,"67":4,"68":5,"70":1,"78":3,"83":1,"90":1,"97":2,"99":3,"109":1,"111":1,"113":9,"114":1,"116":2,"119":1,"126":2,"129":1,"130":3,"131":2,"134":2,"137":1,"140":3,"141":1,"142":1,"144":5,"145":1,"146":6,"148":2,"150":1,"151":1,"152":1,"153":2,"169":1,"172":2,"174":1,"176":1,"178":1,"179":1,"183":1,"185":1,"186":2,"192":1,"194":2,"195":1,"206":1,"207":4,"208":1,"209":2,"210":2,"211":2,"216":1,"219":4,"224":2,"227":3,"228":2,"232":2,"233":1,"234":1,"235":2,"238":1,"239":1,"241":2,"242":14,"244":1,"248":1,"249":5,"250":3,"254":16,"256":2,"257":7}}],["functionalities",{"2":{"33":1,"40":1}}],["functionality",{"0":{"33":1,"97":1,"98":1,"121":1},"2":{"6":1,"52":1,"66":1,"79":1,"90":2,"97":1,"138":2,"172":1}}],["functional",{"2":{"2":5,"3":5,"42":1,"117":2,"118":1,"166":1,"172":1,"180":2,"189":2,"197":2,"203":1,"214":2,"221":2,"229":2,"237":2,"246":2,"251":2,"260":2}}],["full",{"0":{"152":1},"2":{"146":1,"152":16}}],["fully",{"0":{"18":1},"2":{"24":1,"53":1,"55":1,"67":2,"104":1,"118":1}}],["future",{"2":{"144":1}}],["further",{"2":{"52":1}}],["fusion",{"2":{"16":1,"18":1}}],["fuse",{"2":{"16":1}}],["fuses",{"2":{"16":1}}],["fused",{"2":{"16":2,"18":2,"53":1,"158":3,"166":1}}],["fp32",{"2":{"13":1}}],["f",{"2":{"13":4,"16":2,"18":2,"27":5,"28":7,"32":3,"48":2,"49":6,"52":2,"55":4,"59":1,"62":4,"68":6,"134":1,"169":1,"176":3,"177":1,"178":1,"179":1,"219":1}}],["flexibility",{"2":{"142":1}}],["flexible",{"2":{"7":1}}],["flow",{"2":{"113":2}}],["float16",{"2":{"25":8,"56":1,"57":6}}],["floating",{"0":{"56":1},"2":{"13":1,"56":3}}],["float32",{"2":{"5":3,"24":6,"25":8,"37":1,"39":1,"53":6,"56":2,"57":5,"62":2,"68":2,"77":57,"78":1,"110":6,"111":3,"112":3,"113":28,"114":1,"116":1,"117":1,"125":9,"126":27,"129":10,"132":6,"133":2,"140":2,"141":2,"142":3,"145":10,"146":2,"147":11,"148":11,"152":2,"155":5,"168":5,"171":8,"172":1,"176":5,"177":4,"178":1,"179":8,"183":1,"192":1,"195":1,"206":1,"213":77,"218":4,"224":3,"227":4,"243":5,"244":1,"248":8,"256":7}}],["float64",{"2":{"5":4,"25":8,"53":1,"56":1,"57":4,"59":4,"153":7,"155":3,"171":5,"174":1,"218":4,"249":13,"255":1,"256":1,"257":1,"258":2}}],["flipkernel=true",{"2":{"100":1}}],["flat",{"2":{"210":1}}],["flattening",{"2":{"97":1}}],["flatten",{"2":{"68":1}}],["flattens",{"2":{"68":1}}],["flattenlayer",{"2":{"39":1,"68":3,"193":3,"208":1,"213":9,"234":1}}],["flattened",{"2":{"37":1,"68":3,"247":1}}],["flaky",{"2":{"121":1}}],["flag",{"2":{"39":1}}],["fluxlinear",{"2":{"134":5}}],["fluxlayer",{"2":{"37":2}}],["fluxmpifluxmodel",{"2":{"121":1}}],["fluxmpi",{"0":{"120":1},"1":{"121":1,"122":1},"2":{"118":1,"120":3,"121":1,"122":2}}],["flux",{"0":{"37":1,"83":1,"133":1,"137":1},"1":{"134":1,"135":1,"136":1,"137":1},"2":{"37":14,"66":3,"81":1,"83":4,"121":1,"133":3,"134":5,"136":4,"137":1,"140":2,"170":1,"247":1,"252":1}}],["fmaps",{"2":{"8":1}}],["fmap",{"2":{"7":3,"8":2,"10":1,"32":1,"55":7,"249":1}}],["framerate=10",{"2":{"245":1}}],["framework",{"2":{"81":1,"83":1,"138":1,"170":1,"173":1,"190":1}}],["frameworks",{"0":{"36":1},"1":{"37":1},"2":{"63":1,"66":1,"81":3,"138":1,"171":1,"256":1}}],["frequently",{"2":{"202":1}}],["frees",{"2":{"160":1}}],["freeze",{"2":{"31":5,"128":1,"129":6,"130":6,"131":5,"132":1}}],["freezing",{"0":{"31":1,"128":1,"129":1,"130":1,"131":1,"132":1},"1":{"129":1,"130":1,"131":1,"132":1},"2":{"128":1,"130":1,"131":2}}],["free",{"2":{"5":1,"24":1,"52":1,"254":1}}],["freeable",{"2":{"5":1}}],["friendly",{"2":{"81":2}}],["frozen",{"2":{"31":8,"129":9,"132":4}}],["frozenlayer",{"2":{"31":8}}],["fromfluxadaptor",{"2":{"37":5,"137":1}}],["from",{"0":{"36":1,"120":1,"133":1},"1":{"37":1,"121":1,"122":1,"134":1,"135":1,"136":1,"137":1},"2":{"4":1,"5":3,"7":2,"11":1,"13":1,"17":1,"20":1,"24":6,"25":12,"32":1,"37":1,"39":1,"52":5,"53":2,"54":1,"59":1,"62":1,"63":2,"64":1,"66":10,"67":1,"69":2,"77":1,"78":1,"83":1,"97":2,"98":1,"99":2,"115":1,"140":1,"141":1,"142":1,"145":2,"146":2,"147":1,"148":1,"155":1,"158":1,"160":3,"171":1,"179":2,"184":1,"190":1,"204":1,"213":3,"215":1,"219":1,"222":1,"224":1,"226":1,"238":1,"247":1,"249":3,"250":4,"252":2,"254":3,"256":1}}],["familiar",{"2":{"181":1,"233":1}}],["far",{"2":{"140":1}}],["farley",{"2":{"68":1}}],["fake",{"2":{"126":1}}],["favor",{"2":{"63":1}}],["facusapienza",{"2":{"145":1}}],["fact",{"2":{"122":1}}],["factor",{"2":{"17":2,"19":8,"24":2,"53":2,"70":2}}],["facilitates",{"2":{"58":1}}],["fausto",{"2":{"53":1}}],["fashionmnist",{"0":{"230":1},"1":{"231":1,"232":1,"233":1,"234":1,"235":1,"236":1,"237":1},"2":{"232":1,"236":2}}],["fashion",{"2":{"42":1}}],["fastest",{"2":{"103":2,"150":1}}],["faster",{"0":{"158":1},"2":{"3":1,"13":2,"14":3,"103":1,"144":1,"158":2,"159":1}}],["fast",{"2":{"13":4,"15":2,"19":1,"20":1,"30":1,"39":1,"69":1,"97":1,"149":1,"158":2,"160":1,"177":1,"256":3}}],["failed",{"2":{"125":1}}],["failing",{"2":{"49":1}}],["failures",{"2":{"37":1}}],["fail",{"2":{"37":1,"49":4,"104":1}}],["fails",{"2":{"33":1,"48":1,"103":2}}],["fancy",{"2":{"113":1}}],["fan",{"2":{"24":6,"63":2}}],["fallback",{"2":{"7":1,"11":3,"16":2,"18":2,"20":1,"90":1,"137":1}}],["fall",{"2":{"3":1}}],["falls",{"2":{"2":1,"13":1}}],["false",{"2":{"2":2,"10":1,"17":1,"20":1,"33":1,"37":1,"39":2,"50":1,"53":5,"54":1,"55":1,"58":1,"62":2,"63":2,"66":10,"67":3,"99":1,"144":1,"156":1,"162":1,"163":1,"205":1,"207":3,"211":2,"213":13,"231":1,"239":1,"257":1}}],["fitting",{"0":{"222":1},"1":{"223":1,"224":1,"225":1,"226":1,"227":1,"228":1,"229":1}}],["fit",{"2":{"219":1,"222":1,"244":4,"250":1}}],["figure",{"2":{"217":1,"220":1,"224":1,"228":1,"245":1,"248":1,"255":1,"256":1,"259":2}}],["figured",{"2":{"126":1}}],["fig",{"2":{"217":3,"220":3,"224":3,"228":3,"245":6,"248":3,"250":6,"255":3,"256":3,"259":6}}],["fix",{"2":{"104":1,"125":1,"126":2,"145":2,"149":1,"155":2,"202":1}}],["fixing",{"2":{"93":1,"148":1,"168":1}}],["fix1",{"2":{"64":1,"68":1,"144":3,"147":1,"148":2,"208":1,"213":9,"256":2}}],["fixed=",{"2":{"59":1}}],["fixed",{"2":{"17":1,"58":1,"59":4,"98":2,"125":4,"173":1}}],["finetune",{"2":{"219":1}}],["fine",{"2":{"141":1}}],["finite",{"2":{"145":4,"146":2,"149":1}}],["finitediff",{"2":{"49":1,"144":1,"145":2,"146":2}}],["finish",{"2":{"124":1}}],["findmax",{"2":{"250":1}}],["find",{"2":{"59":1,"127":1,"153":1,"179":1,"202":1,"250":1}}],["final",{"2":{"59":2,"236":3}}],["finally",{"0":{"196":1},"2":{"42":1,"59":1,"119":1,"140":1,"141":1,"171":1,"179":1,"184":1,"213":1,"228":1,"259":1}}],["fill",{"2":{"53":1,"171":1}}],["filter",{"2":{"24":1}}],["file",{"2":{"1":1,"116":3}}],["fields",{"2":{"52":1,"55":1,"62":10,"68":2,"142":1}}],["fieldnames",{"2":{"7":1,"184":1}}],["field",{"2":{"7":3,"8":1,"37":2,"54":1,"62":1,"184":1}}],["first",{"2":{"2":1,"8":1,"32":1,"34":1,"37":1,"39":1,"59":6,"62":2,"65":3,"68":2,"77":1,"105":1,"113":2,"116":1,"120":1,"126":4,"133":1,"134":1,"140":2,"142":2,"144":1,"145":1,"153":2,"155":2,"161":1,"173":1,"174":2,"176":1,"179":1,"184":3,"194":1,"196":1,"207":1,"209":1,"228":1,"235":1,"240":1,"247":1,"248":2,"250":3,"255":1,"256":2,"257":1,"259":1}}],["footnotes",{"0":{"105":1}}],["foldl",{"2":{"54":3}}],["follow",{"2":{"114":1}}],["follows",{"2":{"3":1,"5":1,"62":1}}],["following",{"2":{"2":1,"5":1,"20":1,"28":1,"32":1,"55":1,"56":1,"57":2,"71":2,"72":2,"73":2,"114":1,"115":1,"129":1,"133":1,"138":1,"144":1,"149":1,"154":1,"155":1,"159":1,"161":2,"163":1,"184":1,"242":1,"250":1}}],["focuses",{"2":{"53":1}}],["focalloss",{"2":{"53":2}}],["focal",{"2":{"53":4}}],["four",{"2":{"171":1}}],["fourth",{"2":{"53":1}}],["found",{"2":{"2":1,"74":1,"203":1}}],["forum",{"2":{"144":1}}],["forget",{"2":{"124":1}}],["formulas",{"2":{"254":1}}],["format",{"2":{"171":1}}],["formats",{"2":{"62":4,"68":1}}],["form",{"2":{"59":1,"67":1,"153":1,"167":1,"173":2}}],["forms",{"2":{"53":1}}],["forwarded",{"2":{"48":1}}],["forward",{"2":{"33":1,"54":1,"59":5,"66":1,"67":2,"78":1,"102":2,"126":1,"127":1,"145":1,"147":1,"148":1,"175":1,"176":2,"177":2,"249":1,"250":5}}],["forwarddiff",{"2":{"20":1,"49":1,"55":1,"102":1,"144":3,"145":2,"147":4,"148":2,"152":1,"175":2,"176":4,"177":1}}],["forbidden",{"2":{"24":1}}],["forces",{"2":{"83":1}}],["force",{"2":{"2":6,"37":4,"48":1}}],["for",{"0":{"38":1,"112":1,"146":1,"159":1,"161":1,"170":1,"257":1},"1":{"39":1,"162":1,"163":1,"164":1,"165":1,"166":1,"167":1,"171":1,"172":1,"173":1,"174":1,"175":1,"176":1,"177":1,"178":1,"179":1,"180":1},"2":{"0":1,"1":1,"2":3,"3":14,"4":9,"5":3,"6":1,"7":11,"8":7,"11":1,"12":1,"13":1,"14":1,"16":5,"17":8,"18":5,"19":15,"20":3,"21":1,"24":11,"27":2,"28":3,"29":1,"31":5,"32":3,"33":8,"34":2,"37":3,"39":5,"41":2,"42":8,"43":2,"47":2,"48":1,"49":5,"52":5,"53":9,"54":5,"55":15,"56":1,"57":4,"58":2,"59":16,"60":3,"62":11,"63":10,"65":15,"66":24,"67":12,"68":6,"69":18,"70":8,"76":1,"77":2,"78":7,"79":1,"80":5,"81":1,"82":1,"83":9,"84":1,"87":2,"88":2,"90":2,"91":1,"92":1,"93":1,"94":1,"95":1,"97":1,"99":2,"100":1,"101":2,"103":11,"104":2,"105":1,"107":1,"109":2,"113":5,"114":4,"115":1,"118":1,"119":1,"122":1,"123":2,"124":1,"125":1,"126":1,"128":1,"130":2,"133":1,"136":1,"138":2,"140":6,"141":3,"142":3,"143":1,"144":6,"146":1,"147":2,"148":1,"149":1,"150":1,"152":2,"153":4,"154":2,"155":3,"157":1,"159":1,"160":3,"162":2,"164":1,"165":1,"166":5,"167":1,"168":2,"169":1,"170":1,"171":3,"172":1,"173":2,"174":2,"175":5,"176":2,"177":2,"179":3,"183":3,"184":4,"185":2,"186":1,"187":3,"190":1,"194":1,"195":2,"196":1,"203":1,"206":1,"207":2,"209":1,"210":5,"213":3,"215":2,"219":3,"225":1,"228":2,"235":1,"236":3,"238":1,"243":2,"244":1,"245":2,"248":5,"249":2,"250":5,"255":1}}],["tmp",{"2":{"254":4}}],["tmatch",{"2":{"8":3}}],["t∈",{"2":{"243":1}}],["ttest",{"2":{"210":1,"236":2}}],["ttraining",{"2":{"210":1,"236":2}}],["ttime",{"2":{"195":2,"210":3,"236":3}}],["tl",{"2":{"124":1}}],["tloss",{"2":{"114":1}}],["td",{"0":{"112":1}}],["tdchain",{"0":{"110":1},"2":{"109":4,"111":1,"112":1}}],["tpu",{"2":{"73":1,"113":1}}],["tsteps",{"2":{"255":5,"256":4,"259":6}}],["tstate",{"2":{"179":6,"210":7,"228":9}}],["tsit5",{"2":{"213":13,"217":1,"219":1,"220":1}}],["tspan",{"2":{"207":5,"211":3,"213":7,"217":5,"220":2,"255":4,"256":1,"259":1}}],["tspan=",{"2":{"207":2,"211":1}}],["tsung",{"2":{"53":2}}],["ts",{"2":{"52":16,"245":6,"248":1,"249":4}}],["t=rand",{"2":{"49":1}}],["t=float32",{"2":{"24":8}}],["tail",{"2":{"249":1}}],["tab>`",{"2":{"176":1}}],["table",{"2":{"67":1,"171":1}}],["tall",{"2":{"175":1}}],["tasklocalrng",{"2":{"77":1,"132":1,"170":1,"179":1}}],["tasks",{"2":{"53":3}}],["taking",{"2":{"53":1,"54":1,"68":1}}],["takeaway",{"2":{"142":1}}],["takes",{"2":{"8":1,"53":2,"59":1,"62":4,"78":1,"113":1,"219":1,"227":1,"250":1,"256":2}}],["taken",{"2":{"5":1,"24":1,"60":1,"63":2,"67":1,"99":1,"113":1,"148":1}}],["take",{"2":{"1":1,"25":1,"32":1,"52":1,"53":2,"60":1,"63":1,"77":1,"104":1,"108":1,"145":1,"169":1,"241":1,"243":1,"249":1}}],["targets",{"2":{"53":1,"192":1,"206":1}}],["target",{"2":{"48":10,"53":2,"194":3,"209":3,"235":3,"242":6,"243":12,"244":10}}],["tanh",{"2":{"34":2,"66":1,"77":11,"145":1,"146":1,"147":3,"148":3,"152":3,"208":4,"213":36,"219":2,"241":3,"249":3}}],["turing",{"2":{"247":6}}],["tutorials",{"0":{"198":1,"199":1,"200":1,"201":1,"203":1},"1":{"199":1,"200":1,"201":1,"202":1,"203":1},"2":{"59":1,"84":1,"203":1,"238":1,"244":4}}],["tutorial",{"2":{"58":1,"78":1,"170":3,"175":1,"181":2,"190":2,"203":1,"215":6,"222":1,"238":1,"247":2}}],["tu",{"2":{"27":1}}],["tuple=true",{"2":{"210":1}}],["tuples",{"2":{"7":2}}],["tuple",{"2":{"3":2,"7":2,"19":2,"20":1,"24":3,"31":4,"32":1,"39":1,"52":1,"53":1,"55":1,"62":7,"63":11,"65":15,"66":22,"67":5,"69":1,"70":3,"77":12,"82":1,"109":1,"147":1,"148":1,"153":1,"208":2,"213":36,"218":2,"249":1}}],["two",{"2":{"24":3,"55":2,"62":4,"67":1,"69":1,"70":3,"116":1,"140":1,"141":1,"142":1,"149":1,"169":1,"249":1,"254":4,"256":1}}],["temporal",{"2":{"243":1}}],["te",{"2":{"195":4,"196":1,"210":2}}],["technology",{"2":{"74":1}}],["terminate",{"2":{"219":1}}],["terminology",{"2":{"219":1}}],["terms",{"2":{"105":1}}],["term",{"2":{"66":1,"145":1,"152":1,"249":2}}],["terrible",{"2":{"52":1}}],["tested",{"2":{"82":1,"83":1,"104":2,"175":1,"202":1}}],["test",{"0":{"50":1},"2":{"48":7,"49":10,"50":8,"64":3,"69":2,"83":1,"105":1,"113":1,"145":2,"153":1,"192":5,"195":3,"196":20,"206":5,"210":3,"232":5,"236":13,"255":1}}],["tests",{"2":{"48":2,"49":2,"104":1,"123":2,"149":1}}],["testing",{"0":{"48":1},"2":{"47":3,"82":1}}],["testmode`",{"2":{"145":2}}],["testmode",{"2":{"10":1,"64":3,"69":3,"113":3,"136":1,"187":1,"194":1,"209":1,"235":1,"244":1}}],["tends",{"2":{"17":1,"145":1,"146":1}}],["tensors",{"2":{"70":1}}],["tensorflow",{"2":{"66":1}}],["tensor",{"2":{"16":3,"24":1,"69":1,"171":1,"254":1}}],["tile",{"2":{"171":2}}],["tiles",{"2":{"171":1}}],["tightly",{"2":{"167":1}}],["tier",{"2":{"102":8,"104":3}}],["tied",{"0":{"34":1},"2":{"83":1}}],["title",{"2":{"74":2,"245":1,"250":1}}],["tips",{"2":{"154":2}}],["tip",{"2":{"8":1,"18":1,"37":1,"39":1,"48":1,"59":1,"66":1,"118":1,"140":1,"144":2,"203":1,"254":1}}],["timewrapper",{"2":{"218":7,"219":1}}],["timelastindex",{"2":{"54":1,"66":2}}],["timestep",{"2":{"255":1}}],["timespace",{"2":{"255":1}}],["times",{"2":{"47":1,"62":3,"171":1,"174":1,"215":1}}],["time",{"0":{"109":1},"2":{"3":1,"37":1,"66":2,"103":2,"108":3,"111":5,"113":1,"195":3,"196":20,"210":3,"212":1,"218":1,"236":2,"245":1,"255":2,"256":3,"257":1,"259":2}}],["typing",{"2":{"76":1}}],["typical",{"2":{"59":1}}],["typically",{"2":{"7":1,"66":1,"83":1,"147":1,"160":1,"186":1,"243":1,"256":1}}],["typed",{"2":{"176":1}}],["typeof",{"2":{"58":1,"77":8,"110":2,"113":3,"126":1,"140":4,"213":80,"228":2,"256":2}}],["types",{"0":{"7":1,"22":1,"106":1},"1":{"107":1,"108":1,"109":1,"110":1,"111":1,"112":1},"2":{"3":1,"8":2,"20":2,"31":1,"55":6,"92":2,"95":1,"142":1,"143":1,"166":1,"168":2}}],["type",{"0":{"57":1,"155":1,"157":1,"213":1},"2":{"3":13,"4":8,"7":6,"8":5,"16":1,"20":1,"22":2,"24":7,"25":1,"37":1,"39":1,"42":5,"53":1,"55":6,"57":12,"58":3,"59":4,"62":2,"69":1,"107":1,"113":1,"119":3,"125":5,"126":13,"129":1,"130":1,"141":1,"142":3,"143":1,"155":2,"157":2,"166":2,"169":1,"184":2,"187":2,"212":1,"213":1,"232":1}}],["tr",{"2":{"149":2,"152":11,"195":4,"210":2}}],["trying",{"2":{"140":1,"219":1}}],["try",{"2":{"103":1,"110":1,"113":1,"125":2,"126":1,"142":2,"152":1,"171":1,"179":1,"188":1,"203":1}}],["treat",{"2":{"49":1,"141":1}}],["treated",{"2":{"15":1,"59":1}}],["truth",{"2":{"147":1,"179":1}}],["truncation",{"2":{"97":2}}],["truncated",{"2":{"22":2,"24":2}}],["truly",{"2":{"83":1}}],["true",{"0":{"255":1},"2":{"2":2,"3":3,"10":1,"17":6,"19":4,"24":2,"32":1,"33":2,"34":1,"37":2,"39":1,"49":2,"53":40,"54":3,"55":1,"58":1,"59":4,"62":3,"63":2,"64":4,"66":11,"70":1,"77":8,"82":1,"99":1,"110":2,"113":3,"117":1,"125":1,"126":2,"129":2,"132":2,"145":3,"146":1,"147":1,"148":1,"150":1,"151":1,"152":1,"163":2,"167":1,"179":2,"186":4,"194":1,"209":1,"211":1,"213":58,"217":2,"219":2,"224":1,"228":3,"235":1,"242":3,"244":2,"247":2,"249":1,"255":1,"256":2}}],["trivial",{"2":{"83":1,"138":1,"173":1,"213":26,"219":1}}],["trilinear",{"2":{"70":6}}],["tries",{"2":{"16":1}}],["trigger",{"2":{"3":4,"4":2,"115":1,"116":2,"119":1}}],["traditional",{"2":{"67":1,"249":1}}],["transitioned",{"2":{"115":1}}],["transposed",{"2":{"63":2}}],["transpose",{"2":{"63":3,"171":1}}],["transformation",{"2":{"69":1}}],["transformations",{"2":{"37":1}}],["transforms",{"2":{"65":3}}],["transform",{"2":{"37":1}}],["transformed",{"2":{"15":1}}],["transferred",{"2":{"3":1,"134":1}}],["transferring",{"2":{"0":1,"5":1,"160":1}}],["transfer",{"0":{"2":1,"160":1},"2":{"2":1,"134":1,"160":2,"188":1}}],["trace",{"0":{"149":1},"1":{"150":1,"151":1,"152":1},"2":{"149":7,"150":3,"151":2,"152":10,"254":4}}],["tracing",{"2":{"55":1,"113":1}}],["tracking",{"0":{"126":1},"2":{"100":1,"127":2}}],["track",{"2":{"33":1,"57":1,"62":2,"69":12,"125":1,"126":5,"155":1}}],["tracker",{"2":{"16":1,"18":1,"20":1,"49":1,"52":1,"55":1,"102":1,"110":1,"244":12,"247":1}}],["tracked",{"2":{"125":1}}],["trackedarray",{"2":{"8":1,"110":2}}],["trackedreals",{"2":{"8":1}}],["train=1024",{"2":{"232":1}}],["trainstate",{"0":{"114":1},"2":{"52":11,"77":3,"78":1,"97":1,"113":2,"114":3,"179":1,"187":1,"195":1,"210":1,"215":1,"228":4,"236":1,"241":1,"244":1}}],["trained2",{"2":{"187":2}}],["trained",{"2":{"39":1,"187":2,"188":8,"219":2,"220":2,"244":5,"245":1,"259":3}}],["train",{"0":{"212":1},"2":{"39":1,"52":6,"59":1,"66":24,"77":8,"78":7,"113":1,"114":10,"179":4,"183":4,"187":12,"190":1,"192":6,"195":15,"196":3,"206":6,"210":8,"215":2,"219":3,"228":1,"232":10,"236":24,"241":1,"243":1,"244":9}}],["trainmode",{"2":{"10":1}}],["trainable",{"2":{"7":1,"31":1,"52":2,"59":9,"63":2,"66":4,"67":3,"69":1,"134":9}}],["training=val",{"2":{"64":3}}],["training",{"0":{"52":1,"118":1,"136":1,"181":1,"187":1,"195":1,"196":1,"210":1,"215":1,"217":1,"219":1,"228":1,"230":1,"236":1,"238":1,"244":1,"252":1,"257":1,"258":1},"1":{"119":1,"120":1,"121":1,"122":1,"123":1,"182":1,"183":1,"184":1,"185":1,"186":1,"187":1,"188":1,"189":1,"216":1,"217":1,"218":1,"219":1,"220":1,"221":1,"231":1,"232":1,"233":1,"234":1,"235":1,"236":1,"237":1,"239":1,"240":1,"241":1,"242":1,"243":1,"244":1,"245":1,"246":1,"253":1,"254":1,"255":1,"256":1,"257":1,"258":1,"259":1,"260":1},"2":{"4":3,"10":2,"17":9,"19":8,"24":2,"33":1,"41":2,"42":4,"52":14,"53":2,"54":3,"64":6,"69":9,"74":1,"77":8,"78":3,"83":2,"97":1,"98":2,"113":1,"114":5,"118":2,"125":1,"126":3,"129":2,"131":1,"132":2,"136":2,"179":5,"181":1,"187":2,"190":1,"195":4,"196":20,"210":5,"212":1,"215":1,"227":1,"228":5,"236":2,"241":1,"244":2,"257":2,"258":1}}],["t",{"2":{"2":1,"3":5,"4":6,"8":1,"13":2,"16":1,"18":1,"24":20,"25":1,"32":1,"34":1,"37":1,"47":1,"49":1,"52":1,"54":1,"59":6,"66":1,"68":1,"77":1,"78":1,"83":1,"90":2,"93":1,"97":1,"104":2,"105":1,"107":1,"108":1,"109":4,"111":2,"122":1,"123":1,"124":1,"127":1,"134":1,"136":1,"137":1,"140":4,"142":3,"143":1,"144":2,"145":1,"146":1,"147":10,"149":1,"153":1,"171":2,"173":2,"177":1,"179":1,"183":1,"184":4,"185":2,"188":1,"192":1,"195":3,"202":1,"206":1,"207":5,"211":3,"215":1,"217":6,"218":11,"219":8,"220":9,"228":1,"233":1,"234":1,"236":2,"243":6,"244":12,"254":16,"255":1,"256":1,"257":2}}],["thousands",{"2":{"171":1}}],["though",{"2":{"140":1,"159":1,"175":1}}],["those",{"2":{"7":1,"8":1,"49":1,"70":1,"79":1,"123":1,"126":1,"141":1,"171":1,"207":1,"250":1}}],["thunk",{"2":{"113":1}}],["thumb",{"2":{"70":1}}],["thus",{"2":{"19":1,"62":1,"70":1}}],["threads",{"2":{"180":3,"189":3,"197":3,"214":3,"221":3,"229":3,"237":3,"246":3,"251":3,"260":3}}],["three",{"2":{"68":1,"171":1}}],["through",{"2":{"5":1,"8":1,"62":4,"69":4,"76":1,"84":2,"108":1,"134":1,"142":1,"154":1,"173":1,"184":3,"218":1,"250":1}}],["throws",{"2":{"50":1}}],["throw",{"2":{"2":1,"3":1,"33":1,"52":1,"57":1,"90":1,"244":1}}],["thrown",{"2":{"2":2,"31":1,"33":2}}],["than",{"2":{"24":2,"175":1,"210":1}}],["that",{"2":{"2":3,"3":8,"5":1,"7":4,"8":5,"10":1,"11":1,"13":2,"16":1,"17":1,"18":2,"20":1,"24":3,"30":1,"31":1,"33":1,"34":2,"39":2,"44":2,"47":1,"52":1,"53":1,"54":1,"55":3,"58":1,"59":5,"62":5,"63":2,"64":2,"65":6,"67":1,"68":4,"69":6,"77":1,"79":1,"83":2,"85":2,"90":2,"93":2,"105":3,"113":1,"114":2,"119":5,"120":1,"122":1,"124":2,"125":3,"126":1,"127":2,"133":1,"134":2,"137":1,"140":3,"141":4,"142":1,"143":2,"144":3,"145":2,"146":3,"147":2,"149":2,"152":3,"153":2,"155":3,"156":1,"161":1,"163":1,"167":1,"171":1,"173":3,"174":1,"176":1,"177":1,"184":3,"188":2,"202":1,"210":1,"213":1,"215":2,"219":4,"225":1,"227":1,"240":1,"241":1,"243":1,"249":1,"250":3,"256":3}}],["third",{"2":{"171":2}}],["thirteenth",{"2":{"24":2}}],["thing",{"2":{"68":2,"153":1,"155":1}}],["things",{"2":{"59":1,"140":1,"142":1,"171":1}}],["think",{"2":{"59":1,"140":1}}],["this",{"2":{"2":3,"3":8,"4":10,"5":1,"7":5,"8":6,"10":1,"11":6,"13":3,"14":1,"16":3,"18":3,"19":2,"20":4,"21":1,"24":5,"27":2,"28":2,"30":2,"32":2,"33":5,"37":6,"39":3,"41":2,"42":3,"45":1,"46":1,"47":2,"48":1,"49":2,"52":6,"53":4,"54":1,"55":12,"57":7,"58":6,"59":11,"62":3,"63":5,"65":3,"66":6,"67":5,"68":1,"69":5,"70":3,"74":2,"79":1,"82":1,"83":2,"85":2,"90":6,"91":1,"92":1,"93":3,"98":1,"99":1,"100":1,"101":1,"103":2,"105":1,"113":5,"114":3,"115":1,"116":2,"119":3,"121":2,"123":2,"124":2,"125":3,"127":2,"128":2,"130":1,"134":2,"136":3,"138":1,"140":8,"142":6,"143":1,"144":6,"145":9,"146":5,"147":1,"148":1,"149":3,"150":1,"152":2,"153":5,"155":7,"156":1,"157":1,"159":1,"160":4,"162":1,"163":2,"164":3,"166":1,"167":1,"170":1,"171":5,"173":4,"175":1,"179":1,"180":1,"181":2,"183":1,"185":2,"189":1,"190":1,"193":1,"196":1,"197":1,"210":1,"211":1,"213":2,"214":1,"215":3,"219":5,"221":1,"222":1,"225":1,"227":1,"229":1,"233":1,"237":1,"238":2,"246":1,"247":1,"249":4,"251":1,"252":1,"254":3,"256":2,"258":1,"260":1}}],["theoretical",{"2":{"254":1}}],["theoretically",{"2":{"175":1}}],["theorem",{"2":{"68":1}}],["thesis",{"2":{"74":1}}],["these",{"2":{"7":5,"8":1,"25":1,"30":1,"37":3,"39":3,"40":1,"42":1,"52":1,"69":1,"77":1,"81":2,"83":1,"90":2,"97":3,"104":7,"108":1,"123":1,"140":2,"141":2,"144":1,"148":1,"159":1,"163":1,"166":1,"167":3,"170":1,"173":1,"177":1,"202":3,"203":1,"204":1,"249":1}}],["they",{"2":{"52":1,"59":2,"126":1,"129":1,"134":1,"171":1,"175":2}}],["there",{"2":{"31":1,"39":1,"52":1,"77":1,"92":1,"103":1,"105":1,"119":1,"126":1,"127":1,"144":1,"147":2,"155":1,"159":1,"169":1,"171":1,"196":1}}],["them",{"0":{"154":1},"1":{"155":1,"156":1,"157":1,"158":1,"159":1,"160":1},"2":{"30":1,"32":1,"53":1,"59":1,"62":1,"67":1,"70":1,"77":1,"81":1,"82":1,"90":1,"97":1,"104":1,"153":1,"155":1,"166":1,"171":2,"174":1,"177":1,"203":2,"241":1,"249":1,"256":2}}],["their",{"2":{"7":2,"63":1,"84":1,"158":1,"171":1,"173":2}}],["then",{"2":{"1":2,"2":6,"3":1,"8":1,"17":2,"19":1,"28":2,"31":3,"33":2,"48":1,"49":2,"50":1,"53":6,"54":1,"55":2,"58":2,"60":1,"62":5,"63":4,"64":4,"66":9,"67":7,"68":1,"74":1,"76":1,"83":1,"113":1,"116":3,"140":1,"141":3,"149":2,"161":1}}],["the",{"0":{"110":1,"111":1,"112":1,"114":1,"131":1,"148":2,"150":1,"151":1,"152":1,"170":1,"185":1,"187":1,"188":1,"193":1,"195":1,"196":1,"207":1,"208":1,"212":1,"218":1,"219":1,"220":1,"234":1,"241":1,"242":1,"243":1,"245":1,"249":1,"255":1,"257":1,"258":1,"259":1},"1":{"171":1,"172":1,"173":1,"174":1,"175":1,"176":1,"177":1,"178":1,"179":1,"180":1},"2":{"1":6,"2":12,"3":31,"4":14,"5":13,"6":3,"7":19,"8":22,"9":4,"10":7,"11":6,"13":10,"14":2,"15":3,"16":11,"17":16,"18":6,"19":21,"20":5,"24":60,"25":25,"27":20,"28":13,"29":1,"30":1,"31":14,"32":22,"33":15,"34":14,"37":12,"39":9,"40":1,"42":10,"43":4,"44":11,"45":5,"46":3,"48":6,"49":9,"50":4,"52":35,"53":55,"54":4,"55":13,"56":6,"57":19,"58":18,"59":49,"60":6,"62":46,"63":38,"64":6,"65":45,"66":69,"67":19,"68":33,"69":58,"70":14,"71":7,"72":2,"73":2,"76":3,"77":6,"78":8,"79":1,"81":1,"82":5,"83":6,"84":4,"85":2,"87":2,"90":2,"91":2,"92":2,"93":4,"94":1,"97":11,"99":9,"100":4,"101":3,"103":7,"104":2,"105":1,"107":2,"108":2,"109":1,"111":3,"112":2,"113":23,"114":7,"115":3,"116":5,"118":1,"119":22,"120":3,"121":1,"122":6,"124":3,"125":6,"126":19,"129":1,"130":7,"131":3,"133":4,"134":6,"136":4,"137":1,"138":6,"140":20,"141":10,"142":4,"143":5,"144":9,"145":5,"146":16,"147":5,"148":13,"149":11,"150":2,"152":7,"153":10,"154":1,"155":9,"157":1,"158":3,"159":2,"160":8,"161":4,"162":1,"163":1,"164":1,"165":1,"166":10,"167":4,"169":11,"170":2,"171":12,"172":7,"173":2,"174":5,"175":6,"176":1,"177":4,"178":2,"179":6,"181":2,"183":6,"184":24,"185":3,"186":2,"187":6,"188":5,"190":2,"192":2,"193":3,"195":2,"196":5,"202":1,"203":6,"206":2,"207":13,"208":1,"210":3,"211":2,"212":3,"213":5,"215":5,"218":8,"219":11,"224":4,"227":3,"228":2,"233":6,"236":1,"238":2,"240":3,"241":2,"242":4,"243":3,"247":5,"248":3,"249":16,"250":22,"252":1,"254":7,"255":2,"256":10,"257":4,"258":2,"259":2}}],["top",{"2":{"113":1,"138":1}}],["topic",{"2":{"66":1}}],["toolchain",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["tools",{"2":{"33":2,"59":1,"124":1,"170":1,"175":1}}],["too",{"2":{"81":1,"175":1,"250":1}}],["towards",{"2":{"55":1,"173":1,"215":1}}],["toarray",{"2":{"39":1}}],["tosimplechainsadaptor",{"2":{"39":4,"83":1,"193":2}}],["together",{"2":{"32":1}}],["total",{"2":{"9":1,"10":1,"34":1,"43":2,"59":4,"62":4,"69":3,"77":1,"78":1,"109":1,"125":1,"126":1,"193":2,"194":6,"209":6,"225":1,"235":6,"244":3,"256":1}}],["to",{"0":{"37":1,"39":1,"50":1,"71":1,"84":1,"85":1,"119":1,"133":1,"154":1,"252":1},"1":{"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"96":1,"97":1,"98":1,"99":1,"100":1,"134":1,"135":1,"136":1,"137":1,"155":1,"156":1,"157":1,"158":1,"159":1,"160":1,"253":1,"254":1,"255":1,"256":1,"257":1,"258":1,"259":1,"260":1},"2":{"1":3,"2":7,"3":10,"4":5,"5":5,"6":2,"7":4,"8":10,"10":2,"11":2,"13":7,"14":2,"15":4,"16":5,"17":13,"18":3,"19":16,"20":2,"24":14,"27":8,"28":5,"30":1,"31":7,"32":2,"33":10,"34":5,"37":14,"39":17,"42":9,"44":6,"46":1,"47":2,"48":3,"49":10,"52":8,"53":14,"54":3,"55":9,"56":4,"57":4,"58":4,"59":21,"60":1,"62":18,"63":19,"64":13,"65":9,"66":59,"67":7,"68":9,"69":22,"70":8,"71":2,"72":1,"73":1,"74":1,"76":3,"77":2,"78":2,"81":2,"82":1,"83":9,"84":2,"85":5,"87":1,"90":5,"91":1,"92":1,"93":5,"94":2,"97":6,"98":3,"99":6,"100":3,"104":3,"105":1,"107":2,"108":2,"109":1,"113":14,"114":8,"115":3,"116":2,"118":1,"119":5,"120":3,"122":4,"124":4,"125":1,"126":7,"128":1,"129":1,"130":1,"131":1,"133":3,"134":8,"136":1,"137":3,"138":5,"140":7,"141":5,"142":4,"143":2,"144":7,"145":10,"146":6,"147":1,"148":4,"149":6,"152":1,"153":9,"155":7,"156":1,"157":2,"158":1,"160":3,"161":4,"162":2,"163":3,"164":4,"166":4,"167":3,"168":1,"169":3,"170":4,"171":7,"172":1,"173":3,"175":1,"176":1,"177":3,"179":2,"181":2,"183":3,"184":10,"186":1,"188":1,"190":2,"192":1,"193":3,"202":1,"203":6,"204":2,"206":1,"207":6,"208":1,"210":1,"211":1,"213":11,"215":4,"218":6,"219":7,"227":1,"233":1,"234":1,"238":2,"242":2,"243":2,"247":1,"248":3,"249":12,"250":5,"254":5,"256":6,"257":2,"258":2}}],["toml",{"2":{"1":1,"47":1}}],["l3",{"2":{"259":2}}],["lb",{"2":{"256":1,"259":1}}],["lbfgs",{"2":{"215":1,"219":3}}],["lr",{"2":{"244":2}}],["ld",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["llvm",{"2":{"180":2,"189":2,"197":1,"214":2,"221":2,"229":2,"237":2,"246":2,"251":1,"260":1}}],["ll",{"2":{"170":1,"248":1,"249":1,"256":2}}],["lpnorm",{"2":{"100":1}}],["lppool",{"2":{"65":1,"100":1}}],["lp",{"2":{"65":4,"249":1,"250":1}}],["l=",{"2":{"53":1}}],["ls",{"2":{"53":4}}],["lstmcell",{"2":{"66":6,"99":1,"100":1,"184":3,"185":1}}],["lstm",{"0":{"181":1},"1":{"182":1,"183":1,"184":1,"185":1,"186":1,"187":1,"188":1,"189":1},"2":{"7":1,"66":1,"184":17,"185":4}}],["l2",{"2":{"34":5,"141":4,"256":2,"259":2}}],["l2=dense",{"2":{"34":1}}],["l1",{"2":{"34":5,"141":4,"256":2,"259":2}}],["l1=dense",{"2":{"34":1}}],["lecture",{"2":{"204":1}}],["lecun",{"2":{"53":1}}],["leveraging",{"2":{"153":1}}],["levels=10",{"2":{"245":1}}],["level",{"2":{"24":2,"101":1,"114":1,"153":1,"166":2}}],["less",{"2":{"68":1,"81":1,"104":1,"175":1}}],["lets",{"2":{"142":1,"195":1,"210":1,"236":1,"247":1}}],["let",{"2":{"59":1,"113":2,"114":1,"120":1,"124":1,"125":2,"126":7,"129":1,"134":2,"140":1,"141":2,"142":2,"144":3,"145":2,"147":1,"148":1,"152":3,"153":1,"155":1,"170":2,"171":1,"174":1,"176":1,"177":1,"178":1,"179":4,"184":1,"186":1,"188":1,"210":1,"212":1,"219":2,"224":1,"225":1,"228":1,"249":1,"255":1,"256":1,"257":1,"259":2}}],["len",{"2":{"49":2,"183":1,"243":11}}],["length=25",{"2":{"250":4}}],["length=bc",{"2":{"243":3}}],["length=grid",{"2":{"243":1}}],["length=datasize",{"2":{"217":1,"255":1}}],["length=50",{"2":{"183":1}}],["length",{"2":{"24":7,"25":24,"34":2,"62":2,"63":2,"65":6,"140":8,"141":2,"183":5,"186":1,"194":1,"209":1,"218":2,"235":1,"245":8,"249":3,"254":2,"259":1}}],["leibler",{"2":{"53":1}}],["lei",{"2":{"19":1}}],["lempitsky",{"2":{"19":1,"69":1}}],["leakyrelu",{"2":{"99":1}}],["learn",{"2":{"171":1}}],["learned",{"2":{"83":1}}],["learnable",{"2":{"67":1,"69":4}}],["learning",{"2":{"2":1,"17":1,"19":1,"21":1,"24":3,"53":1,"149":1,"155":1,"158":1,"168":1,"169":1,"171":1,"179":1,"215":1,"254":1}}],["leads",{"2":{"142":1}}],["leading",{"2":{"70":1}}],["lead",{"2":{"13":1,"33":1,"37":1,"55":1,"59":2,"115":1,"153":1,"219":1}}],["leaf",{"2":{"3":1,"8":1,"55":2,"77":12}}],["leaves",{"2":{"3":1,"55":4}}],["l",{"2":{"8":5,"9":2,"10":2,"31":13,"32":5,"37":2,"39":1,"62":2,"64":1,"109":5,"129":2,"130":2,"134":4,"140":16,"179":1,"184":2,"207":4,"219":4,"224":2,"228":2,"255":2,"257":3}}],["lag",{"2":{"244":1}}],["latter",{"2":{"158":2}}],["later",{"2":{"248":1}}],["latest",{"2":{"71":1,"203":1}}],["latentsize",{"2":{"66":3}}],["lazy",{"2":{"134":1}}],["language",{"2":{"55":2}}],["label=l",{"2":{"217":2,"220":4}}],["labels",{"2":{"53":2,"183":3,"192":2,"206":2,"232":4}}],["label",{"2":{"53":18}}],["larger",{"0":{"202":1},"2":{"83":1,"171":1,"202":1}}],["large",{"2":{"37":1,"83":3,"175":1}}],["layerfreezing",{"2":{"131":1}}],["layer2",{"2":{"62":1}}],["layer1",{"2":{"62":1}}],["layernorm",{"2":{"19":1,"69":4,"87":1}}],["layer",{"0":{"11":1,"32":1,"58":1,"59":1,"130":1,"139":1,"140":1,"141":1,"207":1,"208":1,"211":1,"233":1},"1":{"140":1,"141":1},"2":{"7":13,"8":9,"9":4,"10":4,"11":4,"19":3,"31":7,"32":6,"33":13,"37":10,"39":11,"57":5,"58":7,"59":11,"62":67,"63":5,"64":3,"65":12,"66":2,"67":5,"68":8,"69":24,"70":3,"77":47,"83":2,"97":2,"98":1,"99":1,"107":2,"109":3,"111":5,"113":24,"124":2,"125":30,"126":69,"129":9,"130":9,"131":5,"132":9,"134":5,"140":8,"141":12,"144":1,"145":4,"146":1,"147":4,"148":6,"153":2,"155":1,"166":1,"179":1,"184":1,"193":18,"207":2,"213":211,"225":2,"227":4,"228":4,"233":1,"234":1,"249":1,"256":12,"258":4}}],["layers",{"0":{"16":1,"18":1,"61":1,"63":1,"64":1,"65":1,"66":1,"67":1,"68":1,"69":1,"78":1,"129":1,"134":1,"137":1},"1":{"62":1,"63":1,"64":1,"65":1,"66":1,"67":1,"68":1,"69":1,"70":1},"2":{"6":1,"7":9,"8":2,"24":8,"32":3,"33":2,"37":2,"57":1,"58":2,"62":39,"63":1,"68":12,"78":1,"82":4,"83":4,"88":1,"97":2,"100":1,"109":4,"125":9,"126":19,"129":1,"133":1,"134":3,"138":2,"140":1,"141":3,"144":1,"155":1,"159":1,"165":1,"166":1,"184":1,"185":1,"207":1,"212":1,"213":6,"233":1,"249":2}}],["last",{"2":{"2":1,"15":1,"24":1,"58":1,"59":1,"66":1,"68":2,"70":2,"109":1,"119":1,"146":1,"207":1,"248":2}}],["luxlinear",{"2":{"134":7}}],["luxlib",{"0":{"12":1,"86":1},"1":{"13":1,"14":1,"15":1,"16":1,"17":1,"18":1,"19":1,"20":1,"87":1,"88":1},"2":{"13":2,"14":1,"15":2,"16":1,"17":2,"18":1,"19":4,"20":1,"48":2,"60":2,"87":1,"145":4,"158":8,"161":1,"166":2,"167":2,"256":2}}],["luxflux",{"2":{"133":1,"134":2}}],["luxdeviceutils",{"2":{"93":3}}],["luxdl",{"2":{"66":1,"71":1,"79":1}}],["luxops",{"0":{"54":1},"2":{"54":8,"184":1,"185":1}}],["luxtestutils",{"0":{"47":1},"1":{"48":1,"49":1,"50":1},"2":{"48":3,"49":2,"50":1}}],["luxcorearrayinterfacereversediffext",{"2":{"110":2}}],["luxcorearrayinterfacetrackerext",{"2":{"110":2}}],["luxcore",{"0":{"6":1,"89":1},"1":{"7":1,"8":1,"9":1,"10":1,"11":1,"90":1,"91":1},"2":{"6":2,"7":3,"8":7,"9":2,"10":5,"11":1,"60":2,"90":2,"110":5,"138":3,"140":14,"141":8,"142":1,"161":1,"166":3}}],["luxcudadevice",{"2":{"94":1}}],["luxcuda",{"2":{"3":1,"72":2,"77":1,"78":1,"80":1,"115":1,"153":1,"168":1,"172":3,"182":1,"205":1,"216":1,"223":1,"231":1,"239":1}}],["lux",{"0":{"35":1,"37":1,"38":1,"39":1,"71":1,"81":1,"83":1,"85":1,"96":1,"113":1,"124":1,"133":1,"138":1,"161":1,"170":1,"215":1},"1":{"36":1,"37":1,"38":1,"39":2,"82":1,"83":1,"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"96":1,"97":2,"98":2,"99":2,"100":2,"114":1,"125":1,"126":1,"127":1,"134":1,"135":1,"136":1,"137":1,"139":1,"140":1,"141":1,"142":1,"143":1,"162":1,"163":1,"164":1,"165":1,"166":1,"167":1,"171":1,"172":1,"173":1,"174":1,"175":1,"176":1,"177":1,"178":1,"179":1,"180":1,"216":1,"217":1,"218":1,"219":1,"220":1,"221":1},"2":{"4":4,"6":4,"7":3,"8":4,"11":1,"12":1,"27":2,"28":1,"31":13,"32":4,"33":8,"34":3,"37":11,"39":15,"40":1,"41":2,"42":3,"43":2,"44":4,"45":1,"46":1,"47":1,"48":2,"52":9,"53":16,"54":9,"55":9,"56":4,"57":2,"58":5,"59":19,"60":1,"62":11,"63":3,"64":7,"65":9,"66":9,"67":4,"68":12,"69":8,"70":2,"71":5,"72":4,"73":3,"74":1,"76":4,"77":8,"78":4,"79":1,"80":1,"81":1,"83":9,"84":1,"85":2,"90":3,"93":1,"94":2,"97":6,"98":8,"101":2,"104":1,"105":2,"107":1,"109":3,"110":4,"111":4,"112":1,"113":7,"114":1,"115":3,"116":1,"118":1,"122":1,"124":3,"125":6,"126":4,"127":1,"129":6,"130":2,"131":2,"132":3,"133":3,"134":13,"136":2,"137":2,"138":7,"140":3,"141":2,"142":1,"144":4,"145":3,"146":1,"147":1,"148":1,"152":1,"153":8,"155":6,"157":2,"161":3,"166":3,"169":1,"170":3,"172":1,"173":1,"174":2,"175":1,"177":1,"179":2,"181":2,"182":1,"184":7,"185":1,"187":2,"190":1,"191":1,"193":4,"194":1,"195":1,"196":2,"202":1,"203":3,"205":1,"207":5,"208":1,"209":1,"211":4,"213":96,"215":2,"216":1,"219":1,"223":1,"227":2,"228":4,"231":1,"233":4,"234":2,"235":1,"236":1,"238":2,"239":1,"240":1,"241":1,"244":6,"247":4,"249":7,"253":1,"256":2}}],["lt",{"2":{"4":2,"5":1,"24":3,"53":1,"59":2,"79":1,"90":2,"116":1,"141":2,"144":12,"217":1,"220":1}}],["literate",{"2":{"180":2,"189":2,"197":2,"214":2,"221":2,"229":2,"237":2,"246":2,"251":2,"260":2}}],["literature",{"2":{"149":1}}],["little",{"2":{"113":1,"126":1}}],["lib64",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["libllvm",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["libopenlibm",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["libm",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["libraries",{"2":{"144":1,"169":1,"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1,"247":2,"249":1}}],["library",{"2":{"74":1,"133":1,"173":1,"180":1,"188":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["lib",{"2":{"110":6,"125":1,"145":4,"180":1,"189":1,"197":1,"213":3,"214":1,"221":1,"229":1,"237":1,"244":4,"246":1}}],["linux",{"2":{"180":2,"189":2,"197":2,"214":2,"221":2,"229":2,"237":2,"246":2,"251":2,"260":2}}],["linked",{"2":{"203":1}}],["link",{"2":{"170":1}}],["linking",{"2":{"62":1}}],["lin",{"2":{"53":2}}],["liner",{"2":{"249":1}}],["linewidth=2",{"2":{"245":1,"255":1,"256":2,"259":3}}],["linewidth=3",{"2":{"224":1,"228":1,"250":3}}],["linewidth=4",{"2":{"217":2,"220":4,"259":1}}],["linesearch=linesearches",{"2":{"258":1}}],["linesearches",{"2":{"253":1}}],["linestyle=",{"2":{"217":2,"220":2}}],["lines",{"2":{"217":2,"220":4,"224":1,"228":1,"255":1,"256":2,"259":4}}],["line",{"2":{"49":1}}],["linearalgebra",{"2":{"144":1,"247":1}}],["linear",{"0":{"67":1,"179":1},"2":{"24":1,"59":4,"68":1,"70":1,"140":12,"141":23,"153":1,"179":1}}],["lighter",{"2":{"138":1}}],["light",{"2":{"21":1}}],["lightweight",{"2":{"0":1}}],["like",{"2":{"15":1,"16":2,"18":1,"20":1,"24":1,"28":1,"47":1,"52":1,"53":3,"55":1,"59":3,"63":2,"66":3,"83":2,"91":1,"133":1,"134":2,"138":1,"140":2,"142":1,"160":1,"169":1,"171":3,"177":1,"207":1,"210":1,"215":1,"248":1,"255":1,"256":1}}],["limits=extrema",{"2":{"245":1}}],["limiter",{"2":{"213":26}}],["limitations",{"2":{"37":1,"52":1,"83":1}}],["limit",{"2":{"13":1,"17":1,"54":1,"180":2,"189":2,"197":1,"214":2,"221":2,"229":2,"237":2,"246":2,"251":1,"260":1}}],["lists",{"2":{"34":1,"101":1}}],["listed",{"2":{"30":1,"57":1}}],["list",{"2":{"3":1,"34":5,"42":1,"48":1,"49":3,"62":4,"68":1,"78":1,"85":2,"161":1,"168":1,"171":1,"203":1,"236":4}}],["lost",{"2":{"170":1}}],["lossfn",{"2":{"179":3,"186":2,"187":2}}],["lossfunctions",{"2":{"53":1}}],["losses",{"2":{"53":1,"257":2,"259":3}}],["loss",{"0":{"53":1,"145":1,"147":1,"148":1,"186":1,"227":1,"242":1},"1":{"146":1},"2":{"52":5,"53":35,"59":5,"77":2,"78":14,"113":5,"114":4,"144":1,"145":10,"146":9,"147":4,"148":6,"179":19,"186":4,"187":456,"194":1,"195":2,"219":30,"227":4,"228":10,"235":1,"236":1,"238":1,"240":1,"242":23,"244":436,"257":6,"258":1,"259":2}}],["lower",{"2":{"210":1}}],["low",{"2":{"114":1}}],["love",{"2":{"104":1}}],["lotka",{"2":{"217":2}}],["lot",{"2":{"83":1,"174":1}}],["logs",{"2":{"119":1}}],["logging",{"2":{"119":1,"247":1}}],["logarithm",{"2":{"53":1}}],["logarithmic",{"2":{"53":1}}],["log⁡",{"2":{"53":1}}],["log",{"2":{"53":2,"54":2,"249":1,"250":1}}],["logitcrossentropy",{"2":{"209":1,"210":1}}],["logitbinarycrossentropy",{"2":{"186":1}}],["logitbce",{"2":{"53":5}}],["logit",{"2":{"53":1}}],["logits=val",{"2":{"53":2,"194":1,"209":1,"235":1}}],["logits",{"2":{"53":4}}],["longer",{"2":{"97":2,"121":3}}],["long",{"2":{"37":1,"66":1,"142":1}}],["location",{"2":{"33":3,"125":4,"126":10}}],["local",{"2":{"4":1,"43":2,"59":1,"119":1,"120":1,"180":2,"189":2,"196":1,"197":2,"214":2,"221":2,"229":2,"237":2,"246":2}}],["localpreferences",{"2":{"1":1,"116":2}}],["loosely",{"2":{"170":1}}],["looks",{"2":{"160":1}}],["lookup",{"2":{"67":1}}],["look",{"2":{"31":1,"70":1,"177":1,"184":1,"204":1}}],["loops",{"2":{"20":1,"55":1}}],["loopedarrayop",{"2":{"20":1}}],["loopvectorization",{"2":{"13":1,"14":2,"18":1,"20":1,"159":1,"167":1}}],["loop",{"0":{"167":1,"195":1},"2":{"13":1,"20":1,"159":1,"167":1,"228":1}}],["looping",{"2":{"5":1}}],["lo",{"2":{"24":2}}],["loadmnist",{"2":{"192":2,"195":1,"206":2,"210":1}}],["loader",{"2":{"114":1,"187":4}}],["loaded",{"2":{"2":2,"3":7,"4":2,"10":1,"11":1,"18":1,"46":1,"90":2,"116":2,"119":1,"137":1,"167":1,"172":1}}],["load",{"2":{"13":1,"14":1,"18":1,"46":1,"47":1,"97":1,"114":1,"115":1,"159":1,"188":1,"192":1,"206":1,"232":4,"236":1}}],["loading",{"0":{"160":1,"192":1,"206":1,"232":1},"2":{"7":1,"14":1,"18":1,"37":1,"39":1,"80":1,"160":1,"188":1}}],["=ϕwhere",{"2":{"255":1,"256":1}}],["=χu",{"2":{"255":1,"256":1}}],["=∫θp",{"2":{"250":1}}],["=wx+b",{"2":{"179":1}}],["=x",{"2":{"176":1}}],["=12xtx",{"2":{"176":1}}],["=1v∑i=1vvitjvinote",{"2":{"149":1}}],["=1v∑i=1vvitaviwe",{"2":{"149":1}}],["=e",{"2":{"149":1}}],["=i",{"2":{"149":1}}],["=vcat",{"2":{"66":1}}],["=val",{"2":{"39":1,"53":1}}],["=true",{"2":{"33":1}}],["=static",{"2":{"33":1}}],["=>",{"2":{"31":2,"32":3,"34":8,"37":2,"39":5,"59":8,"62":6,"63":2,"66":4,"67":4,"69":12,"77":6,"78":8,"109":4,"113":6,"114":3,"125":17,"126":14,"133":4,"145":2,"146":2,"147":4,"148":4,"152":4,"155":1,"179":1,"184":2,"185":2,"193":15,"208":5,"225":4,"228":2,"234":1,"241":4,"249":3,"256":6}}],["=0",{"2":{"24":2}}],["=nothing",{"2":{"2":1,"53":2,"66":1,"69":1}}],["==3",{"2":{"254":1}}],["===",{"2":{"34":4}}],["==",{"2":{"1":1,"3":1,"17":1,"24":4,"28":1,"54":2,"58":1,"59":1,"63":10,"65":15,"67":3,"70":2,"78":2,"109":1,"114":2,"119":1,"130":1,"131":2,"142":2,"143":1,"179":2,"186":1,"194":1,"209":1,"219":1,"228":2,"235":1,"236":2,"244":2,"249":1,"254":5}}],["=",{"2":{"1":2,"2":2,"3":1,"5":8,"15":1,"17":3,"19":6,"24":14,"28":1,"31":2,"32":5,"34":8,"37":4,"39":5,"41":3,"48":3,"49":2,"53":59,"55":1,"58":2,"59":46,"62":40,"63":7,"64":6,"65":9,"66":6,"67":14,"68":25,"69":15,"70":3,"72":4,"73":3,"74":13,"77":52,"78":26,"90":2,"109":10,"110":3,"111":3,"112":2,"113":61,"114":10,"116":3,"117":7,"119":7,"120":1,"125":25,"126":47,"129":29,"130":1,"132":23,"133":7,"134":12,"140":8,"141":9,"142":5,"145":21,"146":12,"147":20,"148":21,"150":2,"151":2,"152":12,"153":19,"155":5,"160":6,"168":9,"169":6,"170":1,"171":8,"172":1,"173":3,"174":3,"176":3,"177":4,"178":1,"179":17,"180":8,"183":6,"184":6,"185":5,"186":5,"187":13,"189":8,"192":7,"193":21,"194":5,"195":12,"196":1,"197":8,"206":7,"207":6,"208":5,"209":5,"210":10,"211":3,"213":136,"214":8,"216":2,"217":12,"218":3,"219":19,"220":6,"221":8,"224":8,"225":3,"226":1,"227":12,"228":13,"229":8,"232":4,"233":2,"234":3,"235":5,"236":21,"237":8,"239":2,"242":13,"243":19,"244":20,"245":11,"246":8,"248":21,"249":19,"250":19,"251":7,"254":55,"255":20,"256":38,"257":4,"258":14,"259":13,"260":7}}],["jointly",{"2":{"184":1}}],["journal",{"2":{"17":1}}],["jvi",{"2":{"149":1}}],["jvp",{"0":{"27":1},"2":{"27":1,"151":6,"152":10,"175":4,"177":4}}],["j∈rd×d",{"2":{"149":1}}],["jet`",{"2":{"48":1}}],["jet",{"0":{"48":1},"2":{"48":14}}],["jax",{"2":{"170":1}}],["jacobian`",{"2":{"145":1}}],["jacobian",{"0":{"145":1,"146":1,"148":1,"150":1,"151":1,"152":1,"177":1,"178":1},"1":{"146":1},"2":{"27":11,"28":6,"144":3,"145":3,"146":9,"148":5,"149":4,"150":1,"151":1,"152":17,"175":6,"177":2,"178":1}}],["jamie",{"2":{"19":1}}],["j",{"2":{"24":1,"28":2,"145":2,"146":3,"148":2,"149":1,"152":8}}],["jimmy",{"2":{"19":1}}],["just",{"2":{"3":1,"59":1,"62":1,"64":3,"69":3,"77":1,"116":1,"122":1,"138":2,"169":1,"171":1,"177":1,"210":1}}],["julia∂t",{"2":{"147":1}}],["julia∂x",{"2":{"145":1,"146":1,"148":1}}],["juliazygote",{"2":{"126":1}}],["juliazeros",{"2":{"171":2}}],["juliazerosc64",{"2":{"25":1}}],["juliazerosc32",{"2":{"25":1}}],["juliazerosc16",{"2":{"25":1}}],["juliazeros64",{"2":{"25":1}}],["juliazeros32",{"2":{"25":1}}],["juliazeros16",{"2":{"25":1}}],["juliax",{"2":{"113":1,"155":2,"171":11,"173":2,"179":1}}],["juliaxt",{"2":{"111":1}}],["juliaxlogy",{"2":{"54":1}}],["juliaxlogx",{"2":{"54":1}}],["juliaxla",{"2":{"2":1}}],["juliaw",{"2":{"171":1,"179":1}}],["juliaweights",{"2":{"168":1,"169":3}}],["juliaweightnorm",{"2":{"69":1}}],["juliawrappedfunction",{"2":{"68":1}}],["juliann",{"2":{"153":1}}],["julian",{"2":{"78":1,"179":1}}],["julianooplayer",{"2":{"68":1}}],["juliancclbackend",{"2":{"41":1}}],["juliaembedding",{"2":{"67":1}}],["juliaeachslice",{"2":{"54":1}}],["juliavjp",{"2":{"178":1,"228":1}}],["juliavariationalhiddendropout",{"2":{"64":1}}],["juliavector",{"2":{"27":1}}],["juliay",{"2":{"62":2}}],["juliapkg>",{"2":{"161":1}}],["juliaprob",{"2":{"255":1,"256":1,"259":1}}],["juliaprintln",{"2":{"152":1,"176":1}}],["juliapred",{"2":{"113":2}}],["juliaps",{"2":{"119":1,"126":1,"179":1,"187":1}}],["juliapixelshuffle",{"2":{"70":1}}],["juliaparallel",{"2":{"62":1}}],["juliaparameterlength",{"2":{"9":1}}],["juliapairwisefusion",{"2":{"62":1}}],["juliapoissonloss",{"2":{"53":1}}],["juliamodel",{"2":{"112":1,"113":2,"114":1,"125":2,"126":4,"141":1,"146":1,"152":1,"179":1,"213":2,"225":1}}],["juliameanpool",{"2":{"65":1}}],["juliamaxout",{"2":{"68":1}}],["juliamaxpool",{"2":{"65":1}}],["juliamatch",{"2":{"57":1}}],["juliamaeloss",{"2":{"53":1}}],["juliamultigate",{"2":{"54":1}}],["juliamsleloss",{"2":{"53":1}}],["juliamseloss",{"2":{"53":1}}],["juliampibackend",{"2":{"41":1}}],["juliakldivergenceloss",{"2":{"53":1}}],["juliakaiming",{"2":{"24":2}}],["juliahuberloss",{"2":{"53":1}}],["juliahingeloss",{"2":{"53":1}}],["juliaupsample",{"2":{"70":1}}],["juliaupdate",{"2":{"10":1}}],["juliausing",{"2":{"48":1,"72":8,"73":4,"77":1,"78":1,"109":1,"113":1,"125":1,"126":1,"129":1,"132":1,"133":2,"134":2,"140":1,"142":1,"144":1,"153":1,"155":1,"156":1,"161":1,"168":2,"170":1,"172":1,"175":1,"179":1,"180":1,"182":1,"189":1,"191":1,"197":1,"205":1,"214":1,"216":1,"221":1,"223":1,"229":1,"231":1,"237":1,"239":1,"246":1,"251":1,"253":1,"260":1}}],["juliaunfreeze",{"2":{"31":2}}],["juliajvp",{"2":{"177":1}}],["juliajet",{"2":{"48":1}}],["juliajacobian",{"2":{"27":1}}],["juliajulia>",{"2":{"5":1,"24":2,"31":1,"32":1,"34":1,"37":1,"39":1,"48":1,"49":1,"53":15,"59":6,"62":3,"68":4,"69":3,"71":2}}],["juliarng",{"2":{"78":1,"110":1,"125":1,"134":2,"140":1,"170":1,"174":1,"224":1}}],["juliarnncell",{"2":{"66":1}}],["juliarandom",{"2":{"174":1}}],["juliarandc64",{"2":{"25":1}}],["juliarandc32",{"2":{"25":1}}],["juliarandc16",{"2":{"25":1}}],["juliarand64",{"2":{"25":1}}],["juliarandnc64",{"2":{"25":1}}],["juliarandnc32",{"2":{"25":1}}],["juliarandnc16",{"2":{"25":1}}],["juliarandn64",{"2":{"25":1}}],["juliarandn32",{"2":{"25":1}}],["juliarandn16",{"2":{"25":1}}],["juliarand32",{"2":{"25":1}}],["juliarand16",{"2":{"25":1}}],["juliareversesequence",{"2":{"68":1}}],["juliarecurrence",{"2":{"66":1}}],["juliarecursive",{"2":{"55":6}}],["juliareshapelayer",{"2":{"68":1}}],["juliares",{"2":{"62":2}}],["juliareset",{"2":{"3":1}}],["juliarepeatedlayer",{"2":{"62":1}}],["juliareplicate",{"2":{"8":1}}],["juliareduce",{"2":{"44":1}}],["juliaopt",{"2":{"119":1,"226":1}}],["juliaonesc64",{"2":{"25":1}}],["juliaonesc32",{"2":{"25":1}}],["juliaonesc16",{"2":{"25":1}}],["juliaones64",{"2":{"25":1}}],["juliaones32",{"2":{"25":1}}],["juliaones16",{"2":{"25":1}}],["juliaorthogonal",{"2":{"24":1}}],["juliaoutputsize",{"2":{"11":1}}],["julialux",{"2":{"193":1}}],["julialuxops",{"2":{"54":1}}],["julialength",{"2":{"171":1}}],["julialang",{"2":{"110":3,"125":1,"145":2,"180":1,"189":1,"197":1,"213":3,"214":1,"221":1,"229":1,"237":1,"244":4,"246":1,"251":1,"260":1}}],["julialayer",{"2":{"32":1}}],["julialayernorm",{"2":{"19":1,"69":1}}],["julialstmcell",{"2":{"66":1}}],["julialppool",{"2":{"65":1}}],["julialossfn",{"2":{"179":1}}],["julialoss",{"2":{"113":1,"257":1}}],["julialocal",{"2":{"43":1}}],["julialoaded",{"2":{"3":1}}],["juliabegin",{"2":{"224":1,"228":1,"259":1}}],["juliabackend",{"2":{"119":1,"153":2}}],["juliabatchnorm",{"2":{"19":1,"69":1}}],["juliabatched",{"2":{"14":1,"28":1}}],["juliabranchlayer",{"2":{"62":1}}],["juliabilinear",{"2":{"67":1}}],["juliabidirectionalrnn",{"2":{"66":1}}],["juliabinaryfocalloss",{"2":{"53":1}}],["juliabinarycrossentropyloss",{"2":{"53":1}}],["juliabias",{"2":{"15":2}}],["juliabcast",{"2":{"44":1}}],["juliafig",{"2":{"250":2}}],["juliaf",{"2":{"176":1,"177":1}}],["juliafmap",{"2":{"113":1}}],["juliaflattenlayer",{"2":{"68":1}}],["juliafluxlayer",{"2":{"37":1}}],["juliaf64",{"2":{"56":1}}],["juliaf32",{"2":{"56":1}}],["juliaf16",{"2":{"56":1}}],["juliafor",{"2":{"174":1}}],["juliafoldl",{"2":{"54":1}}],["juliafocalloss",{"2":{"53":1}}],["juliafromfluxadaptor",{"2":{"37":1}}],["juliafrozenlayer",{"2":{"31":1}}],["juliafreeze",{"2":{"31":2}}],["juliafunction",{"2":{"111":1,"113":2,"126":1,"140":2,"145":1,"147":1,"148":1,"150":1,"151":1,"152":1,"179":1,"183":1,"184":2,"185":1,"187":1,"192":1,"195":1,"206":1,"207":2,"208":1,"210":1,"217":1,"219":1,"224":1,"228":1,"232":1,"233":2,"234":1,"236":1,"242":1,"244":1,"249":1,"254":4,"255":1,"256":1}}],["juliafunctional",{"2":{"3":1}}],["juliafused",{"2":{"16":1,"18":1}}],["juliafast",{"2":{"13":2}}],["juliats",{"2":{"245":1}}],["juliatstate",{"2":{"228":1}}],["juliatest",{"2":{"49":1}}],["juliatestmode",{"2":{"10":1}}],["juliatotal",{"2":{"43":1}}],["juliatosimplechainsadaptor",{"2":{"39":1}}],["juliatr",{"2":{"152":1,"196":1}}],["juliatry",{"2":{"125":1,"126":1}}],["juliatrain",{"2":{"196":1,"210":4,"212":1}}],["juliatrainstate",{"2":{"52":1}}],["juliatrainmode",{"2":{"10":1}}],["juliatruncated",{"2":{"24":1}}],["juliaimport",{"2":{"76":1}}],["juliaistraining",{"2":{"54":1}}],["juliaisleaf",{"2":{"3":1}}],["juliaidentity",{"2":{"24":1}}],["juliainput",{"2":{"153":1}}],["juliainternal",{"2":{"20":1}}],["juliainstancenorm",{"2":{"19":1,"69":1}}],["juliainitialized",{"2":{"42":1}}],["juliainitialize",{"2":{"42":1}}],["juliainitialstates",{"2":{"10":1}}],["juliainitialparameters",{"2":{"9":1}}],["juliadudt",{"2":{"220":1}}],["juliadataloader",{"2":{"160":2}}],["juliadata",{"2":{"119":1}}],["juliadicecoeffloss",{"2":{"53":1}}],["juliadistributedutils",{"2":{"119":1}}],["juliadistributeddatacontainer",{"2":{"46":1}}],["juliadistributedoptimizer",{"2":{"45":1}}],["juliadisplay",{"2":{"8":1}}],["juliadropout",{"2":{"17":1,"64":1}}],["juliadense",{"2":{"67":1}}],["juliadebuglayer",{"2":{"33":1}}],["juliadeviceiterator",{"2":{"5":1}}],["juliadefault",{"2":{"3":1}}],["juliacdev",{"2":{"117":1}}],["juliachain",{"2":{"62":1}}],["juliacheck",{"2":{"8":1}}],["juliacrossentropyloss",{"2":{"53":1}}],["juliaconst",{"2":{"113":1,"186":1,"194":1,"209":1,"227":1,"235":1,"249":1,"256":2,"257":2}}],["juliaconvtranspose",{"2":{"63":1}}],["juliaconv",{"2":{"63":1}}],["juliacontains",{"2":{"8":1}}],["juliacompute",{"2":{"52":1}}],["juliacpu",{"2":{"2":1}}],["juliaadtype",{"2":{"258":1}}],["juliaadaptor",{"2":{"193":1}}],["juliaadaptivemeanpool",{"2":{"65":1}}],["juliaadaptivemaxpool",{"2":{"65":1}}],["juliaadaptivelppool",{"2":{"65":1}}],["juliaadapt",{"2":{"37":1,"39":1}}],["juliaanalytical",{"2":{"243":1}}],["juliaallreduce",{"2":{"44":1}}],["juliaalphadropout",{"2":{"64":1}}],["juliaalpha",{"2":{"17":1}}],["juliaapply",{"2":{"8":1,"52":2}}],["juliaabstract",{"2":{"7":3}}],["julia>",{"2":{"5":4,"24":3,"32":6,"34":3,"37":6,"39":7,"48":1,"49":2,"53":45,"59":34,"62":3,"68":8,"71":2}}],["juliastruct",{"2":{"111":1,"141":1,"142":1,"184":1,"207":1,"211":1,"218":1,"241":1}}],["juliastatefulrecurrentcell",{"2":{"66":1}}],["juliastatefulluxlayer",{"2":{"58":1}}],["juliastatelength",{"2":{"10":1}}],["juliastateless",{"2":{"8":1}}],["juliaselectdim",{"2":{"68":1}}],["juliasetup",{"2":{"8":1}}],["juliaset",{"2":{"4":2,"60":1}}],["juliascale",{"2":{"67":1}}],["juliaskipconnection",{"2":{"62":1}}],["juliasquaredhingeloss",{"2":{"53":1}}],["juliasize",{"2":{"171":1}}],["juliasiamesecontrastiveloss",{"2":{"53":1}}],["juliasingle",{"2":{"52":2}}],["juliasimplechainslayer",{"2":{"39":1}}],["juliasynchronize",{"2":{"44":1}}],["juliashare",{"2":{"34":1}}],["juliasparse",{"2":{"24":1}}],["juliasupported",{"2":{"3":1}}],["juliagdev",{"2":{"153":1}}],["juliagrucell",{"2":{"66":1}}],["juliagroupnorm",{"2":{"19":1,"69":1}}],["juliaglobalmeanpool",{"2":{"65":1}}],["juliaglobalmaxpool",{"2":{"65":1}}],["juliagloballppool",{"2":{"65":1}}],["juliaglorot",{"2":{"24":2}}],["juliagenericlossfunction",{"2":{"53":1}}],["juliagetproperty",{"2":{"54":1}}],["juliaget",{"2":{"3":2,"42":1}}],["juliagpu",{"2":{"1":1,"2":1}}],["julia",{"0":{"170":1},"1":{"171":1,"172":1,"173":1,"174":1,"175":1,"176":1,"177":1,"178":1,"179":1,"180":1},"2":{"1":1,"16":1,"20":1,"33":1,"37":1,"48":1,"49":1,"50":1,"59":3,"60":1,"71":2,"74":1,"76":2,"77":3,"79":1,"81":1,"83":1,"84":1,"97":2,"101":1,"113":1,"115":1,"130":2,"131":2,"140":1,"144":1,"145":1,"147":1,"148":1,"152":1,"153":2,"154":1,"155":1,"167":2,"168":4,"170":2,"171":7,"174":1,"175":1,"180":12,"188":2,"189":12,"197":9,"213":2,"214":12,"221":12,"229":12,"237":12,"242":1,"246":12,"247":1,"248":1,"249":4,"250":2,"251":9,"254":1,"260":9}}],["jld2",{"2":{"182":1,"188":3}}],["jll",{"2":{"180":2,"189":2,"214":2,"221":2,"229":2,"237":2,"246":2}}],["jl`",{"2":{"18":1,"145":2}}],["jl",{"0":{"45":1,"46":1,"48":1,"71":1,"86":1,"89":1,"92":1,"93":1,"96":1,"113":1,"120":1,"161":1,"215":1},"1":{"87":1,"88":1,"90":1,"91":1,"94":1,"95":1,"97":1,"98":1,"99":1,"100":1,"114":1,"121":1,"122":1,"162":1,"163":1,"164":1,"165":1,"166":1,"167":1,"216":1,"217":1,"218":1,"219":1,"220":1,"221":1},"2":{"0":1,"2":3,"3":8,"6":5,"7":2,"8":1,"10":2,"11":1,"12":1,"13":3,"14":1,"18":2,"20":2,"22":2,"27":1,"28":1,"37":1,"39":4,"42":8,"45":1,"46":2,"47":1,"48":1,"49":6,"52":7,"53":2,"54":1,"60":1,"66":1,"71":4,"76":2,"78":3,"79":1,"80":5,"83":2,"90":3,"93":5,"95":1,"97":1,"102":8,"103":7,"105":1,"110":6,"113":3,"114":1,"115":1,"118":1,"119":1,"120":1,"121":1,"122":1,"125":2,"138":5,"140":1,"145":4,"153":3,"157":2,"158":2,"159":2,"160":3,"161":3,"163":1,"167":2,"168":1,"170":1,"172":1,"173":1,"175":4,"177":1,"179":1,"180":1,"181":2,"189":1,"190":4,"193":1,"196":1,"197":1,"203":3,"204":1,"207":1,"213":6,"214":1,"215":3,"219":3,"221":1,"226":1,"229":1,"237":1,"238":3,"244":4,"246":1,"247":2,"251":1,"252":1,"255":1,"256":1,"260":1}}],["p=res",{"2":{"259":1}}],["p=θ",{"2":{"257":1}}],["p=params",{"2":{"256":1}}],["p=2",{"2":{"65":3}}],["p^",{"2":{"255":1,"256":1}}],["p^2",{"2":{"255":1}}],["pdes",{"2":{"238":1}}],["pde",{"0":{"238":1},"1":{"239":1,"240":1,"241":1,"242":1,"243":1,"244":1,"245":1,"246":1},"2":{"243":8,"244":2,"245":3}}],["pcie",{"2":{"180":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["physics",{"2":{"242":6,"244":108,"256":1}}],["philosophies",{"2":{"134":1}}],["phase",{"2":{"69":4}}],["pptional",{"2":{"77":1,"78":1}}],["pkg>",{"2":{"161":2}}],["pkg",{"2":{"71":4,"72":9,"73":2,"76":2,"77":1,"79":2,"161":1,"180":2,"189":2,"197":2,"214":2,"221":2,"229":2,"237":2,"246":2,"251":2,"260":2}}],["pytorch",{"2":{"63":3,"67":1,"83":1,"99":3,"100":1,"170":1}}],["p2",{"2":{"53":6}}],["p1",{"2":{"53":4}}],["pipe",{"2":{"218":1}}],["pipeline",{"2":{"112":1}}],["pipelines",{"2":{"52":1}}],["pitfalls",{"0":{"154":1},"1":{"155":1,"156":1,"157":1,"158":1,"159":1,"160":1}}],["pinn2dpde",{"2":{"244":8}}],["pinn",{"0":{"238":1},"1":{"239":1,"240":1,"241":1,"242":1,"243":1,"244":1,"245":1,"246":1},"2":{"238":1,"241":4,"244":5,"245":1}}],["pinns",{"2":{"147":1,"238":1}}],["pin",{"2":{"124":2}}],["pixel",{"2":{"70":2}}],["pixelshuffle",{"2":{"70":1}}],["pixels",{"2":{"65":3,"70":2}}],["pi",{"2":{"53":1}}],["pmlr",{"2":{"19":1}}],["p",{"2":{"17":7,"37":1,"59":2,"64":12,"207":6,"211":2,"217":2,"219":4,"220":2,"250":2,"254":3,"255":6,"256":2,"258":1}}],["peel",{"2":{"184":1,"185":1}}],["peel`",{"2":{"184":1}}],["people",{"2":{"140":1}}],["pesky",{"2":{"126":1}}],["pended",{"2":{"97":1}}],["penalties",{"2":{"59":1}}],["penultimate",{"2":{"15":1,"16":1,"66":2}}],["perspective",{"2":{"254":1}}],["perceptron",{"2":{"222":1}}],["per",{"2":{"69":4,"146":1,"249":2}}],["periodic",{"2":{"63":1}}],["period",{"2":{"30":1}}],["perfect",{"2":{"24":1}}],["performs",{"2":{"116":1,"219":1}}],["performing",{"2":{"65":3}}],["performed",{"2":{"39":2,"63":1,"249":1}}],["performance",{"0":{"154":1,"159":1},"1":{"155":1,"156":1,"157":1,"158":1,"159":1,"160":1},"2":{"13":1,"24":2,"33":1,"52":1,"59":3,"103":2,"104":2,"105":1,"115":2,"153":1,"154":2,"155":2,"159":1}}],["perform",{"2":{"8":1,"44":2,"52":2,"63":3,"134":1,"249":1,"254":1}}],["plot",{"2":{"228":1,"248":3,"250":9,"255":1,"256":1,"259":1}}],["plotting",{"0":{"220":1}}],["plugin",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["plus",{"2":{"31":1,"34":1,"59":3,"62":6,"69":7,"77":1,"78":1,"109":1,"125":2,"126":2,"193":2,"225":1,"256":1}}],["platform",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["plan",{"2":{"144":1}}],["places",{"2":{"59":2}}],["place",{"2":{"13":1,"15":2,"55":5,"115":1,"122":1}}],["please",{"2":{"4":2,"74":2,"76":1,"78":1,"84":1,"105":1,"123":1,"127":1,"144":1,"184":1,"202":1,"203":3,"215":1,"238":1}}],["push",{"2":{"257":1}}],["pullback",{"2":{"126":2}}],["pull",{"2":{"84":1,"90":1}}],["publisher",{"2":{"74":1}}],["public",{"2":{"3":1,"53":1}}],["purpose",{"2":{"175":1}}],["purposes",{"2":{"57":1,"142":1,"206":1,"219":1}}],["pure",{"2":{"8":1,"81":1,"82":1,"83":1,"173":1}}],["pseudorandom",{"2":{"174":1}}],["pseudo",{"2":{"64":3,"170":1}}],["ps",{"2":{"7":2,"8":5,"31":2,"32":18,"34":17,"37":4,"39":2,"44":2,"53":2,"57":1,"58":5,"59":22,"62":4,"68":9,"77":3,"78":6,"107":3,"109":2,"110":2,"111":6,"112":2,"113":16,"114":6,"119":2,"125":5,"126":12,"129":9,"130":7,"131":6,"132":2,"133":5,"134":7,"140":7,"141":7,"142":10,"144":3,"145":9,"146":9,"147":8,"148":11,"150":2,"151":2,"152":9,"153":7,"155":5,"179":7,"184":4,"186":2,"187":3,"188":3,"194":2,"195":2,"207":2,"208":5,"209":2,"210":2,"211":3,"213":15,"219":4,"220":1,"227":1,"228":1,"233":2,"235":2,"236":2,"242":4,"244":3,"249":10,"250":1,"256":2}}],["power",{"2":{"250":1}}],["powerful",{"2":{"171":1}}],["pooling",{"0":{"65":1},"2":{"65":21,"100":1}}],["poisson",{"2":{"53":1}}],["poissonloss",{"2":{"53":2}}],["points",{"2":{"134":1,"179":1,"224":1,"248":4,"249":1,"250":1}}],["point",{"0":{"56":1},"2":{"4":2,"13":1,"56":3,"115":1,"119":1,"124":2,"128":1,"171":1,"255":1,"256":1}}],["populated",{"2":{"184":2}}],["populate",{"2":{"33":1}}],["polynomial",{"0":{"222":1},"1":{"223":1,"224":1,"225":1,"226":1,"227":1,"228":1,"229":1},"2":{"222":1,"224":1}}],["polyester",{"2":{"20":1}}],["polyalgorithm",{"2":{"18":1}}],["position=",{"2":{"217":1,"220":1,"256":1,"259":1}}],["position",{"2":{"68":2,"254":1}}],["possibly",{"2":{"63":2,"65":3,"103":1}}],["possible",{"2":{"1":1,"2":1,"7":1,"11":1,"13":3,"15":1,"16":2,"18":1,"37":2,"42":2,"104":1,"145":1}}],["posterior",{"2":{"250":2}}],["posted",{"2":{"144":1}}],["post",{"2":{"7":1,"39":1}}],["potentially",{"2":{"7":1,"11":1,"39":1}}],["painful",{"2":{"124":1}}],["pairwisefusion",{"2":{"62":3}}],["pairs",{"2":{"53":1,"213":13}}],["pair",{"2":{"53":1,"63":2,"66":1}}],["past",{"2":{"83":1}}],["passes",{"2":{"62":2,"127":1,"173":1}}],["passed",{"2":{"10":1,"19":1,"34":2,"48":1,"49":1,"59":1,"62":6,"66":5,"68":6,"82":1,"99":1,"141":1}}],["passing",{"2":{"8":1,"59":2,"62":1,"69":1,"119":2,"168":2}}],["pass",{"2":{"8":1,"27":2,"49":1,"50":1,"54":2,"56":1,"59":3,"62":1,"63":1,"67":2,"69":1,"78":1,"83":1,"97":1,"119":1,"126":3,"140":1,"168":1,"184":3}}],["pal2023efficient",{"2":{"74":1}}],["pal2023lux",{"2":{"74":1}}],["pal",{"2":{"74":2}}],["pattern",{"2":{"53":1,"113":1,"160":1,"248":1}}],["path",{"2":{"10":1,"62":1,"98":2,"129":2,"180":2,"189":2,"197":2,"214":2,"221":2,"229":2,"237":2,"246":2,"251":1,"254":4,"260":1}}],["page",{"2":{"29":1,"30":1,"31":1,"58":1,"85":1,"113":1,"124":1,"153":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["pad",{"2":{"63":6,"65":3}}],["pad=0",{"2":{"63":2,"65":3}}],["padding",{"2":{"24":1,"63":9,"65":12}}],["pads",{"2":{"24":1}}],["parse",{"2":{"146":1}}],["parallelism",{"2":{"160":1}}],["parallel=true",{"2":{"160":2}}],["parallel",{"0":{"118":1},"1":{"119":1,"120":1,"121":1,"122":1,"123":1},"2":{"32":1,"62":12,"68":1}}],["params=nothing",{"2":{"254":2}}],["params",{"2":{"31":14,"32":6,"52":2,"69":3,"129":3,"132":1,"254":4,"255":3,"256":6,"257":2,"258":1,"259":1}}],["parameterized",{"2":{"250":1}}],["parameterization",{"2":{"74":1,"247":1}}],["parameter",{"0":{"31":1,"142":1},"2":{"24":3,"31":2,"34":2,"53":1,"59":6,"63":4,"68":1,"69":2,"77":1,"82":1,"83":4,"119":1,"126":1,"131":2,"134":1,"140":5,"141":2,"142":5,"210":1,"219":2,"247":1,"249":2}}],["parameterlength",{"2":{"7":1,"9":1,"140":4,"141":1,"234":1,"249":3}}],["parameters",{"0":{"9":1,"34":1,"128":1,"131":1,"148":1},"1":{"129":1,"130":1,"131":1,"132":1},"2":{"3":1,"7":5,"8":1,"9":2,"24":1,"31":13,"32":7,"33":1,"34":23,"37":4,"39":1,"45":1,"52":9,"53":1,"56":2,"57":4,"58":5,"59":17,"62":24,"63":2,"66":9,"67":4,"68":2,"69":31,"77":5,"78":7,"81":1,"83":2,"90":2,"100":1,"109":5,"114":1,"119":1,"125":6,"126":7,"128":2,"131":3,"134":6,"138":1,"140":5,"141":3,"142":7,"144":1,"148":1,"175":1,"179":6,"184":2,"187":2,"188":1,"193":12,"195":2,"207":1,"210":2,"219":5,"225":3,"227":1,"228":3,"233":1,"236":4,"244":1,"249":79,"250":2,"256":6}}],["parts",{"2":{"219":1}}],["party",{"0":{"203":1}}],["particle",{"2":{"255":2,"256":1}}],["particles",{"2":{"254":1}}],["particular",{"0":{"129":1},"2":{"124":1,"129":1}}],["participate",{"0":{"107":1}}],["partition",{"2":{"46":1}}],["part",{"0":{"131":1,"132":1},"2":{"3":1,"54":1,"85":1,"145":1,"202":1,"207":1,"215":1}}],["packages",{"0":{"35":1,"79":1,"216":1},"1":{"36":1,"37":1,"38":1,"39":1},"2":{"3":3,"27":4,"28":2,"39":1,"52":2,"60":1,"77":1,"78":1,"79":3,"80":1,"90":1,"93":1,"101":2,"104":3,"105":2,"115":1,"154":1,"159":1,"166":1,"167":3,"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1,"247":1}}],["package",{"0":{"182":1,"191":1,"205":1,"223":1,"231":1,"239":1,"253":1},"2":{"0":1,"3":1,"4":3,"21":1,"22":1,"45":1,"47":3,"72":1,"73":1,"76":1,"79":1,"93":3,"97":1,"101":1,"102":1,"105":1,"116":2,"164":1,"169":1,"172":1,"203":1,"238":1}}],["practitioners",{"2":{"219":1}}],["prngs",{"2":{"174":1}}],["prng",{"2":{"170":1,"174":2}}],["prs",{"2":{"144":1}}],["primarily",{"2":{"249":1}}],["primitives",{"0":{"44":1,"158":1},"2":{"158":1,"249":1}}],["principles",{"0":{"82":1}}],["printf",{"2":{"78":2,"113":1,"114":1,"179":2,"182":1,"187":2,"191":1,"195":1,"205":1,"210":1,"216":1,"219":1,"223":1,"228":1,"231":1,"236":2,"239":1,"244":1,"253":1,"257":1}}],["printouts",{"2":{"83":1}}],["printout",{"2":{"59":1}}],["print",{"2":{"57":1,"59":1}}],["printing",{"2":{"39":1,"68":1,"78":1,"83":1}}],["println",{"2":{"32":1,"125":2,"126":2,"140":2,"141":3,"142":2,"145":2,"146":2,"147":2,"148":2,"152":6,"173":2,"174":2,"176":2,"177":1,"178":1,"179":3,"180":2,"189":2,"197":2,"214":2,"221":2,"229":2,"236":1,"237":2,"246":2,"251":2,"260":2}}],["prints",{"2":{"4":2,"126":1}}],["printed",{"2":{"2":1,"8":1,"37":1,"59":1}}],["priority",{"2":{"104":2}}],["prior",{"2":{"63":1,"249":1}}],["pr",{"2":{"11":1,"202":1,"203":1}}],["precompile",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["precision",{"0":{"56":1},"2":{"16":2,"56":1,"155":3,"171":1}}],["press",{"2":{"161":1}}],["pressing",{"2":{"76":1}}],["presence",{"2":{"59":1}}],["presented",{"2":{"177":1}}],["presently",{"2":{"113":1}}],["present",{"2":{"37":1,"39":1,"48":1,"54":1,"63":2,"66":10,"67":2,"97":1,"116":2,"125":1,"126":1}}],["preserving",{"2":{"39":1,"70":1}}],["preservation",{"2":{"37":1}}],["preserved",{"2":{"39":1}}],["preserve",{"2":{"37":7,"39":1}}],["pretty",{"2":{"68":1,"78":1,"83":1,"120":1,"145":1}}],["preds",{"2":{"249":2}}],["pred=ŷ",{"2":{"186":1}}],["predictive",{"2":{"250":1}}],["predictions",{"2":{"228":1,"249":2,"250":2}}],["prediction",{"0":{"250":1},"2":{"53":2,"249":1,"250":1}}],["predictor",{"2":{"245":1}}],["predict",{"2":{"183":1,"250":6}}],["predicted",{"2":{"53":3,"194":2,"209":2,"235":2,"250":2}}],["pred",{"2":{"53":8,"113":4,"186":5,"219":2,"220":3,"228":2,"245":4,"257":4}}],["preprint",{"2":{"19":2,"69":1}}],["preprocessing",{"2":{"8":1}}],["prevents",{"2":{"97":1}}],["prevent",{"2":{"17":2,"42":1,"52":1,"53":1,"97":1,"140":1}}],["previously",{"2":{"7":1,"11":1,"83":1,"90":1,"99":1,"121":1}}],["previous",{"2":{"5":1,"7":1,"83":1,"146":1}}],["pre",{"2":{"7":1,"11":1,"63":1,"76":1,"77":1,"97":1}}],["prefer",{"2":{"158":1}}],["preferably",{"2":{"20":1}}],["preferred",{"2":{"5":1,"20":1}}],["preferencetools",{"2":{"161":2}}],["preference",{"2":{"1":2,"2":1,"57":1,"60":2,"144":1,"155":1,"157":1,"161":6,"164":2,"165":1,"166":3,"167":1}}],["preferences",{"0":{"1":1,"161":1},"1":{"162":1,"163":1,"164":1,"165":1,"166":1,"167":1},"2":{"57":1,"60":4,"97":1,"157":2,"161":4,"163":3,"166":2}}],["progress",{"2":{"247":3}}],["programming",{"2":{"170":1}}],["proto",{"2":{"195":4}}],["probabilistic",{"2":{"249":2}}],["probability",{"2":{"17":3,"53":1,"64":3}}],["prob",{"2":{"207":4,"211":2,"217":2,"219":9,"220":2,"255":1,"256":1,"257":1,"259":1}}],["problem",{"0":{"240":1},"2":{"125":1,"126":1,"145":1,"148":1,"173":1,"179":2,"211":1,"213":1,"219":1,"225":1,"240":1}}],["problematic",{"2":{"124":1,"125":1}}],["problems",{"0":{"125":1},"2":{"81":1,"113":1}}],["promotion",{"0":{"155":1},"2":{"155":1}}],["promotions",{"2":{"57":1,"155":1}}],["promote",{"2":{"16":1,"155":1}}],["project",{"2":{"47":1}}],["produce",{"2":{"54":1,"90":1}}],["products",{"2":{"27":2}}],["product",{"0":{"150":1,"151":1,"177":1,"178":1},"2":{"27":8,"144":2,"149":4,"150":1,"151":1,"175":5,"177":2,"178":1,"243":1,"245":1}}],["prod",{"2":{"24":1}}],["propagating",{"2":{"58":1}}],["propagated",{"2":{"62":1}}],["propagate",{"2":{"8":1}}],["proper",{"2":{"112":1,"170":1}}],["properly",{"2":{"33":1}}],["properties",{"2":{"28":1,"62":1}}],["proportion",{"2":{"24":3}}],["providing",{"2":{"21":1,"193":1}}],["provides",{"2":{"39":1,"49":1,"58":1,"77":1,"95":1,"138":1,"161":1,"168":1,"177":1,"211":1,"215":1}}],["provide",{"2":{"11":1,"24":1,"37":1,"52":2,"59":1,"79":1,"101":1,"149":1,"172":1}}],["provided",{"2":{"4":2,"5":1,"17":1,"30":1,"32":2,"54":1,"66":3,"119":1,"138":1,"172":1,"227":1,"250":1}}],["proceeding",{"2":{"140":1}}],["proceedings",{"2":{"19":1,"24":5,"53":2}}],["proceeds",{"2":{"66":8}}],["processor",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["processes",{"2":{"45":1,"46":1,"119":3,"160":1}}],["processing",{"2":{"17":1,"66":1}}],["process",{"2":{"4":1,"119":1,"160":1,"192":1,"206":1,"243":1}}],["ddot",{"2":{"254":2}}],["ddp",{"2":{"118":1}}],["dt^2",{"2":{"254":1}}],["dt2",{"2":{"254":3}}],["dt",{"2":{"254":21,"255":4,"256":2,"257":2,"259":2}}],["dset",{"2":{"232":4}}],["dnns",{"2":{"124":1}}],["dl",{"2":{"54":1,"256":1}}],["dynamic",{"2":{"47":1}}],["dynamics",{"2":{"24":1}}],["d2",{"2":{"34":5,"109":1,"110":3,"254":3}}],["d2=dense",{"2":{"34":1,"109":1,"112":1}}],["d3",{"2":{"34":9}}],["d3=chain",{"2":{"34":1}}],["d1",{"2":{"34":5,"109":1,"110":3}}],["d1=dense",{"2":{"34":1,"109":1,"112":1}}],["d1×",{"2":{"19":2,"69":2}}],["driver",{"2":{"180":3,"189":3,"214":3,"221":3,"229":3,"237":3,"246":3}}],["dr",{"2":{"124":1}}],["drawn",{"2":{"24":5,"250":1}}],["drop",{"2":{"53":1,"144":1}}],["dropped",{"2":{"17":2,"27":2}}],["dropout",{"0":{"17":1,"64":1},"2":{"17":14,"64":17,"83":1,"129":1,"132":1,"136":1,"143":1}}],["duration",{"2":{"249":2}}],["during",{"2":{"3":1,"69":4}}],["du",{"2":{"217":3}}],["dudt",{"2":{"207":4,"211":2,"219":2,"220":1}}],["due",{"2":{"146":1,"153":1,"213":1}}],["dummy",{"2":{"77":1}}],["dual",{"2":{"20":1}}],["dmitry",{"2":{"19":1,"69":1}}],["d",{"2":{"8":1,"59":11,"63":4,"65":6,"68":2,"70":4,"104":1,"129":2,"130":5,"131":6,"142":4,"183":4,"210":2,"254":2}}],["domain",{"2":{"243":1}}],["domainerror",{"2":{"33":1,"126":2}}],["doubt",{"2":{"140":1}}],["dot",{"2":{"110":3,"125":1,"145":2,"213":3,"217":2,"220":2,"244":4}}],["doi",{"2":{"74":2,"254":2}}],["doing",{"2":{"55":4,"114":1,"233":1,"249":1}}],["document",{"2":{"101":1}}],["documented",{"2":{"97":1}}],["documentations",{"2":{"154":1}}],["documentation",{"2":{"7":1,"8":1,"14":1,"49":1,"60":1,"70":1,"79":1,"84":1,"99":2,"140":1,"165":1,"166":1,"196":1,"203":1}}],["doctor",{"0":{"166":1},"2":{"60":4,"157":1,"166":3}}],["docstrings",{"2":{"140":1}}],["docstring",{"2":{"97":1}}],["docs",{"2":{"59":2,"87":1,"215":1,"244":4,"247":2}}],["downstream",{"2":{"83":1,"105":1,"203":1}}],["downright",{"2":{"83":1,"138":1}}],["down",{"0":{"126":1},"2":{"53":2,"57":1,"125":1,"126":1,"127":1,"141":1,"155":1,"171":2}}],["does",{"2":{"13":1,"19":2,"57":1,"68":1}}],["doesn",{"2":{"13":2,"32":1,"34":1,"54":1,"59":3,"66":1,"107":1,"136":1,"140":2,"142":1,"143":1,"145":1,"234":1}}],["do",{"2":{"6":1,"59":14,"62":1,"68":2,"76":1,"78":2,"92":1,"113":2,"114":1,"136":1,"140":1,"141":1,"142":1,"143":1,"144":1,"149":2,"153":1,"155":1,"160":3,"171":2,"173":1,"184":1,"185":1,"193":1,"207":1,"219":2,"225":1,"233":1,"245":1,"249":1,"250":1,"254":1,"256":1}}],["done",{"2":{"13":2,"32":1,"57":1,"77":1,"116":1,"119":1,"146":1,"167":1}}],["don",{"2":{"4":2,"16":1,"18":1,"25":1,"47":1,"59":2,"77":1,"83":1,"104":2,"105":1,"122":1,"123":1,"124":1,"127":1,"134":1,"140":2,"142":1,"144":1,"146":1,"171":2,"173":2,"177":1,"183":1,"184":1,"188":1,"192":1,"206":1,"218":1,"233":1}}],["digits=2",{"2":{"236":4}}],["digits",{"2":{"171":2}}],["direactly",{"2":{"97":1}}],["direct",{"2":{"97":1}}],["direction",{"2":{"69":2}}],["directly",{"2":{"3":1,"5":1,"6":1,"8":1,"17":1,"31":1,"41":2,"52":1,"55":2,"62":2,"68":1,"70":1,"94":1,"98":1,"117":1,"119":1,"144":1,"168":1,"204":1}}],["diagonal",{"2":{"67":1,"249":1}}],["divisible",{"2":{"63":2}}],["divides",{"2":{"70":1}}],["divide",{"2":{"63":2}}],["diverges",{"2":{"53":1}}],["divergence",{"2":{"53":2}}],["dilation",{"2":{"63":2,"65":3}}],["dilation=1",{"2":{"63":2,"65":3}}],["dice",{"2":{"53":2}}],["dicecoeffloss",{"2":{"53":4}}],["diffeqsol",{"2":{"207":3,"208":1,"213":9}}],["diffeqflux",{"2":{"204":1}}],["differ",{"2":{"175":1}}],["differern",{"2":{"146":1}}],["differences",{"0":{"122":1},"2":{"118":1,"134":1,"145":2}}],["difference",{"2":{"64":1,"90":1,"113":3,"141":1,"145":2,"146":2,"149":1,"212":1,"254":2}}],["differentiate",{"2":{"113":1,"152":1,"173":1}}],["differentiationinterface",{"2":{"144":1,"177":2}}],["differentiation",{"0":{"26":1,"101":1,"144":1,"162":1,"175":1},"1":{"27":1,"28":1,"29":1,"102":1,"103":1,"104":1,"105":1,"145":1,"146":1,"147":1,"148":1,"149":1,"150":1,"151":1,"152":1,"176":1,"177":1,"178":1},"2":{"29":1,"113":1,"142":1,"144":1,"147":1,"153":1,"162":2,"170":1,"177":1}}],["differential",{"2":{"74":1,"257":1}}],["differently",{"2":{"62":1}}],["different",{"0":{"38":1},"1":{"39":1},"2":{"18":1,"20":1,"32":1,"53":1,"60":1,"62":1,"99":1,"134":1,"146":1,"165":1,"174":1,"219":1}}],["diff",{"2":{"145":1,"147":1,"148":1,"175":1}}],["diffractor",{"2":{"102":1}}],["difficulty",{"2":{"24":2}}],["dim",{"2":{"68":6,"114":1,"179":7}}],["dimwhere",{"2":{"53":1}}],["dims=3",{"2":{"183":1}}],["dims=ndims",{"2":{"109":1}}],["dims=colon",{"2":{"69":1}}],["dims=2",{"2":{"66":1}}],["dims=",{"2":{"64":2}}],["dims=pad",{"2":{"63":1}}],["dims=1",{"2":{"19":1,"53":1,"243":5}}],["dims",{"2":{"17":2,"19":3,"24":11,"39":2,"53":2,"54":1,"63":1,"64":4,"66":31,"67":55,"68":7,"69":3,"87":1,"140":12,"169":4,"184":9,"185":7,"241":11,"244":2}}],["dimensionmismatch",{"2":{"125":2}}],["dimensionality",{"2":{"53":1}}],["dimensional",{"2":{"19":2,"67":3,"70":2,"177":1}}],["dimensions",{"2":{"19":2,"24":11,"28":2,"39":1,"63":3,"65":9,"66":2,"67":10,"68":5,"69":4,"70":8,"100":1,"179":1,"193":1}}],["dimension",{"0":{"125":1},"2":{"15":2,"16":1,"19":1,"39":1,"54":1,"63":4,"64":2,"65":6,"66":8,"67":1,"68":9,"69":14,"87":1,"109":1,"112":1,"124":1,"169":1}}],["disabling",{"0":{"167":1},"2":{"159":1}}],["disabled",{"2":{"8":1,"63":2,"67":3,"156":1}}],["disable",{"2":{"8":1,"33":1,"60":3,"97":2,"126":1,"144":1,"156":1,"162":1,"166":1,"167":2}}],["disallow",{"2":{"156":1}}],["disaster",{"2":{"155":1}}],["discrete",{"2":{"207":1,"210":1}}],["discouraged",{"2":{"145":2}}],["discourse",{"2":{"144":1,"145":1,"147":1}}],["discuss",{"2":{"215":1}}],["discussed",{"2":{"127":1}}],["discussions",{"2":{"84":1}}],["discussion",{"2":{"66":1,"147":1,"177":1}}],["disruptive",{"2":{"81":1}}],["dissimilar",{"2":{"53":1}}],["distinguish",{"2":{"134":2}}],["distinction",{"2":{"83":1}}],["distinct",{"2":{"66":1}}],["distance",{"2":{"53":1}}],["distributions",{"2":{"53":1,"249":2}}],["distribution",{"2":{"24":8,"25":12,"53":5,"63":2,"66":6,"67":3,"250":1}}],["distributeddatacontainer",{"2":{"46":1,"119":2,"120":1}}],["distributedoptimizer",{"2":{"45":2,"119":2,"120":1}}],["distributedutils",{"0":{"119":1},"2":{"4":2,"40":1,"41":2,"42":3,"43":2,"44":6,"45":1,"46":1,"118":1,"119":11,"120":5,"121":1,"122":3}}],["distributed",{"0":{"40":1,"118":1},"1":{"41":1,"42":1,"43":1,"44":1,"45":1,"46":1,"119":1,"120":1,"121":1,"122":1,"123":1},"2":{"4":3,"24":2,"41":4,"42":7,"83":1,"119":2}}],["disjoint",{"2":{"34":1}}],["displays",{"2":{"248":1,"250":1}}],["displayed",{"2":{"116":1}}],["display",{"2":{"8":1,"83":1,"141":1}}],["dispatch=",{"2":{"233":1}}],["dispatch=nothing",{"2":{"59":1}}],["dispatch₋₋₋",{"2":{"213":3}}],["dispatching",{"0":{"106":1},"1":{"107":1,"108":1,"109":1,"110":1,"111":1,"112":1}}],["dispatchdoctor",{"2":{"8":1,"60":1,"157":1}}],["dispatches",{"2":{"3":1,"8":1,"20":2,"54":1,"59":1,"138":1}}],["dispatch",{"0":{"107":1,"111":1,"166":1},"2":{"3":1,"47":1,"59":2,"60":4,"107":2,"111":1,"112":1,"143":1,"153":1,"157":1,"166":3}}],["date",{"2":{"203":2}}],["datapoints",{"2":{"224":1}}],["datasize",{"2":{"217":1,"255":1}}],["datasets",{"0":{"232":1},"2":{"183":1,"232":2,"236":1}}],["dataset",{"0":{"183":1,"224":1},"2":{"46":1,"160":2,"183":7,"192":3,"206":3,"219":1,"224":2,"232":2,"248":2}}],["datatype",{"2":{"8":1}}],["dataloaders",{"2":{"183":3,"187":2,"236":3}}],["dataloader",{"0":{"218":1},"2":{"5":8,"95":1,"114":4,"160":5,"183":5,"192":3,"194":2,"195":5,"205":1,"206":3,"209":2,"210":5,"218":5,"219":4,"232":2,"235":2,"236":9,"244":6}}],["data",{"0":{"2":1,"118":1,"160":1,"217":1,"243":1,"248":1},"1":{"119":1,"120":1,"121":1,"122":1,"123":1},"2":{"0":1,"2":1,"3":3,"5":1,"46":2,"52":6,"53":1,"59":10,"63":5,"65":9,"66":1,"68":1,"69":6,"70":2,"78":10,"83":1,"95":1,"113":1,"114":2,"119":3,"140":1,"153":1,"155":1,"160":5,"179":1,"183":8,"192":6,"206":6,"217":3,"218":3,"219":3,"220":2,"222":1,"224":4,"227":1,"228":5,"235":2,"236":16,"242":5,"243":10,"244":113,"248":6,"249":1,"250":7,"255":3,"256":2,"257":1,"259":2}}],["danger",{"2":{"2":1,"4":2,"28":1,"42":1}}],["derivative",{"2":{"147":1}}],["derivatives",{"2":{"145":1,"146":1,"177":1,"240":1,"256":1}}],["de",{"2":{"145":2}}],["demonstration",{"2":{"206":1,"219":1,"238":1}}],["demonstrative",{"2":{"142":1}}],["demonstrate",{"2":{"134":1,"145":1,"179":1,"190":1}}],["deal",{"2":{"147":1,"207":1}}],["deadlocks",{"2":{"123":1}}],["deactivate",{"2":{"66":3}}],["decision",{"2":{"161":1}}],["decides",{"2":{"136":1}}],["decouples",{"2":{"69":1}}],["declared",{"2":{"59":1}}],["decrease",{"2":{"13":1}}],["debuglayer",{"2":{"33":3,"125":4,"126":4}}],["debug",{"2":{"33":5,"98":1,"124":4,"125":6,"126":10,"155":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["debugging",{"0":{"33":1,"124":1},"1":{"125":1,"126":1,"127":1},"2":{"33":3,"57":1,"124":2}}],["delta=0",{"2":{"53":1}}],["delta",{"2":{"53":2}}],["delving",{"2":{"24":2}}],["deleted",{"2":{"1":1}}],["descent",{"2":{"179":2}}],["describe",{"2":{"153":1}}],["describes",{"2":{"39":1,"124":1,"255":1,"256":1}}],["described",{"2":{"24":3,"62":2}}],["despite",{"2":{"52":1}}],["destructure",{"2":{"37":3,"83":2,"137":1}}],["desirable",{"2":{"167":1,"249":1}}],["desired",{"2":{"1":1,"63":1,"100":1}}],["design",{"0":{"82":1},"2":{"5":1,"81":1,"134":1}}],["density",{"2":{"249":1}}],["denselayerparameters",{"2":{"142":3}}],["dense",{"2":{"18":2,"31":2,"32":18,"34":4,"37":2,"39":3,"53":2,"59":10,"62":12,"67":2,"68":1,"69":12,"77":17,"78":6,"88":1,"99":1,"109":6,"110":2,"112":2,"113":9,"114":3,"125":17,"126":14,"129":9,"130":3,"132":3,"133":5,"140":1,"142":2,"145":2,"146":2,"147":4,"148":4,"152":4,"153":2,"155":1,"158":1,"166":1,"179":2,"184":2,"185":1,"193":9,"208":5,"213":45,"219":3,"225":4,"228":4,"234":4,"241":4,"249":4,"256":6}}],["denom",{"2":{"255":3,"256":3}}],["denominator",{"2":{"19":4,"69":4}}],["denotes",{"2":{"3":4}}],["detour",{"2":{"175":1}}],["detection",{"2":{"53":2}}],["detected",{"2":{"33":1,"126":2,"244":1}}],["deterministic",{"2":{"24":1,"83":1}}],["determined",{"2":{"77":1}}],["determines",{"2":{"39":1}}],["determine",{"2":{"3":1,"17":2,"19":2,"55":1,"122":1,"249":1}}],["details",{"0":{"135":1},"1":{"136":1},"2":{"14":1,"17":2,"19":4,"33":1,"34":1,"37":1,"39":2,"49":1,"58":1,"59":2,"60":1,"69":1,"70":1,"87":1,"90":1,"92":1,"97":1,"99":2,"140":1,"162":1,"165":1,"166":1,"172":1}}],["detailed",{"2":{"7":1,"31":1,"125":1}}],["depots",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["depot",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["depwarn",{"2":{"97":1}}],["deprecated",{"2":{"87":1,"244":4}}],["deprecation",{"2":{"30":1,"93":2,"145":2}}],["deprecations",{"2":{"2":1,"97":1}}],["depthwise",{"2":{"63":2}}],["depths",{"2":{"32":1}}],["dependent",{"0":{"109":1},"2":{"108":1}}],["dependencies",{"0":{"159":1},"2":{"47":1,"90":1,"167":1,"249":1}}],["dependency",{"2":{"6":1,"21":1,"47":1,"138":1,"146":1}}],["depend",{"2":{"6":1,"19":1,"138":1,"140":1}}],["depending",{"2":{"6":1,"8":1,"24":1}}],["defiing",{"0":{"256":1}}],["definition",{"0":{"240":1}}],["definitions",{"2":{"141":1}}],["definitely",{"2":{"152":1}}],["defining",{"0":{"78":1,"186":1},"2":{"0":1,"3":2,"11":1,"59":1,"78":1,"107":1,"113":1,"138":1,"140":1,"141":1,"142":1,"184":1,"185":2,"193":1,"233":1}}],["define",{"0":{"193":1,"195":1,"207":1,"209":1,"218":1,"235":1,"241":1,"242":1,"254":1},"2":{"7":1,"20":1,"78":1,"107":2,"108":1,"111":1,"126":2,"134":2,"138":2,"140":3,"141":1,"142":2,"153":1,"179":1,"184":3,"185":1,"186":1,"207":1,"218":1,"219":1,"241":1,"242":1,"249":3,"254":2,"256":2,"257":2}}],["defines",{"2":{"6":1,"7":2,"55":1,"254":1,"255":1}}],["defined",{"2":{"3":1,"8":1,"11":1}}],["defer",{"2":{"177":1}}],["defaults",{"0":{"99":1},"2":{"58":1,"66":3,"99":4,"256":1}}],["default",{"2":{"3":2,"8":1,"19":10,"22":5,"24":8,"25":24,"32":1,"37":1,"39":3,"56":1,"57":1,"59":1,"66":1,"68":4,"69":1,"73":4,"77":1,"78":1,"83":1,"87":1,"90":2,"97":1,"99":2,"113":1,"114":1,"132":1,"133":2,"134":2,"136":2,"140":1,"142":5,"155":1,"156":1,"163":1,"166":1,"167":1,"168":4,"169":1,"170":1,"171":1,"173":1,"179":1,"180":1,"184":1,"189":1,"197":1,"208":1,"213":1,"214":1,"218":1,"219":1,"221":1,"229":1,"233":1,"237":1,"244":1,"246":1,"248":1,"251":1,"256":1,"260":1}}],["dev=gpu",{"2":{"208":1}}],["developer",{"2":{"113":1}}],["developed",{"2":{"83":1,"203":1}}],["deviate",{"2":{"256":1}}],["deviation",{"2":{"24":3,"69":1}}],["devicememory",{"2":{"5":3,"77":18,"153":2,"168":2,"172":1,"213":18}}],["deviceiterator",{"2":{"5":3,"95":2,"114":2,"218":1}}],["device",{"0":{"160":1},"2":{"2":25,"3":32,"4":11,"5":3,"20":1,"42":1,"72":5,"73":4,"77":2,"78":1,"93":1,"94":3,"98":2,"113":5,"114":5,"116":7,"117":2,"122":4,"134":3,"153":1,"160":5,"180":1,"187":2,"208":1,"210":2,"213":1,"214":1,"216":2,"218":1,"221":1,"227":2,"228":1,"229":1,"236":1,"237":1,"239":2,"246":1}}],["devices",{"2":{"0":1,"42":4,"134":1,"189":1}}],["dev",{"2":{"2":1,"3":1,"4":2,"5":4,"20":2,"72":4,"73":3,"77":5,"78":4,"187":3,"208":2,"210":3,"227":3,"228":2,"236":4}}],["deepcopy",{"2":{"52":1}}],["deep",{"2":{"2":1,"19":1,"21":1,"24":6,"74":1,"83":1,"155":1,"158":1,"168":1,"169":1}}],["axes",{"2":{"233":3}}],["ax",{"2":{"217":4,"220":6,"224":4,"228":5,"245":4,"248":3,"255":4,"256":6,"259":11}}],["axislegend",{"2":{"217":1,"220":1,"224":1,"228":1,"255":1,"256":1,"259":1}}],["axis",{"2":{"213":44,"217":1,"220":1,"224":1,"228":1,"245":1,"248":1,"250":1,"255":1,"256":1,"259":2}}],["a100",{"2":{"180":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["ai",{"2":{"177":1}}],["aims",{"2":{"24":1}}],["a∈rd×d",{"2":{"149":1}}],["a=layer",{"2":{"134":1}}],["a×b×x",{"2":{"134":1}}],["ah",{"2":{"126":1}}],["ahmadi",{"2":{"53":1}}],["ahmad",{"2":{"53":1}}],["aware",{"0":{"163":1},"2":{"122":2,"123":1,"163":4}}],["author",{"2":{"74":2}}],["autojacvec=reversediffvjp",{"2":{"210":1}}],["autojacvec=zygotevjp",{"2":{"208":1,"210":1}}],["auto",{"2":{"136":1,"155":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["autoreactant",{"2":{"52":1}}],["autoreversediff",{"2":{"49":1,"52":2}}],["autoenzyme",{"2":{"49":1,"52":1,"114":2}}],["autofinitediff",{"2":{"49":1}}],["autoforwarddiff",{"2":{"27":1,"28":1,"49":1,"146":1,"151":1,"177":2}}],["autotracker",{"2":{"49":1,"52":1}}],["autozygote",{"2":{"27":1,"28":1,"49":1,"52":1,"77":2,"78":1,"150":1,"178":1,"179":1,"187":1,"195":2,"210":1,"219":1,"228":2,"236":1,"244":1,"258":1}}],["autodiff",{"2":{"17":2,"19":2,"81":1,"142":1,"144":1,"145":2,"175":2}}],["autoselection",{"2":{"2":1}}],["automatically",{"2":{"5":1,"7":2,"8":1,"17":3,"19":2,"66":2,"122":1,"136":1,"137":1,"144":1,"159":1,"183":1,"184":2,"185":1,"192":1,"206":1,"249":1}}],["automatic",{"0":{"26":1,"101":1,"116":1,"144":1,"162":1,"165":1,"175":1},"1":{"27":1,"28":1,"29":1,"102":1,"103":1,"104":1,"105":1,"145":1,"146":1,"147":1,"148":1,"149":1,"150":1,"151":1,"152":1,"176":1,"177":1,"178":1},"2":{"2":1,"3":1,"8":1,"29":1,"113":1,"116":2,"117":1,"142":1,"144":2,"153":1,"162":4,"164":1,"170":1,"177":1}}],["affected",{"2":{"149":1}}],["affects",{"2":{"63":1}}],["affine",{"2":{"69":1}}],["affine=false",{"2":{"69":5,"99":1}}],["affine=true",{"2":{"62":2,"69":20,"99":1,"125":1,"126":2}}],["afterwards",{"2":{"69":1}}],["after",{"2":{"17":2,"33":1,"59":1,"62":2,"64":1,"65":3,"69":4,"83":1,"119":1,"122":1,"124":1,"160":1,"179":14,"184":1}}],["ab7d",{"2":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["abyss",{"2":{"170":1}}],["ability",{"2":{"138":1}}],["able",{"2":{"90":1,"181":1}}],["above",{"2":{"54":1,"62":2,"76":1,"148":1,"169":1,"172":1,"250":1}}],["about",{"2":{"33":1,"57":1,"83":1,"140":1,"171":1,"174":1,"184":1,"243":1,"250":1}}],["abstol",{"2":{"213":13}}],["abstol=1",{"2":{"208":1}}],["abstraction",{"2":{"93":1}}],["abstractions",{"2":{"20":1}}],["abstractexplicitcontainerlayer",{"2":{"90":2,"91":1}}],["abstractexplicitlayer",{"2":{"90":1}}],["abstractrecurrentcell",{"2":{"66":2}}],["abstractrng=utils",{"2":{"24":8,"25":24}}],["abstractrng",{"2":{"7":2,"8":2,"9":1,"10":1,"17":4,"24":3,"134":2,"140":2,"224":1,"233":1}}],["abstracttimeseriesdatabatchordering=batchlastindex",{"2":{"66":2}}],["abstractadtype",{"2":{"27":2,"28":1,"52":1}}],["abstractarrays",{"2":{"49":1}}],["abstractarray",{"2":{"13":2,"16":2,"19":1,"20":1,"24":16,"25":60,"28":1,"54":1,"55":1,"64":3,"67":6,"68":6,"69":1,"111":1,"134":2,"144":3,"148":1,"184":1,"185":1,"219":1,"220":1,"242":3}}],["abstractmatrix",{"2":{"18":2,"68":1,"140":1,"141":1,"207":1}}],["abstractvector",{"2":{"16":1,"18":1,"68":1,"249":1,"254":2}}],["abstractluxdistributedbacked",{"2":{"45":1}}],["abstractluxdistributedbackend",{"2":{"42":3,"43":2,"44":7,"46":1}}],["abstractluxwrapperlayer",{"2":{"7":4,"32":1,"90":1,"91":2,"109":1,"141":1,"207":1,"211":1}}],["abstractluxcontainerlayer",{"2":{"7":5,"90":1,"141":3,"184":2,"241":1}}],["abstractluxlayers",{"2":{"62":1}}],["abstractluxlayer",{"2":{"7":5,"8":2,"31":4,"32":3,"33":1,"39":3,"58":1,"62":4,"69":1,"90":1,"107":2,"110":3,"111":2,"134":1,"140":2,"207":3,"211":2,"233":2}}],["abstract",{"0":{"7":1},"2":{"3":2,"6":1,"7":3,"67":4,"219":1}}],["abstractdevice",{"2":{"2":1,"3":9,"4":4,"5":1}}],["abstractgpudevice",{"2":{"1":1,"117":1}}],["absolute",{"2":{"53":1,"155":1}}],["absolutely",{"2":{"52":1}}],["abs2",{"2":{"49":1,"53":1,"59":3,"145":2,"146":2,"147":2,"148":1,"242":3,"249":1}}],["abs",{"2":{"24":1,"68":1,"245":2,"254":1}}],["amazing",{"2":{"203":1}}],["am",{"2":{"147":1,"256":1}}],["ambiguous",{"2":{"55":1,"90":1}}],["amp",{"0":{"27":1,"154":1,"170":1},"1":{"155":1,"156":1,"157":1,"158":1,"159":1,"160":1,"171":1,"172":1,"173":1,"174":1,"175":1,"176":1,"177":1,"178":1,"179":1,"180":1},"2":{"27":2,"28":1,"52":1,"63":4,"66":1,"67":1,"68":1,"69":1,"81":2}}],["amd",{"2":{"3":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["amdgpudevice",{"2":{"4":2,"117":2,"122":1,"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["amdgpu",{"2":{"2":2,"3":1,"22":2,"42":1,"72":2,"77":1,"78":1,"80":2,"104":1,"115":2,"123":1,"180":2,"189":2,"197":2,"214":2,"221":2,"229":2,"237":2,"246":2,"251":2,"260":2}}],["average",{"2":{"250":3}}],["averages",{"2":{"44":2,"45":1}}],["avik",{"2":{"74":2}}],["avg",{"2":{"44":2}}],["avoids",{"2":{"211":1}}],["avoiding",{"2":{"146":1}}],["avoid",{"2":{"17":1,"66":1,"83":1,"122":1,"211":1,"213":1,"249":2}}],["available",{"2":{"13":2,"16":1,"18":1,"40":1,"46":1,"76":1,"79":1,"101":1,"113":1,"116":1,"117":1,"137":1,"159":1,"180":1,"189":2,"214":1,"221":1,"229":1,"237":1,"246":1}}],["aka",{"2":{"16":1,"18":1}}],["academic",{"2":{"74":1}}],["achieved",{"2":{"63":1,"146":1}}],["achieve",{"2":{"24":1,"66":1}}],["acc",{"2":{"187":2,"195":8,"196":2,"210":4,"236":13}}],["accumulated",{"2":{"219":1}}],["accumulates",{"2":{"69":2}}],["accuracy",{"0":{"186":1},"2":{"13":1,"186":2,"187":102,"194":2,"195":4,"196":40,"209":2,"210":94,"212":18,"235":2,"236":212}}],["account",{"2":{"59":1}}],["according",{"2":{"24":1}}],["accordingly",{"2":{"19":2,"69":2}}],["accidental",{"2":{"57":1}}],["accelerate",{"2":{"167":1}}],["accelerating",{"2":{"19":1}}],["acceptance",{"2":{"249":1}}],["accept",{"2":{"142":1,"249":1}}],["accepts",{"2":{"70":1}}],["access",{"2":{"59":1,"62":2,"72":1,"73":1,"140":1,"141":1,"142":1}}],["accessors",{"2":{"34":1}}],["accessing",{"2":{"32":1,"37":1,"39":1}}],["acts",{"2":{"249":1}}],["action",{"2":{"60":1}}],["activates",{"2":{"166":1}}],["activated",{"2":{"66":4}}],["activate",{"2":{"49":1}}],["activation=tanh",{"2":{"66":1}}],["activation=identity",{"2":{"63":2,"67":4,"69":4}}],["activations",{"2":{"13":1,"16":1,"249":1}}],["activation",{"0":{"13":1,"15":1},"2":{"13":7,"15":12,"16":4,"18":3,"19":5,"59":1,"63":6,"66":3,"67":10,"69":12,"97":3,"99":3,"158":7,"166":1,"249":1,"256":3}}],["activity",{"2":{"49":2}}],["actively",{"2":{"88":1,"113":1}}],["active",{"2":{"37":2}}],["act=relu",{"2":{"59":2,"78":1}}],["actually",{"2":{"90":1,"138":1}}],["actual",{"2":{"33":1,"176":2,"228":1}}],["act",{"2":{"13":2,"19":2,"59":8,"78":5,"241":4}}],["across",{"2":{"0":1,"19":2,"44":2,"45":1,"46":1,"82":2,"119":3,"171":2,"250":1}}],["adjust",{"2":{"244":1}}],["adjoint",{"2":{"219":2}}],["adam",{"2":{"59":1,"77":15,"78":1,"114":1,"187":1,"195":1,"210":1,"219":4,"226":3,"228":1,"236":1,"244":1}}],["adapted",{"2":{"252":2}}],["adaptive=false",{"2":{"255":1,"256":1,"257":1,"259":1}}],["adaptivemeanpool",{"2":{"65":1}}],["adaptivemaxpool",{"2":{"65":1}}],["adaptive",{"2":{"65":3}}],["adaptivelppool",{"2":{"65":1,"100":1}}],["adaptor",{"2":{"39":4,"94":1,"193":1}}],["adapt",{"2":{"3":4,"37":6,"39":6}}],["ads",{"2":{"55":1}}],["adtype=autotracker",{"2":{"249":1}}],["adtypes",{"2":{"52":1,"144":1,"182":1,"191":1,"223":1,"228":1,"231":1,"239":1}}],["adtype",{"2":{"49":1,"258":1}}],["advances",{"2":{"17":1}}],["advancedvi",{"2":{"247":1}}],["advanced",{"0":{"201":1},"2":{"7":2,"113":1}}],["ad",{"0":{"28":1,"29":1},"2":{"16":1,"18":1,"27":6,"28":1,"29":1,"33":2,"52":3,"53":1,"55":2,"58":2,"77":2,"82":1,"83":3,"101":4,"102":2,"105":2,"144":4,"147":2,"154":1,"162":1,"170":1,"173":1,"175":2,"176":5,"177":2,"210":1,"228":1,"238":1,"240":2,"242":1,"245":1}}],["adding",{"2":{"123":1}}],["additional",{"0":{"79":1},"2":{"48":1,"49":1,"54":1,"79":1,"80":1,"133":1,"172":1,"177":1,"179":1}}],["additionally",{"2":{"7":1,"52":1,"53":1,"54":2,"101":1,"134":1,"138":1,"149":1,"153":1,"160":1,"188":1,"218":1,"242":1}}],["addition",{"2":{"15":1,"55":1}}],["address",{"2":{"81":1}}],["add",{"2":{"47":1,"55":3,"71":2,"72":5,"73":1,"76":2,"77":1,"79":1,"100":1,"104":1,"145":1,"161":3,"171":1,"172":1,"203":1}}],["added",{"2":{"15":1,"19":4,"53":2,"63":2,"65":3,"68":1,"69":4,"85":1,"100":1}}],["adds",{"2":{"14":1,"33":1,"171":1}}],["at=train",{"2":{"192":1,"206":1}}],["at=0",{"2":{"183":1}}],["atleast",{"2":{"19":1}}],["attempts",{"2":{"14":1,"18":1,"37":1}}],["at",{"2":{"4":2,"17":1,"31":1,"44":2,"53":1,"59":1,"63":2,"65":3,"66":1,"70":1,"77":1,"113":1,"115":1,"123":1,"125":4,"126":10,"128":1,"142":1,"166":2,"177":1,"184":1,"203":2,"244":4,"250":2,"254":2,"255":1}}],["april",{"2":{"74":1}}],["append",{"2":{"248":2}}],["appendix",{"0":{"180":1,"189":1,"197":1,"214":1,"221":1,"229":1,"237":1,"246":1,"251":1,"260":1}}],["appreciate",{"2":{"59":1}}],["approach",{"0":{"116":1},"2":{"113":1,"219":1}}],["approximation",{"2":{"68":1}}],["approximately",{"2":{"24":1}}],["approx",{"2":{"49":1}}],["appropriate",{"2":{"8":1,"24":1}}],["applications",{"2":{"83":1,"173":1}}],["applicable",{"2":{"2":1,"4":1}}],["applies",{"2":{"15":1,"19":1,"62":1,"69":6,"70":2,"119":1}}],["applied",{"2":{"8":1,"24":3,"53":2,"55":1,"62":1,"64":4,"69":4,"134":2}}],["applychain",{"2":{"213":3}}],["applying",{"2":{"17":2,"24":1,"62":1}}],["apply",{"0":{"13":1},"2":{"8":7,"52":5,"55":1,"62":1,"63":2,"64":2,"65":3,"77":3,"107":1,"109":1,"110":4,"111":3,"140":1,"141":1,"153":1,"166":1,"228":1,"249":1}}],["appleaccelerate",{"2":{"18":1}}],["apple",{"2":{"3":1,"80":1}}],["api",{"0":{"23":1,"52":1,"114":1,"185":1},"1":{"24":1,"25":1},"2":{"3":1,"13":2,"14":1,"15":2,"16":1,"17":2,"18":1,"19":4,"37":1,"44":3,"52":2,"53":2,"62":9,"68":2,"77":3,"85":1,"87":2,"92":1,"113":2,"114":1,"128":1,"133":1,"179":1,"180":1,"181":1,"185":1,"189":1,"190":1,"207":1,"211":1,"213":1,"214":1,"215":1,"221":1,"227":1,"229":1,"237":1,"246":1,"256":2}}],["astroinformatics",{"2":{"252":1}}],["ask",{"2":{"171":3}}],["asymmetric",{"2":{"63":2,"65":3}}],["assert",{"2":{"174":1,"249":1,"254":5}}],["associated",{"2":{"81":1}}],["assume",{"2":{"113":1,"254":1}}],["assumed",{"2":{"49":1}}],["assumes",{"2":{"11":1,"62":1,"99":1}}],["assigned",{"2":{"59":1}}],["assign",{"2":{"42":1}}],["as",{"2":{"3":2,"4":2,"5":3,"7":4,"13":2,"15":2,"17":2,"19":3,"24":5,"27":2,"33":1,"34":1,"37":1,"39":1,"48":2,"49":2,"50":4,"52":2,"53":8,"54":2,"55":1,"57":2,"59":10,"62":10,"63":1,"65":3,"66":3,"68":3,"69":1,"70":1,"71":1,"74":1,"78":2,"83":2,"85":1,"97":2,"98":2,"103":1,"108":1,"113":6,"114":1,"119":1,"120":1,"122":2,"126":1,"141":3,"142":2,"145":1,"146":1,"147":2,"148":1,"152":1,"153":2,"155":2,"165":1,"169":2,"170":1,"171":1,"173":1,"174":2,"176":1,"185":1,"190":2,"196":1,"207":1,"213":1,"215":1,"219":1,"233":1,"247":1,"249":6,"250":1,"256":2}}],["agent",{"2":{"110":3,"125":1,"145":2,"213":3,"244":4}}],["aggressive",{"2":{"93":1}}],["aggregation",{"2":{"53":1}}],["aggregated",{"2":{"53":1}}],["agg=sum",{"2":{"53":2}}],["agg=mean",{"2":{"53":1}}],["agg",{"2":{"53":26}}],["agnostic",{"2":{"3":3,"44":3,"160":1}}],["against",{"2":{"104":1,"149":1}}],["again",{"2":{"3":1,"119":1,"146":1}}],["algebras",{"2":{"177":1}}],["algebraic",{"2":{"146":1}}],["algorithm",{"2":{"2":1,"149":1,"247":1}}],["aligned",{"2":{"70":1}}],["align",{"2":{"70":2,"99":2,"100":1}}],["alias",{"2":{"54":1}}],["aliased",{"2":{"52":3}}],["aliases",{"2":{"15":1}}],["alternate",{"0":{"211":1}}],["alternatives",{"2":{"158":1}}],["alternatively",{"2":{"49":1,"66":2,"70":1,"76":1,"119":1,"155":1}}],["alternative",{"2":{"3":1}}],["alts",{"2":{"68":2}}],["already",{"2":{"60":1,"77":1,"81":1,"174":1,"227":1}}],["almost",{"2":{"37":1}}],["always",{"2":{"27":2,"30":1,"31":1,"37":1,"53":1,"55":1,"99":1,"143":1}}],["al",{"2":{"17":2,"24":2,"53":2,"252":1}}],["alpha=0",{"2":{"224":1,"228":2,"255":2,"256":4,"259":7}}],["alphadropout",{"2":{"64":4}}],["alpha",{"2":{"17":4,"249":2}}],["along",{"2":{"15":1,"19":1,"24":1,"53":1,"54":1,"62":1,"63":1,"64":2,"66":2,"69":1,"83":1,"109":1}}],["also",{"2":{"3":1,"7":1,"15":2,"24":2,"31":1,"42":2,"54":1,"55":2,"57":1,"59":1,"62":2,"64":5,"68":1,"69":7,"70":2,"76":1,"83":2,"85":1,"93":1,"140":2,"168":1,"171":1,"185":1,"187":1,"207":1,"210":2,"249":1,"250":1}}],["allocate",{"2":{"153":1}}],["allow",{"2":{"34":1,"49":1,"55":1,"93":1,"97":1,"155":1}}],["allowscalar",{"2":{"156":1,"205":1,"231":1,"239":1}}],["allows",{"2":{"6":1,"7":1,"8":1,"27":2,"44":2,"55":1,"59":1,"62":1,"66":1,"68":1,"84":1,"100":1,"141":1,"142":1,"210":1}}],["allreduce",{"2":{"44":3,"45":1,"121":1}}],["all",{"2":{"3":1,"6":1,"7":1,"8":1,"10":3,"24":1,"30":1,"31":3,"32":2,"39":2,"44":5,"48":2,"49":1,"52":2,"55":1,"56":1,"58":1,"62":3,"63":2,"65":6,"67":1,"68":2,"70":2,"77":1,"79":2,"82":3,"83":3,"93":1,"95":1,"113":1,"119":3,"122":1,"131":2,"140":1,"160":1,"166":1,"167":1,"169":1,"171":3,"172":1,"173":1,"218":1,"241":1,"248":1,"249":2}}],["artifact",{"2":{"180":1,"189":1,"214":1,"221":1,"229":1,"237":1,"246":1}}],["artificially",{"2":{"126":1}}],["artificial",{"2":{"24":2,"248":2}}],["arranged",{"2":{"171":1,"248":1}}],["arrayandtime",{"2":{"111":8,"112":1}}],["array",{"2":{"8":1,"13":5,"17":4,"19":5,"20":1,"22":3,"24":9,"28":2,"39":7,"53":1,"55":2,"59":1,"63":5,"65":6,"66":2,"67":4,"68":6,"69":16,"111":3,"113":1,"114":2,"146":1,"147":1,"169":1,"171":8,"172":1,"173":6,"194":1,"207":3,"208":1,"213":9,"217":1,"219":1,"248":4,"249":1,"255":1,"256":1,"257":1,"259":1}}],["arrays",{"0":{"156":1,"171":1,"172":1},"1":{"172":1},"2":{"3":1,"11":1,"16":2,"18":3,"20":7,"55":1,"56":1,"62":1,"67":1,"68":1,"70":5,"113":1,"134":2,"140":1,"153":2,"171":4,"173":1}}],["architectural",{"2":{"140":1}}],["architecture",{"2":{"134":1,"140":2}}],["architectures",{"2":{"83":1}}],["arbitrary",{"2":{"70":1,"210":1}}],["args",{"2":{"48":2,"49":4,"55":2,"57":6,"98":1}}],["argumenterror",{"2":{"244":1}}],["argument",{"2":{"8":2,"25":1,"59":1,"62":4,"66":1,"68":1,"90":1,"99":1,"100":1,"130":1}}],["arguments",{"2":{"2":2,"4":2,"8":1,"13":2,"15":1,"16":1,"17":2,"18":1,"19":4,"24":3,"27":2,"28":1,"31":1,"33":3,"34":1,"37":2,"39":2,"45":1,"48":3,"49":5,"52":3,"58":1,"59":2,"62":11,"63":4,"64":5,"65":9,"66":7,"67":8,"68":7,"69":9,"70":2,"87":1,"140":1,"169":1,"213":3}}],["arxiv",{"2":{"19":4,"24":1,"68":1,"69":2}}],["around",{"2":{"14":1,"27":2,"37":1,"63":2,"65":3,"83":1,"141":1,"148":1}}],["aren",{"2":{"202":1}}],["are",{"2":{"2":1,"3":2,"6":1,"7":2,"8":1,"11":1,"13":1,"18":1,"19":3,"20":1,"24":4,"28":2,"30":2,"31":6,"33":4,"34":1,"39":2,"40":1,"42":2,"49":2,"52":6,"53":6,"54":2,"55":1,"57":2,"59":2,"60":1,"67":3,"68":2,"69":5,"70":2,"76":1,"78":1,"79":1,"82":2,"83":2,"90":1,"98":1,"100":1,"103":3,"104":5,"105":2,"110":1,"113":2,"114":1,"115":1,"119":1,"122":1,"123":1,"124":1,"126":1,"129":1,"140":3,"141":2,"142":2,"143":1,"144":2,"145":2,"146":1,"149":1,"152":3,"153":1,"155":2,"158":1,"159":2,"160":1,"163":2,"164":1,"166":1,"167":4,"171":1,"173":1,"175":1,"184":2,"202":2,"203":2,"207":1,"219":1,"233":1,"249":1,"250":1,"255":1,"256":1}}],["animation",{"2":{"250":1}}],["analytical",{"2":{"243":4,"245":1}}],["anticlockwise",{"2":{"181":1,"183":4}}],["anonymous",{"2":{"97":1}}],["another",{"2":{"67":1,"141":1}}],["answers",{"2":{"84":1}}],["anything",{"2":{"140":1}}],["anywhere",{"2":{"90":1}}],["any",{"2":{"8":2,"11":1,"16":1,"18":1,"30":1,"33":1,"39":1,"49":1,"52":2,"53":3,"55":2,"59":2,"62":1,"66":3,"68":1,"82":1,"93":2,"105":1,"110":7,"113":3,"114":1,"122":1,"125":1,"127":1,"134":1,"138":2,"140":2,"142":1,"144":1,"153":1,"167":1,"172":1,"173":2,"174":1,"175":1,"188":1,"203":1,"210":1,"213":15,"227":1,"234":1}}],["an",{"2":{"2":5,"3":2,"4":1,"5":1,"8":3,"13":1,"17":4,"19":3,"24":19,"25":36,"27":2,"33":1,"41":2,"44":1,"45":1,"50":3,"52":2,"53":2,"55":1,"57":1,"59":1,"62":10,"63":3,"64":3,"65":3,"66":2,"67":8,"68":2,"69":7,"77":1,"83":1,"90":1,"97":1,"99":2,"100":1,"101":1,"103":1,"105":1,"108":1,"113":1,"114":1,"116":1,"123":1,"124":1,"126":1,"127":2,"144":1,"145":2,"146":1,"148":1,"155":1,"159":1,"161":2,"171":3,"174":1,"190":1,"202":1,"203":3,"219":1,"248":1,"249":1,"250":1}}],["andrea",{"2":{"19":1,"69":1}}],["and",{"0":{"35":1,"160":1,"186":1,"208":1,"230":1,"234":1},"1":{"36":1,"37":1,"38":1,"39":1,"231":1,"232":1,"233":1,"234":1,"235":1,"236":1,"237":1},"2":{"1":1,"2":10,"3":3,"4":7,"5":4,"7":7,"8":7,"13":1,"14":1,"15":1,"16":4,"17":2,"18":3,"19":20,"24":13,"28":1,"30":2,"31":4,"32":7,"33":5,"34":3,"37":5,"39":2,"42":4,"44":2,"46":2,"47":2,"48":2,"50":2,"52":8,"53":19,"54":2,"55":6,"56":1,"57":4,"58":1,"59":5,"60":1,"62":10,"63":9,"65":3,"66":31,"67":8,"68":3,"69":22,"70":8,"76":1,"77":4,"78":5,"81":3,"82":2,"83":6,"84":2,"90":5,"95":2,"97":5,"98":3,"99":3,"100":4,"103":4,"104":2,"112":1,"113":6,"114":2,"115":1,"116":3,"117":1,"119":6,"120":2,"122":1,"123":1,"125":3,"126":6,"127":3,"129":1,"134":10,"136":1,"138":2,"140":9,"141":8,"142":3,"143":1,"144":2,"145":5,"147":1,"148":1,"149":2,"150":2,"152":1,"153":5,"155":3,"158":2,"159":1,"160":5,"164":2,"166":2,"167":4,"169":2,"171":7,"172":2,"173":1,"174":3,"175":3,"176":1,"178":1,"179":3,"181":2,"183":3,"184":10,"185":1,"188":3,"192":1,"193":1,"196":1,"202":1,"203":3,"206":1,"207":2,"210":2,"213":1,"219":3,"224":1,"227":2,"228":1,"238":1,"241":1,"243":2,"248":1,"249":12,"250":3,"254":3,"255":2,"256":6}}],["a",{"0":{"38":1,"129":1,"132":1,"181":1,"184":1,"222":1,"230":1,"233":1,"238":1,"252":1,"256":1},"1":{"39":1,"182":1,"183":1,"184":1,"185":1,"186":1,"187":1,"188":1,"189":1,"223":1,"224":1,"225":1,"226":1,"227":1,"228":1,"229":1,"231":1,"232":1,"233":1,"234":1,"235":1,"236":1,"237":1,"239":1,"240":1,"241":1,"242":1,"243":1,"244":1,"245":1,"246":1,"253":1,"254":1,"255":1,"256":1,"257":1,"258":1,"259":1,"260":1},"2":{"0":1,"1":2,"2":5,"3":5,"4":5,"5":3,"6":1,"7":10,"8":12,"10":1,"11":4,"14":1,"15":3,"16":2,"17":4,"18":2,"19":2,"21":1,"24":20,"25":13,"27":2,"28":4,"30":1,"31":4,"32":1,"33":3,"34":4,"37":9,"39":9,"42":2,"44":3,"45":1,"47":2,"48":1,"49":4,"50":5,"52":5,"53":4,"54":5,"55":5,"57":3,"58":4,"59":21,"62":27,"63":21,"65":18,"66":43,"67":8,"68":10,"69":20,"70":6,"72":1,"73":1,"76":1,"77":2,"78":3,"81":2,"82":1,"83":4,"84":1,"85":2,"90":9,"91":2,"92":2,"95":3,"107":2,"108":1,"111":3,"112":1,"113":4,"114":3,"115":1,"116":7,"118":2,"119":1,"122":1,"123":1,"124":1,"125":3,"126":5,"128":1,"129":1,"131":2,"134":17,"136":1,"137":1,"138":3,"140":8,"141":8,"142":2,"144":6,"145":7,"146":2,"147":3,"148":1,"149":10,"152":1,"153":4,"155":5,"160":1,"163":1,"164":1,"168":2,"169":2,"170":3,"171":12,"172":1,"174":3,"175":12,"176":1,"177":2,"179":4,"181":1,"183":2,"184":3,"185":1,"190":2,"196":1,"202":1,"207":3,"210":2,"211":1,"212":1,"215":3,"218":1,"219":6,"222":2,"225":1,"228":2,"234":1,"238":2,"241":3,"242":1,"243":1,"247":1,"248":3,"249":7,"250":5,"254":9,"256":3,"257":1,"258":1}}]],"serializationVersion":2}';export{e as default}; diff --git a/previews/PR1023/assets/chunks/VPLocalSearchBox.CkYqsyE0.js b/previews/PR1023/assets/chunks/VPLocalSearchBox.CkYqsyE0.js new file mode 100644 index 0000000000..1ddae88c7d --- /dev/null +++ b/previews/PR1023/assets/chunks/VPLocalSearchBox.CkYqsyE0.js @@ -0,0 +1,7 @@ +var Ft=Object.defineProperty;var Ot=(a,e,t)=>e in a?Ft(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var Me=(a,e,t)=>Ot(a,typeof e!="symbol"?e+"":e,t);import{V as Rt,p as ie,h as me,aj as et,ak as Ct,al as Mt,q as $e,am as At,d as Lt,D as xe,an as tt,ao as Dt,ap as zt,s as Pt,aq as jt,v as Ae,P as he,O as Se,ar as Vt,as as $t,W as Bt,R as Wt,$ as Kt,o as H,b as Jt,j as S,a0 as Ut,k as L,at as qt,au as Gt,av as Ht,c as Z,n as st,e as _e,C as nt,F as it,a as fe,t as pe,aw as Qt,ax as rt,ay as Yt,a9 as Zt,af as Xt,az as es,_ as ts}from"./framework.DFwXuivk.js";import{u as ss,d as ns}from"./theme.BkveSZIg.js";const is={root:()=>Rt(()=>import("./@localSearchIndexroot.Div4qI0f.js"),[])};/*! +* tabbable 6.2.0 +* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE +*/var mt=["input:not([inert])","select:not([inert])","textarea:not([inert])","a[href]:not([inert])","button:not([inert])","[tabindex]:not(slot):not([inert])","audio[controls]:not([inert])","video[controls]:not([inert])",'[contenteditable]:not([contenteditable="false"]):not([inert])',"details>summary:first-of-type:not([inert])","details:not([inert])"],Ne=mt.join(","),gt=typeof Element>"u",ae=gt?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,Fe=!gt&&Element.prototype.getRootNode?function(a){var e;return a==null||(e=a.getRootNode)===null||e===void 0?void 0:e.call(a)}:function(a){return a==null?void 0:a.ownerDocument},Oe=function a(e,t){var s;t===void 0&&(t=!0);var n=e==null||(s=e.getAttribute)===null||s===void 0?void 0:s.call(e,"inert"),r=n===""||n==="true",i=r||t&&e&&a(e.parentNode);return i},rs=function(e){var t,s=e==null||(t=e.getAttribute)===null||t===void 0?void 0:t.call(e,"contenteditable");return s===""||s==="true"},bt=function(e,t,s){if(Oe(e))return[];var n=Array.prototype.slice.apply(e.querySelectorAll(Ne));return t&&ae.call(e,Ne)&&n.unshift(e),n=n.filter(s),n},yt=function a(e,t,s){for(var n=[],r=Array.from(e);r.length;){var i=r.shift();if(!Oe(i,!1))if(i.tagName==="SLOT"){var o=i.assignedElements(),l=o.length?o:i.children,c=a(l,!0,s);s.flatten?n.push.apply(n,c):n.push({scopeParent:i,candidates:c})}else{var h=ae.call(i,Ne);h&&s.filter(i)&&(t||!e.includes(i))&&n.push(i);var m=i.shadowRoot||typeof s.getShadowRoot=="function"&&s.getShadowRoot(i),f=!Oe(m,!1)&&(!s.shadowRootFilter||s.shadowRootFilter(i));if(m&&f){var b=a(m===!0?i.children:m.children,!0,s);s.flatten?n.push.apply(n,b):n.push({scopeParent:i,candidates:b})}else r.unshift.apply(r,i.children)}}return n},wt=function(e){return!isNaN(parseInt(e.getAttribute("tabindex"),10))},re=function(e){if(!e)throw new Error("No node provided");return e.tabIndex<0&&(/^(AUDIO|VIDEO|DETAILS)$/.test(e.tagName)||rs(e))&&!wt(e)?0:e.tabIndex},as=function(e,t){var s=re(e);return s<0&&t&&!wt(e)?0:s},os=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},xt=function(e){return e.tagName==="INPUT"},ls=function(e){return xt(e)&&e.type==="hidden"},cs=function(e){var t=e.tagName==="DETAILS"&&Array.prototype.slice.apply(e.children).some(function(s){return s.tagName==="SUMMARY"});return t},us=function(e,t){for(var s=0;ssummary:first-of-type"),i=r?e.parentElement:e;if(ae.call(i,"details:not([open]) *"))return!0;if(!s||s==="full"||s==="legacy-full"){if(typeof n=="function"){for(var o=e;e;){var l=e.parentElement,c=Fe(e);if(l&&!l.shadowRoot&&n(l)===!0)return at(e);e.assignedSlot?e=e.assignedSlot:!l&&c!==e.ownerDocument?e=c.host:e=l}e=o}if(ps(e))return!e.getClientRects().length;if(s!=="legacy-full")return!0}else if(s==="non-zero-area")return at(e);return!1},ms=function(e){if(/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(e.tagName))for(var t=e.parentElement;t;){if(t.tagName==="FIELDSET"&&t.disabled){for(var s=0;s=0)},bs=function a(e){var t=[],s=[];return e.forEach(function(n,r){var i=!!n.scopeParent,o=i?n.scopeParent:n,l=as(o,i),c=i?a(n.candidates):o;l===0?i?t.push.apply(t,c):t.push(o):s.push({documentOrder:r,tabIndex:l,item:n,isScope:i,content:c})}),s.sort(os).reduce(function(n,r){return r.isScope?n.push.apply(n,r.content):n.push(r.content),n},[]).concat(t)},ys=function(e,t){t=t||{};var s;return t.getShadowRoot?s=yt([e],t.includeContainer,{filter:Be.bind(null,t),flatten:!1,getShadowRoot:t.getShadowRoot,shadowRootFilter:gs}):s=bt(e,t.includeContainer,Be.bind(null,t)),bs(s)},ws=function(e,t){t=t||{};var s;return t.getShadowRoot?s=yt([e],t.includeContainer,{filter:Re.bind(null,t),flatten:!0,getShadowRoot:t.getShadowRoot}):s=bt(e,t.includeContainer,Re.bind(null,t)),s},oe=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return ae.call(e,Ne)===!1?!1:Be(t,e)},xs=mt.concat("iframe").join(","),Le=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return ae.call(e,xs)===!1?!1:Re(t,e)};/*! +* focus-trap 7.6.0 +* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE +*/function Ss(a,e,t){return(e=Es(e))in a?Object.defineProperty(a,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):a[e]=t,a}function ot(a,e){var t=Object.keys(a);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(a);e&&(s=s.filter(function(n){return Object.getOwnPropertyDescriptor(a,n).enumerable})),t.push.apply(t,s)}return t}function lt(a){for(var e=1;e0){var s=e[e.length-1];s!==t&&s.pause()}var n=e.indexOf(t);n===-1||e.splice(n,1),e.push(t)},deactivateTrap:function(e,t){var s=e.indexOf(t);s!==-1&&e.splice(s,1),e.length>0&&e[e.length-1].unpause()}},Ts=function(e){return e.tagName&&e.tagName.toLowerCase()==="input"&&typeof e.select=="function"},Is=function(e){return(e==null?void 0:e.key)==="Escape"||(e==null?void 0:e.key)==="Esc"||(e==null?void 0:e.keyCode)===27},ge=function(e){return(e==null?void 0:e.key)==="Tab"||(e==null?void 0:e.keyCode)===9},ks=function(e){return ge(e)&&!e.shiftKey},Ns=function(e){return ge(e)&&e.shiftKey},ut=function(e){return setTimeout(e,0)},dt=function(e,t){var s=-1;return e.every(function(n,r){return t(n)?(s=r,!1):!0}),s},ve=function(e){for(var t=arguments.length,s=new Array(t>1?t-1:0),n=1;n1?g-1:0),T=1;T=0)d=s.activeElement;else{var u=i.tabbableGroups[0],g=u&&u.firstTabbableNode;d=g||h("fallbackFocus")}if(!d)throw new Error("Your focus-trap needs to have at least one focusable element");return d},f=function(){if(i.containerGroups=i.containers.map(function(d){var u=ys(d,r.tabbableOptions),g=ws(d,r.tabbableOptions),E=u.length>0?u[0]:void 0,T=u.length>0?u[u.length-1]:void 0,N=g.find(function(v){return oe(v)}),O=g.slice().reverse().find(function(v){return oe(v)}),A=!!u.find(function(v){return re(v)>0});return{container:d,tabbableNodes:u,focusableNodes:g,posTabIndexesFound:A,firstTabbableNode:E,lastTabbableNode:T,firstDomTabbableNode:N,lastDomTabbableNode:O,nextTabbableNode:function(p){var _=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,F=u.indexOf(p);return F<0?_?g.slice(g.indexOf(p)+1).find(function(z){return oe(z)}):g.slice(0,g.indexOf(p)).reverse().find(function(z){return oe(z)}):u[F+(_?1:-1)]}}}),i.tabbableGroups=i.containerGroups.filter(function(d){return d.tabbableNodes.length>0}),i.tabbableGroups.length<=0&&!h("fallbackFocus"))throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times");if(i.containerGroups.find(function(d){return d.posTabIndexesFound})&&i.containerGroups.length>1)throw new Error("At least one node with a positive tabindex was found in one of your focus-trap's multiple containers. Positive tabindexes are only supported in single-container focus-traps.")},b=function(d){var u=d.activeElement;if(u)return u.shadowRoot&&u.shadowRoot.activeElement!==null?b(u.shadowRoot):u},y=function(d){if(d!==!1&&d!==b(document)){if(!d||!d.focus){y(m());return}d.focus({preventScroll:!!r.preventScroll}),i.mostRecentlyFocusedNode=d,Ts(d)&&d.select()}},x=function(d){var u=h("setReturnFocus",d);return u||(u===!1?!1:d)},w=function(d){var u=d.target,g=d.event,E=d.isBackward,T=E===void 0?!1:E;u=u||Ee(g),f();var N=null;if(i.tabbableGroups.length>0){var O=c(u,g),A=O>=0?i.containerGroups[O]:void 0;if(O<0)T?N=i.tabbableGroups[i.tabbableGroups.length-1].lastTabbableNode:N=i.tabbableGroups[0].firstTabbableNode;else if(T){var v=dt(i.tabbableGroups,function(j){var I=j.firstTabbableNode;return u===I});if(v<0&&(A.container===u||Le(u,r.tabbableOptions)&&!oe(u,r.tabbableOptions)&&!A.nextTabbableNode(u,!1))&&(v=O),v>=0){var p=v===0?i.tabbableGroups.length-1:v-1,_=i.tabbableGroups[p];N=re(u)>=0?_.lastTabbableNode:_.lastDomTabbableNode}else ge(g)||(N=A.nextTabbableNode(u,!1))}else{var F=dt(i.tabbableGroups,function(j){var I=j.lastTabbableNode;return u===I});if(F<0&&(A.container===u||Le(u,r.tabbableOptions)&&!oe(u,r.tabbableOptions)&&!A.nextTabbableNode(u))&&(F=O),F>=0){var z=F===i.tabbableGroups.length-1?0:F+1,P=i.tabbableGroups[z];N=re(u)>=0?P.firstTabbableNode:P.firstDomTabbableNode}else ge(g)||(N=A.nextTabbableNode(u))}}else N=h("fallbackFocus");return N},R=function(d){var u=Ee(d);if(!(c(u,d)>=0)){if(ve(r.clickOutsideDeactivates,d)){o.deactivate({returnFocus:r.returnFocusOnDeactivate});return}ve(r.allowOutsideClick,d)||d.preventDefault()}},C=function(d){var u=Ee(d),g=c(u,d)>=0;if(g||u instanceof Document)g&&(i.mostRecentlyFocusedNode=u);else{d.stopImmediatePropagation();var E,T=!0;if(i.mostRecentlyFocusedNode)if(re(i.mostRecentlyFocusedNode)>0){var N=c(i.mostRecentlyFocusedNode),O=i.containerGroups[N].tabbableNodes;if(O.length>0){var A=O.findIndex(function(v){return v===i.mostRecentlyFocusedNode});A>=0&&(r.isKeyForward(i.recentNavEvent)?A+1=0&&(E=O[A-1],T=!1))}}else i.containerGroups.some(function(v){return v.tabbableNodes.some(function(p){return re(p)>0})})||(T=!1);else T=!1;T&&(E=w({target:i.mostRecentlyFocusedNode,isBackward:r.isKeyBackward(i.recentNavEvent)})),y(E||i.mostRecentlyFocusedNode||m())}i.recentNavEvent=void 0},J=function(d){var u=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;i.recentNavEvent=d;var g=w({event:d,isBackward:u});g&&(ge(d)&&d.preventDefault(),y(g))},Q=function(d){(r.isKeyForward(d)||r.isKeyBackward(d))&&J(d,r.isKeyBackward(d))},W=function(d){Is(d)&&ve(r.escapeDeactivates,d)!==!1&&(d.preventDefault(),o.deactivate())},V=function(d){var u=Ee(d);c(u,d)>=0||ve(r.clickOutsideDeactivates,d)||ve(r.allowOutsideClick,d)||(d.preventDefault(),d.stopImmediatePropagation())},$=function(){if(i.active)return ct.activateTrap(n,o),i.delayInitialFocusTimer=r.delayInitialFocus?ut(function(){y(m())}):y(m()),s.addEventListener("focusin",C,!0),s.addEventListener("mousedown",R,{capture:!0,passive:!1}),s.addEventListener("touchstart",R,{capture:!0,passive:!1}),s.addEventListener("click",V,{capture:!0,passive:!1}),s.addEventListener("keydown",Q,{capture:!0,passive:!1}),s.addEventListener("keydown",W),o},be=function(){if(i.active)return s.removeEventListener("focusin",C,!0),s.removeEventListener("mousedown",R,!0),s.removeEventListener("touchstart",R,!0),s.removeEventListener("click",V,!0),s.removeEventListener("keydown",Q,!0),s.removeEventListener("keydown",W),o},M=function(d){var u=d.some(function(g){var E=Array.from(g.removedNodes);return E.some(function(T){return T===i.mostRecentlyFocusedNode})});u&&y(m())},U=typeof window<"u"&&"MutationObserver"in window?new MutationObserver(M):void 0,q=function(){U&&(U.disconnect(),i.active&&!i.paused&&i.containers.map(function(d){U.observe(d,{subtree:!0,childList:!0})}))};return o={get active(){return i.active},get paused(){return i.paused},activate:function(d){if(i.active)return this;var u=l(d,"onActivate"),g=l(d,"onPostActivate"),E=l(d,"checkCanFocusTrap");E||f(),i.active=!0,i.paused=!1,i.nodeFocusedBeforeActivation=s.activeElement,u==null||u();var T=function(){E&&f(),$(),q(),g==null||g()};return E?(E(i.containers.concat()).then(T,T),this):(T(),this)},deactivate:function(d){if(!i.active)return this;var u=lt({onDeactivate:r.onDeactivate,onPostDeactivate:r.onPostDeactivate,checkCanReturnFocus:r.checkCanReturnFocus},d);clearTimeout(i.delayInitialFocusTimer),i.delayInitialFocusTimer=void 0,be(),i.active=!1,i.paused=!1,q(),ct.deactivateTrap(n,o);var g=l(u,"onDeactivate"),E=l(u,"onPostDeactivate"),T=l(u,"checkCanReturnFocus"),N=l(u,"returnFocus","returnFocusOnDeactivate");g==null||g();var O=function(){ut(function(){N&&y(x(i.nodeFocusedBeforeActivation)),E==null||E()})};return N&&T?(T(x(i.nodeFocusedBeforeActivation)).then(O,O),this):(O(),this)},pause:function(d){if(i.paused||!i.active)return this;var u=l(d,"onPause"),g=l(d,"onPostPause");return i.paused=!0,u==null||u(),be(),q(),g==null||g(),this},unpause:function(d){if(!i.paused||!i.active)return this;var u=l(d,"onUnpause"),g=l(d,"onPostUnpause");return i.paused=!1,u==null||u(),f(),$(),q(),g==null||g(),this},updateContainerElements:function(d){var u=[].concat(d).filter(Boolean);return i.containers=u.map(function(g){return typeof g=="string"?s.querySelector(g):g}),i.active&&f(),q(),this}},o.updateContainerElements(e),o};function Rs(a,e={}){let t;const{immediate:s,...n}=e,r=ie(!1),i=ie(!1),o=f=>t&&t.activate(f),l=f=>t&&t.deactivate(f),c=()=>{t&&(t.pause(),i.value=!0)},h=()=>{t&&(t.unpause(),i.value=!1)},m=me(()=>{const f=et(a);return(Array.isArray(f)?f:[f]).map(b=>{const y=et(b);return typeof y=="string"?y:Ct(y)}).filter(Mt)});return $e(m,f=>{f.length&&(t=Os(f,{...n,onActivate(){r.value=!0,e.onActivate&&e.onActivate()},onDeactivate(){r.value=!1,e.onDeactivate&&e.onDeactivate()}}),s&&o())},{flush:"post"}),At(()=>l()),{hasFocus:r,isPaused:i,activate:o,deactivate:l,pause:c,unpause:h}}class ce{constructor(e,t=!0,s=[],n=5e3){this.ctx=e,this.iframes=t,this.exclude=s,this.iframesTimeout=n}static matches(e,t){const s=typeof t=="string"?[t]:t,n=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(n){let r=!1;return s.every(i=>n.call(e,i)?(r=!0,!1):!0),r}else return!1}getContexts(){let e,t=[];return typeof this.ctx>"u"||!this.ctx?e=[]:NodeList.prototype.isPrototypeOf(this.ctx)?e=Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?e=this.ctx:typeof this.ctx=="string"?e=Array.prototype.slice.call(document.querySelectorAll(this.ctx)):e=[this.ctx],e.forEach(s=>{const n=t.filter(r=>r.contains(s)).length>0;t.indexOf(s)===-1&&!n&&t.push(s)}),t}getIframeContents(e,t,s=()=>{}){let n;try{const r=e.contentWindow;if(n=r.document,!r||!n)throw new Error("iframe inaccessible")}catch{s()}n&&t(n)}isIframeBlank(e){const t="about:blank",s=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&s!==t&&s}observeIframeLoad(e,t,s){let n=!1,r=null;const i=()=>{if(!n){n=!0,clearTimeout(r);try{this.isIframeBlank(e)||(e.removeEventListener("load",i),this.getIframeContents(e,t,s))}catch{s()}}};e.addEventListener("load",i),r=setTimeout(i,this.iframesTimeout)}onIframeReady(e,t,s){try{e.contentWindow.document.readyState==="complete"?this.isIframeBlank(e)?this.observeIframeLoad(e,t,s):this.getIframeContents(e,t,s):this.observeIframeLoad(e,t,s)}catch{s()}}waitForIframes(e,t){let s=0;this.forEachIframe(e,()=>!0,n=>{s++,this.waitForIframes(n.querySelector("html"),()=>{--s||t()})},n=>{n||t()})}forEachIframe(e,t,s,n=()=>{}){let r=e.querySelectorAll("iframe"),i=r.length,o=0;r=Array.prototype.slice.call(r);const l=()=>{--i<=0&&n(o)};i||l(),r.forEach(c=>{ce.matches(c,this.exclude)?l():this.onIframeReady(c,h=>{t(c)&&(o++,s(h)),l()},l)})}createIterator(e,t,s){return document.createNodeIterator(e,t,s,!1)}createInstanceOnIframe(e){return new ce(e.querySelector("html"),this.iframes)}compareNodeIframe(e,t,s){const n=e.compareDocumentPosition(s),r=Node.DOCUMENT_POSITION_PRECEDING;if(n&r)if(t!==null){const i=t.compareDocumentPosition(s),o=Node.DOCUMENT_POSITION_FOLLOWING;if(i&o)return!0}else return!0;return!1}getIteratorNode(e){const t=e.previousNode();let s;return t===null?s=e.nextNode():s=e.nextNode()&&e.nextNode(),{prevNode:t,node:s}}checkIframeFilter(e,t,s,n){let r=!1,i=!1;return n.forEach((o,l)=>{o.val===s&&(r=l,i=o.handled)}),this.compareNodeIframe(e,t,s)?(r===!1&&!i?n.push({val:s,handled:!0}):r!==!1&&!i&&(n[r].handled=!0),!0):(r===!1&&n.push({val:s,handled:!1}),!1)}handleOpenIframes(e,t,s,n){e.forEach(r=>{r.handled||this.getIframeContents(r.val,i=>{this.createInstanceOnIframe(i).forEachNode(t,s,n)})})}iterateThroughNodes(e,t,s,n,r){const i=this.createIterator(t,e,n);let o=[],l=[],c,h,m=()=>({prevNode:h,node:c}=this.getIteratorNode(i),c);for(;m();)this.iframes&&this.forEachIframe(t,f=>this.checkIframeFilter(c,h,f,o),f=>{this.createInstanceOnIframe(f).forEachNode(e,b=>l.push(b),n)}),l.push(c);l.forEach(f=>{s(f)}),this.iframes&&this.handleOpenIframes(o,e,s,n),r()}forEachNode(e,t,s,n=()=>{}){const r=this.getContexts();let i=r.length;i||n(),r.forEach(o=>{const l=()=>{this.iterateThroughNodes(e,o,t,s,()=>{--i<=0&&n()})};this.iframes?this.waitForIframes(o,l):l()})}}let Cs=class{constructor(e){this.ctx=e,this.ie=!1;const t=window.navigator.userAgent;(t.indexOf("MSIE")>-1||t.indexOf("Trident")>-1)&&(this.ie=!0)}set opt(e){this._opt=Object.assign({},{element:"",className:"",exclude:[],iframes:!1,iframesTimeout:5e3,separateWordSearch:!0,diacritics:!0,synonyms:{},accuracy:"partially",acrossElements:!1,caseSensitive:!1,ignoreJoiners:!1,ignoreGroups:0,ignorePunctuation:[],wildcards:"disabled",each:()=>{},noMatch:()=>{},filter:()=>!0,done:()=>{},debug:!1,log:window.console},e)}get opt(){return this._opt}get iterator(){return new ce(this.ctx,this.opt.iframes,this.opt.exclude,this.opt.iframesTimeout)}log(e,t="debug"){const s=this.opt.log;this.opt.debug&&typeof s=="object"&&typeof s[t]=="function"&&s[t](`mark.js: ${e}`)}escapeStr(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}createRegExp(e){return this.opt.wildcards!=="disabled"&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),this.opt.wildcards!=="disabled"&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e),e}createSynonymsRegExp(e){const t=this.opt.synonyms,s=this.opt.caseSensitive?"":"i",n=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(let r in t)if(t.hasOwnProperty(r)){const i=t[r],o=this.opt.wildcards!=="disabled"?this.setupWildcardsRegExp(r):this.escapeStr(r),l=this.opt.wildcards!=="disabled"?this.setupWildcardsRegExp(i):this.escapeStr(i);o!==""&&l!==""&&(e=e.replace(new RegExp(`(${this.escapeStr(o)}|${this.escapeStr(l)})`,`gm${s}`),n+`(${this.processSynomyms(o)}|${this.processSynomyms(l)})`+n))}return e}processSynomyms(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}setupWildcardsRegExp(e){return e=e.replace(/(?:\\)*\?/g,t=>t.charAt(0)==="\\"?"?":""),e.replace(/(?:\\)*\*/g,t=>t.charAt(0)==="\\"?"*":"")}createWildcardsRegExp(e){let t=this.opt.wildcards==="withSpaces";return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}setupIgnoreJoinersRegExp(e){return e.replace(/[^(|)\\]/g,(t,s,n)=>{let r=n.charAt(s+1);return/[(|)\\]/.test(r)||r===""?t:t+"\0"})}createJoinersRegExp(e){let t=[];const s=this.opt.ignorePunctuation;return Array.isArray(s)&&s.length&&t.push(this.escapeStr(s.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join(`[${t.join("")}]*`):e}createDiacriticsRegExp(e){const t=this.opt.caseSensitive?"":"i",s=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"];let n=[];return e.split("").forEach(r=>{s.every(i=>{if(i.indexOf(r)!==-1){if(n.indexOf(i)>-1)return!1;e=e.replace(new RegExp(`[${i}]`,`gm${t}`),`[${i}]`),n.push(i)}return!0})}),e}createMergedBlanksRegExp(e){return e.replace(/[\s]+/gmi,"[\\s]+")}createAccuracyRegExp(e){const t="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿";let s=this.opt.accuracy,n=typeof s=="string"?s:s.value,r=typeof s=="string"?[]:s.limiters,i="";switch(r.forEach(o=>{i+=`|${this.escapeStr(o)}`}),n){case"partially":default:return`()(${e})`;case"complementary":return i="\\s"+(i||this.escapeStr(t)),`()([^${i}]*${e}[^${i}]*)`;case"exactly":return`(^|\\s${i})(${e})(?=$|\\s${i})`}}getSeparatedKeywords(e){let t=[];return e.forEach(s=>{this.opt.separateWordSearch?s.split(" ").forEach(n=>{n.trim()&&t.indexOf(n)===-1&&t.push(n)}):s.trim()&&t.indexOf(s)===-1&&t.push(s)}),{keywords:t.sort((s,n)=>n.length-s.length),length:t.length}}isNumeric(e){return Number(parseFloat(e))==e}checkRanges(e){if(!Array.isArray(e)||Object.prototype.toString.call(e[0])!=="[object Object]")return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];const t=[];let s=0;return e.sort((n,r)=>n.start-r.start).forEach(n=>{let{start:r,end:i,valid:o}=this.callNoMatchOnInvalidRanges(n,s);o&&(n.start=r,n.length=i-r,t.push(n),s=i)}),t}callNoMatchOnInvalidRanges(e,t){let s,n,r=!1;return e&&typeof e.start<"u"?(s=parseInt(e.start,10),n=s+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&n-t>0&&n-s>0?r=!0:(this.log(`Ignoring invalid or overlapping range: ${JSON.stringify(e)}`),this.opt.noMatch(e))):(this.log(`Ignoring invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)),{start:s,end:n,valid:r}}checkWhitespaceRanges(e,t,s){let n,r=!0,i=s.length,o=t-i,l=parseInt(e.start,10)-o;return l=l>i?i:l,n=l+parseInt(e.length,10),n>i&&(n=i,this.log(`End range automatically set to the max value of ${i}`)),l<0||n-l<0||l>i||n>i?(r=!1,this.log(`Invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)):s.substring(l,n).replace(/\s+/g,"")===""&&(r=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:l,end:n,valid:r}}getTextNodes(e){let t="",s=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,n=>{s.push({start:t.length,end:(t+=n.textContent).length,node:n})},n=>this.matchesExclude(n.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT,()=>{e({value:t,nodes:s})})}matchesExclude(e){return ce.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}wrapRangeInTextNode(e,t,s){const n=this.opt.element?this.opt.element:"mark",r=e.splitText(t),i=r.splitText(s-t);let o=document.createElement(n);return o.setAttribute("data-markjs","true"),this.opt.className&&o.setAttribute("class",this.opt.className),o.textContent=r.textContent,r.parentNode.replaceChild(o,r),i}wrapRangeInMappedTextNode(e,t,s,n,r){e.nodes.every((i,o)=>{const l=e.nodes[o+1];if(typeof l>"u"||l.start>t){if(!n(i.node))return!1;const c=t-i.start,h=(s>i.end?i.end:s)-i.start,m=e.value.substr(0,i.start),f=e.value.substr(h+i.start);if(i.node=this.wrapRangeInTextNode(i.node,c,h),e.value=m+f,e.nodes.forEach((b,y)=>{y>=o&&(e.nodes[y].start>0&&y!==o&&(e.nodes[y].start-=h),e.nodes[y].end-=h)}),s-=h,r(i.node.previousSibling,i.start),s>i.end)t=i.end;else return!1}return!0})}wrapMatches(e,t,s,n,r){const i=t===0?0:t+1;this.getTextNodes(o=>{o.nodes.forEach(l=>{l=l.node;let c;for(;(c=e.exec(l.textContent))!==null&&c[i]!=="";){if(!s(c[i],l))continue;let h=c.index;if(i!==0)for(let m=1;m{let l;for(;(l=e.exec(o.value))!==null&&l[i]!=="";){let c=l.index;if(i!==0)for(let m=1;ms(l[i],m),(m,f)=>{e.lastIndex=f,n(m)})}r()})}wrapRangeFromIndex(e,t,s,n){this.getTextNodes(r=>{const i=r.value.length;e.forEach((o,l)=>{let{start:c,end:h,valid:m}=this.checkWhitespaceRanges(o,i,r.value);m&&this.wrapRangeInMappedTextNode(r,c,h,f=>t(f,o,r.value.substring(c,h),l),f=>{s(f,o)})}),n()})}unwrapMatches(e){const t=e.parentNode;let s=document.createDocumentFragment();for(;e.firstChild;)s.appendChild(e.removeChild(e.firstChild));t.replaceChild(s,e),this.ie?this.normalizeTextNode(t):t.normalize()}normalizeTextNode(e){if(e){if(e.nodeType===3)for(;e.nextSibling&&e.nextSibling.nodeType===3;)e.nodeValue+=e.nextSibling.nodeValue,e.parentNode.removeChild(e.nextSibling);else this.normalizeTextNode(e.firstChild);this.normalizeTextNode(e.nextSibling)}}markRegExp(e,t){this.opt=t,this.log(`Searching with expression "${e}"`);let s=0,n="wrapMatches";const r=i=>{s++,this.opt.each(i)};this.opt.acrossElements&&(n="wrapMatchesAcrossElements"),this[n](e,this.opt.ignoreGroups,(i,o)=>this.opt.filter(o,i,s),r,()=>{s===0&&this.opt.noMatch(e),this.opt.done(s)})}mark(e,t){this.opt=t;let s=0,n="wrapMatches";const{keywords:r,length:i}=this.getSeparatedKeywords(typeof e=="string"?[e]:e),o=this.opt.caseSensitive?"":"i",l=c=>{let h=new RegExp(this.createRegExp(c),`gm${o}`),m=0;this.log(`Searching with expression "${h}"`),this[n](h,1,(f,b)=>this.opt.filter(b,c,s,m),f=>{m++,s++,this.opt.each(f)},()=>{m===0&&this.opt.noMatch(c),r[i-1]===c?this.opt.done(s):l(r[r.indexOf(c)+1])})};this.opt.acrossElements&&(n="wrapMatchesAcrossElements"),i===0?this.opt.done(s):l(r[0])}markRanges(e,t){this.opt=t;let s=0,n=this.checkRanges(e);n&&n.length?(this.log("Starting to mark with the following ranges: "+JSON.stringify(n)),this.wrapRangeFromIndex(n,(r,i,o,l)=>this.opt.filter(r,i,o,l),(r,i)=>{s++,this.opt.each(r,i)},()=>{this.opt.done(s)})):this.opt.done(s)}unmark(e){this.opt=e;let t=this.opt.element?this.opt.element:"*";t+="[data-markjs]",this.opt.className&&(t+=`.${this.opt.className}`),this.log(`Removal selector "${t}"`),this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT,s=>{this.unwrapMatches(s)},s=>{const n=ce.matches(s,t),r=this.matchesExclude(s);return!n||r?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},this.opt.done)}};function Ms(a){const e=new Cs(a);return this.mark=(t,s)=>(e.mark(t,s),this),this.markRegExp=(t,s)=>(e.markRegExp(t,s),this),this.markRanges=(t,s)=>(e.markRanges(t,s),this),this.unmark=t=>(e.unmark(t),this),this}function ke(a,e,t,s){function n(r){return r instanceof t?r:new t(function(i){i(r)})}return new(t||(t=Promise))(function(r,i){function o(h){try{c(s.next(h))}catch(m){i(m)}}function l(h){try{c(s.throw(h))}catch(m){i(m)}}function c(h){h.done?r(h.value):n(h.value).then(o,l)}c((s=s.apply(a,[])).next())})}const As="ENTRIES",St="KEYS",_t="VALUES",D="";class De{constructor(e,t){const s=e._tree,n=Array.from(s.keys());this.set=e,this._type=t,this._path=n.length>0?[{node:s,keys:n}]:[]}next(){const e=this.dive();return this.backtrack(),e}dive(){if(this._path.length===0)return{done:!0,value:void 0};const{node:e,keys:t}=le(this._path);if(le(t)===D)return{done:!1,value:this.result()};const s=e.get(le(t));return this._path.push({node:s,keys:Array.from(s.keys())}),this.dive()}backtrack(){if(this._path.length===0)return;const e=le(this._path).keys;e.pop(),!(e.length>0)&&(this._path.pop(),this.backtrack())}key(){return this.set._prefix+this._path.map(({keys:e})=>le(e)).filter(e=>e!==D).join("")}value(){return le(this._path).node.get(D)}result(){switch(this._type){case _t:return this.value();case St:return this.key();default:return[this.key(),this.value()]}}[Symbol.iterator](){return this}}const le=a=>a[a.length-1],Ls=(a,e,t)=>{const s=new Map;if(e===void 0)return s;const n=e.length+1,r=n+t,i=new Uint8Array(r*n).fill(t+1);for(let o=0;o{const l=r*i;e:for(const c of a.keys())if(c===D){const h=n[l-1];h<=t&&s.set(o,[a.get(c),h])}else{let h=r;for(let m=0;mt)continue e}Et(a.get(c),e,t,s,n,h,i,o+c)}};class X{constructor(e=new Map,t=""){this._size=void 0,this._tree=e,this._prefix=t}atPrefix(e){if(!e.startsWith(this._prefix))throw new Error("Mismatched prefix");const[t,s]=Ce(this._tree,e.slice(this._prefix.length));if(t===void 0){const[n,r]=Ue(s);for(const i of n.keys())if(i!==D&&i.startsWith(r)){const o=new Map;return o.set(i.slice(r.length),n.get(i)),new X(o,e)}}return new X(t,e)}clear(){this._size=void 0,this._tree.clear()}delete(e){return this._size=void 0,Ds(this._tree,e)}entries(){return new De(this,As)}forEach(e){for(const[t,s]of this)e(t,s,this)}fuzzyGet(e,t){return Ls(this._tree,e,t)}get(e){const t=We(this._tree,e);return t!==void 0?t.get(D):void 0}has(e){const t=We(this._tree,e);return t!==void 0&&t.has(D)}keys(){return new De(this,St)}set(e,t){if(typeof e!="string")throw new Error("key must be a string");return this._size=void 0,ze(this._tree,e).set(D,t),this}get size(){if(this._size)return this._size;this._size=0;const e=this.entries();for(;!e.next().done;)this._size+=1;return this._size}update(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;const s=ze(this._tree,e);return s.set(D,t(s.get(D))),this}fetch(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;const s=ze(this._tree,e);let n=s.get(D);return n===void 0&&s.set(D,n=t()),n}values(){return new De(this,_t)}[Symbol.iterator](){return this.entries()}static from(e){const t=new X;for(const[s,n]of e)t.set(s,n);return t}static fromObject(e){return X.from(Object.entries(e))}}const Ce=(a,e,t=[])=>{if(e.length===0||a==null)return[a,t];for(const s of a.keys())if(s!==D&&e.startsWith(s))return t.push([a,s]),Ce(a.get(s),e.slice(s.length),t);return t.push([a,e]),Ce(void 0,"",t)},We=(a,e)=>{if(e.length===0||a==null)return a;for(const t of a.keys())if(t!==D&&e.startsWith(t))return We(a.get(t),e.slice(t.length))},ze=(a,e)=>{const t=e.length;e:for(let s=0;a&&s{const[t,s]=Ce(a,e);if(t!==void 0){if(t.delete(D),t.size===0)Tt(s);else if(t.size===1){const[n,r]=t.entries().next().value;It(s,n,r)}}},Tt=a=>{if(a.length===0)return;const[e,t]=Ue(a);if(e.delete(t),e.size===0)Tt(a.slice(0,-1));else if(e.size===1){const[s,n]=e.entries().next().value;s!==D&&It(a.slice(0,-1),s,n)}},It=(a,e,t)=>{if(a.length===0)return;const[s,n]=Ue(a);s.set(n+e,t),s.delete(n)},Ue=a=>a[a.length-1],qe="or",kt="and",zs="and_not";class ue{constructor(e){if((e==null?void 0:e.fields)==null)throw new Error('MiniSearch: option "fields" must be provided');const t=e.autoVacuum==null||e.autoVacuum===!0?Ve:e.autoVacuum;this._options=Object.assign(Object.assign(Object.assign({},je),e),{autoVacuum:t,searchOptions:Object.assign(Object.assign({},ht),e.searchOptions||{}),autoSuggestOptions:Object.assign(Object.assign({},Bs),e.autoSuggestOptions||{})}),this._index=new X,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldIds={},this._fieldLength=new Map,this._avgFieldLength=[],this._nextId=0,this._storedFields=new Map,this._dirtCount=0,this._currentVacuum=null,this._enqueuedVacuum=null,this._enqueuedVacuumConditions=Je,this.addFields(this._options.fields)}add(e){const{extractField:t,tokenize:s,processTerm:n,fields:r,idField:i}=this._options,o=t(e,i);if(o==null)throw new Error(`MiniSearch: document does not have ID field "${i}"`);if(this._idToShortId.has(o))throw new Error(`MiniSearch: duplicate ID ${o}`);const l=this.addDocumentId(o);this.saveStoredFields(l,e);for(const c of r){const h=t(e,c);if(h==null)continue;const m=s(h.toString(),c),f=this._fieldIds[c],b=new Set(m).size;this.addFieldLength(l,f,this._documentCount-1,b);for(const y of m){const x=n(y,c);if(Array.isArray(x))for(const w of x)this.addTerm(f,l,w);else x&&this.addTerm(f,l,x)}}}addAll(e){for(const t of e)this.add(t)}addAllAsync(e,t={}){const{chunkSize:s=10}=t,n={chunk:[],promise:Promise.resolve()},{chunk:r,promise:i}=e.reduce(({chunk:o,promise:l},c,h)=>(o.push(c),(h+1)%s===0?{chunk:[],promise:l.then(()=>new Promise(m=>setTimeout(m,0))).then(()=>this.addAll(o))}:{chunk:o,promise:l}),n);return i.then(()=>this.addAll(r))}remove(e){const{tokenize:t,processTerm:s,extractField:n,fields:r,idField:i}=this._options,o=n(e,i);if(o==null)throw new Error(`MiniSearch: document does not have ID field "${i}"`);const l=this._idToShortId.get(o);if(l==null)throw new Error(`MiniSearch: cannot remove document with ID ${o}: it is not in the index`);for(const c of r){const h=n(e,c);if(h==null)continue;const m=t(h.toString(),c),f=this._fieldIds[c],b=new Set(m).size;this.removeFieldLength(l,f,this._documentCount,b);for(const y of m){const x=s(y,c);if(Array.isArray(x))for(const w of x)this.removeTerm(f,l,w);else x&&this.removeTerm(f,l,x)}}this._storedFields.delete(l),this._documentIds.delete(l),this._idToShortId.delete(o),this._fieldLength.delete(l),this._documentCount-=1}removeAll(e){if(e)for(const t of e)this.remove(t);else{if(arguments.length>0)throw new Error("Expected documents to be present. Omit the argument to remove all documents.");this._index=new X,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldLength=new Map,this._avgFieldLength=[],this._storedFields=new Map,this._nextId=0}}discard(e){const t=this._idToShortId.get(e);if(t==null)throw new Error(`MiniSearch: cannot discard document with ID ${e}: it is not in the index`);this._idToShortId.delete(e),this._documentIds.delete(t),this._storedFields.delete(t),(this._fieldLength.get(t)||[]).forEach((s,n)=>{this.removeFieldLength(t,n,this._documentCount,s)}),this._fieldLength.delete(t),this._documentCount-=1,this._dirtCount+=1,this.maybeAutoVacuum()}maybeAutoVacuum(){if(this._options.autoVacuum===!1)return;const{minDirtFactor:e,minDirtCount:t,batchSize:s,batchWait:n}=this._options.autoVacuum;this.conditionalVacuum({batchSize:s,batchWait:n},{minDirtCount:t,minDirtFactor:e})}discardAll(e){const t=this._options.autoVacuum;try{this._options.autoVacuum=!1;for(const s of e)this.discard(s)}finally{this._options.autoVacuum=t}this.maybeAutoVacuum()}replace(e){const{idField:t,extractField:s}=this._options,n=s(e,t);this.discard(n),this.add(e)}vacuum(e={}){return this.conditionalVacuum(e)}conditionalVacuum(e,t){return this._currentVacuum?(this._enqueuedVacuumConditions=this._enqueuedVacuumConditions&&t,this._enqueuedVacuum!=null?this._enqueuedVacuum:(this._enqueuedVacuum=this._currentVacuum.then(()=>{const s=this._enqueuedVacuumConditions;return this._enqueuedVacuumConditions=Je,this.performVacuuming(e,s)}),this._enqueuedVacuum)):this.vacuumConditionsMet(t)===!1?Promise.resolve():(this._currentVacuum=this.performVacuuming(e),this._currentVacuum)}performVacuuming(e,t){return ke(this,void 0,void 0,function*(){const s=this._dirtCount;if(this.vacuumConditionsMet(t)){const n=e.batchSize||Ke.batchSize,r=e.batchWait||Ke.batchWait;let i=1;for(const[o,l]of this._index){for(const[c,h]of l)for(const[m]of h)this._documentIds.has(m)||(h.size<=1?l.delete(c):h.delete(m));this._index.get(o).size===0&&this._index.delete(o),i%n===0&&(yield new Promise(c=>setTimeout(c,r))),i+=1}this._dirtCount-=s}yield null,this._currentVacuum=this._enqueuedVacuum,this._enqueuedVacuum=null})}vacuumConditionsMet(e){if(e==null)return!0;let{minDirtCount:t,minDirtFactor:s}=e;return t=t||Ve.minDirtCount,s=s||Ve.minDirtFactor,this.dirtCount>=t&&this.dirtFactor>=s}get isVacuuming(){return this._currentVacuum!=null}get dirtCount(){return this._dirtCount}get dirtFactor(){return this._dirtCount/(1+this._documentCount+this._dirtCount)}has(e){return this._idToShortId.has(e)}getStoredFields(e){const t=this._idToShortId.get(e);if(t!=null)return this._storedFields.get(t)}search(e,t={}){const s=this.executeQuery(e,t),n=[];for(const[r,{score:i,terms:o,match:l}]of s){const c=o.length||1,h={id:this._documentIds.get(r),score:i*c,terms:Object.keys(l),queryTerms:o,match:l};Object.assign(h,this._storedFields.get(r)),(t.filter==null||t.filter(h))&&n.push(h)}return e===ue.wildcard&&t.boostDocument==null&&this._options.searchOptions.boostDocument==null||n.sort(pt),n}autoSuggest(e,t={}){t=Object.assign(Object.assign({},this._options.autoSuggestOptions),t);const s=new Map;for(const{score:r,terms:i}of this.search(e,t)){const o=i.join(" "),l=s.get(o);l!=null?(l.score+=r,l.count+=1):s.set(o,{score:r,terms:i,count:1})}const n=[];for(const[r,{score:i,terms:o,count:l}]of s)n.push({suggestion:r,terms:o,score:i/l});return n.sort(pt),n}get documentCount(){return this._documentCount}get termCount(){return this._index.size}static loadJSON(e,t){if(t==null)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJS(JSON.parse(e),t)}static loadJSONAsync(e,t){return ke(this,void 0,void 0,function*(){if(t==null)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJSAsync(JSON.parse(e),t)})}static getDefault(e){if(je.hasOwnProperty(e))return Pe(je,e);throw new Error(`MiniSearch: unknown option "${e}"`)}static loadJS(e,t){const{index:s,documentIds:n,fieldLength:r,storedFields:i,serializationVersion:o}=e,l=this.instantiateMiniSearch(e,t);l._documentIds=Te(n),l._fieldLength=Te(r),l._storedFields=Te(i);for(const[c,h]of l._documentIds)l._idToShortId.set(h,c);for(const[c,h]of s){const m=new Map;for(const f of Object.keys(h)){let b=h[f];o===1&&(b=b.ds),m.set(parseInt(f,10),Te(b))}l._index.set(c,m)}return l}static loadJSAsync(e,t){return ke(this,void 0,void 0,function*(){const{index:s,documentIds:n,fieldLength:r,storedFields:i,serializationVersion:o}=e,l=this.instantiateMiniSearch(e,t);l._documentIds=yield Ie(n),l._fieldLength=yield Ie(r),l._storedFields=yield Ie(i);for(const[h,m]of l._documentIds)l._idToShortId.set(m,h);let c=0;for(const[h,m]of s){const f=new Map;for(const b of Object.keys(m)){let y=m[b];o===1&&(y=y.ds),f.set(parseInt(b,10),yield Ie(y))}++c%1e3===0&&(yield Nt(0)),l._index.set(h,f)}return l})}static instantiateMiniSearch(e,t){const{documentCount:s,nextId:n,fieldIds:r,averageFieldLength:i,dirtCount:o,serializationVersion:l}=e;if(l!==1&&l!==2)throw new Error("MiniSearch: cannot deserialize an index created with an incompatible version");const c=new ue(t);return c._documentCount=s,c._nextId=n,c._idToShortId=new Map,c._fieldIds=r,c._avgFieldLength=i,c._dirtCount=o||0,c._index=new X,c}executeQuery(e,t={}){if(e===ue.wildcard)return this.executeWildcardQuery(t);if(typeof e!="string"){const f=Object.assign(Object.assign(Object.assign({},t),e),{queries:void 0}),b=e.queries.map(y=>this.executeQuery(y,f));return this.combineResults(b,f.combineWith)}const{tokenize:s,processTerm:n,searchOptions:r}=this._options,i=Object.assign(Object.assign({tokenize:s,processTerm:n},r),t),{tokenize:o,processTerm:l}=i,m=o(e).flatMap(f=>l(f)).filter(f=>!!f).map($s(i)).map(f=>this.executeQuerySpec(f,i));return this.combineResults(m,i.combineWith)}executeQuerySpec(e,t){const s=Object.assign(Object.assign({},this._options.searchOptions),t),n=(s.fields||this._options.fields).reduce((x,w)=>Object.assign(Object.assign({},x),{[w]:Pe(s.boost,w)||1}),{}),{boostDocument:r,weights:i,maxFuzzy:o,bm25:l}=s,{fuzzy:c,prefix:h}=Object.assign(Object.assign({},ht.weights),i),m=this._index.get(e.term),f=this.termResults(e.term,e.term,1,e.termBoost,m,n,r,l);let b,y;if(e.prefix&&(b=this._index.atPrefix(e.term)),e.fuzzy){const x=e.fuzzy===!0?.2:e.fuzzy,w=x<1?Math.min(o,Math.round(e.term.length*x)):x;w&&(y=this._index.fuzzyGet(e.term,w))}if(b)for(const[x,w]of b){const R=x.length-e.term.length;if(!R)continue;y==null||y.delete(x);const C=h*x.length/(x.length+.3*R);this.termResults(e.term,x,C,e.termBoost,w,n,r,l,f)}if(y)for(const x of y.keys()){const[w,R]=y.get(x);if(!R)continue;const C=c*x.length/(x.length+R);this.termResults(e.term,x,C,e.termBoost,w,n,r,l,f)}return f}executeWildcardQuery(e){const t=new Map,s=Object.assign(Object.assign({},this._options.searchOptions),e);for(const[n,r]of this._documentIds){const i=s.boostDocument?s.boostDocument(r,"",this._storedFields.get(n)):1;t.set(n,{score:i,terms:[],match:{}})}return t}combineResults(e,t=qe){if(e.length===0)return new Map;const s=t.toLowerCase(),n=Ps[s];if(!n)throw new Error(`Invalid combination operator: ${t}`);return e.reduce(n)||new Map}toJSON(){const e=[];for(const[t,s]of this._index){const n={};for(const[r,i]of s)n[r]=Object.fromEntries(i);e.push([t,n])}return{documentCount:this._documentCount,nextId:this._nextId,documentIds:Object.fromEntries(this._documentIds),fieldIds:this._fieldIds,fieldLength:Object.fromEntries(this._fieldLength),averageFieldLength:this._avgFieldLength,storedFields:Object.fromEntries(this._storedFields),dirtCount:this._dirtCount,index:e,serializationVersion:2}}termResults(e,t,s,n,r,i,o,l,c=new Map){if(r==null)return c;for(const h of Object.keys(i)){const m=i[h],f=this._fieldIds[h],b=r.get(f);if(b==null)continue;let y=b.size;const x=this._avgFieldLength[f];for(const w of b.keys()){if(!this._documentIds.has(w)){this.removeTerm(f,w,t),y-=1;continue}const R=o?o(this._documentIds.get(w),t,this._storedFields.get(w)):1;if(!R)continue;const C=b.get(w),J=this._fieldLength.get(w)[f],Q=Vs(C,y,this._documentCount,J,x,l),W=s*n*m*R*Q,V=c.get(w);if(V){V.score+=W,Ws(V.terms,e);const $=Pe(V.match,t);$?$.push(h):V.match[t]=[h]}else c.set(w,{score:W,terms:[e],match:{[t]:[h]}})}}return c}addTerm(e,t,s){const n=this._index.fetch(s,vt);let r=n.get(e);if(r==null)r=new Map,r.set(t,1),n.set(e,r);else{const i=r.get(t);r.set(t,(i||0)+1)}}removeTerm(e,t,s){if(!this._index.has(s)){this.warnDocumentChanged(t,e,s);return}const n=this._index.fetch(s,vt),r=n.get(e);r==null||r.get(t)==null?this.warnDocumentChanged(t,e,s):r.get(t)<=1?r.size<=1?n.delete(e):r.delete(t):r.set(t,r.get(t)-1),this._index.get(s).size===0&&this._index.delete(s)}warnDocumentChanged(e,t,s){for(const n of Object.keys(this._fieldIds))if(this._fieldIds[n]===t){this._options.logger("warn",`MiniSearch: document with ID ${this._documentIds.get(e)} has changed before removal: term "${s}" was not present in field "${n}". Removing a document after it has changed can corrupt the index!`,"version_conflict");return}}addDocumentId(e){const t=this._nextId;return this._idToShortId.set(e,t),this._documentIds.set(t,e),this._documentCount+=1,this._nextId+=1,t}addFields(e){for(let t=0;tObject.prototype.hasOwnProperty.call(a,e)?a[e]:void 0,Ps={[qe]:(a,e)=>{for(const t of e.keys()){const s=a.get(t);if(s==null)a.set(t,e.get(t));else{const{score:n,terms:r,match:i}=e.get(t);s.score=s.score+n,s.match=Object.assign(s.match,i),ft(s.terms,r)}}return a},[kt]:(a,e)=>{const t=new Map;for(const s of e.keys()){const n=a.get(s);if(n==null)continue;const{score:r,terms:i,match:o}=e.get(s);ft(n.terms,i),t.set(s,{score:n.score+r,terms:n.terms,match:Object.assign(n.match,o)})}return t},[zs]:(a,e)=>{for(const t of e.keys())a.delete(t);return a}},js={k:1.2,b:.7,d:.5},Vs=(a,e,t,s,n,r)=>{const{k:i,b:o,d:l}=r;return Math.log(1+(t-e+.5)/(e+.5))*(l+a*(i+1)/(a+i*(1-o+o*s/n)))},$s=a=>(e,t,s)=>{const n=typeof a.fuzzy=="function"?a.fuzzy(e,t,s):a.fuzzy||!1,r=typeof a.prefix=="function"?a.prefix(e,t,s):a.prefix===!0,i=typeof a.boostTerm=="function"?a.boostTerm(e,t,s):1;return{term:e,fuzzy:n,prefix:r,termBoost:i}},je={idField:"id",extractField:(a,e)=>a[e],tokenize:a=>a.split(Ks),processTerm:a=>a.toLowerCase(),fields:void 0,searchOptions:void 0,storeFields:[],logger:(a,e)=>{typeof(console==null?void 0:console[a])=="function"&&console[a](e)},autoVacuum:!0},ht={combineWith:qe,prefix:!1,fuzzy:!1,maxFuzzy:6,boost:{},weights:{fuzzy:.45,prefix:.375},bm25:js},Bs={combineWith:kt,prefix:(a,e,t)=>e===t.length-1},Ke={batchSize:1e3,batchWait:10},Je={minDirtFactor:.1,minDirtCount:20},Ve=Object.assign(Object.assign({},Ke),Je),Ws=(a,e)=>{a.includes(e)||a.push(e)},ft=(a,e)=>{for(const t of e)a.includes(t)||a.push(t)},pt=({score:a},{score:e})=>e-a,vt=()=>new Map,Te=a=>{const e=new Map;for(const t of Object.keys(a))e.set(parseInt(t,10),a[t]);return e},Ie=a=>ke(void 0,void 0,void 0,function*(){const e=new Map;let t=0;for(const s of Object.keys(a))e.set(parseInt(s,10),a[s]),++t%1e3===0&&(yield Nt(0));return e}),Nt=a=>new Promise(e=>setTimeout(e,a)),Ks=/[\n\r\p{Z}\p{P}]+/u;class Js{constructor(e=10){Me(this,"max");Me(this,"cache");this.max=e,this.cache=new Map}get(e){let t=this.cache.get(e);return t!==void 0&&(this.cache.delete(e),this.cache.set(e,t)),t}set(e,t){this.cache.has(e)?this.cache.delete(e):this.cache.size===this.max&&this.cache.delete(this.first()),this.cache.set(e,t)}first(){return this.cache.keys().next().value}clear(){this.cache.clear()}}const Us=["aria-owns"],qs={class:"shell"},Gs=["title"],Hs={class:"search-actions before"},Qs=["title"],Ys=["aria-activedescendant","aria-controls","placeholder"],Zs={class:"search-actions"},Xs=["title"],en=["disabled","title"],tn=["id","role","aria-labelledby"],sn=["id","aria-selected"],nn=["href","aria-label","onMouseenter","onFocusin","data-index"],rn={class:"titles"},an=["innerHTML"],on={class:"title main"},ln=["innerHTML"],cn={key:0,class:"excerpt-wrapper"},un={key:0,class:"excerpt",inert:""},dn=["innerHTML"],hn={key:0,class:"no-results"},fn={class:"search-keyboard-shortcuts"},pn=["aria-label"],vn=["aria-label"],mn=["aria-label"],gn=["aria-label"],bn=Lt({__name:"VPLocalSearchBox",emits:["close"],setup(a,{emit:e}){var O,A;const t=e,s=xe(),n=xe(),r=xe(is),i=ss(),{activate:o}=Rs(s,{immediate:!0,allowOutsideClick:!0,clickOutsideDeactivates:!0,escapeDeactivates:!0}),{localeIndex:l,theme:c}=i,h=tt(async()=>{var v,p,_,F,z,P,j,I,K;return rt(ue.loadJSON((_=await((p=(v=r.value)[l.value])==null?void 0:p.call(v)))==null?void 0:_.default,{fields:["title","titles","text"],storeFields:["title","titles"],searchOptions:{fuzzy:.2,prefix:!0,boost:{title:4,text:2,titles:1},...((F=c.value.search)==null?void 0:F.provider)==="local"&&((P=(z=c.value.search.options)==null?void 0:z.miniSearch)==null?void 0:P.searchOptions)},...((j=c.value.search)==null?void 0:j.provider)==="local"&&((K=(I=c.value.search.options)==null?void 0:I.miniSearch)==null?void 0:K.options)}))}),f=me(()=>{var v,p;return((v=c.value.search)==null?void 0:v.provider)==="local"&&((p=c.value.search.options)==null?void 0:p.disableQueryPersistence)===!0}).value?ie(""):Dt("vitepress:local-search-filter",""),b=zt("vitepress:local-search-detailed-list",((O=c.value.search)==null?void 0:O.provider)==="local"&&((A=c.value.search.options)==null?void 0:A.detailedView)===!0),y=me(()=>{var v,p,_;return((v=c.value.search)==null?void 0:v.provider)==="local"&&(((p=c.value.search.options)==null?void 0:p.disableDetailedView)===!0||((_=c.value.search.options)==null?void 0:_.detailedView)===!1)}),x=me(()=>{var p,_,F,z,P,j,I;const v=((p=c.value.search)==null?void 0:p.options)??c.value.algolia;return((P=(z=(F=(_=v==null?void 0:v.locales)==null?void 0:_[l.value])==null?void 0:F.translations)==null?void 0:z.button)==null?void 0:P.buttonText)||((I=(j=v==null?void 0:v.translations)==null?void 0:j.button)==null?void 0:I.buttonText)||"Search"});Pt(()=>{y.value&&(b.value=!1)});const w=xe([]),R=ie(!1);$e(f,()=>{R.value=!1});const C=tt(async()=>{if(n.value)return rt(new Ms(n.value))},null),J=new Js(16);jt(()=>[h.value,f.value,b.value],async([v,p,_],F,z)=>{var ee,ye,Ge,He;(F==null?void 0:F[0])!==v&&J.clear();let P=!1;if(z(()=>{P=!0}),!v)return;w.value=v.search(p).slice(0,16),R.value=!0;const j=_?await Promise.all(w.value.map(B=>Q(B.id))):[];if(P)return;for(const{id:B,mod:te}of j){const se=B.slice(0,B.indexOf("#"));let Y=J.get(se);if(Y)continue;Y=new Map,J.set(se,Y);const G=te.default??te;if(G!=null&&G.render||G!=null&&G.setup){const ne=Yt(G);ne.config.warnHandler=()=>{},ne.provide(Zt,i),Object.defineProperties(ne.config.globalProperties,{$frontmatter:{get(){return i.frontmatter.value}},$params:{get(){return i.page.value.params}}});const Qe=document.createElement("div");ne.mount(Qe),Qe.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach(de=>{var Xe;const we=(Xe=de.querySelector("a"))==null?void 0:Xe.getAttribute("href"),Ye=(we==null?void 0:we.startsWith("#"))&&we.slice(1);if(!Ye)return;let Ze="";for(;(de=de.nextElementSibling)&&!/^h[1-6]$/i.test(de.tagName);)Ze+=de.outerHTML;Y.set(Ye,Ze)}),ne.unmount()}if(P)return}const I=new Set;if(w.value=w.value.map(B=>{const[te,se]=B.id.split("#"),Y=J.get(te),G=(Y==null?void 0:Y.get(se))??"";for(const ne in B.match)I.add(ne);return{...B,text:G}}),await he(),P)return;await new Promise(B=>{var te;(te=C.value)==null||te.unmark({done:()=>{var se;(se=C.value)==null||se.markRegExp(T(I),{done:B})}})});const K=((ee=s.value)==null?void 0:ee.querySelectorAll(".result .excerpt"))??[];for(const B of K)(ye=B.querySelector('mark[data-markjs="true"]'))==null||ye.scrollIntoView({block:"center"});(He=(Ge=n.value)==null?void 0:Ge.firstElementChild)==null||He.scrollIntoView({block:"start"})},{debounce:200,immediate:!0});async function Q(v){const p=Xt(v.slice(0,v.indexOf("#")));try{if(!p)throw new Error(`Cannot find file for id: ${v}`);return{id:v,mod:await import(p)}}catch(_){return console.error(_),{id:v,mod:{}}}}const W=ie(),V=me(()=>{var v;return((v=f.value)==null?void 0:v.length)<=0});function $(v=!0){var p,_;(p=W.value)==null||p.focus(),v&&((_=W.value)==null||_.select())}Ae(()=>{$()});function be(v){v.pointerType==="mouse"&&$()}const M=ie(-1),U=ie(!0);$e(w,v=>{M.value=v.length?0:-1,q()});function q(){he(()=>{const v=document.querySelector(".result.selected");v==null||v.scrollIntoView({block:"nearest"})})}Se("ArrowUp",v=>{v.preventDefault(),M.value--,M.value<0&&(M.value=w.value.length-1),U.value=!0,q()}),Se("ArrowDown",v=>{v.preventDefault(),M.value++,M.value>=w.value.length&&(M.value=0),U.value=!0,q()});const k=Vt();Se("Enter",v=>{if(v.isComposing||v.target instanceof HTMLButtonElement&&v.target.type!=="submit")return;const p=w.value[M.value];if(v.target instanceof HTMLInputElement&&!p){v.preventDefault();return}p&&(k.go(p.id),t("close"))}),Se("Escape",()=>{t("close")});const u=ns({modal:{displayDetails:"Display detailed list",resetButtonTitle:"Reset search",backButtonTitle:"Close search",noResultsText:"No results for",footer:{selectText:"to select",selectKeyAriaLabel:"enter",navigateText:"to navigate",navigateUpKeyAriaLabel:"up arrow",navigateDownKeyAriaLabel:"down arrow",closeText:"to close",closeKeyAriaLabel:"escape"}}});Ae(()=>{window.history.pushState(null,"",null)}),$t("popstate",v=>{v.preventDefault(),t("close")});const g=Bt(Wt?document.body:null);Ae(()=>{he(()=>{g.value=!0,he().then(()=>o())})}),Kt(()=>{g.value=!1});function E(){f.value="",he().then(()=>$(!1))}function T(v){return new RegExp([...v].sort((p,_)=>_.length-p.length).map(p=>`(${es(p)})`).join("|"),"gi")}function N(v){var F;if(!U.value)return;const p=(F=v.target)==null?void 0:F.closest(".result"),_=Number.parseInt(p==null?void 0:p.dataset.index);_>=0&&_!==M.value&&(M.value=_),U.value=!1}return(v,p)=>{var _,F,z,P,j;return H(),Jt(Qt,{to:"body"},[S("div",{ref_key:"el",ref:s,role:"button","aria-owns":(_=w.value)!=null&&_.length?"localsearch-list":void 0,"aria-expanded":"true","aria-haspopup":"listbox","aria-labelledby":"localsearch-label",class:"VPLocalSearchBox"},[S("div",{class:"backdrop",onClick:p[0]||(p[0]=I=>v.$emit("close"))}),S("div",qs,[S("form",{class:"search-bar",onPointerup:p[4]||(p[4]=I=>be(I)),onSubmit:p[5]||(p[5]=Ut(()=>{},["prevent"]))},[S("label",{title:x.value,id:"localsearch-label",for:"localsearch-input"},p[7]||(p[7]=[S("span",{"aria-hidden":"true",class:"vpi-search search-icon local-search-icon"},null,-1)]),8,Gs),S("div",Hs,[S("button",{class:"back-button",title:L(u)("modal.backButtonTitle"),onClick:p[1]||(p[1]=I=>v.$emit("close"))},p[8]||(p[8]=[S("span",{class:"vpi-arrow-left local-search-icon"},null,-1)]),8,Qs)]),qt(S("input",{ref_key:"searchInput",ref:W,"onUpdate:modelValue":p[2]||(p[2]=I=>Ht(f)?f.value=I:null),"aria-activedescendant":M.value>-1?"localsearch-item-"+M.value:void 0,"aria-autocomplete":"both","aria-controls":(F=w.value)!=null&&F.length?"localsearch-list":void 0,"aria-labelledby":"localsearch-label",autocapitalize:"off",autocomplete:"off",autocorrect:"off",class:"search-input",id:"localsearch-input",enterkeyhint:"go",maxlength:"64",placeholder:x.value,spellcheck:"false",type:"search"},null,8,Ys),[[Gt,L(f)]]),S("div",Zs,[y.value?_e("",!0):(H(),Z("button",{key:0,class:st(["toggle-layout-button",{"detailed-list":L(b)}]),type:"button",title:L(u)("modal.displayDetails"),onClick:p[3]||(p[3]=I=>M.value>-1&&(b.value=!L(b)))},p[9]||(p[9]=[S("span",{class:"vpi-layout-list local-search-icon"},null,-1)]),10,Xs)),S("button",{class:"clear-button",type:"reset",disabled:V.value,title:L(u)("modal.resetButtonTitle"),onClick:E},p[10]||(p[10]=[S("span",{class:"vpi-delete local-search-icon"},null,-1)]),8,en)])],32),S("ul",{ref_key:"resultsEl",ref:n,id:(z=w.value)!=null&&z.length?"localsearch-list":void 0,role:(P=w.value)!=null&&P.length?"listbox":void 0,"aria-labelledby":(j=w.value)!=null&&j.length?"localsearch-label":void 0,class:"results",onMousemove:N},[(H(!0),Z(it,null,nt(w.value,(I,K)=>(H(),Z("li",{key:I.id,id:"localsearch-item-"+K,"aria-selected":M.value===K?"true":"false",role:"option"},[S("a",{href:I.id,class:st(["result",{selected:M.value===K}]),"aria-label":[...I.titles,I.title].join(" > "),onMouseenter:ee=>!U.value&&(M.value=K),onFocusin:ee=>M.value=K,onClick:p[6]||(p[6]=ee=>v.$emit("close")),"data-index":K},[S("div",null,[S("div",rn,[p[12]||(p[12]=S("span",{class:"title-icon"},"#",-1)),(H(!0),Z(it,null,nt(I.titles,(ee,ye)=>(H(),Z("span",{key:ye,class:"title"},[S("span",{class:"text",innerHTML:ee},null,8,an),p[11]||(p[11]=S("span",{class:"vpi-chevron-right local-search-icon"},null,-1))]))),128)),S("span",on,[S("span",{class:"text",innerHTML:I.title},null,8,ln)])]),L(b)?(H(),Z("div",cn,[I.text?(H(),Z("div",un,[S("div",{class:"vp-doc",innerHTML:I.text},null,8,dn)])):_e("",!0),p[13]||(p[13]=S("div",{class:"excerpt-gradient-bottom"},null,-1)),p[14]||(p[14]=S("div",{class:"excerpt-gradient-top"},null,-1))])):_e("",!0)])],42,nn)],8,sn))),128)),L(f)&&!w.value.length&&R.value?(H(),Z("li",hn,[fe(pe(L(u)("modal.noResultsText"))+' "',1),S("strong",null,pe(L(f)),1),p[15]||(p[15]=fe('" '))])):_e("",!0)],40,tn),S("div",fn,[S("span",null,[S("kbd",{"aria-label":L(u)("modal.footer.navigateUpKeyAriaLabel")},p[16]||(p[16]=[S("span",{class:"vpi-arrow-up navigate-icon"},null,-1)]),8,pn),S("kbd",{"aria-label":L(u)("modal.footer.navigateDownKeyAriaLabel")},p[17]||(p[17]=[S("span",{class:"vpi-arrow-down navigate-icon"},null,-1)]),8,vn),fe(" "+pe(L(u)("modal.footer.navigateText")),1)]),S("span",null,[S("kbd",{"aria-label":L(u)("modal.footer.selectKeyAriaLabel")},p[18]||(p[18]=[S("span",{class:"vpi-corner-down-left navigate-icon"},null,-1)]),8,mn),fe(" "+pe(L(u)("modal.footer.selectText")),1)]),S("span",null,[S("kbd",{"aria-label":L(u)("modal.footer.closeKeyAriaLabel")},"esc",8,gn),fe(" "+pe(L(u)("modal.footer.closeText")),1)])])])],8,Us)])}}}),En=ts(bn,[["__scopeId","data-v-42e65fb9"]]);export{En as default}; diff --git a/previews/PR1023/assets/chunks/framework.DFwXuivk.js b/previews/PR1023/assets/chunks/framework.DFwXuivk.js new file mode 100644 index 0000000000..40428fe2ba --- /dev/null +++ b/previews/PR1023/assets/chunks/framework.DFwXuivk.js @@ -0,0 +1,18 @@ +/** +* @vue/shared v3.5.12 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**//*! #__NO_SIDE_EFFECTS__ */function Ns(e){const t=Object.create(null);for(const n of e.split(","))t[n]=1;return n=>n in t}const Z={},Et=[],ke=()=>{},Uo=()=>!1,Zt=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),Fs=e=>e.startsWith("onUpdate:"),ce=Object.assign,Hs=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},ko=Object.prototype.hasOwnProperty,z=(e,t)=>ko.call(e,t),K=Array.isArray,Tt=e=>In(e)==="[object Map]",si=e=>In(e)==="[object Set]",q=e=>typeof e=="function",re=e=>typeof e=="string",Ye=e=>typeof e=="symbol",ne=e=>e!==null&&typeof e=="object",ri=e=>(ne(e)||q(e))&&q(e.then)&&q(e.catch),ii=Object.prototype.toString,In=e=>ii.call(e),Bo=e=>In(e).slice(8,-1),oi=e=>In(e)==="[object Object]",$s=e=>re(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Ct=Ns(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Nn=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},Wo=/-(\w)/g,Le=Nn(e=>e.replace(Wo,(t,n)=>n?n.toUpperCase():"")),Ko=/\B([A-Z])/g,st=Nn(e=>e.replace(Ko,"-$1").toLowerCase()),Fn=Nn(e=>e.charAt(0).toUpperCase()+e.slice(1)),vn=Nn(e=>e?`on${Fn(e)}`:""),tt=(e,t)=>!Object.is(e,t),bn=(e,...t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:s,value:n})},vs=e=>{const t=parseFloat(e);return isNaN(t)?e:t},qo=e=>{const t=re(e)?Number(e):NaN;return isNaN(t)?e:t};let ar;const Hn=()=>ar||(ar=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Ds(e){if(K(e)){const t={};for(let n=0;n{if(n){const s=n.split(Yo);s.length>1&&(t[s[0].trim()]=s[1].trim())}}),t}function js(e){let t="";if(re(e))t=e;else if(K(e))for(let n=0;n!!(e&&e.__v_isRef===!0),Zo=e=>re(e)?e:e==null?"":K(e)||ne(e)&&(e.toString===ii||!q(e.toString))?ai(e)?Zo(e.value):JSON.stringify(e,fi,2):String(e),fi=(e,t)=>ai(t)?fi(e,t.value):Tt(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[s,r],i)=>(n[zn(s,i)+" =>"]=r,n),{})}:si(t)?{[`Set(${t.size})`]:[...t.values()].map(n=>zn(n))}:Ye(t)?zn(t):ne(t)&&!K(t)&&!oi(t)?String(t):t,zn=(e,t="")=>{var n;return Ye(e)?`Symbol(${(n=e.description)!=null?n:t})`:e};/** +* @vue/reactivity v3.5.12 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let _e;class el{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this._isPaused=!1,this.parent=_e,!t&&_e&&(this.index=(_e.scopes||(_e.scopes=[])).push(this)-1)}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,n;if(this.scopes)for(t=0,n=this.scopes.length;t0)return;if(jt){let t=jt;for(jt=void 0;t;){const n=t.next;t.next=void 0,t.flags&=-9,t=n}}let e;for(;Dt;){let t=Dt;for(Dt=void 0;t;){const n=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(s){e||(e=s)}t=n}}if(e)throw e}function gi(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function mi(e){let t,n=e.depsTail,s=n;for(;s;){const r=s.prevDep;s.version===-1?(s===n&&(n=r),ks(s),nl(s)):t=s,s.dep.activeLink=s.prevActiveLink,s.prevActiveLink=void 0,s=r}e.deps=t,e.depsTail=n}function bs(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(yi(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function yi(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===Kt))return;e.globalVersion=Kt;const t=e.dep;if(e.flags|=2,t.version>0&&!e.isSSR&&e.deps&&!bs(e)){e.flags&=-3;return}const n=te,s=Ne;te=e,Ne=!0;try{gi(e);const r=e.fn(e._value);(t.version===0||tt(r,e._value))&&(e._value=r,t.version++)}catch(r){throw t.version++,r}finally{te=n,Ne=s,mi(e),e.flags&=-3}}function ks(e,t=!1){const{dep:n,prevSub:s,nextSub:r}=e;if(s&&(s.nextSub=r,e.prevSub=void 0),r&&(r.prevSub=s,e.nextSub=void 0),n.subs===e&&(n.subs=s,!s&&n.computed)){n.computed.flags&=-5;for(let i=n.computed.deps;i;i=i.nextDep)ks(i,!0)}!t&&!--n.sc&&n.map&&n.map.delete(n.key)}function nl(e){const{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}let Ne=!0;const vi=[];function rt(){vi.push(Ne),Ne=!1}function it(){const e=vi.pop();Ne=e===void 0?!0:e}function fr(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const n=te;te=void 0;try{t()}finally{te=n}}}let Kt=0;class sl{constructor(t,n){this.sub=t,this.dep=n,this.version=n.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class $n{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0}track(t){if(!te||!Ne||te===this.computed)return;let n=this.activeLink;if(n===void 0||n.sub!==te)n=this.activeLink=new sl(te,this),te.deps?(n.prevDep=te.depsTail,te.depsTail.nextDep=n,te.depsTail=n):te.deps=te.depsTail=n,bi(n);else if(n.version===-1&&(n.version=this.version,n.nextDep)){const s=n.nextDep;s.prevDep=n.prevDep,n.prevDep&&(n.prevDep.nextDep=s),n.prevDep=te.depsTail,n.nextDep=void 0,te.depsTail.nextDep=n,te.depsTail=n,te.deps===n&&(te.deps=s)}return n}trigger(t){this.version++,Kt++,this.notify(t)}notify(t){Vs();try{for(let n=this.subs;n;n=n.prevSub)n.sub.notify()&&n.sub.dep.notify()}finally{Us()}}}function bi(e){if(e.dep.sc++,e.sub.flags&4){const t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let s=t.deps;s;s=s.nextDep)bi(s)}const n=e.dep.subs;n!==e&&(e.prevSub=n,n&&(n.nextSub=e)),e.dep.subs=e}}const Tn=new WeakMap,dt=Symbol(""),_s=Symbol(""),qt=Symbol("");function me(e,t,n){if(Ne&&te){let s=Tn.get(e);s||Tn.set(e,s=new Map);let r=s.get(n);r||(s.set(n,r=new $n),r.map=s,r.key=n),r.track()}}function qe(e,t,n,s,r,i){const o=Tn.get(e);if(!o){Kt++;return}const l=c=>{c&&c.trigger()};if(Vs(),t==="clear")o.forEach(l);else{const c=K(e),f=c&&$s(n);if(c&&n==="length"){const a=Number(s);o.forEach((d,y)=>{(y==="length"||y===qt||!Ye(y)&&y>=a)&&l(d)})}else switch((n!==void 0||o.has(void 0))&&l(o.get(n)),f&&l(o.get(qt)),t){case"add":c?f&&l(o.get("length")):(l(o.get(dt)),Tt(e)&&l(o.get(_s)));break;case"delete":c||(l(o.get(dt)),Tt(e)&&l(o.get(_s)));break;case"set":Tt(e)&&l(o.get(dt));break}}Us()}function rl(e,t){const n=Tn.get(e);return n&&n.get(t)}function bt(e){const t=J(e);return t===e?t:(me(t,"iterate",qt),Pe(e)?t:t.map(ye))}function Dn(e){return me(e=J(e),"iterate",qt),e}const il={__proto__:null,[Symbol.iterator](){return Zn(this,Symbol.iterator,ye)},concat(...e){return bt(this).concat(...e.map(t=>K(t)?bt(t):t))},entries(){return Zn(this,"entries",e=>(e[1]=ye(e[1]),e))},every(e,t){return We(this,"every",e,t,void 0,arguments)},filter(e,t){return We(this,"filter",e,t,n=>n.map(ye),arguments)},find(e,t){return We(this,"find",e,t,ye,arguments)},findIndex(e,t){return We(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return We(this,"findLast",e,t,ye,arguments)},findLastIndex(e,t){return We(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return We(this,"forEach",e,t,void 0,arguments)},includes(...e){return es(this,"includes",e)},indexOf(...e){return es(this,"indexOf",e)},join(e){return bt(this).join(e)},lastIndexOf(...e){return es(this,"lastIndexOf",e)},map(e,t){return We(this,"map",e,t,void 0,arguments)},pop(){return Ft(this,"pop")},push(...e){return Ft(this,"push",e)},reduce(e,...t){return ur(this,"reduce",e,t)},reduceRight(e,...t){return ur(this,"reduceRight",e,t)},shift(){return Ft(this,"shift")},some(e,t){return We(this,"some",e,t,void 0,arguments)},splice(...e){return Ft(this,"splice",e)},toReversed(){return bt(this).toReversed()},toSorted(e){return bt(this).toSorted(e)},toSpliced(...e){return bt(this).toSpliced(...e)},unshift(...e){return Ft(this,"unshift",e)},values(){return Zn(this,"values",ye)}};function Zn(e,t,n){const s=Dn(e),r=s[t]();return s!==e&&!Pe(e)&&(r._next=r.next,r.next=()=>{const i=r._next();return i.value&&(i.value=n(i.value)),i}),r}const ol=Array.prototype;function We(e,t,n,s,r,i){const o=Dn(e),l=o!==e&&!Pe(e),c=o[t];if(c!==ol[t]){const d=c.apply(e,i);return l?ye(d):d}let f=n;o!==e&&(l?f=function(d,y){return n.call(this,ye(d),y,e)}:n.length>2&&(f=function(d,y){return n.call(this,d,y,e)}));const a=c.call(o,f,s);return l&&r?r(a):a}function ur(e,t,n,s){const r=Dn(e);let i=n;return r!==e&&(Pe(e)?n.length>3&&(i=function(o,l,c){return n.call(this,o,l,c,e)}):i=function(o,l,c){return n.call(this,o,ye(l),c,e)}),r[t](i,...s)}function es(e,t,n){const s=J(e);me(s,"iterate",qt);const r=s[t](...n);return(r===-1||r===!1)&&Ks(n[0])?(n[0]=J(n[0]),s[t](...n)):r}function Ft(e,t,n=[]){rt(),Vs();const s=J(e)[t].apply(e,n);return Us(),it(),s}const ll=Ns("__proto__,__v_isRef,__isVue"),_i=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Ye));function cl(e){Ye(e)||(e=String(e));const t=J(this);return me(t,"has",e),t.hasOwnProperty(e)}class wi{constructor(t=!1,n=!1){this._isReadonly=t,this._isShallow=n}get(t,n,s){const r=this._isReadonly,i=this._isShallow;if(n==="__v_isReactive")return!r;if(n==="__v_isReadonly")return r;if(n==="__v_isShallow")return i;if(n==="__v_raw")return s===(r?i?vl:Ti:i?Ei:xi).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(s)?t:void 0;const o=K(t);if(!r){let c;if(o&&(c=il[n]))return c;if(n==="hasOwnProperty")return cl}const l=Reflect.get(t,n,fe(t)?t:s);return(Ye(n)?_i.has(n):ll(n))||(r||me(t,"get",n),i)?l:fe(l)?o&&$s(n)?l:l.value:ne(l)?r?Vn(l):jn(l):l}}class Si extends wi{constructor(t=!1){super(!1,t)}set(t,n,s,r){let i=t[n];if(!this._isShallow){const c=yt(i);if(!Pe(s)&&!yt(s)&&(i=J(i),s=J(s)),!K(t)&&fe(i)&&!fe(s))return c?!1:(i.value=s,!0)}const o=K(t)&&$s(n)?Number(n)e,ln=e=>Reflect.getPrototypeOf(e);function hl(e,t,n){return function(...s){const r=this.__v_raw,i=J(r),o=Tt(i),l=e==="entries"||e===Symbol.iterator&&o,c=e==="keys"&&o,f=r[e](...s),a=n?ws:t?Ss:ye;return!t&&me(i,"iterate",c?_s:dt),{next(){const{value:d,done:y}=f.next();return y?{value:d,done:y}:{value:l?[a(d[0]),a(d[1])]:a(d),done:y}},[Symbol.iterator](){return this}}}}function cn(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function pl(e,t){const n={get(r){const i=this.__v_raw,o=J(i),l=J(r);e||(tt(r,l)&&me(o,"get",r),me(o,"get",l));const{has:c}=ln(o),f=t?ws:e?Ss:ye;if(c.call(o,r))return f(i.get(r));if(c.call(o,l))return f(i.get(l));i!==o&&i.get(r)},get size(){const r=this.__v_raw;return!e&&me(J(r),"iterate",dt),Reflect.get(r,"size",r)},has(r){const i=this.__v_raw,o=J(i),l=J(r);return e||(tt(r,l)&&me(o,"has",r),me(o,"has",l)),r===l?i.has(r):i.has(r)||i.has(l)},forEach(r,i){const o=this,l=o.__v_raw,c=J(l),f=t?ws:e?Ss:ye;return!e&&me(c,"iterate",dt),l.forEach((a,d)=>r.call(i,f(a),f(d),o))}};return ce(n,e?{add:cn("add"),set:cn("set"),delete:cn("delete"),clear:cn("clear")}:{add(r){!t&&!Pe(r)&&!yt(r)&&(r=J(r));const i=J(this);return ln(i).has.call(i,r)||(i.add(r),qe(i,"add",r,r)),this},set(r,i){!t&&!Pe(i)&&!yt(i)&&(i=J(i));const o=J(this),{has:l,get:c}=ln(o);let f=l.call(o,r);f||(r=J(r),f=l.call(o,r));const a=c.call(o,r);return o.set(r,i),f?tt(i,a)&&qe(o,"set",r,i):qe(o,"add",r,i),this},delete(r){const i=J(this),{has:o,get:l}=ln(i);let c=o.call(i,r);c||(r=J(r),c=o.call(i,r)),l&&l.call(i,r);const f=i.delete(r);return c&&qe(i,"delete",r,void 0),f},clear(){const r=J(this),i=r.size!==0,o=r.clear();return i&&qe(r,"clear",void 0,void 0),o}}),["keys","values","entries",Symbol.iterator].forEach(r=>{n[r]=hl(r,e,t)}),n}function Bs(e,t){const n=pl(e,t);return(s,r,i)=>r==="__v_isReactive"?!e:r==="__v_isReadonly"?e:r==="__v_raw"?s:Reflect.get(z(n,r)&&r in s?n:s,r,i)}const gl={get:Bs(!1,!1)},ml={get:Bs(!1,!0)},yl={get:Bs(!0,!1)};const xi=new WeakMap,Ei=new WeakMap,Ti=new WeakMap,vl=new WeakMap;function bl(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function _l(e){return e.__v_skip||!Object.isExtensible(e)?0:bl(Bo(e))}function jn(e){return yt(e)?e:Ws(e,!1,fl,gl,xi)}function wl(e){return Ws(e,!1,dl,ml,Ei)}function Vn(e){return Ws(e,!0,ul,yl,Ti)}function Ws(e,t,n,s,r){if(!ne(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const i=r.get(e);if(i)return i;const o=_l(e);if(o===0)return e;const l=new Proxy(e,o===2?s:n);return r.set(e,l),l}function ht(e){return yt(e)?ht(e.__v_raw):!!(e&&e.__v_isReactive)}function yt(e){return!!(e&&e.__v_isReadonly)}function Pe(e){return!!(e&&e.__v_isShallow)}function Ks(e){return e?!!e.__v_raw:!1}function J(e){const t=e&&e.__v_raw;return t?J(t):e}function _n(e){return!z(e,"__v_skip")&&Object.isExtensible(e)&&li(e,"__v_skip",!0),e}const ye=e=>ne(e)?jn(e):e,Ss=e=>ne(e)?Vn(e):e;function fe(e){return e?e.__v_isRef===!0:!1}function oe(e){return Ci(e,!1)}function qs(e){return Ci(e,!0)}function Ci(e,t){return fe(e)?e:new Sl(e,t)}class Sl{constructor(t,n){this.dep=new $n,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=n?t:J(t),this._value=n?t:ye(t),this.__v_isShallow=n}get value(){return this.dep.track(),this._value}set value(t){const n=this._rawValue,s=this.__v_isShallow||Pe(t)||yt(t);t=s?t:J(t),tt(t,n)&&(this._rawValue=t,this._value=s?t:ye(t),this.dep.trigger())}}function Ai(e){return fe(e)?e.value:e}const xl={get:(e,t,n)=>t==="__v_raw"?e:Ai(Reflect.get(e,t,n)),set:(e,t,n,s)=>{const r=e[t];return fe(r)&&!fe(n)?(r.value=n,!0):Reflect.set(e,t,n,s)}};function Ri(e){return ht(e)?e:new Proxy(e,xl)}class El{constructor(t){this.__v_isRef=!0,this._value=void 0;const n=this.dep=new $n,{get:s,set:r}=t(n.track.bind(n),n.trigger.bind(n));this._get=s,this._set=r}get value(){return this._value=this._get()}set value(t){this._set(t)}}function Tl(e){return new El(e)}class Cl{constructor(t,n,s){this._object=t,this._key=n,this._defaultValue=s,this.__v_isRef=!0,this._value=void 0}get value(){const t=this._object[this._key];return this._value=t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return rl(J(this._object),this._key)}}class Al{constructor(t){this._getter=t,this.__v_isRef=!0,this.__v_isReadonly=!0,this._value=void 0}get value(){return this._value=this._getter()}}function Rl(e,t,n){return fe(e)?e:q(e)?new Al(e):ne(e)&&arguments.length>1?Ol(e,t,n):oe(e)}function Ol(e,t,n){const s=e[t];return fe(s)?s:new Cl(e,t,n)}class Ml{constructor(t,n,s){this.fn=t,this.setter=n,this._value=void 0,this.dep=new $n(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=Kt-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!n,this.isSSR=s}notify(){if(this.flags|=16,!(this.flags&8)&&te!==this)return pi(this,!0),!0}get value(){const t=this.dep.track();return yi(this),t&&(t.version=this.dep.version),this._value}set value(t){this.setter&&this.setter(t)}}function Pl(e,t,n=!1){let s,r;return q(e)?s=e:(s=e.get,r=e.set),new Ml(s,r,n)}const an={},Cn=new WeakMap;let ft;function Ll(e,t=!1,n=ft){if(n){let s=Cn.get(n);s||Cn.set(n,s=[]),s.push(e)}}function Il(e,t,n=Z){const{immediate:s,deep:r,once:i,scheduler:o,augmentJob:l,call:c}=n,f=g=>r?g:Pe(g)||r===!1||r===0?Ge(g,1):Ge(g);let a,d,y,v,S=!1,b=!1;if(fe(e)?(d=()=>e.value,S=Pe(e)):ht(e)?(d=()=>f(e),S=!0):K(e)?(b=!0,S=e.some(g=>ht(g)||Pe(g)),d=()=>e.map(g=>{if(fe(g))return g.value;if(ht(g))return f(g);if(q(g))return c?c(g,2):g()})):q(e)?t?d=c?()=>c(e,2):e:d=()=>{if(y){rt();try{y()}finally{it()}}const g=ft;ft=a;try{return c?c(e,3,[v]):e(v)}finally{ft=g}}:d=ke,t&&r){const g=d,M=r===!0?1/0:r;d=()=>Ge(g(),M)}const B=ui(),N=()=>{a.stop(),B&&Hs(B.effects,a)};if(i&&t){const g=t;t=(...M)=>{g(...M),N()}}let j=b?new Array(e.length).fill(an):an;const p=g=>{if(!(!(a.flags&1)||!a.dirty&&!g))if(t){const M=a.run();if(r||S||(b?M.some((F,$)=>tt(F,j[$])):tt(M,j))){y&&y();const F=ft;ft=a;try{const $=[M,j===an?void 0:b&&j[0]===an?[]:j,v];c?c(t,3,$):t(...$),j=M}finally{ft=F}}}else a.run()};return l&&l(p),a=new di(d),a.scheduler=o?()=>o(p,!1):p,v=g=>Ll(g,!1,a),y=a.onStop=()=>{const g=Cn.get(a);if(g){if(c)c(g,4);else for(const M of g)M();Cn.delete(a)}},t?s?p(!0):j=a.run():o?o(p.bind(null,!0),!0):a.run(),N.pause=a.pause.bind(a),N.resume=a.resume.bind(a),N.stop=N,N}function Ge(e,t=1/0,n){if(t<=0||!ne(e)||e.__v_skip||(n=n||new Set,n.has(e)))return e;if(n.add(e),t--,fe(e))Ge(e.value,t,n);else if(K(e))for(let s=0;s{Ge(s,t,n)});else if(oi(e)){for(const s in e)Ge(e[s],t,n);for(const s of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,s)&&Ge(e[s],t,n)}return e}/** +* @vue/runtime-core v3.5.12 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/function en(e,t,n,s){try{return s?e(...s):e()}catch(r){tn(r,t,n)}}function He(e,t,n,s){if(q(e)){const r=en(e,t,n,s);return r&&ri(r)&&r.catch(i=>{tn(i,t,n)}),r}if(K(e)){const r=[];for(let i=0;i>>1,r=we[s],i=Gt(r);i=Gt(n)?we.push(e):we.splice(Fl(t),0,e),e.flags|=1,Mi()}}function Mi(){An||(An=Oi.then(Pi))}function Hl(e){K(e)?At.push(...e):Qe&&e.id===-1?Qe.splice(wt+1,0,e):e.flags&1||(At.push(e),e.flags|=1),Mi()}function dr(e,t,n=Ve+1){for(;nGt(n)-Gt(s));if(At.length=0,Qe){Qe.push(...t);return}for(Qe=t,wt=0;wte.id==null?e.flags&2?-1:1/0:e.id;function Pi(e){try{for(Ve=0;Ve{s._d&&Cr(-1);const i=On(t);let o;try{o=e(...r)}finally{On(i),s._d&&Cr(1)}return o};return s._n=!0,s._c=!0,s._d=!0,s}function bf(e,t){if(de===null)return e;const n=Gn(de),s=e.dirs||(e.dirs=[]);for(let r=0;re.__isTeleport,Vt=e=>e&&(e.disabled||e.disabled===""),Dl=e=>e&&(e.defer||e.defer===""),hr=e=>typeof SVGElement<"u"&&e instanceof SVGElement,pr=e=>typeof MathMLElement=="function"&&e instanceof MathMLElement,xs=(e,t)=>{const n=e&&e.to;return re(n)?t?t(n):null:n},jl={name:"Teleport",__isTeleport:!0,process(e,t,n,s,r,i,o,l,c,f){const{mc:a,pc:d,pbc:y,o:{insert:v,querySelector:S,createText:b,createComment:B}}=f,N=Vt(t.props);let{shapeFlag:j,children:p,dynamicChildren:g}=t;if(e==null){const M=t.el=b(""),F=t.anchor=b("");v(M,n,s),v(F,n,s);const $=(R,_)=>{j&16&&(r&&r.isCE&&(r.ce._teleportTarget=R),a(p,R,_,r,i,o,l,c))},V=()=>{const R=t.target=xs(t.props,S),_=Fi(R,t,b,v);R&&(o!=="svg"&&hr(R)?o="svg":o!=="mathml"&&pr(R)&&(o="mathml"),N||($(R,_),wn(t,!1)))};N&&($(n,F),wn(t,!0)),Dl(t.props)?xe(V,i):V()}else{t.el=e.el,t.targetStart=e.targetStart;const M=t.anchor=e.anchor,F=t.target=e.target,$=t.targetAnchor=e.targetAnchor,V=Vt(e.props),R=V?n:F,_=V?M:$;if(o==="svg"||hr(F)?o="svg":(o==="mathml"||pr(F))&&(o="mathml"),g?(y(e.dynamicChildren,g,R,r,i,o,l),Qs(e,t,!0)):c||d(e,t,R,_,r,i,o,l,!1),N)V?t.props&&e.props&&t.props.to!==e.props.to&&(t.props.to=e.props.to):fn(t,n,M,f,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const I=t.target=xs(t.props,S);I&&fn(t,I,null,f,0)}else V&&fn(t,F,$,f,1);wn(t,N)}},remove(e,t,n,{um:s,o:{remove:r}},i){const{shapeFlag:o,children:l,anchor:c,targetStart:f,targetAnchor:a,target:d,props:y}=e;if(d&&(r(f),r(a)),i&&r(c),o&16){const v=i||!Vt(y);for(let S=0;S{e.isMounted=!0}),ki(()=>{e.isUnmounting=!0}),e}const Re=[Function,Array],Hi={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Re,onEnter:Re,onAfterEnter:Re,onEnterCancelled:Re,onBeforeLeave:Re,onLeave:Re,onAfterLeave:Re,onLeaveCancelled:Re,onBeforeAppear:Re,onAppear:Re,onAfterAppear:Re,onAppearCancelled:Re},$i=e=>{const t=e.subTree;return t.component?$i(t.component):t},kl={name:"BaseTransition",props:Hi,setup(e,{slots:t}){const n=qn(),s=Ul();return()=>{const r=t.default&&Vi(t.default(),!0);if(!r||!r.length)return;const i=Di(r),o=J(e),{mode:l}=o;if(s.isLeaving)return ts(i);const c=gr(i);if(!c)return ts(i);let f=Es(c,o,s,n,y=>f=y);c.type!==ve&&Yt(c,f);const a=n.subTree,d=a&&gr(a);if(d&&d.type!==ve&&!ut(c,d)&&$i(n).type!==ve){const y=Es(d,o,s,n);if(Yt(d,y),l==="out-in"&&c.type!==ve)return s.isLeaving=!0,y.afterLeave=()=>{s.isLeaving=!1,n.job.flags&8||n.update(),delete y.afterLeave},ts(i);l==="in-out"&&c.type!==ve&&(y.delayLeave=(v,S,b)=>{const B=ji(s,d);B[String(d.key)]=d,v[Ze]=()=>{S(),v[Ze]=void 0,delete f.delayedLeave},f.delayedLeave=b})}return i}}};function Di(e){let t=e[0];if(e.length>1){for(const n of e)if(n.type!==ve){t=n;break}}return t}const Bl=kl;function ji(e,t){const{leavingVNodes:n}=e;let s=n.get(t.type);return s||(s=Object.create(null),n.set(t.type,s)),s}function Es(e,t,n,s,r){const{appear:i,mode:o,persisted:l=!1,onBeforeEnter:c,onEnter:f,onAfterEnter:a,onEnterCancelled:d,onBeforeLeave:y,onLeave:v,onAfterLeave:S,onLeaveCancelled:b,onBeforeAppear:B,onAppear:N,onAfterAppear:j,onAppearCancelled:p}=t,g=String(e.key),M=ji(n,e),F=(R,_)=>{R&&He(R,s,9,_)},$=(R,_)=>{const I=_[1];F(R,_),K(R)?R.every(E=>E.length<=1)&&I():R.length<=1&&I()},V={mode:o,persisted:l,beforeEnter(R){let _=c;if(!n.isMounted)if(i)_=B||c;else return;R[Ze]&&R[Ze](!0);const I=M[g];I&&ut(e,I)&&I.el[Ze]&&I.el[Ze](),F(_,[R])},enter(R){let _=f,I=a,E=d;if(!n.isMounted)if(i)_=N||f,I=j||a,E=p||d;else return;let W=!1;const se=R[un]=ae=>{W||(W=!0,ae?F(E,[R]):F(I,[R]),V.delayedLeave&&V.delayedLeave(),R[un]=void 0)};_?$(_,[R,se]):se()},leave(R,_){const I=String(e.key);if(R[un]&&R[un](!0),n.isUnmounting)return _();F(y,[R]);let E=!1;const W=R[Ze]=se=>{E||(E=!0,_(),se?F(b,[R]):F(S,[R]),R[Ze]=void 0,M[I]===e&&delete M[I])};M[I]=e,v?$(v,[R,W]):W()},clone(R){const _=Es(R,t,n,s,r);return r&&r(_),_}};return V}function ts(e){if(nn(e))return e=nt(e),e.children=null,e}function gr(e){if(!nn(e))return Ni(e.type)&&e.children?Di(e.children):e;const{shapeFlag:t,children:n}=e;if(n){if(t&16)return n[0];if(t&32&&q(n.default))return n.default()}}function Yt(e,t){e.shapeFlag&6&&e.component?(e.transition=t,Yt(e.component.subTree,t)):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Vi(e,t=!1,n){let s=[],r=0;for(let i=0;i1)for(let i=0;iMn(S,t&&(K(t)?t[b]:t),n,s,r));return}if(pt(s)&&!r)return;const i=s.shapeFlag&4?Gn(s.component):s.el,o=r?null:i,{i:l,r:c}=e,f=t&&t.r,a=l.refs===Z?l.refs={}:l.refs,d=l.setupState,y=J(d),v=d===Z?()=>!1:S=>z(y,S);if(f!=null&&f!==c&&(re(f)?(a[f]=null,v(f)&&(d[f]=null)):fe(f)&&(f.value=null)),q(c))en(c,l,12,[o,a]);else{const S=re(c),b=fe(c);if(S||b){const B=()=>{if(e.f){const N=S?v(c)?d[c]:a[c]:c.value;r?K(N)&&Hs(N,i):K(N)?N.includes(i)||N.push(i):S?(a[c]=[i],v(c)&&(d[c]=a[c])):(c.value=[i],e.k&&(a[e.k]=c.value))}else S?(a[c]=o,v(c)&&(d[c]=o)):b&&(c.value=o,e.k&&(a[e.k]=o))};o?(B.id=-1,xe(B,n)):B()}}}let mr=!1;const _t=()=>{mr||(console.error("Hydration completed but contains mismatches."),mr=!0)},Wl=e=>e.namespaceURI.includes("svg")&&e.tagName!=="foreignObject",Kl=e=>e.namespaceURI.includes("MathML"),dn=e=>{if(e.nodeType===1){if(Wl(e))return"svg";if(Kl(e))return"mathml"}},xt=e=>e.nodeType===8;function ql(e){const{mt:t,p:n,o:{patchProp:s,createText:r,nextSibling:i,parentNode:o,remove:l,insert:c,createComment:f}}=e,a=(p,g)=>{if(!g.hasChildNodes()){n(null,p,g),Rn(),g._vnode=p;return}d(g.firstChild,p,null,null,null),Rn(),g._vnode=p},d=(p,g,M,F,$,V=!1)=>{V=V||!!g.dynamicChildren;const R=xt(p)&&p.data==="[",_=()=>b(p,g,M,F,$,R),{type:I,ref:E,shapeFlag:W,patchFlag:se}=g;let ae=p.nodeType;g.el=p,se===-2&&(V=!1,g.dynamicChildren=null);let U=null;switch(I){case gt:ae!==3?g.children===""?(c(g.el=r(""),o(p),p),U=p):U=_():(p.data!==g.children&&(_t(),p.data=g.children),U=i(p));break;case ve:j(p)?(U=i(p),N(g.el=p.content.firstChild,p,M)):ae!==8||R?U=_():U=i(p);break;case kt:if(R&&(p=i(p),ae=p.nodeType),ae===1||ae===3){U=p;const Y=!g.children.length;for(let D=0;D{V=V||!!g.dynamicChildren;const{type:R,props:_,patchFlag:I,shapeFlag:E,dirs:W,transition:se}=g,ae=R==="input"||R==="option";if(ae||I!==-1){W&&Ue(g,null,M,"created");let U=!1;if(j(p)){U=io(null,se)&&M&&M.vnode.props&&M.vnode.props.appear;const D=p.content.firstChild;U&&se.beforeEnter(D),N(D,p,M),g.el=p=D}if(E&16&&!(_&&(_.innerHTML||_.textContent))){let D=v(p.firstChild,g,p,M,F,$,V);for(;D;){hn(p,1)||_t();const he=D;D=D.nextSibling,l(he)}}else if(E&8){let D=g.children;D[0]===` +`&&(p.tagName==="PRE"||p.tagName==="TEXTAREA")&&(D=D.slice(1)),p.textContent!==D&&(hn(p,0)||_t(),p.textContent=g.children)}if(_){if(ae||!V||I&48){const D=p.tagName.includes("-");for(const he in _)(ae&&(he.endsWith("value")||he==="indeterminate")||Zt(he)&&!Ct(he)||he[0]==="."||D)&&s(p,he,null,_[he],void 0,M)}else if(_.onClick)s(p,"onClick",null,_.onClick,void 0,M);else if(I&4&&ht(_.style))for(const D in _.style)_.style[D]}let Y;(Y=_&&_.onVnodeBeforeMount)&&Oe(Y,M,g),W&&Ue(g,null,M,"beforeMount"),((Y=_&&_.onVnodeMounted)||W||U)&&fo(()=>{Y&&Oe(Y,M,g),U&&se.enter(p),W&&Ue(g,null,M,"mounted")},F)}return p.nextSibling},v=(p,g,M,F,$,V,R)=>{R=R||!!g.dynamicChildren;const _=g.children,I=_.length;for(let E=0;E{const{slotScopeIds:R}=g;R&&($=$?$.concat(R):R);const _=o(p),I=v(i(p),g,_,M,F,$,V);return I&&xt(I)&&I.data==="]"?i(g.anchor=I):(_t(),c(g.anchor=f("]"),_,I),I)},b=(p,g,M,F,$,V)=>{if(hn(p.parentElement,1)||_t(),g.el=null,V){const I=B(p);for(;;){const E=i(p);if(E&&E!==I)l(E);else break}}const R=i(p),_=o(p);return l(p),n(null,g,_,R,M,F,dn(_),$),R},B=(p,g="[",M="]")=>{let F=0;for(;p;)if(p=i(p),p&&xt(p)&&(p.data===g&&F++,p.data===M)){if(F===0)return i(p);F--}return p},N=(p,g,M)=>{const F=g.parentNode;F&&F.replaceChild(p,g);let $=M;for(;$;)$.vnode.el===g&&($.vnode.el=$.subTree.el=p),$=$.parent},j=p=>p.nodeType===1&&p.tagName==="TEMPLATE";return[a,d]}const yr="data-allow-mismatch",Gl={0:"text",1:"children",2:"class",3:"style",4:"attribute"};function hn(e,t){if(t===0||t===1)for(;e&&!e.hasAttribute(yr);)e=e.parentElement;const n=e&&e.getAttribute(yr);if(n==null)return!1;if(n==="")return!0;{const s=n.split(",");return t===0&&s.includes("children")?!0:n.split(",").includes(Gl[t])}}Hn().requestIdleCallback;Hn().cancelIdleCallback;function Yl(e,t){if(xt(e)&&e.data==="["){let n=1,s=e.nextSibling;for(;s;){if(s.nodeType===1){if(t(s)===!1)break}else if(xt(s))if(s.data==="]"){if(--n===0)break}else s.data==="["&&n++;s=s.nextSibling}}else t(e)}const pt=e=>!!e.type.__asyncLoader;/*! #__NO_SIDE_EFFECTS__ */function wf(e){q(e)&&(e={loader:e});const{loader:t,loadingComponent:n,errorComponent:s,delay:r=200,hydrate:i,timeout:o,suspensible:l=!0,onError:c}=e;let f=null,a,d=0;const y=()=>(d++,f=null,v()),v=()=>{let S;return f||(S=f=t().catch(b=>{if(b=b instanceof Error?b:new Error(String(b)),c)return new Promise((B,N)=>{c(b,()=>B(y()),()=>N(b),d+1)});throw b}).then(b=>S!==f&&f?f:(b&&(b.__esModule||b[Symbol.toStringTag]==="Module")&&(b=b.default),a=b,b)))};return Ys({name:"AsyncComponentWrapper",__asyncLoader:v,__asyncHydrate(S,b,B){const N=i?()=>{const j=i(B,p=>Yl(S,p));j&&(b.bum||(b.bum=[])).push(j)}:B;a?N():v().then(()=>!b.isUnmounted&&N())},get __asyncResolved(){return a},setup(){const S=ue;if(Xs(S),a)return()=>ns(a,S);const b=p=>{f=null,tn(p,S,13,!s)};if(l&&S.suspense||Mt)return v().then(p=>()=>ns(p,S)).catch(p=>(b(p),()=>s?le(s,{error:p}):null));const B=oe(!1),N=oe(),j=oe(!!r);return r&&setTimeout(()=>{j.value=!1},r),o!=null&&setTimeout(()=>{if(!B.value&&!N.value){const p=new Error(`Async component timed out after ${o}ms.`);b(p),N.value=p}},o),v().then(()=>{B.value=!0,S.parent&&nn(S.parent.vnode)&&S.parent.update()}).catch(p=>{b(p),N.value=p}),()=>{if(B.value&&a)return ns(a,S);if(N.value&&s)return le(s,{error:N.value});if(n&&!j.value)return le(n)}}})}function ns(e,t){const{ref:n,props:s,children:r,ce:i}=t.vnode,o=le(e,s,r);return o.ref=n,o.ce=i,delete t.vnode.ce,o}const nn=e=>e.type.__isKeepAlive;function Xl(e,t){Ui(e,"a",t)}function Jl(e,t){Ui(e,"da",t)}function Ui(e,t,n=ue){const s=e.__wdc||(e.__wdc=()=>{let r=n;for(;r;){if(r.isDeactivated)return;r=r.parent}return e()});if(kn(t,s,n),n){let r=n.parent;for(;r&&r.parent;)nn(r.parent.vnode)&&zl(s,t,n,r),r=r.parent}}function zl(e,t,n,s){const r=kn(t,e,s,!0);Bn(()=>{Hs(s[t],r)},n)}function kn(e,t,n=ue,s=!1){if(n){const r=n[e]||(n[e]=[]),i=t.__weh||(t.__weh=(...o)=>{rt();const l=sn(n),c=He(t,n,e,o);return l(),it(),c});return s?r.unshift(i):r.push(i),i}}const Xe=e=>(t,n=ue)=>{(!Mt||e==="sp")&&kn(e,(...s)=>t(...s),n)},Ql=Xe("bm"),Lt=Xe("m"),Zl=Xe("bu"),ec=Xe("u"),ki=Xe("bum"),Bn=Xe("um"),tc=Xe("sp"),nc=Xe("rtg"),sc=Xe("rtc");function rc(e,t=ue){kn("ec",e,t)}const Bi="components";function Sf(e,t){return Ki(Bi,e,!0,t)||e}const Wi=Symbol.for("v-ndc");function xf(e){return re(e)?Ki(Bi,e,!1)||e:e||Wi}function Ki(e,t,n=!0,s=!1){const r=de||ue;if(r){const i=r.type;{const l=Bc(i,!1);if(l&&(l===t||l===Le(t)||l===Fn(Le(t))))return i}const o=vr(r[e]||i[e],t)||vr(r.appContext[e],t);return!o&&s?i:o}}function vr(e,t){return e&&(e[t]||e[Le(t)]||e[Fn(Le(t))])}function Ef(e,t,n,s){let r;const i=n,o=K(e);if(o||re(e)){const l=o&&ht(e);let c=!1;l&&(c=!Pe(e),e=Dn(e)),r=new Array(e.length);for(let f=0,a=e.length;ft(l,c,void 0,i));else{const l=Object.keys(e);r=new Array(l.length);for(let c=0,f=l.length;cJt(t)?!(t.type===ve||t.type===Se&&!qi(t.children)):!0)?e:null}function Cf(e,t){const n={};for(const s in e)n[/[A-Z]/.test(s)?`on:${s}`:vn(s)]=e[s];return n}const Ts=e=>e?mo(e)?Gn(e):Ts(e.parent):null,Ut=ce(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Ts(e.parent),$root:e=>Ts(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>Js(e),$forceUpdate:e=>e.f||(e.f=()=>{Gs(e.update)}),$nextTick:e=>e.n||(e.n=Un.bind(e.proxy)),$watch:e=>Cc.bind(e)}),ss=(e,t)=>e!==Z&&!e.__isScriptSetup&&z(e,t),ic={get({_:e},t){if(t==="__v_skip")return!0;const{ctx:n,setupState:s,data:r,props:i,accessCache:o,type:l,appContext:c}=e;let f;if(t[0]!=="$"){const v=o[t];if(v!==void 0)switch(v){case 1:return s[t];case 2:return r[t];case 4:return n[t];case 3:return i[t]}else{if(ss(s,t))return o[t]=1,s[t];if(r!==Z&&z(r,t))return o[t]=2,r[t];if((f=e.propsOptions[0])&&z(f,t))return o[t]=3,i[t];if(n!==Z&&z(n,t))return o[t]=4,n[t];Cs&&(o[t]=0)}}const a=Ut[t];let d,y;if(a)return t==="$attrs"&&me(e.attrs,"get",""),a(e);if((d=l.__cssModules)&&(d=d[t]))return d;if(n!==Z&&z(n,t))return o[t]=4,n[t];if(y=c.config.globalProperties,z(y,t))return y[t]},set({_:e},t,n){const{data:s,setupState:r,ctx:i}=e;return ss(r,t)?(r[t]=n,!0):s!==Z&&z(s,t)?(s[t]=n,!0):z(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(i[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:s,appContext:r,propsOptions:i}},o){let l;return!!n[o]||e!==Z&&z(e,o)||ss(t,o)||(l=i[0])&&z(l,o)||z(s,o)||z(Ut,o)||z(r.config.globalProperties,o)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:z(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function Af(){return oc().slots}function oc(){const e=qn();return e.setupContext||(e.setupContext=vo(e))}function br(e){return K(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}let Cs=!0;function lc(e){const t=Js(e),n=e.proxy,s=e.ctx;Cs=!1,t.beforeCreate&&_r(t.beforeCreate,e,"bc");const{data:r,computed:i,methods:o,watch:l,provide:c,inject:f,created:a,beforeMount:d,mounted:y,beforeUpdate:v,updated:S,activated:b,deactivated:B,beforeDestroy:N,beforeUnmount:j,destroyed:p,unmounted:g,render:M,renderTracked:F,renderTriggered:$,errorCaptured:V,serverPrefetch:R,expose:_,inheritAttrs:I,components:E,directives:W,filters:se}=t;if(f&&cc(f,s,null),o)for(const Y in o){const D=o[Y];q(D)&&(s[Y]=D.bind(n))}if(r){const Y=r.call(n,n);ne(Y)&&(e.data=jn(Y))}if(Cs=!0,i)for(const Y in i){const D=i[Y],he=q(D)?D.bind(n,n):q(D.get)?D.get.bind(n,n):ke,rn=!q(D)&&q(D.set)?D.set.bind(n):ke,ot=ie({get:he,set:rn});Object.defineProperty(s,Y,{enumerable:!0,configurable:!0,get:()=>ot.value,set:De=>ot.value=De})}if(l)for(const Y in l)Gi(l[Y],s,n,Y);if(c){const Y=q(c)?c.call(n):c;Reflect.ownKeys(Y).forEach(D=>{pc(D,Y[D])})}a&&_r(a,e,"c");function U(Y,D){K(D)?D.forEach(he=>Y(he.bind(n))):D&&Y(D.bind(n))}if(U(Ql,d),U(Lt,y),U(Zl,v),U(ec,S),U(Xl,b),U(Jl,B),U(rc,V),U(sc,F),U(nc,$),U(ki,j),U(Bn,g),U(tc,R),K(_))if(_.length){const Y=e.exposed||(e.exposed={});_.forEach(D=>{Object.defineProperty(Y,D,{get:()=>n[D],set:he=>n[D]=he})})}else e.exposed||(e.exposed={});M&&e.render===ke&&(e.render=M),I!=null&&(e.inheritAttrs=I),E&&(e.components=E),W&&(e.directives=W),R&&Xs(e)}function cc(e,t,n=ke){K(e)&&(e=As(e));for(const s in e){const r=e[s];let i;ne(r)?"default"in r?i=Ot(r.from||s,r.default,!0):i=Ot(r.from||s):i=Ot(r),fe(i)?Object.defineProperty(t,s,{enumerable:!0,configurable:!0,get:()=>i.value,set:o=>i.value=o}):t[s]=i}}function _r(e,t,n){He(K(e)?e.map(s=>s.bind(t.proxy)):e.bind(t.proxy),t,n)}function Gi(e,t,n,s){let r=s.includes(".")?lo(n,s):()=>n[s];if(re(e)){const i=t[e];q(i)&&Fe(r,i)}else if(q(e))Fe(r,e.bind(n));else if(ne(e))if(K(e))e.forEach(i=>Gi(i,t,n,s));else{const i=q(e.handler)?e.handler.bind(n):t[e.handler];q(i)&&Fe(r,i,e)}}function Js(e){const t=e.type,{mixins:n,extends:s}=t,{mixins:r,optionsCache:i,config:{optionMergeStrategies:o}}=e.appContext,l=i.get(t);let c;return l?c=l:!r.length&&!n&&!s?c=t:(c={},r.length&&r.forEach(f=>Pn(c,f,o,!0)),Pn(c,t,o)),ne(t)&&i.set(t,c),c}function Pn(e,t,n,s=!1){const{mixins:r,extends:i}=t;i&&Pn(e,i,n,!0),r&&r.forEach(o=>Pn(e,o,n,!0));for(const o in t)if(!(s&&o==="expose")){const l=ac[o]||n&&n[o];e[o]=l?l(e[o],t[o]):t[o]}return e}const ac={data:wr,props:Sr,emits:Sr,methods:$t,computed:$t,beforeCreate:be,created:be,beforeMount:be,mounted:be,beforeUpdate:be,updated:be,beforeDestroy:be,beforeUnmount:be,destroyed:be,unmounted:be,activated:be,deactivated:be,errorCaptured:be,serverPrefetch:be,components:$t,directives:$t,watch:uc,provide:wr,inject:fc};function wr(e,t){return t?e?function(){return ce(q(e)?e.call(this,this):e,q(t)?t.call(this,this):t)}:t:e}function fc(e,t){return $t(As(e),As(t))}function As(e){if(K(e)){const t={};for(let n=0;n1)return n&&q(t)?t.call(s&&s.proxy):t}}const Xi={},Ji=()=>Object.create(Xi),zi=e=>Object.getPrototypeOf(e)===Xi;function gc(e,t,n,s=!1){const r={},i=Ji();e.propsDefaults=Object.create(null),Qi(e,t,r,i);for(const o in e.propsOptions[0])o in r||(r[o]=void 0);n?e.props=s?r:wl(r):e.type.props?e.props=r:e.props=i,e.attrs=i}function mc(e,t,n,s){const{props:r,attrs:i,vnode:{patchFlag:o}}=e,l=J(r),[c]=e.propsOptions;let f=!1;if((s||o>0)&&!(o&16)){if(o&8){const a=e.vnode.dynamicProps;for(let d=0;d{c=!0;const[y,v]=Zi(d,t,!0);ce(o,y),v&&l.push(...v)};!n&&t.mixins.length&&t.mixins.forEach(a),e.extends&&a(e.extends),e.mixins&&e.mixins.forEach(a)}if(!i&&!c)return ne(e)&&s.set(e,Et),Et;if(K(i))for(let a=0;ae[0]==="_"||e==="$stable",zs=e=>K(e)?e.map(Me):[Me(e)],vc=(e,t,n)=>{if(t._n)return t;const s=$l((...r)=>zs(t(...r)),n);return s._c=!1,s},to=(e,t,n)=>{const s=e._ctx;for(const r in e){if(eo(r))continue;const i=e[r];if(q(i))t[r]=vc(r,i,s);else if(i!=null){const o=zs(i);t[r]=()=>o}}},no=(e,t)=>{const n=zs(t);e.slots.default=()=>n},so=(e,t,n)=>{for(const s in t)(n||s!=="_")&&(e[s]=t[s])},bc=(e,t,n)=>{const s=e.slots=Ji();if(e.vnode.shapeFlag&32){const r=t._;r?(so(s,t,n),n&&li(s,"_",r,!0)):to(t,s)}else t&&no(e,t)},_c=(e,t,n)=>{const{vnode:s,slots:r}=e;let i=!0,o=Z;if(s.shapeFlag&32){const l=t._;l?n&&l===1?i=!1:so(r,t,n):(i=!t.$stable,to(t,r)),o=t}else t&&(no(e,t),o={default:1});if(i)for(const l in r)!eo(l)&&o[l]==null&&delete r[l]},xe=fo;function wc(e){return ro(e)}function Sc(e){return ro(e,ql)}function ro(e,t){const n=Hn();n.__VUE__=!0;const{insert:s,remove:r,patchProp:i,createElement:o,createText:l,createComment:c,setText:f,setElementText:a,parentNode:d,nextSibling:y,setScopeId:v=ke,insertStaticContent:S}=e,b=(u,h,m,T=null,w=null,x=null,P=void 0,O=null,A=!!h.dynamicChildren)=>{if(u===h)return;u&&!ut(u,h)&&(T=on(u),De(u,w,x,!0),u=null),h.patchFlag===-2&&(A=!1,h.dynamicChildren=null);const{type:C,ref:k,shapeFlag:L}=h;switch(C){case gt:B(u,h,m,T);break;case ve:N(u,h,m,T);break;case kt:u==null&&j(h,m,T,P);break;case Se:E(u,h,m,T,w,x,P,O,A);break;default:L&1?M(u,h,m,T,w,x,P,O,A):L&6?W(u,h,m,T,w,x,P,O,A):(L&64||L&128)&&C.process(u,h,m,T,w,x,P,O,A,vt)}k!=null&&w&&Mn(k,u&&u.ref,x,h||u,!h)},B=(u,h,m,T)=>{if(u==null)s(h.el=l(h.children),m,T);else{const w=h.el=u.el;h.children!==u.children&&f(w,h.children)}},N=(u,h,m,T)=>{u==null?s(h.el=c(h.children||""),m,T):h.el=u.el},j=(u,h,m,T)=>{[u.el,u.anchor]=S(u.children,h,m,T,u.el,u.anchor)},p=({el:u,anchor:h},m,T)=>{let w;for(;u&&u!==h;)w=y(u),s(u,m,T),u=w;s(h,m,T)},g=({el:u,anchor:h})=>{let m;for(;u&&u!==h;)m=y(u),r(u),u=m;r(h)},M=(u,h,m,T,w,x,P,O,A)=>{h.type==="svg"?P="svg":h.type==="math"&&(P="mathml"),u==null?F(h,m,T,w,x,P,O,A):R(u,h,w,x,P,O,A)},F=(u,h,m,T,w,x,P,O)=>{let A,C;const{props:k,shapeFlag:L,transition:H,dirs:G}=u;if(A=u.el=o(u.type,x,k&&k.is,k),L&8?a(A,u.children):L&16&&V(u.children,A,null,T,w,rs(u,x),P,O),G&&Ue(u,null,T,"created"),$(A,u,u.scopeId,P,T),k){for(const ee in k)ee!=="value"&&!Ct(ee)&&i(A,ee,null,k[ee],x,T);"value"in k&&i(A,"value",null,k.value,x),(C=k.onVnodeBeforeMount)&&Oe(C,T,u)}G&&Ue(u,null,T,"beforeMount");const X=io(w,H);X&&H.beforeEnter(A),s(A,h,m),((C=k&&k.onVnodeMounted)||X||G)&&xe(()=>{C&&Oe(C,T,u),X&&H.enter(A),G&&Ue(u,null,T,"mounted")},w)},$=(u,h,m,T,w)=>{if(m&&v(u,m),T)for(let x=0;x{for(let C=A;C{const O=h.el=u.el;let{patchFlag:A,dynamicChildren:C,dirs:k}=h;A|=u.patchFlag&16;const L=u.props||Z,H=h.props||Z;let G;if(m&<(m,!1),(G=H.onVnodeBeforeUpdate)&&Oe(G,m,h,u),k&&Ue(h,u,m,"beforeUpdate"),m&<(m,!0),(L.innerHTML&&H.innerHTML==null||L.textContent&&H.textContent==null)&&a(O,""),C?_(u.dynamicChildren,C,O,m,T,rs(h,w),x):P||D(u,h,O,null,m,T,rs(h,w),x,!1),A>0){if(A&16)I(O,L,H,m,w);else if(A&2&&L.class!==H.class&&i(O,"class",null,H.class,w),A&4&&i(O,"style",L.style,H.style,w),A&8){const X=h.dynamicProps;for(let ee=0;ee{G&&Oe(G,m,h,u),k&&Ue(h,u,m,"updated")},T)},_=(u,h,m,T,w,x,P)=>{for(let O=0;O{if(h!==m){if(h!==Z)for(const x in h)!Ct(x)&&!(x in m)&&i(u,x,h[x],null,w,T);for(const x in m){if(Ct(x))continue;const P=m[x],O=h[x];P!==O&&x!=="value"&&i(u,x,O,P,w,T)}"value"in m&&i(u,"value",h.value,m.value,w)}},E=(u,h,m,T,w,x,P,O,A)=>{const C=h.el=u?u.el:l(""),k=h.anchor=u?u.anchor:l("");let{patchFlag:L,dynamicChildren:H,slotScopeIds:G}=h;G&&(O=O?O.concat(G):G),u==null?(s(C,m,T),s(k,m,T),V(h.children||[],m,k,w,x,P,O,A)):L>0&&L&64&&H&&u.dynamicChildren?(_(u.dynamicChildren,H,m,w,x,P,O),(h.key!=null||w&&h===w.subTree)&&Qs(u,h,!0)):D(u,h,m,k,w,x,P,O,A)},W=(u,h,m,T,w,x,P,O,A)=>{h.slotScopeIds=O,u==null?h.shapeFlag&512?w.ctx.activate(h,m,T,P,A):se(h,m,T,w,x,P,A):ae(u,h,A)},se=(u,h,m,T,w,x,P)=>{const O=u.component=jc(u,T,w);if(nn(u)&&(O.ctx.renderer=vt),Vc(O,!1,P),O.asyncDep){if(w&&w.registerDep(O,U,P),!u.el){const A=O.subTree=le(ve);N(null,A,h,m)}}else U(O,u,h,m,w,x,P)},ae=(u,h,m)=>{const T=h.component=u.component;if(Pc(u,h,m))if(T.asyncDep&&!T.asyncResolved){Y(T,h,m);return}else T.next=h,T.update();else h.el=u.el,T.vnode=h},U=(u,h,m,T,w,x,P)=>{const O=()=>{if(u.isMounted){let{next:L,bu:H,u:G,parent:X,vnode:ee}=u;{const Te=oo(u);if(Te){L&&(L.el=ee.el,Y(u,L,P)),Te.asyncDep.then(()=>{u.isUnmounted||O()});return}}let Q=L,Ee;lt(u,!1),L?(L.el=ee.el,Y(u,L,P)):L=ee,H&&bn(H),(Ee=L.props&&L.props.onVnodeBeforeUpdate)&&Oe(Ee,X,L,ee),lt(u,!0);const pe=is(u),Ie=u.subTree;u.subTree=pe,b(Ie,pe,d(Ie.el),on(Ie),u,w,x),L.el=pe.el,Q===null&&Lc(u,pe.el),G&&xe(G,w),(Ee=L.props&&L.props.onVnodeUpdated)&&xe(()=>Oe(Ee,X,L,ee),w)}else{let L;const{el:H,props:G}=h,{bm:X,m:ee,parent:Q,root:Ee,type:pe}=u,Ie=pt(h);if(lt(u,!1),X&&bn(X),!Ie&&(L=G&&G.onVnodeBeforeMount)&&Oe(L,Q,h),lt(u,!0),H&&Jn){const Te=()=>{u.subTree=is(u),Jn(H,u.subTree,u,w,null)};Ie&&pe.__asyncHydrate?pe.__asyncHydrate(H,u,Te):Te()}else{Ee.ce&&Ee.ce._injectChildStyle(pe);const Te=u.subTree=is(u);b(null,Te,m,T,u,w,x),h.el=Te.el}if(ee&&xe(ee,w),!Ie&&(L=G&&G.onVnodeMounted)){const Te=h;xe(()=>Oe(L,Q,Te),w)}(h.shapeFlag&256||Q&&pt(Q.vnode)&&Q.vnode.shapeFlag&256)&&u.a&&xe(u.a,w),u.isMounted=!0,h=m=T=null}};u.scope.on();const A=u.effect=new di(O);u.scope.off();const C=u.update=A.run.bind(A),k=u.job=A.runIfDirty.bind(A);k.i=u,k.id=u.uid,A.scheduler=()=>Gs(k),lt(u,!0),C()},Y=(u,h,m)=>{h.component=u;const T=u.vnode.props;u.vnode=h,u.next=null,mc(u,h.props,T,m),_c(u,h.children,m),rt(),dr(u),it()},D=(u,h,m,T,w,x,P,O,A=!1)=>{const C=u&&u.children,k=u?u.shapeFlag:0,L=h.children,{patchFlag:H,shapeFlag:G}=h;if(H>0){if(H&128){rn(C,L,m,T,w,x,P,O,A);return}else if(H&256){he(C,L,m,T,w,x,P,O,A);return}}G&8?(k&16&&It(C,w,x),L!==C&&a(m,L)):k&16?G&16?rn(C,L,m,T,w,x,P,O,A):It(C,w,x,!0):(k&8&&a(m,""),G&16&&V(L,m,T,w,x,P,O,A))},he=(u,h,m,T,w,x,P,O,A)=>{u=u||Et,h=h||Et;const C=u.length,k=h.length,L=Math.min(C,k);let H;for(H=0;Hk?It(u,w,x,!0,!1,L):V(h,m,T,w,x,P,O,A,L)},rn=(u,h,m,T,w,x,P,O,A)=>{let C=0;const k=h.length;let L=u.length-1,H=k-1;for(;C<=L&&C<=H;){const G=u[C],X=h[C]=A?et(h[C]):Me(h[C]);if(ut(G,X))b(G,X,m,null,w,x,P,O,A);else break;C++}for(;C<=L&&C<=H;){const G=u[L],X=h[H]=A?et(h[H]):Me(h[H]);if(ut(G,X))b(G,X,m,null,w,x,P,O,A);else break;L--,H--}if(C>L){if(C<=H){const G=H+1,X=GH)for(;C<=L;)De(u[C],w,x,!0),C++;else{const G=C,X=C,ee=new Map;for(C=X;C<=H;C++){const Ce=h[C]=A?et(h[C]):Me(h[C]);Ce.key!=null&&ee.set(Ce.key,C)}let Q,Ee=0;const pe=H-X+1;let Ie=!1,Te=0;const Nt=new Array(pe);for(C=0;C=pe){De(Ce,w,x,!0);continue}let je;if(Ce.key!=null)je=ee.get(Ce.key);else for(Q=X;Q<=H;Q++)if(Nt[Q-X]===0&&ut(Ce,h[Q])){je=Q;break}je===void 0?De(Ce,w,x,!0):(Nt[je-X]=C+1,je>=Te?Te=je:Ie=!0,b(Ce,h[je],m,null,w,x,P,O,A),Ee++)}const lr=Ie?xc(Nt):Et;for(Q=lr.length-1,C=pe-1;C>=0;C--){const Ce=X+C,je=h[Ce],cr=Ce+1{const{el:x,type:P,transition:O,children:A,shapeFlag:C}=u;if(C&6){ot(u.component.subTree,h,m,T);return}if(C&128){u.suspense.move(h,m,T);return}if(C&64){P.move(u,h,m,vt);return}if(P===Se){s(x,h,m);for(let L=0;LO.enter(x),w);else{const{leave:L,delayLeave:H,afterLeave:G}=O,X=()=>s(x,h,m),ee=()=>{L(x,()=>{X(),G&&G()})};H?H(x,X,ee):ee()}else s(x,h,m)},De=(u,h,m,T=!1,w=!1)=>{const{type:x,props:P,ref:O,children:A,dynamicChildren:C,shapeFlag:k,patchFlag:L,dirs:H,cacheIndex:G}=u;if(L===-2&&(w=!1),O!=null&&Mn(O,null,m,u,!0),G!=null&&(h.renderCache[G]=void 0),k&256){h.ctx.deactivate(u);return}const X=k&1&&H,ee=!pt(u);let Q;if(ee&&(Q=P&&P.onVnodeBeforeUnmount)&&Oe(Q,h,u),k&6)Vo(u.component,m,T);else{if(k&128){u.suspense.unmount(m,T);return}X&&Ue(u,null,h,"beforeUnmount"),k&64?u.type.remove(u,h,m,vt,T):C&&!C.hasOnce&&(x!==Se||L>0&&L&64)?It(C,h,m,!1,!0):(x===Se&&L&384||!w&&k&16)&&It(A,h,m),T&&ir(u)}(ee&&(Q=P&&P.onVnodeUnmounted)||X)&&xe(()=>{Q&&Oe(Q,h,u),X&&Ue(u,null,h,"unmounted")},m)},ir=u=>{const{type:h,el:m,anchor:T,transition:w}=u;if(h===Se){jo(m,T);return}if(h===kt){g(u);return}const x=()=>{r(m),w&&!w.persisted&&w.afterLeave&&w.afterLeave()};if(u.shapeFlag&1&&w&&!w.persisted){const{leave:P,delayLeave:O}=w,A=()=>P(m,x);O?O(u.el,x,A):A()}else x()},jo=(u,h)=>{let m;for(;u!==h;)m=y(u),r(u),u=m;r(h)},Vo=(u,h,m)=>{const{bum:T,scope:w,job:x,subTree:P,um:O,m:A,a:C}=u;Er(A),Er(C),T&&bn(T),w.stop(),x&&(x.flags|=8,De(P,u,h,m)),O&&xe(O,h),xe(()=>{u.isUnmounted=!0},h),h&&h.pendingBranch&&!h.isUnmounted&&u.asyncDep&&!u.asyncResolved&&u.suspenseId===h.pendingId&&(h.deps--,h.deps===0&&h.resolve())},It=(u,h,m,T=!1,w=!1,x=0)=>{for(let P=x;P{if(u.shapeFlag&6)return on(u.component.subTree);if(u.shapeFlag&128)return u.suspense.next();const h=y(u.anchor||u.el),m=h&&h[Ii];return m?y(m):h};let Yn=!1;const or=(u,h,m)=>{u==null?h._vnode&&De(h._vnode,null,null,!0):b(h._vnode||null,u,h,null,null,null,m),h._vnode=u,Yn||(Yn=!0,dr(),Rn(),Yn=!1)},vt={p:b,um:De,m:ot,r:ir,mt:se,mc:V,pc:D,pbc:_,n:on,o:e};let Xn,Jn;return t&&([Xn,Jn]=t(vt)),{render:or,hydrate:Xn,createApp:hc(or,Xn)}}function rs({type:e,props:t},n){return n==="svg"&&e==="foreignObject"||n==="mathml"&&e==="annotation-xml"&&t&&t.encoding&&t.encoding.includes("html")?void 0:n}function lt({effect:e,job:t},n){n?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function io(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function Qs(e,t,n=!1){const s=e.children,r=t.children;if(K(s)&&K(r))for(let i=0;i>1,e[n[l]]0&&(t[s]=n[i-1]),n[i]=s)}}for(i=n.length,o=n[i-1];i-- >0;)n[i]=o,o=t[o];return n}function oo(e){const t=e.subTree.component;if(t)return t.asyncDep&&!t.asyncResolved?t:oo(t)}function Er(e){if(e)for(let t=0;tOt(Ec);function Zs(e,t){return Wn(e,null,t)}function Rf(e,t){return Wn(e,null,{flush:"post"})}function Fe(e,t,n){return Wn(e,t,n)}function Wn(e,t,n=Z){const{immediate:s,deep:r,flush:i,once:o}=n,l=ce({},n),c=t&&s||!t&&i!=="post";let f;if(Mt){if(i==="sync"){const v=Tc();f=v.__watcherHandles||(v.__watcherHandles=[])}else if(!c){const v=()=>{};return v.stop=ke,v.resume=ke,v.pause=ke,v}}const a=ue;l.call=(v,S,b)=>He(v,a,S,b);let d=!1;i==="post"?l.scheduler=v=>{xe(v,a&&a.suspense)}:i!=="sync"&&(d=!0,l.scheduler=(v,S)=>{S?v():Gs(v)}),l.augmentJob=v=>{t&&(v.flags|=4),d&&(v.flags|=2,a&&(v.id=a.uid,v.i=a))};const y=Il(e,t,l);return Mt&&(f?f.push(y):c&&y()),y}function Cc(e,t,n){const s=this.proxy,r=re(e)?e.includes(".")?lo(s,e):()=>s[e]:e.bind(s,s);let i;q(t)?i=t:(i=t.handler,n=t);const o=sn(this),l=Wn(r,i.bind(s),n);return o(),l}function lo(e,t){const n=t.split(".");return()=>{let s=e;for(let r=0;rt==="modelValue"||t==="model-value"?e.modelModifiers:e[`${t}Modifiers`]||e[`${Le(t)}Modifiers`]||e[`${st(t)}Modifiers`];function Rc(e,t,...n){if(e.isUnmounted)return;const s=e.vnode.props||Z;let r=n;const i=t.startsWith("update:"),o=i&&Ac(s,t.slice(7));o&&(o.trim&&(r=n.map(a=>re(a)?a.trim():a)),o.number&&(r=n.map(vs)));let l,c=s[l=vn(t)]||s[l=vn(Le(t))];!c&&i&&(c=s[l=vn(st(t))]),c&&He(c,e,6,r);const f=s[l+"Once"];if(f){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,He(f,e,6,r)}}function co(e,t,n=!1){const s=t.emitsCache,r=s.get(e);if(r!==void 0)return r;const i=e.emits;let o={},l=!1;if(!q(e)){const c=f=>{const a=co(f,t,!0);a&&(l=!0,ce(o,a))};!n&&t.mixins.length&&t.mixins.forEach(c),e.extends&&c(e.extends),e.mixins&&e.mixins.forEach(c)}return!i&&!l?(ne(e)&&s.set(e,null),null):(K(i)?i.forEach(c=>o[c]=null):ce(o,i),ne(e)&&s.set(e,o),o)}function Kn(e,t){return!e||!Zt(t)?!1:(t=t.slice(2).replace(/Once$/,""),z(e,t[0].toLowerCase()+t.slice(1))||z(e,st(t))||z(e,t))}function is(e){const{type:t,vnode:n,proxy:s,withProxy:r,propsOptions:[i],slots:o,attrs:l,emit:c,render:f,renderCache:a,props:d,data:y,setupState:v,ctx:S,inheritAttrs:b}=e,B=On(e);let N,j;try{if(n.shapeFlag&4){const g=r||s,M=g;N=Me(f.call(M,g,a,d,v,y,S)),j=l}else{const g=t;N=Me(g.length>1?g(d,{attrs:l,slots:o,emit:c}):g(d,null)),j=t.props?l:Oc(l)}}catch(g){Bt.length=0,tn(g,e,1),N=le(ve)}let p=N;if(j&&b!==!1){const g=Object.keys(j),{shapeFlag:M}=p;g.length&&M&7&&(i&&g.some(Fs)&&(j=Mc(j,i)),p=nt(p,j,!1,!0))}return n.dirs&&(p=nt(p,null,!1,!0),p.dirs=p.dirs?p.dirs.concat(n.dirs):n.dirs),n.transition&&Yt(p,n.transition),N=p,On(B),N}const Oc=e=>{let t;for(const n in e)(n==="class"||n==="style"||Zt(n))&&((t||(t={}))[n]=e[n]);return t},Mc=(e,t)=>{const n={};for(const s in e)(!Fs(s)||!(s.slice(9)in t))&&(n[s]=e[s]);return n};function Pc(e,t,n){const{props:s,children:r,component:i}=e,{props:o,children:l,patchFlag:c}=t,f=i.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&c>=0){if(c&1024)return!0;if(c&16)return s?Tr(s,o,f):!!o;if(c&8){const a=t.dynamicProps;for(let d=0;de.__isSuspense;function fo(e,t){t&&t.pendingBranch?K(e)?t.effects.push(...e):t.effects.push(e):Hl(e)}const Se=Symbol.for("v-fgt"),gt=Symbol.for("v-txt"),ve=Symbol.for("v-cmt"),kt=Symbol.for("v-stc"),Bt=[];let Ae=null;function Os(e=!1){Bt.push(Ae=e?null:[])}function Ic(){Bt.pop(),Ae=Bt[Bt.length-1]||null}let Xt=1;function Cr(e){Xt+=e,e<0&&Ae&&(Ae.hasOnce=!0)}function uo(e){return e.dynamicChildren=Xt>0?Ae||Et:null,Ic(),Xt>0&&Ae&&Ae.push(e),e}function Of(e,t,n,s,r,i){return uo(po(e,t,n,s,r,i,!0))}function Ms(e,t,n,s,r){return uo(le(e,t,n,s,r,!0))}function Jt(e){return e?e.__v_isVNode===!0:!1}function ut(e,t){return e.type===t.type&&e.key===t.key}const ho=({key:e})=>e??null,Sn=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?re(e)||fe(e)||q(e)?{i:de,r:e,k:t,f:!!n}:e:null);function po(e,t=null,n=null,s=0,r=null,i=e===Se?0:1,o=!1,l=!1){const c={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&ho(t),ref:t&&Sn(t),scopeId:Li,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:i,patchFlag:s,dynamicProps:r,dynamicChildren:null,appContext:null,ctx:de};return l?(er(c,n),i&128&&e.normalize(c)):n&&(c.shapeFlag|=re(n)?8:16),Xt>0&&!o&&Ae&&(c.patchFlag>0||i&6)&&c.patchFlag!==32&&Ae.push(c),c}const le=Nc;function Nc(e,t=null,n=null,s=0,r=null,i=!1){if((!e||e===Wi)&&(e=ve),Jt(e)){const l=nt(e,t,!0);return n&&er(l,n),Xt>0&&!i&&Ae&&(l.shapeFlag&6?Ae[Ae.indexOf(e)]=l:Ae.push(l)),l.patchFlag=-2,l}if(Wc(e)&&(e=e.__vccOpts),t){t=Fc(t);let{class:l,style:c}=t;l&&!re(l)&&(t.class=js(l)),ne(c)&&(Ks(c)&&!K(c)&&(c=ce({},c)),t.style=Ds(c))}const o=re(e)?1:ao(e)?128:Ni(e)?64:ne(e)?4:q(e)?2:0;return po(e,t,n,s,r,o,i,!0)}function Fc(e){return e?Ks(e)||zi(e)?ce({},e):e:null}function nt(e,t,n=!1,s=!1){const{props:r,ref:i,patchFlag:o,children:l,transition:c}=e,f=t?Hc(r||{},t):r,a={__v_isVNode:!0,__v_skip:!0,type:e.type,props:f,key:f&&ho(f),ref:t&&t.ref?n&&i?K(i)?i.concat(Sn(t)):[i,Sn(t)]:Sn(t):i,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:l,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==Se?o===-1?16:o|16:o,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:c,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&nt(e.ssContent),ssFallback:e.ssFallback&&nt(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return c&&s&&Yt(a,c.clone(a)),a}function go(e=" ",t=0){return le(gt,null,e,t)}function Mf(e,t){const n=le(kt,null,e);return n.staticCount=t,n}function Pf(e="",t=!1){return t?(Os(),Ms(ve,null,e)):le(ve,null,e)}function Me(e){return e==null||typeof e=="boolean"?le(ve):K(e)?le(Se,null,e.slice()):Jt(e)?et(e):le(gt,null,String(e))}function et(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:nt(e)}function er(e,t){let n=0;const{shapeFlag:s}=e;if(t==null)t=null;else if(K(t))n=16;else if(typeof t=="object")if(s&65){const r=t.default;r&&(r._c&&(r._d=!1),er(e,r()),r._c&&(r._d=!0));return}else{n=32;const r=t._;!r&&!zi(t)?t._ctx=de:r===3&&de&&(de.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else q(t)?(t={default:t,_ctx:de},n=32):(t=String(t),s&64?(n=16,t=[go(t)]):n=8);e.children=t,e.shapeFlag|=n}function Hc(...e){const t={};for(let n=0;nue||de;let Ln,Ps;{const e=Hn(),t=(n,s)=>{let r;return(r=e[n])||(r=e[n]=[]),r.push(s),i=>{r.length>1?r.forEach(o=>o(i)):r[0](i)}};Ln=t("__VUE_INSTANCE_SETTERS__",n=>ue=n),Ps=t("__VUE_SSR_SETTERS__",n=>Mt=n)}const sn=e=>{const t=ue;return Ln(e),e.scope.on(),()=>{e.scope.off(),Ln(t)}},Ar=()=>{ue&&ue.scope.off(),Ln(null)};function mo(e){return e.vnode.shapeFlag&4}let Mt=!1;function Vc(e,t=!1,n=!1){t&&Ps(t);const{props:s,children:r}=e.vnode,i=mo(e);gc(e,s,i,t),bc(e,r,n);const o=i?Uc(e,t):void 0;return t&&Ps(!1),o}function Uc(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,ic);const{setup:s}=n;if(s){rt();const r=e.setupContext=s.length>1?vo(e):null,i=sn(e),o=en(s,e,0,[e.props,r]),l=ri(o);if(it(),i(),(l||e.sp)&&!pt(e)&&Xs(e),l){if(o.then(Ar,Ar),t)return o.then(c=>{Rr(e,c,t)}).catch(c=>{tn(c,e,0)});e.asyncDep=o}else Rr(e,o,t)}else yo(e,t)}function Rr(e,t,n){q(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:ne(t)&&(e.setupState=Ri(t)),yo(e,n)}let Or;function yo(e,t,n){const s=e.type;if(!e.render){if(!t&&Or&&!s.render){const r=s.template||Js(e).template;if(r){const{isCustomElement:i,compilerOptions:o}=e.appContext.config,{delimiters:l,compilerOptions:c}=s,f=ce(ce({isCustomElement:i,delimiters:l},o),c);s.render=Or(r,f)}}e.render=s.render||ke}{const r=sn(e);rt();try{lc(e)}finally{it(),r()}}}const kc={get(e,t){return me(e,"get",""),e[t]}};function vo(e){const t=n=>{e.exposed=n||{}};return{attrs:new Proxy(e.attrs,kc),slots:e.slots,emit:e.emit,expose:t}}function Gn(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(Ri(_n(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Ut)return Ut[n](e)},has(t,n){return n in t||n in Ut}})):e.proxy}function Bc(e,t=!0){return q(e)?e.displayName||e.name:e.name||t&&e.__name}function Wc(e){return q(e)&&"__vccOpts"in e}const ie=(e,t)=>Pl(e,t,Mt);function Ls(e,t,n){const s=arguments.length;return s===2?ne(t)&&!K(t)?Jt(t)?le(e,null,[t]):le(e,t):le(e,null,t):(s>3?n=Array.prototype.slice.call(arguments,2):s===3&&Jt(n)&&(n=[n]),le(e,t,n))}const Kc="3.5.12";/** +* @vue/runtime-dom v3.5.12 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let Is;const Mr=typeof window<"u"&&window.trustedTypes;if(Mr)try{Is=Mr.createPolicy("vue",{createHTML:e=>e})}catch{}const bo=Is?e=>Is.createHTML(e):e=>e,qc="http://www.w3.org/2000/svg",Gc="http://www.w3.org/1998/Math/MathML",Ke=typeof document<"u"?document:null,Pr=Ke&&Ke.createElement("template"),Yc={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,s)=>{const r=t==="svg"?Ke.createElementNS(qc,e):t==="mathml"?Ke.createElementNS(Gc,e):n?Ke.createElement(e,{is:n}):Ke.createElement(e);return e==="select"&&s&&s.multiple!=null&&r.setAttribute("multiple",s.multiple),r},createText:e=>Ke.createTextNode(e),createComment:e=>Ke.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Ke.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,s,r,i){const o=n?n.previousSibling:t.lastChild;if(r&&(r===i||r.nextSibling))for(;t.insertBefore(r.cloneNode(!0),n),!(r===i||!(r=r.nextSibling)););else{Pr.innerHTML=bo(s==="svg"?`${e}`:s==="mathml"?`${e}`:e);const l=Pr.content;if(s==="svg"||s==="mathml"){const c=l.firstChild;for(;c.firstChild;)l.appendChild(c.firstChild);l.removeChild(c)}t.insertBefore(l,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},Je="transition",Ht="animation",zt=Symbol("_vtc"),_o={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},Xc=ce({},Hi,_o),Jc=e=>(e.displayName="Transition",e.props=Xc,e),Lf=Jc((e,{slots:t})=>Ls(Bl,zc(e),t)),ct=(e,t=[])=>{K(e)?e.forEach(n=>n(...t)):e&&e(...t)},Lr=e=>e?K(e)?e.some(t=>t.length>1):e.length>1:!1;function zc(e){const t={};for(const E in e)E in _o||(t[E]=e[E]);if(e.css===!1)return t;const{name:n="v",type:s,duration:r,enterFromClass:i=`${n}-enter-from`,enterActiveClass:o=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:c=i,appearActiveClass:f=o,appearToClass:a=l,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:y=`${n}-leave-active`,leaveToClass:v=`${n}-leave-to`}=e,S=Qc(r),b=S&&S[0],B=S&&S[1],{onBeforeEnter:N,onEnter:j,onEnterCancelled:p,onLeave:g,onLeaveCancelled:M,onBeforeAppear:F=N,onAppear:$=j,onAppearCancelled:V=p}=t,R=(E,W,se)=>{at(E,W?a:l),at(E,W?f:o),se&&se()},_=(E,W)=>{E._isLeaving=!1,at(E,d),at(E,v),at(E,y),W&&W()},I=E=>(W,se)=>{const ae=E?$:j,U=()=>R(W,E,se);ct(ae,[W,U]),Ir(()=>{at(W,E?c:i),ze(W,E?a:l),Lr(ae)||Nr(W,s,b,U)})};return ce(t,{onBeforeEnter(E){ct(N,[E]),ze(E,i),ze(E,o)},onBeforeAppear(E){ct(F,[E]),ze(E,c),ze(E,f)},onEnter:I(!1),onAppear:I(!0),onLeave(E,W){E._isLeaving=!0;const se=()=>_(E,W);ze(E,d),ze(E,y),ta(),Ir(()=>{E._isLeaving&&(at(E,d),ze(E,v),Lr(g)||Nr(E,s,B,se))}),ct(g,[E,se])},onEnterCancelled(E){R(E,!1),ct(p,[E])},onAppearCancelled(E){R(E,!0),ct(V,[E])},onLeaveCancelled(E){_(E),ct(M,[E])}})}function Qc(e){if(e==null)return null;if(ne(e))return[os(e.enter),os(e.leave)];{const t=os(e);return[t,t]}}function os(e){return qo(e)}function ze(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[zt]||(e[zt]=new Set)).add(t)}function at(e,t){t.split(/\s+/).forEach(s=>s&&e.classList.remove(s));const n=e[zt];n&&(n.delete(t),n.size||(e[zt]=void 0))}function Ir(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Zc=0;function Nr(e,t,n,s){const r=e._endId=++Zc,i=()=>{r===e._endId&&s()};if(n!=null)return setTimeout(i,n);const{type:o,timeout:l,propCount:c}=ea(e,t);if(!o)return s();const f=o+"end";let a=0;const d=()=>{e.removeEventListener(f,y),i()},y=v=>{v.target===e&&++a>=c&&d()};setTimeout(()=>{a(n[S]||"").split(", "),r=s(`${Je}Delay`),i=s(`${Je}Duration`),o=Fr(r,i),l=s(`${Ht}Delay`),c=s(`${Ht}Duration`),f=Fr(l,c);let a=null,d=0,y=0;t===Je?o>0&&(a=Je,d=o,y=i.length):t===Ht?f>0&&(a=Ht,d=f,y=c.length):(d=Math.max(o,f),a=d>0?o>f?Je:Ht:null,y=a?a===Je?i.length:c.length:0);const v=a===Je&&/\b(transform|all)(,|$)/.test(s(`${Je}Property`).toString());return{type:a,timeout:d,propCount:y,hasTransform:v}}function Fr(e,t){for(;e.lengthHr(n)+Hr(e[s])))}function Hr(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function ta(){return document.body.offsetHeight}function na(e,t,n){const s=e[zt];s&&(t=(t?[t,...s]:[...s]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const $r=Symbol("_vod"),sa=Symbol("_vsh"),ra=Symbol(""),ia=/(^|;)\s*display\s*:/;function oa(e,t,n){const s=e.style,r=re(n);let i=!1;if(n&&!r){if(t)if(re(t))for(const o of t.split(";")){const l=o.slice(0,o.indexOf(":")).trim();n[l]==null&&xn(s,l,"")}else for(const o in t)n[o]==null&&xn(s,o,"");for(const o in n)o==="display"&&(i=!0),xn(s,o,n[o])}else if(r){if(t!==n){const o=s[ra];o&&(n+=";"+o),s.cssText=n,i=ia.test(n)}}else t&&e.removeAttribute("style");$r in e&&(e[$r]=i?s.display:"",e[sa]&&(s.display="none"))}const Dr=/\s*!important$/;function xn(e,t,n){if(K(n))n.forEach(s=>xn(e,t,s));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const s=la(e,t);Dr.test(n)?e.setProperty(st(s),n.replace(Dr,""),"important"):e[s]=n}}const jr=["Webkit","Moz","ms"],ls={};function la(e,t){const n=ls[t];if(n)return n;let s=Le(t);if(s!=="filter"&&s in e)return ls[t]=s;s=Fn(s);for(let r=0;rcs||(ua.then(()=>cs=0),cs=Date.now());function ha(e,t){const n=s=>{if(!s._vts)s._vts=Date.now();else if(s._vts<=n.attached)return;He(pa(s,n.value),t,5,[s])};return n.value=e,n.attached=da(),n}function pa(e,t){if(K(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(s=>r=>!r._stopped&&s&&s(r))}else return t}const Kr=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,ga=(e,t,n,s,r,i)=>{const o=r==="svg";t==="class"?na(e,s,o):t==="style"?oa(e,n,s):Zt(t)?Fs(t)||aa(e,t,n,s,i):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):ma(e,t,s,o))?(kr(e,t,s),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&Ur(e,t,s,o,i,t!=="value")):e._isVueCE&&(/[A-Z]/.test(t)||!re(s))?kr(e,Le(t),s,i,t):(t==="true-value"?e._trueValue=s:t==="false-value"&&(e._falseValue=s),Ur(e,t,s,o))};function ma(e,t,n,s){if(s)return!!(t==="innerHTML"||t==="textContent"||t in e&&Kr(t)&&q(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const r=e.tagName;if(r==="IMG"||r==="VIDEO"||r==="CANVAS"||r==="SOURCE")return!1}return Kr(t)&&re(n)?!1:t in e}const qr=e=>{const t=e.props["onUpdate:modelValue"]||!1;return K(t)?n=>bn(t,n):t};function ya(e){e.target.composing=!0}function Gr(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const as=Symbol("_assign"),If={created(e,{modifiers:{lazy:t,trim:n,number:s}},r){e[as]=qr(r);const i=s||r.props&&r.props.type==="number";St(e,t?"change":"input",o=>{if(o.target.composing)return;let l=e.value;n&&(l=l.trim()),i&&(l=vs(l)),e[as](l)}),n&&St(e,"change",()=>{e.value=e.value.trim()}),t||(St(e,"compositionstart",ya),St(e,"compositionend",Gr),St(e,"change",Gr))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:s,trim:r,number:i}},o){if(e[as]=qr(o),e.composing)return;const l=(i||e.type==="number")&&!/^0\d/.test(e.value)?vs(e.value):e.value,c=t??"";l!==c&&(document.activeElement===e&&e.type!=="range"&&(s&&t===n||r&&e.value.trim()===c)||(e.value=c))}},va=["ctrl","shift","alt","meta"],ba={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>va.some(n=>e[`${n}Key`]&&!t.includes(n))},Nf=(e,t)=>{const n=e._withMods||(e._withMods={}),s=t.join(".");return n[s]||(n[s]=(r,...i)=>{for(let o=0;o{const n=e._withKeys||(e._withKeys={}),s=t.join(".");return n[s]||(n[s]=r=>{if(!("key"in r))return;const i=st(r.key);if(t.some(o=>o===i||_a[o]===i))return e(r)})},wo=ce({patchProp:ga},Yc);let Wt,Yr=!1;function wa(){return Wt||(Wt=wc(wo))}function Sa(){return Wt=Yr?Wt:Sc(wo),Yr=!0,Wt}const Hf=(...e)=>{const t=wa().createApp(...e),{mount:n}=t;return t.mount=s=>{const r=xo(s);if(!r)return;const i=t._component;!q(i)&&!i.render&&!i.template&&(i.template=r.innerHTML),r.nodeType===1&&(r.textContent="");const o=n(r,!1,So(r));return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),o},t},$f=(...e)=>{const t=Sa().createApp(...e),{mount:n}=t;return t.mount=s=>{const r=xo(s);if(r)return n(r,!0,So(r))},t};function So(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function xo(e){return re(e)?document.querySelector(e):e}const Df=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},xa=window.__VP_SITE_DATA__;function tr(e){return ui()?(tl(e),!0):!1}function Be(e){return typeof e=="function"?e():Ai(e)}const Eo=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const jf=e=>e!=null,Ea=Object.prototype.toString,Ta=e=>Ea.call(e)==="[object Object]",Qt=()=>{},Xr=Ca();function Ca(){var e,t;return Eo&&((e=window==null?void 0:window.navigator)==null?void 0:e.userAgent)&&(/iP(?:ad|hone|od)/.test(window.navigator.userAgent)||((t=window==null?void 0:window.navigator)==null?void 0:t.maxTouchPoints)>2&&/iPad|Macintosh/.test(window==null?void 0:window.navigator.userAgent))}function Aa(e,t){function n(...s){return new Promise((r,i)=>{Promise.resolve(e(()=>t.apply(this,s),{fn:t,thisArg:this,args:s})).then(r).catch(i)})}return n}const To=e=>e();function Ra(e,t={}){let n,s,r=Qt;const i=l=>{clearTimeout(l),r(),r=Qt};return l=>{const c=Be(e),f=Be(t.maxWait);return n&&i(n),c<=0||f!==void 0&&f<=0?(s&&(i(s),s=null),Promise.resolve(l())):new Promise((a,d)=>{r=t.rejectOnCancel?d:a,f&&!s&&(s=setTimeout(()=>{n&&i(n),s=null,a(l())},f)),n=setTimeout(()=>{s&&i(s),s=null,a(l())},c)})}}function Oa(e=To){const t=oe(!0);function n(){t.value=!1}function s(){t.value=!0}const r=(...i)=>{t.value&&e(...i)};return{isActive:Vn(t),pause:n,resume:s,eventFilter:r}}function Ma(e){return qn()}function Co(...e){if(e.length!==1)return Rl(...e);const t=e[0];return typeof t=="function"?Vn(Tl(()=>({get:t,set:Qt}))):oe(t)}function Ao(e,t,n={}){const{eventFilter:s=To,...r}=n;return Fe(e,Aa(s,t),r)}function Pa(e,t,n={}){const{eventFilter:s,...r}=n,{eventFilter:i,pause:o,resume:l,isActive:c}=Oa(s);return{stop:Ao(e,t,{...r,eventFilter:i}),pause:o,resume:l,isActive:c}}function nr(e,t=!0,n){Ma()?Lt(e,n):t?e():Un(e)}function Vf(e,t,n={}){const{debounce:s=0,maxWait:r=void 0,...i}=n;return Ao(e,t,{...i,eventFilter:Ra(s,{maxWait:r})})}function Uf(e,t,n){let s;fe(n)?s={evaluating:n}:s={};const{lazy:r=!1,evaluating:i=void 0,shallow:o=!0,onError:l=Qt}=s,c=oe(!r),f=o?qs(t):oe(t);let a=0;return Zs(async d=>{if(!c.value)return;a++;const y=a;let v=!1;i&&Promise.resolve().then(()=>{i.value=!0});try{const S=await e(b=>{d(()=>{i&&(i.value=!1),v||b()})});y===a&&(f.value=S)}catch(S){l(S)}finally{i&&y===a&&(i.value=!1),v=!0}}),r?ie(()=>(c.value=!0,f.value)):f}const $e=Eo?window:void 0;function Ro(e){var t;const n=Be(e);return(t=n==null?void 0:n.$el)!=null?t:n}function Pt(...e){let t,n,s,r;if(typeof e[0]=="string"||Array.isArray(e[0])?([n,s,r]=e,t=$e):[t,n,s,r]=e,!t)return Qt;Array.isArray(n)||(n=[n]),Array.isArray(s)||(s=[s]);const i=[],o=()=>{i.forEach(a=>a()),i.length=0},l=(a,d,y,v)=>(a.addEventListener(d,y,v),()=>a.removeEventListener(d,y,v)),c=Fe(()=>[Ro(t),Be(r)],([a,d])=>{if(o(),!a)return;const y=Ta(d)?{...d}:d;i.push(...n.flatMap(v=>s.map(S=>l(a,v,S,y))))},{immediate:!0,flush:"post"}),f=()=>{c(),o()};return tr(f),f}function La(e){return typeof e=="function"?e:typeof e=="string"?t=>t.key===e:Array.isArray(e)?t=>e.includes(t.key):()=>!0}function kf(...e){let t,n,s={};e.length===3?(t=e[0],n=e[1],s=e[2]):e.length===2?typeof e[1]=="object"?(t=!0,n=e[0],s=e[1]):(t=e[0],n=e[1]):(t=!0,n=e[0]);const{target:r=$e,eventName:i="keydown",passive:o=!1,dedupe:l=!1}=s,c=La(t);return Pt(r,i,a=>{a.repeat&&Be(l)||c(a)&&n(a)},o)}function Ia(){const e=oe(!1),t=qn();return t&&Lt(()=>{e.value=!0},t),e}function Na(e){const t=Ia();return ie(()=>(t.value,!!e()))}function Oo(e,t={}){const{window:n=$e}=t,s=Na(()=>n&&"matchMedia"in n&&typeof n.matchMedia=="function");let r;const i=oe(!1),o=f=>{i.value=f.matches},l=()=>{r&&("removeEventListener"in r?r.removeEventListener("change",o):r.removeListener(o))},c=Zs(()=>{s.value&&(l(),r=n.matchMedia(Be(e)),"addEventListener"in r?r.addEventListener("change",o):r.addListener(o),i.value=r.matches)});return tr(()=>{c(),l(),r=void 0}),i}const pn=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},gn="__vueuse_ssr_handlers__",Fa=Ha();function Ha(){return gn in pn||(pn[gn]=pn[gn]||{}),pn[gn]}function Mo(e,t){return Fa[e]||t}function sr(e){return Oo("(prefers-color-scheme: dark)",e)}function $a(e){return e==null?"any":e instanceof Set?"set":e instanceof Map?"map":e instanceof Date?"date":typeof e=="boolean"?"boolean":typeof e=="string"?"string":typeof e=="object"?"object":Number.isNaN(e)?"any":"number"}const Da={boolean:{read:e=>e==="true",write:e=>String(e)},object:{read:e=>JSON.parse(e),write:e=>JSON.stringify(e)},number:{read:e=>Number.parseFloat(e),write:e=>String(e)},any:{read:e=>e,write:e=>String(e)},string:{read:e=>e,write:e=>String(e)},map:{read:e=>new Map(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e.entries()))},set:{read:e=>new Set(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e))},date:{read:e=>new Date(e),write:e=>e.toISOString()}},Jr="vueuse-storage";function rr(e,t,n,s={}){var r;const{flush:i="pre",deep:o=!0,listenToStorageChanges:l=!0,writeDefaults:c=!0,mergeDefaults:f=!1,shallow:a,window:d=$e,eventFilter:y,onError:v=_=>{console.error(_)},initOnMounted:S}=s,b=(a?qs:oe)(typeof t=="function"?t():t);if(!n)try{n=Mo("getDefaultStorage",()=>{var _;return(_=$e)==null?void 0:_.localStorage})()}catch(_){v(_)}if(!n)return b;const B=Be(t),N=$a(B),j=(r=s.serializer)!=null?r:Da[N],{pause:p,resume:g}=Pa(b,()=>F(b.value),{flush:i,deep:o,eventFilter:y});d&&l&&nr(()=>{n instanceof Storage?Pt(d,"storage",V):Pt(d,Jr,R),S&&V()}),S||V();function M(_,I){if(d){const E={key:e,oldValue:_,newValue:I,storageArea:n};d.dispatchEvent(n instanceof Storage?new StorageEvent("storage",E):new CustomEvent(Jr,{detail:E}))}}function F(_){try{const I=n.getItem(e);if(_==null)M(I,null),n.removeItem(e);else{const E=j.write(_);I!==E&&(n.setItem(e,E),M(I,E))}}catch(I){v(I)}}function $(_){const I=_?_.newValue:n.getItem(e);if(I==null)return c&&B!=null&&n.setItem(e,j.write(B)),B;if(!_&&f){const E=j.read(I);return typeof f=="function"?f(E,B):N==="object"&&!Array.isArray(E)?{...B,...E}:E}else return typeof I!="string"?I:j.read(I)}function V(_){if(!(_&&_.storageArea!==n)){if(_&&_.key==null){b.value=B;return}if(!(_&&_.key!==e)){p();try{(_==null?void 0:_.newValue)!==j.write(b.value)&&(b.value=$(_))}catch(I){v(I)}finally{_?Un(g):g()}}}}function R(_){V(_.detail)}return b}const ja="*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}";function Va(e={}){const{selector:t="html",attribute:n="class",initialValue:s="auto",window:r=$e,storage:i,storageKey:o="vueuse-color-scheme",listenToStorageChanges:l=!0,storageRef:c,emitAuto:f,disableTransition:a=!0}=e,d={auto:"",light:"light",dark:"dark",...e.modes||{}},y=sr({window:r}),v=ie(()=>y.value?"dark":"light"),S=c||(o==null?Co(s):rr(o,s,i,{window:r,listenToStorageChanges:l})),b=ie(()=>S.value==="auto"?v.value:S.value),B=Mo("updateHTMLAttrs",(g,M,F)=>{const $=typeof g=="string"?r==null?void 0:r.document.querySelector(g):Ro(g);if(!$)return;const V=new Set,R=new Set;let _=null;if(M==="class"){const E=F.split(/\s/g);Object.values(d).flatMap(W=>(W||"").split(/\s/g)).filter(Boolean).forEach(W=>{E.includes(W)?V.add(W):R.add(W)})}else _={key:M,value:F};if(V.size===0&&R.size===0&&_===null)return;let I;a&&(I=r.document.createElement("style"),I.appendChild(document.createTextNode(ja)),r.document.head.appendChild(I));for(const E of V)$.classList.add(E);for(const E of R)$.classList.remove(E);_&&$.setAttribute(_.key,_.value),a&&(r.getComputedStyle(I).opacity,document.head.removeChild(I))});function N(g){var M;B(t,n,(M=d[g])!=null?M:g)}function j(g){e.onChanged?e.onChanged(g,N):N(g)}Fe(b,j,{flush:"post",immediate:!0}),nr(()=>j(b.value));const p=ie({get(){return f?S.value:b.value},set(g){S.value=g}});try{return Object.assign(p,{store:S,system:v,state:b})}catch{return p}}function Ua(e={}){const{valueDark:t="dark",valueLight:n="",window:s=$e}=e,r=Va({...e,onChanged:(l,c)=>{var f;e.onChanged?(f=e.onChanged)==null||f.call(e,l==="dark",c,l):c(l)},modes:{dark:t,light:n}}),i=ie(()=>r.system?r.system.value:sr({window:s}).value?"dark":"light");return ie({get(){return r.value==="dark"},set(l){const c=l?"dark":"light";i.value===c?r.value="auto":r.value=c}})}function fs(e){return typeof Window<"u"&&e instanceof Window?e.document.documentElement:typeof Document<"u"&&e instanceof Document?e.documentElement:e}function Bf(e,t,n={}){const{window:s=$e}=n;return rr(e,t,s==null?void 0:s.localStorage,n)}function Po(e){const t=window.getComputedStyle(e);if(t.overflowX==="scroll"||t.overflowY==="scroll"||t.overflowX==="auto"&&e.clientWidth1?!0:(t.preventDefault&&t.preventDefault(),!1)}const us=new WeakMap;function Wf(e,t=!1){const n=oe(t);let s=null,r="";Fe(Co(e),l=>{const c=fs(Be(l));if(c){const f=c;if(us.get(f)||us.set(f,f.style.overflow),f.style.overflow!=="hidden"&&(r=f.style.overflow),f.style.overflow==="hidden")return n.value=!0;if(n.value)return f.style.overflow="hidden"}},{immediate:!0});const i=()=>{const l=fs(Be(e));!l||n.value||(Xr&&(s=Pt(l,"touchmove",c=>{ka(c)},{passive:!1})),l.style.overflow="hidden",n.value=!0)},o=()=>{const l=fs(Be(e));!l||!n.value||(Xr&&(s==null||s()),l.style.overflow=r,us.delete(l),n.value=!1)};return tr(o),ie({get(){return n.value},set(l){l?i():o()}})}function Kf(e,t,n={}){const{window:s=$e}=n;return rr(e,t,s==null?void 0:s.sessionStorage,n)}function qf(e={}){const{window:t=$e,behavior:n="auto"}=e;if(!t)return{x:oe(0),y:oe(0)};const s=oe(t.scrollX),r=oe(t.scrollY),i=ie({get(){return s.value},set(l){scrollTo({left:l,behavior:n})}}),o=ie({get(){return r.value},set(l){scrollTo({top:l,behavior:n})}});return Pt(t,"scroll",()=>{s.value=t.scrollX,r.value=t.scrollY},{capture:!1,passive:!0}),{x:i,y:o}}function Gf(e={}){const{window:t=$e,initialWidth:n=Number.POSITIVE_INFINITY,initialHeight:s=Number.POSITIVE_INFINITY,listenOrientation:r=!0,includeScrollbar:i=!0,type:o="inner"}=e,l=oe(n),c=oe(s),f=()=>{t&&(o==="outer"?(l.value=t.outerWidth,c.value=t.outerHeight):i?(l.value=t.innerWidth,c.value=t.innerHeight):(l.value=t.document.documentElement.clientWidth,c.value=t.document.documentElement.clientHeight))};if(f(),nr(f),Pt("resize",f,{passive:!0}),r){const a=Oo("(orientation: portrait)");Fe(a,()=>f())}return{width:l,height:c}}const ds={BASE_URL:"/previews/PR1023/",DEV:!1,MODE:"production",PROD:!0,SSR:!1};var hs={};const Lo=/^(?:[a-z]+:|\/\/)/i,Ba="vitepress-theme-appearance",Wa=/#.*$/,Ka=/[?#].*$/,qa=/(?:(^|\/)index)?\.(?:md|html)$/,ge=typeof document<"u",Io={relativePath:"404.md",filePath:"",title:"404",description:"Not Found",headers:[],frontmatter:{sidebar:!1,layout:"page"},lastUpdated:0,isNotFound:!0};function Ga(e,t,n=!1){if(t===void 0)return!1;if(e=zr(`/${e}`),n)return new RegExp(t).test(e);if(zr(t)!==e)return!1;const s=t.match(Wa);return s?(ge?location.hash:"")===s[0]:!0}function zr(e){return decodeURI(e).replace(Ka,"").replace(qa,"$1")}function Ya(e){return Lo.test(e)}function Xa(e,t){return Object.keys((e==null?void 0:e.locales)||{}).find(n=>n!=="root"&&!Ya(n)&&Ga(t,`/${n}/`,!0))||"root"}function Ja(e,t){var s,r,i,o,l,c,f;const n=Xa(e,t);return Object.assign({},e,{localeIndex:n,lang:((s=e.locales[n])==null?void 0:s.lang)??e.lang,dir:((r=e.locales[n])==null?void 0:r.dir)??e.dir,title:((i=e.locales[n])==null?void 0:i.title)??e.title,titleTemplate:((o=e.locales[n])==null?void 0:o.titleTemplate)??e.titleTemplate,description:((l=e.locales[n])==null?void 0:l.description)??e.description,head:Fo(e.head,((c=e.locales[n])==null?void 0:c.head)??[]),themeConfig:{...e.themeConfig,...(f=e.locales[n])==null?void 0:f.themeConfig}})}function No(e,t){const n=t.title||e.title,s=t.titleTemplate??e.titleTemplate;if(typeof s=="string"&&s.includes(":title"))return s.replace(/:title/g,n);const r=za(e.title,s);return n===r.slice(3)?n:`${n}${r}`}function za(e,t){return t===!1?"":t===!0||t===void 0?` | ${e}`:e===t?"":` | ${t}`}function Qa(e,t){const[n,s]=t;if(n!=="meta")return!1;const r=Object.entries(s)[0];return r==null?!1:e.some(([i,o])=>i===n&&o[r[0]]===r[1])}function Fo(e,t){return[...e.filter(n=>!Qa(t,n)),...t]}const Za=/[\u0000-\u001F"#$&*+,:;<=>?[\]^`{|}\u007F]/g,ef=/^[a-z]:/i;function Qr(e){const t=ef.exec(e),n=t?t[0]:"";return n+e.slice(n.length).replace(Za,"_").replace(/(^|\/)_+(?=[^/]*$)/,"$1")}const ps=new Set;function tf(e){if(ps.size===0){const n=typeof process=="object"&&(hs==null?void 0:hs.VITE_EXTRA_EXTENSIONS)||(ds==null?void 0:ds.VITE_EXTRA_EXTENSIONS)||"";("3g2,3gp,aac,ai,apng,au,avif,bin,bmp,cer,class,conf,crl,css,csv,dll,doc,eps,epub,exe,gif,gz,ics,ief,jar,jpe,jpeg,jpg,js,json,jsonld,m4a,man,mid,midi,mjs,mov,mp2,mp3,mp4,mpe,mpeg,mpg,mpp,oga,ogg,ogv,ogx,opus,otf,p10,p7c,p7m,p7s,pdf,png,ps,qt,roff,rtf,rtx,ser,svg,t,tif,tiff,tr,ts,tsv,ttf,txt,vtt,wav,weba,webm,webp,woff,woff2,xhtml,xml,yaml,yml,zip"+(n&&typeof n=="string"?","+n:"")).split(",").forEach(s=>ps.add(s))}const t=e.split(".").pop();return t==null||!ps.has(t.toLowerCase())}function Yf(e){return e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&").replace(/-/g,"\\x2d")}const nf=Symbol(),mt=qs(xa);function Xf(e){const t=ie(()=>Ja(mt.value,e.data.relativePath)),n=t.value.appearance,s=n==="force-dark"?oe(!0):n==="force-auto"?sr():n?Ua({storageKey:Ba,initialValue:()=>n==="dark"?"dark":"auto",...typeof n=="object"?n:{}}):oe(!1),r=oe(ge?location.hash:"");return ge&&window.addEventListener("hashchange",()=>{r.value=location.hash}),Fe(()=>e.data,()=>{r.value=ge?location.hash:""}),{site:t,theme:ie(()=>t.value.themeConfig),page:ie(()=>e.data),frontmatter:ie(()=>e.data.frontmatter),params:ie(()=>e.data.params),lang:ie(()=>t.value.lang),dir:ie(()=>e.data.frontmatter.dir||t.value.dir),localeIndex:ie(()=>t.value.localeIndex||"root"),title:ie(()=>No(t.value,e.data)),description:ie(()=>e.data.description||t.value.description),isDark:s,hash:ie(()=>r.value)}}function sf(){const e=Ot(nf);if(!e)throw new Error("vitepress data not properly injected in app");return e}function rf(e,t){return`${e}${t}`.replace(/\/+/g,"/")}function Zr(e){return Lo.test(e)||!e.startsWith("/")?e:rf(mt.value.base,e)}function of(e){let t=e.replace(/\.html$/,"");if(t=decodeURIComponent(t),t=t.replace(/\/$/,"/index"),ge){const n="/previews/PR1023/";t=Qr(t.slice(n.length).replace(/\//g,"_")||"index")+".md";let s=__VP_HASH_MAP__[t.toLowerCase()];if(s||(t=t.endsWith("_index.md")?t.slice(0,-9)+".md":t.slice(0,-3)+"_index.md",s=__VP_HASH_MAP__[t.toLowerCase()]),!s)return null;t=`${n}assets/${t}.${s}.js`}else t=`./${Qr(t.slice(1).replace(/\//g,"_"))}.md.js`;return t}let En=[];function Jf(e){En.push(e),Bn(()=>{En=En.filter(t=>t!==e)})}function lf(){let e=mt.value.scrollOffset,t=0,n=24;if(typeof e=="object"&&"padding"in e&&(n=e.padding,e=e.selector),typeof e=="number")t=e;else if(typeof e=="string")t=ei(e,n);else if(Array.isArray(e))for(const s of e){const r=ei(s,n);if(r){t=r;break}}return t}function ei(e,t){const n=document.querySelector(e);if(!n)return 0;const s=n.getBoundingClientRect().bottom;return s<0?0:s+t}const cf=Symbol(),Ho="http://a.com",af=()=>({path:"/",component:null,data:Io});function zf(e,t){const n=jn(af()),s={route:n,go:r};async function r(l=ge?location.href:"/"){var c,f;l=gs(l),await((c=s.onBeforeRouteChange)==null?void 0:c.call(s,l))!==!1&&(ge&&l!==gs(location.href)&&(history.replaceState({scrollPosition:window.scrollY},""),history.pushState({},"",l)),await o(l),await((f=s.onAfterRouteChanged)==null?void 0:f.call(s,l)))}let i=null;async function o(l,c=0,f=!1){var y,v;if(await((y=s.onBeforePageLoad)==null?void 0:y.call(s,l))===!1)return;const a=new URL(l,Ho),d=i=a.pathname;try{let S=await e(d);if(!S)throw new Error(`Page not found: ${d}`);if(i===d){i=null;const{default:b,__pageData:B}=S;if(!b)throw new Error(`Invalid route component: ${b}`);await((v=s.onAfterPageLoad)==null?void 0:v.call(s,l)),n.path=ge?d:Zr(d),n.component=_n(b),n.data=_n(B),ge&&Un(()=>{let N=mt.value.base+B.relativePath.replace(/(?:(^|\/)index)?\.md$/,"$1");if(!mt.value.cleanUrls&&!N.endsWith("/")&&(N+=".html"),N!==a.pathname&&(a.pathname=N,l=N+a.search+a.hash,history.replaceState({},"",l)),a.hash&&!c){let j=null;try{j=document.getElementById(decodeURIComponent(a.hash).slice(1))}catch(p){console.warn(p)}if(j){ti(j,a.hash);return}}window.scrollTo(0,c)})}}catch(S){if(!/fetch|Page not found/.test(S.message)&&!/^\/404(\.html|\/)?$/.test(l)&&console.error(S),!f)try{const b=await fetch(mt.value.base+"hashmap.json");window.__VP_HASH_MAP__=await b.json(),await o(l,c,!0);return}catch{}if(i===d){i=null,n.path=ge?d:Zr(d),n.component=t?_n(t):null;const b=ge?d.replace(/(^|\/)$/,"$1index").replace(/(\.html)?$/,".md").replace(/^\//,""):"404.md";n.data={...Io,relativePath:b}}}}return ge&&(history.state===null&&history.replaceState({},""),window.addEventListener("click",l=>{if(l.defaultPrevented||!(l.target instanceof Element)||l.target.closest("button")||l.button!==0||l.ctrlKey||l.shiftKey||l.altKey||l.metaKey)return;const c=l.target.closest("a");if(!c||c.closest(".vp-raw")||c.hasAttribute("download")||c.hasAttribute("target"))return;const f=c.getAttribute("href")??(c instanceof SVGAElement?c.getAttribute("xlink:href"):null);if(f==null)return;const{href:a,origin:d,pathname:y,hash:v,search:S}=new URL(f,c.baseURI),b=new URL(location.href);d===b.origin&&tf(y)&&(l.preventDefault(),y===b.pathname&&S===b.search?(v!==b.hash&&(history.pushState({},"",a),window.dispatchEvent(new HashChangeEvent("hashchange",{oldURL:b.href,newURL:a}))),v?ti(c,v,c.classList.contains("header-anchor")):window.scrollTo(0,0)):r(a))},{capture:!0}),window.addEventListener("popstate",async l=>{var c;l.state!==null&&(await o(gs(location.href),l.state&&l.state.scrollPosition||0),(c=s.onAfterRouteChanged)==null||c.call(s,location.href))}),window.addEventListener("hashchange",l=>{l.preventDefault()})),s}function ff(){const e=Ot(cf);if(!e)throw new Error("useRouter() is called without provider.");return e}function $o(){return ff().route}function ti(e,t,n=!1){let s=null;try{s=e.classList.contains("header-anchor")?e:document.getElementById(decodeURIComponent(t).slice(1))}catch(r){console.warn(r)}if(s){let r=function(){!n||Math.abs(o-window.scrollY)>window.innerHeight?window.scrollTo(0,o):window.scrollTo({left:0,top:o,behavior:"smooth"})};const i=parseInt(window.getComputedStyle(s).paddingTop,10),o=window.scrollY+s.getBoundingClientRect().top-lf()+i;requestAnimationFrame(r)}}function gs(e){const t=new URL(e,Ho);return t.pathname=t.pathname.replace(/(^|\/)index(\.html)?$/,"$1"),mt.value.cleanUrls?t.pathname=t.pathname.replace(/\.html$/,""):!t.pathname.endsWith("/")&&!t.pathname.endsWith(".html")&&(t.pathname+=".html"),t.pathname+t.search+t.hash}const mn=()=>En.forEach(e=>e()),Qf=Ys({name:"VitePressContent",props:{as:{type:[Object,String],default:"div"}},setup(e){const t=$o(),{frontmatter:n,site:s}=sf();return Fe(n,mn,{deep:!0,flush:"post"}),()=>Ls(e.as,s.value.contentProps??{style:{position:"relative"}},[t.component?Ls(t.component,{onVnodeMounted:mn,onVnodeUpdated:mn,onVnodeUnmounted:mn}):"404 Page Not Found"])}}),uf="modulepreload",df=function(e){return"/previews/PR1023/"+e},ni={},Zf=function(t,n,s){let r=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),l=(o==null?void 0:o.nonce)||(o==null?void 0:o.getAttribute("nonce"));r=Promise.allSettled(n.map(c=>{if(c=df(c),c in ni)return;ni[c]=!0;const f=c.endsWith(".css"),a=f?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${a}`))return;const d=document.createElement("link");if(d.rel=f?"stylesheet":uf,f||(d.as="script"),d.crossOrigin="",d.href=c,l&&d.setAttribute("nonce",l),document.head.appendChild(d),f)return new Promise((y,v)=>{d.addEventListener("load",y),d.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${c}`)))})}))}function i(o){const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=o,window.dispatchEvent(l),!l.defaultPrevented)throw o}return r.then(o=>{for(const l of o||[])l.status==="rejected"&&i(l.reason);return t().catch(i)})},eu=Ys({setup(e,{slots:t}){const n=oe(!1);return Lt(()=>{n.value=!0}),()=>n.value&&t.default?t.default():null}});function tu(){ge&&window.addEventListener("click",e=>{var n;const t=e.target;if(t.matches(".vp-code-group input")){const s=(n=t.parentElement)==null?void 0:n.parentElement;if(!s)return;const r=Array.from(s.querySelectorAll("input")).indexOf(t);if(r<0)return;const i=s.querySelector(".blocks");if(!i)return;const o=Array.from(i.children).find(f=>f.classList.contains("active"));if(!o)return;const l=i.children[r];if(!l||o===l)return;o.classList.remove("active"),l.classList.add("active");const c=s==null?void 0:s.querySelector(`label[for="${t.id}"]`);c==null||c.scrollIntoView({block:"nearest"})}})}function nu(){if(ge){const e=new WeakMap;window.addEventListener("click",t=>{var s;const n=t.target;if(n.matches('div[class*="language-"] > button.copy')){const r=n.parentElement,i=(s=n.nextElementSibling)==null?void 0:s.nextElementSibling;if(!r||!i)return;const o=/language-(shellscript|shell|bash|sh|zsh)/.test(r.className),l=[".vp-copy-ignore",".diff.remove"],c=i.cloneNode(!0);c.querySelectorAll(l.join(",")).forEach(a=>a.remove());let f=c.textContent||"";o&&(f=f.replace(/^ *(\$|>) /gm,"").trim()),hf(f).then(()=>{n.classList.add("copied"),clearTimeout(e.get(n));const a=setTimeout(()=>{n.classList.remove("copied"),n.blur(),e.delete(n)},2e3);e.set(n,a)})}})}}async function hf(e){try{return navigator.clipboard.writeText(e)}catch{const t=document.createElement("textarea"),n=document.activeElement;t.value=e,t.setAttribute("readonly",""),t.style.contain="strict",t.style.position="absolute",t.style.left="-9999px",t.style.fontSize="12pt";const s=document.getSelection(),r=s?s.rangeCount>0&&s.getRangeAt(0):null;document.body.appendChild(t),t.select(),t.selectionStart=0,t.selectionEnd=e.length,document.execCommand("copy"),document.body.removeChild(t),r&&(s.removeAllRanges(),s.addRange(r)),n&&n.focus()}}function su(e,t){let n=!0,s=[];const r=i=>{if(n){n=!1,i.forEach(l=>{const c=ms(l);for(const f of document.head.children)if(f.isEqualNode(c)){s.push(f);return}});return}const o=i.map(ms);s.forEach((l,c)=>{const f=o.findIndex(a=>a==null?void 0:a.isEqualNode(l??null));f!==-1?delete o[f]:(l==null||l.remove(),delete s[c])}),o.forEach(l=>l&&document.head.appendChild(l)),s=[...s,...o].filter(Boolean)};Zs(()=>{const i=e.data,o=t.value,l=i&&i.description,c=i&&i.frontmatter.head||[],f=No(o,i);f!==document.title&&(document.title=f);const a=l||o.description;let d=document.querySelector("meta[name=description]");d?d.getAttribute("content")!==a&&d.setAttribute("content",a):ms(["meta",{name:"description",content:a}]),r(Fo(o.head,gf(c)))})}function ms([e,t,n]){const s=document.createElement(e);for(const r in t)s.setAttribute(r,t[r]);return n&&(s.innerHTML=n),e==="script"&&t.async==null&&(s.async=!1),s}function pf(e){return e[0]==="meta"&&e[1]&&e[1].name==="description"}function gf(e){return e.filter(t=>!pf(t))}const ys=new Set,Do=()=>document.createElement("link"),mf=e=>{const t=Do();t.rel="prefetch",t.href=e,document.head.appendChild(t)},yf=e=>{const t=new XMLHttpRequest;t.open("GET",e,t.withCredentials=!0),t.send()};let yn;const vf=ge&&(yn=Do())&&yn.relList&&yn.relList.supports&&yn.relList.supports("prefetch")?mf:yf;function ru(){if(!ge||!window.IntersectionObserver)return;let e;if((e=navigator.connection)&&(e.saveData||/2g/.test(e.effectiveType)))return;const t=window.requestIdleCallback||setTimeout;let n=null;const s=()=>{n&&n.disconnect(),n=new IntersectionObserver(i=>{i.forEach(o=>{if(o.isIntersecting){const l=o.target;n.unobserve(l);const{pathname:c}=l;if(!ys.has(c)){ys.add(c);const f=of(c);f&&vf(f)}}})}),t(()=>{document.querySelectorAll("#app a").forEach(i=>{const{hostname:o,pathname:l}=new URL(i.href instanceof SVGAnimatedString?i.href.animVal:i.href,i.baseURI),c=l.match(/\.\w+$/);c&&c[0]!==".html"||i.target!=="_blank"&&o===location.hostname&&(l!==location.pathname?n.observe(i):ys.add(l))})})};Lt(s);const r=$o();Fe(()=>r.path,s),Bn(()=>{n&&n.disconnect()})}export{ki as $,lf as A,Sf as B,Ef as C,qs as D,Jf as E,Se as F,le as G,xf as H,Lo as I,$o as J,Hc as K,Ot as L,Gf as M,Ds as N,kf as O,Un as P,qf as Q,ge as R,Vn as S,Lf as T,wf as U,Zf as V,Wf as W,pc as X,Ff as Y,Cf as Z,Df as _,go as a,Nf as a0,Af as a1,Mf as a2,jn as a3,Rl as a4,Ls as a5,su as a6,cf as a7,Xf as a8,nf as a9,Qf as aa,eu as ab,mt as ac,$f as ad,zf as ae,of as af,ru as ag,nu as ah,tu as ai,Be as aj,Ro as ak,jf as al,tr as am,Uf as an,Kf as ao,Bf as ap,Vf as aq,ff as ar,Pt as as,bf as at,If as au,fe as av,_f as aw,_n as ax,Hf as ay,Yf as az,Ms as b,Of as c,Ys as d,Pf as e,tf as f,Zr as g,ie as h,Ya as i,po as j,Ai as k,Ga as l,Oo as m,js as n,Os as o,oe as p,Fe as q,Tf as r,Zs as s,Zo as t,sf as u,Lt as v,$l as w,Bn as x,Rf as y,ec as z}; diff --git a/previews/PR1023/assets/chunks/theme.BkveSZIg.js b/previews/PR1023/assets/chunks/theme.BkveSZIg.js new file mode 100644 index 0000000000..ea4865d494 --- /dev/null +++ b/previews/PR1023/assets/chunks/theme.BkveSZIg.js @@ -0,0 +1,2 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/chunks/VPLocalSearchBox.CkYqsyE0.js","assets/chunks/framework.DFwXuivk.js"])))=>i.map(i=>d[i]); +import{d as b,o as a,c as l,r as u,a as F,t as w,n as I,b as $,w as f,e as m,T as pe,_ as k,u as Le,i as Ke,f as qe,g as ve,h as y,j as p,k as i,l as G,m as ie,p as T,q as D,s as Z,v as R,x as fe,y as me,z as We,A as Je,B as K,F as M,C as B,D as Te,E as x,G as g,H as O,I as we,J as ee,K as j,L as W,M as Ye,N as Ne,O as le,P as Ie,Q as Me,R as te,S as Qe,U as Xe,V as Ze,W as Ce,X as he,Y as xe,Z as et,$ as tt,a0 as nt,a1 as Ae,a2 as st,a3 as ot,a4 as at,a5 as ye}from"./framework.DFwXuivk.js";const rt=b({__name:"VPBadge",props:{text:{},type:{default:"tip"}},setup(o){return(e,t)=>(a(),l("span",{class:I(["VPBadge",e.type])},[u(e.$slots,"default",{},()=>[F(w(e.text),1)])],2))}}),it={key:0,class:"VPBackdrop"},lt=b({__name:"VPBackdrop",props:{show:{type:Boolean}},setup(o){return(e,t)=>(a(),$(pe,{name:"fade"},{default:f(()=>[e.show?(a(),l("div",it)):m("",!0)]),_:1}))}}),ct=k(lt,[["__scopeId","data-v-b06cdb19"]]),L=Le;function ut(o,e){let t,s=!1;return()=>{t&&clearTimeout(t),s?t=setTimeout(o,e):(o(),(s=!0)&&setTimeout(()=>s=!1,e))}}function ce(o){return/^\//.test(o)?o:`/${o}`}function _e(o){const{pathname:e,search:t,hash:s,protocol:n}=new URL(o,"http://a.com");if(Ke(o)||o.startsWith("#")||!n.startsWith("http")||!qe(e))return o;const{site:r}=L(),c=e.endsWith("/")||e.endsWith(".html")?o:o.replace(/(?:(^\.+)\/)?.*$/,`$1${e.replace(/(\.md)?$/,r.value.cleanUrls?"":".html")}${t}${s}`);return ve(c)}function Y({correspondingLink:o=!1}={}){const{site:e,localeIndex:t,page:s,theme:n,hash:r}=L(),c=y(()=>{var d,h;return{label:(d=e.value.locales[t.value])==null?void 0:d.label,link:((h=e.value.locales[t.value])==null?void 0:h.link)||(t.value==="root"?"/":`/${t.value}/`)}});return{localeLinks:y(()=>Object.entries(e.value.locales).flatMap(([d,h])=>c.value.label===h.label?[]:{text:h.label,link:dt(h.link||(d==="root"?"/":`/${d}/`),n.value.i18nRouting!==!1&&o,s.value.relativePath.slice(c.value.link.length-1),!e.value.cleanUrls)+r.value})),currentLang:c}}function dt(o,e,t,s){return e?o.replace(/\/$/,"")+ce(t.replace(/(^|\/)index\.md$/,"$1").replace(/\.md$/,s?".html":"")):o}const pt={class:"NotFound"},vt={class:"code"},ft={class:"title"},mt={class:"quote"},ht={class:"action"},_t=["href","aria-label"],bt=b({__name:"NotFound",setup(o){const{theme:e}=L(),{currentLang:t}=Y();return(s,n)=>{var r,c,v,d,h;return a(),l("div",pt,[p("p",vt,w(((r=i(e).notFound)==null?void 0:r.code)??"404"),1),p("h1",ft,w(((c=i(e).notFound)==null?void 0:c.title)??"PAGE NOT FOUND"),1),n[0]||(n[0]=p("div",{class:"divider"},null,-1)),p("blockquote",mt,w(((v=i(e).notFound)==null?void 0:v.quote)??"But if you don't change your direction, and if you keep looking, you may end up where you are heading."),1),p("div",ht,[p("a",{class:"link",href:i(ve)(i(t).link),"aria-label":((d=i(e).notFound)==null?void 0:d.linkLabel)??"go to home"},w(((h=i(e).notFound)==null?void 0:h.linkText)??"Take me home"),9,_t)])])}}}),kt=k(bt,[["__scopeId","data-v-951cab6c"]]);function Be(o,e){if(Array.isArray(o))return Q(o);if(o==null)return[];e=ce(e);const t=Object.keys(o).sort((n,r)=>r.split("/").length-n.split("/").length).find(n=>e.startsWith(ce(n))),s=t?o[t]:[];return Array.isArray(s)?Q(s):Q(s.items,s.base)}function gt(o){const e=[];let t=0;for(const s in o){const n=o[s];if(n.items){t=e.push(n);continue}e[t]||e.push({items:[]}),e[t].items.push(n)}return e}function $t(o){const e=[];function t(s){for(const n of s)n.text&&n.link&&e.push({text:n.text,link:n.link,docFooterText:n.docFooterText}),n.items&&t(n.items)}return t(o),e}function ue(o,e){return Array.isArray(e)?e.some(t=>ue(o,t)):G(o,e.link)?!0:e.items?ue(o,e.items):!1}function Q(o,e){return[...o].map(t=>{const s={...t},n=s.base||e;return n&&s.link&&(s.link=n+s.link),s.items&&(s.items=Q(s.items,n)),s})}function U(){const{frontmatter:o,page:e,theme:t}=L(),s=ie("(min-width: 960px)"),n=T(!1),r=y(()=>{const A=t.value.sidebar,N=e.value.relativePath;return A?Be(A,N):[]}),c=T(r.value);D(r,(A,N)=>{JSON.stringify(A)!==JSON.stringify(N)&&(c.value=r.value)});const v=y(()=>o.value.sidebar!==!1&&c.value.length>0&&o.value.layout!=="home"),d=y(()=>h?o.value.aside==null?t.value.aside==="left":o.value.aside==="left":!1),h=y(()=>o.value.layout==="home"?!1:o.value.aside!=null?!!o.value.aside:t.value.aside!==!1),P=y(()=>v.value&&s.value),_=y(()=>v.value?gt(c.value):[]);function V(){n.value=!0}function S(){n.value=!1}function C(){n.value?S():V()}return{isOpen:n,sidebar:c,sidebarGroups:_,hasSidebar:v,hasAside:h,leftAside:d,isSidebarEnabled:P,open:V,close:S,toggle:C}}function yt(o,e){let t;Z(()=>{t=o.value?document.activeElement:void 0}),R(()=>{window.addEventListener("keyup",s)}),fe(()=>{window.removeEventListener("keyup",s)});function s(n){n.key==="Escape"&&o.value&&(e(),t==null||t.focus())}}function Pt(o){const{page:e,hash:t}=L(),s=T(!1),n=y(()=>o.value.collapsed!=null),r=y(()=>!!o.value.link),c=T(!1),v=()=>{c.value=G(e.value.relativePath,o.value.link)};D([e,o,t],v),R(v);const d=y(()=>c.value?!0:o.value.items?ue(e.value.relativePath,o.value.items):!1),h=y(()=>!!(o.value.items&&o.value.items.length));Z(()=>{s.value=!!(n.value&&o.value.collapsed)}),me(()=>{(c.value||d.value)&&(s.value=!1)});function P(){n.value&&(s.value=!s.value)}return{collapsed:s,collapsible:n,isLink:r,isActiveLink:c,hasActiveLink:d,hasChildren:h,toggle:P}}function Vt(){const{hasSidebar:o}=U(),e=ie("(min-width: 960px)"),t=ie("(min-width: 1280px)");return{isAsideEnabled:y(()=>!t.value&&!e.value?!1:o.value?t.value:e.value)}}const de=[];function Ee(o){return typeof o.outline=="object"&&!Array.isArray(o.outline)&&o.outline.label||o.outlineTitle||"On this page"}function be(o){const e=[...document.querySelectorAll(".VPDoc :where(h1,h2,h3,h4,h5,h6)")].filter(t=>t.id&&t.hasChildNodes()).map(t=>{const s=Number(t.tagName[1]);return{element:t,title:St(t),link:"#"+t.id,level:s}});return Lt(e,o)}function St(o){let e="";for(const t of o.childNodes)if(t.nodeType===1){if(t.classList.contains("VPBadge")||t.classList.contains("header-anchor")||t.classList.contains("ignore-header"))continue;e+=t.textContent}else t.nodeType===3&&(e+=t.textContent);return e.trim()}function Lt(o,e){if(e===!1)return[];const t=(typeof e=="object"&&!Array.isArray(e)?e.level:e)||2,[s,n]=typeof t=="number"?[t,t]:t==="deep"?[2,6]:t;return Nt(o,s,n)}function Tt(o,e){const{isAsideEnabled:t}=Vt(),s=ut(r,100);let n=null;R(()=>{requestAnimationFrame(r),window.addEventListener("scroll",s)}),We(()=>{c(location.hash)}),fe(()=>{window.removeEventListener("scroll",s)});function r(){if(!t.value)return;const v=window.scrollY,d=window.innerHeight,h=document.body.offsetHeight,P=Math.abs(v+d-h)<1,_=de.map(({element:S,link:C})=>({link:C,top:wt(S)})).filter(({top:S})=>!Number.isNaN(S)).sort((S,C)=>S.top-C.top);if(!_.length){c(null);return}if(v<1){c(null);return}if(P){c(_[_.length-1].link);return}let V=null;for(const{link:S,top:C}of _){if(C>v+Je()+4)break;V=S}c(V)}function c(v){n&&n.classList.remove("active"),v==null?n=null:n=o.value.querySelector(`a[href="${decodeURIComponent(v)}"]`);const d=n;d?(d.classList.add("active"),e.value.style.top=d.offsetTop+39+"px",e.value.style.opacity="1"):(e.value.style.top="33px",e.value.style.opacity="0")}}function wt(o){let e=0;for(;o!==document.body;){if(o===null)return NaN;e+=o.offsetTop,o=o.offsetParent}return e}function Nt(o,e,t){de.length=0;const s=[],n=[];return o.forEach(r=>{const c={...r,children:[]};let v=n[n.length-1];for(;v&&v.level>=c.level;)n.pop(),v=n[n.length-1];if(c.element.classList.contains("ignore-header")||v&&"shouldIgnore"in v){n.push({level:c.level,shouldIgnore:!0});return}c.level>t||c.level{const n=K("VPDocOutlineItem",!0);return a(),l("ul",{class:I(["VPDocOutlineItem",t.root?"root":"nested"])},[(a(!0),l(M,null,B(t.headers,({children:r,link:c,title:v})=>(a(),l("li",null,[p("a",{class:"outline-link",href:c,onClick:e,title:v},w(v),9,It),r!=null&&r.length?(a(),$(n,{key:0,headers:r},null,8,["headers"])):m("",!0)]))),256))],2)}}}),He=k(Mt,[["__scopeId","data-v-3f927ebe"]]),Ct={class:"content"},At={"aria-level":"2",class:"outline-title",id:"doc-outline-aria-label",role:"heading"},Bt=b({__name:"VPDocAsideOutline",setup(o){const{frontmatter:e,theme:t}=L(),s=Te([]);x(()=>{s.value=be(e.value.outline??t.value.outline)});const n=T(),r=T();return Tt(n,r),(c,v)=>(a(),l("nav",{"aria-labelledby":"doc-outline-aria-label",class:I(["VPDocAsideOutline",{"has-outline":s.value.length>0}]),ref_key:"container",ref:n},[p("div",Ct,[p("div",{class:"outline-marker",ref_key:"marker",ref:r},null,512),p("div",At,w(i(Ee)(i(t))),1),g(He,{headers:s.value,root:!0},null,8,["headers"])])],2))}}),Et=k(Bt,[["__scopeId","data-v-b38bf2ff"]]),Ht={class:"VPDocAsideCarbonAds"},Ot=b({__name:"VPDocAsideCarbonAds",props:{carbonAds:{}},setup(o){const e=()=>null;return(t,s)=>(a(),l("div",Ht,[g(i(e),{"carbon-ads":t.carbonAds},null,8,["carbon-ads"])]))}}),Dt={class:"VPDocAside"},Ft=b({__name:"VPDocAside",setup(o){const{theme:e}=L();return(t,s)=>(a(),l("div",Dt,[u(t.$slots,"aside-top",{},void 0,!0),u(t.$slots,"aside-outline-before",{},void 0,!0),g(Et),u(t.$slots,"aside-outline-after",{},void 0,!0),s[0]||(s[0]=p("div",{class:"spacer"},null,-1)),u(t.$slots,"aside-ads-before",{},void 0,!0),i(e).carbonAds?(a(),$(Ot,{key:0,"carbon-ads":i(e).carbonAds},null,8,["carbon-ads"])):m("",!0),u(t.$slots,"aside-ads-after",{},void 0,!0),u(t.$slots,"aside-bottom",{},void 0,!0)]))}}),Rt=k(Ft,[["__scopeId","data-v-6d7b3c46"]]);function Ut(){const{theme:o,page:e}=L();return y(()=>{const{text:t="Edit this page",pattern:s=""}=o.value.editLink||{};let n;return typeof s=="function"?n=s(e.value):n=s.replace(/:path/g,e.value.filePath),{url:n,text:t}})}function zt(){const{page:o,theme:e,frontmatter:t}=L();return y(()=>{var h,P,_,V,S,C,A,N;const s=Be(e.value.sidebar,o.value.relativePath),n=$t(s),r=jt(n,E=>E.link.replace(/[?#].*$/,"")),c=r.findIndex(E=>G(o.value.relativePath,E.link)),v=((h=e.value.docFooter)==null?void 0:h.prev)===!1&&!t.value.prev||t.value.prev===!1,d=((P=e.value.docFooter)==null?void 0:P.next)===!1&&!t.value.next||t.value.next===!1;return{prev:v?void 0:{text:(typeof t.value.prev=="string"?t.value.prev:typeof t.value.prev=="object"?t.value.prev.text:void 0)??((_=r[c-1])==null?void 0:_.docFooterText)??((V=r[c-1])==null?void 0:V.text),link:(typeof t.value.prev=="object"?t.value.prev.link:void 0)??((S=r[c-1])==null?void 0:S.link)},next:d?void 0:{text:(typeof t.value.next=="string"?t.value.next:typeof t.value.next=="object"?t.value.next.text:void 0)??((C=r[c+1])==null?void 0:C.docFooterText)??((A=r[c+1])==null?void 0:A.text),link:(typeof t.value.next=="object"?t.value.next.link:void 0)??((N=r[c+1])==null?void 0:N.link)}}})}function jt(o,e){const t=new Set;return o.filter(s=>{const n=e(s);return t.has(n)?!1:t.add(n)})}const H=b({__name:"VPLink",props:{tag:{},href:{},noIcon:{type:Boolean},target:{},rel:{}},setup(o){const e=o,t=y(()=>e.tag??(e.href?"a":"span")),s=y(()=>e.href&&we.test(e.href)||e.target==="_blank");return(n,r)=>(a(),$(O(t.value),{class:I(["VPLink",{link:n.href,"vp-external-link-icon":s.value,"no-icon":n.noIcon}]),href:n.href?i(_e)(n.href):void 0,target:n.target??(s.value?"_blank":void 0),rel:n.rel??(s.value?"noreferrer":void 0)},{default:f(()=>[u(n.$slots,"default")]),_:3},8,["class","href","target","rel"]))}}),Gt={class:"VPLastUpdated"},Kt=["datetime"],qt=b({__name:"VPDocFooterLastUpdated",setup(o){const{theme:e,page:t,lang:s}=L(),n=y(()=>new Date(t.value.lastUpdated)),r=y(()=>n.value.toISOString()),c=T("");return R(()=>{Z(()=>{var v,d,h;c.value=new Intl.DateTimeFormat((d=(v=e.value.lastUpdated)==null?void 0:v.formatOptions)!=null&&d.forceLocale?s.value:void 0,((h=e.value.lastUpdated)==null?void 0:h.formatOptions)??{dateStyle:"short",timeStyle:"short"}).format(n.value)})}),(v,d)=>{var h;return a(),l("p",Gt,[F(w(((h=i(e).lastUpdated)==null?void 0:h.text)||i(e).lastUpdatedText||"Last updated")+": ",1),p("time",{datetime:r.value},w(c.value),9,Kt)])}}}),Wt=k(qt,[["__scopeId","data-v-475f71b8"]]),Jt={key:0,class:"VPDocFooter"},Yt={key:0,class:"edit-info"},Qt={key:0,class:"edit-link"},Xt={key:1,class:"last-updated"},Zt={key:1,class:"prev-next","aria-labelledby":"doc-footer-aria-label"},xt={class:"pager"},en=["innerHTML"],tn=["innerHTML"],nn={class:"pager"},sn=["innerHTML"],on=["innerHTML"],an=b({__name:"VPDocFooter",setup(o){const{theme:e,page:t,frontmatter:s}=L(),n=Ut(),r=zt(),c=y(()=>e.value.editLink&&s.value.editLink!==!1),v=y(()=>t.value.lastUpdated),d=y(()=>c.value||v.value||r.value.prev||r.value.next);return(h,P)=>{var _,V,S,C;return d.value?(a(),l("footer",Jt,[u(h.$slots,"doc-footer-before",{},void 0,!0),c.value||v.value?(a(),l("div",Yt,[c.value?(a(),l("div",Qt,[g(H,{class:"edit-link-button",href:i(n).url,"no-icon":!0},{default:f(()=>[P[0]||(P[0]=p("span",{class:"vpi-square-pen edit-link-icon"},null,-1)),F(" "+w(i(n).text),1)]),_:1},8,["href"])])):m("",!0),v.value?(a(),l("div",Xt,[g(Wt)])):m("",!0)])):m("",!0),(_=i(r).prev)!=null&&_.link||(V=i(r).next)!=null&&V.link?(a(),l("nav",Zt,[P[1]||(P[1]=p("span",{class:"visually-hidden",id:"doc-footer-aria-label"},"Pager",-1)),p("div",xt,[(S=i(r).prev)!=null&&S.link?(a(),$(H,{key:0,class:"pager-link prev",href:i(r).prev.link},{default:f(()=>{var A;return[p("span",{class:"desc",innerHTML:((A=i(e).docFooter)==null?void 0:A.prev)||"Previous page"},null,8,en),p("span",{class:"title",innerHTML:i(r).prev.text},null,8,tn)]}),_:1},8,["href"])):m("",!0)]),p("div",nn,[(C=i(r).next)!=null&&C.link?(a(),$(H,{key:0,class:"pager-link next",href:i(r).next.link},{default:f(()=>{var A;return[p("span",{class:"desc",innerHTML:((A=i(e).docFooter)==null?void 0:A.next)||"Next page"},null,8,sn),p("span",{class:"title",innerHTML:i(r).next.text},null,8,on)]}),_:1},8,["href"])):m("",!0)])])):m("",!0)])):m("",!0)}}}),rn=k(an,[["__scopeId","data-v-4f9813fa"]]),ln={class:"container"},cn={class:"aside-container"},un={class:"aside-content"},dn={class:"content"},pn={class:"content-container"},vn={class:"main"},fn=b({__name:"VPDoc",setup(o){const{theme:e}=L(),t=ee(),{hasSidebar:s,hasAside:n,leftAside:r}=U(),c=y(()=>t.path.replace(/[./]+/g,"_").replace(/_html$/,""));return(v,d)=>{const h=K("Content");return a(),l("div",{class:I(["VPDoc",{"has-sidebar":i(s),"has-aside":i(n)}])},[u(v.$slots,"doc-top",{},void 0,!0),p("div",ln,[i(n)?(a(),l("div",{key:0,class:I(["aside",{"left-aside":i(r)}])},[d[0]||(d[0]=p("div",{class:"aside-curtain"},null,-1)),p("div",cn,[p("div",un,[g(Rt,null,{"aside-top":f(()=>[u(v.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":f(()=>[u(v.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":f(()=>[u(v.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":f(()=>[u(v.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":f(()=>[u(v.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":f(()=>[u(v.$slots,"aside-ads-after",{},void 0,!0)]),_:3})])])],2)):m("",!0),p("div",dn,[p("div",pn,[u(v.$slots,"doc-before",{},void 0,!0),p("main",vn,[g(h,{class:I(["vp-doc",[c.value,i(e).externalLinkIcon&&"external-link-icon-enabled"]])},null,8,["class"])]),g(rn,null,{"doc-footer-before":f(()=>[u(v.$slots,"doc-footer-before",{},void 0,!0)]),_:3}),u(v.$slots,"doc-after",{},void 0,!0)])])]),u(v.$slots,"doc-bottom",{},void 0,!0)],2)}}}),mn=k(fn,[["__scopeId","data-v-83890dd9"]]),hn=b({__name:"VPButton",props:{tag:{},size:{default:"medium"},theme:{default:"brand"},text:{},href:{},target:{},rel:{}},setup(o){const e=o,t=y(()=>e.href&&we.test(e.href)),s=y(()=>e.tag||(e.href?"a":"button"));return(n,r)=>(a(),$(O(s.value),{class:I(["VPButton",[n.size,n.theme]]),href:n.href?i(_e)(n.href):void 0,target:e.target??(t.value?"_blank":void 0),rel:e.rel??(t.value?"noreferrer":void 0)},{default:f(()=>[F(w(n.text),1)]),_:1},8,["class","href","target","rel"]))}}),_n=k(hn,[["__scopeId","data-v-906d7fb4"]]),bn=["src","alt"],kn=b({inheritAttrs:!1,__name:"VPImage",props:{image:{},alt:{}},setup(o){return(e,t)=>{const s=K("VPImage",!0);return e.image?(a(),l(M,{key:0},[typeof e.image=="string"||"src"in e.image?(a(),l("img",j({key:0,class:"VPImage"},typeof e.image=="string"?e.$attrs:{...e.image,...e.$attrs},{src:i(ve)(typeof e.image=="string"?e.image:e.image.src),alt:e.alt??(typeof e.image=="string"?"":e.image.alt||"")}),null,16,bn)):(a(),l(M,{key:1},[g(s,j({class:"dark",image:e.image.dark,alt:e.image.alt},e.$attrs),null,16,["image","alt"]),g(s,j({class:"light",image:e.image.light,alt:e.image.alt},e.$attrs),null,16,["image","alt"])],64))],64)):m("",!0)}}}),X=k(kn,[["__scopeId","data-v-35a7d0b8"]]),gn={class:"container"},$n={class:"main"},yn={key:0,class:"name"},Pn=["innerHTML"],Vn=["innerHTML"],Sn=["innerHTML"],Ln={key:0,class:"actions"},Tn={key:0,class:"image"},wn={class:"image-container"},Nn=b({__name:"VPHero",props:{name:{},text:{},tagline:{},image:{},actions:{}},setup(o){const e=W("hero-image-slot-exists");return(t,s)=>(a(),l("div",{class:I(["VPHero",{"has-image":t.image||i(e)}])},[p("div",gn,[p("div",$n,[u(t.$slots,"home-hero-info-before",{},void 0,!0),u(t.$slots,"home-hero-info",{},()=>[t.name?(a(),l("h1",yn,[p("span",{innerHTML:t.name,class:"clip"},null,8,Pn)])):m("",!0),t.text?(a(),l("p",{key:1,innerHTML:t.text,class:"text"},null,8,Vn)):m("",!0),t.tagline?(a(),l("p",{key:2,innerHTML:t.tagline,class:"tagline"},null,8,Sn)):m("",!0)],!0),u(t.$slots,"home-hero-info-after",{},void 0,!0),t.actions?(a(),l("div",Ln,[(a(!0),l(M,null,B(t.actions,n=>(a(),l("div",{key:n.link,class:"action"},[g(_n,{tag:"a",size:"medium",theme:n.theme,text:n.text,href:n.link,target:n.target,rel:n.rel},null,8,["theme","text","href","target","rel"])]))),128))])):m("",!0),u(t.$slots,"home-hero-actions-after",{},void 0,!0)]),t.image||i(e)?(a(),l("div",Tn,[p("div",wn,[s[0]||(s[0]=p("div",{class:"image-bg"},null,-1)),u(t.$slots,"home-hero-image",{},()=>[t.image?(a(),$(X,{key:0,class:"image-src",image:t.image},null,8,["image"])):m("",!0)],!0)])])):m("",!0)])],2))}}),In=k(Nn,[["__scopeId","data-v-955009fc"]]),Mn=b({__name:"VPHomeHero",setup(o){const{frontmatter:e}=L();return(t,s)=>i(e).hero?(a(),$(In,{key:0,class:"VPHomeHero",name:i(e).hero.name,text:i(e).hero.text,tagline:i(e).hero.tagline,image:i(e).hero.image,actions:i(e).hero.actions},{"home-hero-info-before":f(()=>[u(t.$slots,"home-hero-info-before")]),"home-hero-info":f(()=>[u(t.$slots,"home-hero-info")]),"home-hero-info-after":f(()=>[u(t.$slots,"home-hero-info-after")]),"home-hero-actions-after":f(()=>[u(t.$slots,"home-hero-actions-after")]),"home-hero-image":f(()=>[u(t.$slots,"home-hero-image")]),_:3},8,["name","text","tagline","image","actions"])):m("",!0)}}),Cn={class:"box"},An={key:0,class:"icon"},Bn=["innerHTML"],En=["innerHTML"],Hn=["innerHTML"],On={key:4,class:"link-text"},Dn={class:"link-text-value"},Fn=b({__name:"VPFeature",props:{icon:{},title:{},details:{},link:{},linkText:{},rel:{},target:{}},setup(o){return(e,t)=>(a(),$(H,{class:"VPFeature",href:e.link,rel:e.rel,target:e.target,"no-icon":!0,tag:e.link?"a":"div"},{default:f(()=>[p("article",Cn,[typeof e.icon=="object"&&e.icon.wrap?(a(),l("div",An,[g(X,{image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])])):typeof e.icon=="object"?(a(),$(X,{key:1,image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])):e.icon?(a(),l("div",{key:2,class:"icon",innerHTML:e.icon},null,8,Bn)):m("",!0),p("h2",{class:"title",innerHTML:e.title},null,8,En),e.details?(a(),l("p",{key:3,class:"details",innerHTML:e.details},null,8,Hn)):m("",!0),e.linkText?(a(),l("div",On,[p("p",Dn,[F(w(e.linkText)+" ",1),t[0]||(t[0]=p("span",{class:"vpi-arrow-right link-text-icon"},null,-1))])])):m("",!0)])]),_:1},8,["href","rel","target","tag"]))}}),Rn=k(Fn,[["__scopeId","data-v-f5e9645b"]]),Un={key:0,class:"VPFeatures"},zn={class:"container"},jn={class:"items"},Gn=b({__name:"VPFeatures",props:{features:{}},setup(o){const e=o,t=y(()=>{const s=e.features.length;if(s){if(s===2)return"grid-2";if(s===3)return"grid-3";if(s%3===0)return"grid-6";if(s>3)return"grid-4"}else return});return(s,n)=>s.features?(a(),l("div",Un,[p("div",zn,[p("div",jn,[(a(!0),l(M,null,B(s.features,r=>(a(),l("div",{key:r.title,class:I(["item",[t.value]])},[g(Rn,{icon:r.icon,title:r.title,details:r.details,link:r.link,"link-text":r.linkText,rel:r.rel,target:r.target},null,8,["icon","title","details","link","link-text","rel","target"])],2))),128))])])])):m("",!0)}}),Kn=k(Gn,[["__scopeId","data-v-d0a190d7"]]),qn=b({__name:"VPHomeFeatures",setup(o){const{frontmatter:e}=L();return(t,s)=>i(e).features?(a(),$(Kn,{key:0,class:"VPHomeFeatures",features:i(e).features},null,8,["features"])):m("",!0)}}),Wn=b({__name:"VPHomeContent",setup(o){const{width:e}=Ye({initialWidth:0,includeScrollbar:!1});return(t,s)=>(a(),l("div",{class:"vp-doc container",style:Ne(i(e)?{"--vp-offset":`calc(50% - ${i(e)/2}px)`}:{})},[u(t.$slots,"default",{},void 0,!0)],4))}}),Jn=k(Wn,[["__scopeId","data-v-7a48a447"]]),Yn={class:"VPHome"},Qn=b({__name:"VPHome",setup(o){const{frontmatter:e}=L();return(t,s)=>{const n=K("Content");return a(),l("div",Yn,[u(t.$slots,"home-hero-before",{},void 0,!0),g(Mn,null,{"home-hero-info-before":f(()=>[u(t.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":f(()=>[u(t.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":f(()=>[u(t.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":f(()=>[u(t.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":f(()=>[u(t.$slots,"home-hero-image",{},void 0,!0)]),_:3}),u(t.$slots,"home-hero-after",{},void 0,!0),u(t.$slots,"home-features-before",{},void 0,!0),g(qn),u(t.$slots,"home-features-after",{},void 0,!0),i(e).markdownStyles!==!1?(a(),$(Jn,{key:0},{default:f(()=>[g(n)]),_:1})):(a(),$(n,{key:1}))])}}}),Xn=k(Qn,[["__scopeId","data-v-cbb6ec48"]]),Zn={},xn={class:"VPPage"};function es(o,e){const t=K("Content");return a(),l("div",xn,[u(o.$slots,"page-top"),g(t),u(o.$slots,"page-bottom")])}const ts=k(Zn,[["render",es]]),ns=b({__name:"VPContent",setup(o){const{page:e,frontmatter:t}=L(),{hasSidebar:s}=U();return(n,r)=>(a(),l("div",{class:I(["VPContent",{"has-sidebar":i(s),"is-home":i(t).layout==="home"}]),id:"VPContent"},[i(e).isNotFound?u(n.$slots,"not-found",{key:0},()=>[g(kt)],!0):i(t).layout==="page"?(a(),$(ts,{key:1},{"page-top":f(()=>[u(n.$slots,"page-top",{},void 0,!0)]),"page-bottom":f(()=>[u(n.$slots,"page-bottom",{},void 0,!0)]),_:3})):i(t).layout==="home"?(a(),$(Xn,{key:2},{"home-hero-before":f(()=>[u(n.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info-before":f(()=>[u(n.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":f(()=>[u(n.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":f(()=>[u(n.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":f(()=>[u(n.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":f(()=>[u(n.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":f(()=>[u(n.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":f(()=>[u(n.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":f(()=>[u(n.$slots,"home-features-after",{},void 0,!0)]),_:3})):i(t).layout&&i(t).layout!=="doc"?(a(),$(O(i(t).layout),{key:3})):(a(),$(mn,{key:4},{"doc-top":f(()=>[u(n.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":f(()=>[u(n.$slots,"doc-bottom",{},void 0,!0)]),"doc-footer-before":f(()=>[u(n.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":f(()=>[u(n.$slots,"doc-before",{},void 0,!0)]),"doc-after":f(()=>[u(n.$slots,"doc-after",{},void 0,!0)]),"aside-top":f(()=>[u(n.$slots,"aside-top",{},void 0,!0)]),"aside-outline-before":f(()=>[u(n.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":f(()=>[u(n.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":f(()=>[u(n.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":f(()=>[u(n.$slots,"aside-ads-after",{},void 0,!0)]),"aside-bottom":f(()=>[u(n.$slots,"aside-bottom",{},void 0,!0)]),_:3}))],2))}}),ss=k(ns,[["__scopeId","data-v-91765379"]]),os={class:"container"},as=["innerHTML"],rs=["innerHTML"],is=b({__name:"VPFooter",setup(o){const{theme:e,frontmatter:t}=L(),{hasSidebar:s}=U();return(n,r)=>i(e).footer&&i(t).footer!==!1?(a(),l("footer",{key:0,class:I(["VPFooter",{"has-sidebar":i(s)}])},[p("div",os,[i(e).footer.message?(a(),l("p",{key:0,class:"message",innerHTML:i(e).footer.message},null,8,as)):m("",!0),i(e).footer.copyright?(a(),l("p",{key:1,class:"copyright",innerHTML:i(e).footer.copyright},null,8,rs)):m("",!0)])],2)):m("",!0)}}),ls=k(is,[["__scopeId","data-v-c970a860"]]);function cs(){const{theme:o,frontmatter:e}=L(),t=Te([]),s=y(()=>t.value.length>0);return x(()=>{t.value=be(e.value.outline??o.value.outline)}),{headers:t,hasLocalNav:s}}const us={class:"menu-text"},ds={class:"header"},ps={class:"outline"},vs=b({__name:"VPLocalNavOutlineDropdown",props:{headers:{},navHeight:{}},setup(o){const e=o,{theme:t}=L(),s=T(!1),n=T(0),r=T(),c=T();function v(_){var V;(V=r.value)!=null&&V.contains(_.target)||(s.value=!1)}D(s,_=>{if(_){document.addEventListener("click",v);return}document.removeEventListener("click",v)}),le("Escape",()=>{s.value=!1}),x(()=>{s.value=!1});function d(){s.value=!s.value,n.value=window.innerHeight+Math.min(window.scrollY-e.navHeight,0)}function h(_){_.target.classList.contains("outline-link")&&(c.value&&(c.value.style.transition="none"),Ie(()=>{s.value=!1}))}function P(){s.value=!1,window.scrollTo({top:0,left:0,behavior:"smooth"})}return(_,V)=>(a(),l("div",{class:"VPLocalNavOutlineDropdown",style:Ne({"--vp-vh":n.value+"px"}),ref_key:"main",ref:r},[_.headers.length>0?(a(),l("button",{key:0,onClick:d,class:I({open:s.value})},[p("span",us,w(i(Ee)(i(t))),1),V[0]||(V[0]=p("span",{class:"vpi-chevron-right icon"},null,-1))],2)):(a(),l("button",{key:1,onClick:P},w(i(t).returnToTopLabel||"Return to top"),1)),g(pe,{name:"flyout"},{default:f(()=>[s.value?(a(),l("div",{key:0,ref_key:"items",ref:c,class:"items",onClick:h},[p("div",ds,[p("a",{class:"top-link",href:"#",onClick:P},w(i(t).returnToTopLabel||"Return to top"),1)]),p("div",ps,[g(He,{headers:_.headers},null,8,["headers"])])],512)):m("",!0)]),_:1})],4))}}),fs=k(vs,[["__scopeId","data-v-bc9dc845"]]),ms={class:"container"},hs=["aria-expanded"],_s={class:"menu-text"},bs=b({__name:"VPLocalNav",props:{open:{type:Boolean}},emits:["open-menu"],setup(o){const{theme:e,frontmatter:t}=L(),{hasSidebar:s}=U(),{headers:n}=cs(),{y:r}=Me(),c=T(0);R(()=>{c.value=parseInt(getComputedStyle(document.documentElement).getPropertyValue("--vp-nav-height"))}),x(()=>{n.value=be(t.value.outline??e.value.outline)});const v=y(()=>n.value.length===0),d=y(()=>v.value&&!s.value),h=y(()=>({VPLocalNav:!0,"has-sidebar":s.value,empty:v.value,fixed:d.value}));return(P,_)=>i(t).layout!=="home"&&(!d.value||i(r)>=c.value)?(a(),l("div",{key:0,class:I(h.value)},[p("div",ms,[i(s)?(a(),l("button",{key:0,class:"menu","aria-expanded":P.open,"aria-controls":"VPSidebarNav",onClick:_[0]||(_[0]=V=>P.$emit("open-menu"))},[_[1]||(_[1]=p("span",{class:"vpi-align-left menu-icon"},null,-1)),p("span",_s,w(i(e).sidebarMenuLabel||"Menu"),1)],8,hs)):m("",!0),g(fs,{headers:i(n),navHeight:c.value},null,8,["headers","navHeight"])])],2)):m("",!0)}}),ks=k(bs,[["__scopeId","data-v-070ab83d"]]);function gs(){const o=T(!1);function e(){o.value=!0,window.addEventListener("resize",n)}function t(){o.value=!1,window.removeEventListener("resize",n)}function s(){o.value?t():e()}function n(){window.outerWidth>=768&&t()}const r=ee();return D(()=>r.path,t),{isScreenOpen:o,openScreen:e,closeScreen:t,toggleScreen:s}}const $s={},ys={class:"VPSwitch",type:"button",role:"switch"},Ps={class:"check"},Vs={key:0,class:"icon"};function Ss(o,e){return a(),l("button",ys,[p("span",Ps,[o.$slots.default?(a(),l("span",Vs,[u(o.$slots,"default",{},void 0,!0)])):m("",!0)])])}const Ls=k($s,[["render",Ss],["__scopeId","data-v-4a1c76db"]]),Ts=b({__name:"VPSwitchAppearance",setup(o){const{isDark:e,theme:t}=L(),s=W("toggle-appearance",()=>{e.value=!e.value}),n=T("");return me(()=>{n.value=e.value?t.value.lightModeSwitchTitle||"Switch to light theme":t.value.darkModeSwitchTitle||"Switch to dark theme"}),(r,c)=>(a(),$(Ls,{title:n.value,class:"VPSwitchAppearance","aria-checked":i(e),onClick:i(s)},{default:f(()=>c[0]||(c[0]=[p("span",{class:"vpi-sun sun"},null,-1),p("span",{class:"vpi-moon moon"},null,-1)])),_:1},8,["title","aria-checked","onClick"]))}}),ke=k(Ts,[["__scopeId","data-v-e40a8bb6"]]),ws={key:0,class:"VPNavBarAppearance"},Ns=b({__name:"VPNavBarAppearance",setup(o){const{site:e}=L();return(t,s)=>i(e).appearance&&i(e).appearance!=="force-dark"&&i(e).appearance!=="force-auto"?(a(),l("div",ws,[g(ke)])):m("",!0)}}),Is=k(Ns,[["__scopeId","data-v-af096f4a"]]),ge=T();let Oe=!1,re=0;function Ms(o){const e=T(!1);if(te){!Oe&&Cs(),re++;const t=D(ge,s=>{var n,r,c;s===o.el.value||(n=o.el.value)!=null&&n.contains(s)?(e.value=!0,(r=o.onFocus)==null||r.call(o)):(e.value=!1,(c=o.onBlur)==null||c.call(o))});fe(()=>{t(),re--,re||As()})}return Qe(e)}function Cs(){document.addEventListener("focusin",De),Oe=!0,ge.value=document.activeElement}function As(){document.removeEventListener("focusin",De)}function De(){ge.value=document.activeElement}const Bs={class:"VPMenuLink"},Es=["innerHTML"],Hs=b({__name:"VPMenuLink",props:{item:{}},setup(o){const{page:e}=L();return(t,s)=>(a(),l("div",Bs,[g(H,{class:I({active:i(G)(i(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon},{default:f(()=>[p("span",{innerHTML:t.item.text},null,8,Es)]),_:1},8,["class","href","target","rel","no-icon"])]))}}),ne=k(Hs,[["__scopeId","data-v-acbfed09"]]),Os={class:"VPMenuGroup"},Ds={key:0,class:"title"},Fs=b({__name:"VPMenuGroup",props:{text:{},items:{}},setup(o){return(e,t)=>(a(),l("div",Os,[e.text?(a(),l("p",Ds,w(e.text),1)):m("",!0),(a(!0),l(M,null,B(e.items,s=>(a(),l(M,null,["link"in s?(a(),$(ne,{key:0,item:s},null,8,["item"])):m("",!0)],64))),256))]))}}),Rs=k(Fs,[["__scopeId","data-v-48c802d0"]]),Us={class:"VPMenu"},zs={key:0,class:"items"},js=b({__name:"VPMenu",props:{items:{}},setup(o){return(e,t)=>(a(),l("div",Us,[e.items?(a(),l("div",zs,[(a(!0),l(M,null,B(e.items,s=>(a(),l(M,{key:JSON.stringify(s)},["link"in s?(a(),$(ne,{key:0,item:s},null,8,["item"])):"component"in s?(a(),$(O(s.component),j({key:1,ref_for:!0},s.props),null,16)):(a(),$(Rs,{key:2,text:s.text,items:s.items},null,8,["text","items"]))],64))),128))])):m("",!0),u(e.$slots,"default",{},void 0,!0)]))}}),Gs=k(js,[["__scopeId","data-v-7dd3104a"]]),Ks=["aria-expanded","aria-label"],qs={key:0,class:"text"},Ws=["innerHTML"],Js={key:1,class:"vpi-more-horizontal icon"},Ys={class:"menu"},Qs=b({__name:"VPFlyout",props:{icon:{},button:{},label:{},items:{}},setup(o){const e=T(!1),t=T();Ms({el:t,onBlur:s});function s(){e.value=!1}return(n,r)=>(a(),l("div",{class:"VPFlyout",ref_key:"el",ref:t,onMouseenter:r[1]||(r[1]=c=>e.value=!0),onMouseleave:r[2]||(r[2]=c=>e.value=!1)},[p("button",{type:"button",class:"button","aria-haspopup":"true","aria-expanded":e.value,"aria-label":n.label,onClick:r[0]||(r[0]=c=>e.value=!e.value)},[n.button||n.icon?(a(),l("span",qs,[n.icon?(a(),l("span",{key:0,class:I([n.icon,"option-icon"])},null,2)):m("",!0),n.button?(a(),l("span",{key:1,innerHTML:n.button},null,8,Ws)):m("",!0),r[3]||(r[3]=p("span",{class:"vpi-chevron-down text-icon"},null,-1))])):(a(),l("span",Js))],8,Ks),p("div",Ys,[g(Gs,{items:n.items},{default:f(()=>[u(n.$slots,"default",{},void 0,!0)]),_:3},8,["items"])])],544))}}),$e=k(Qs,[["__scopeId","data-v-04f5c5e9"]]),Xs=["href","aria-label","innerHTML"],Zs=b({__name:"VPSocialLink",props:{icon:{},link:{},ariaLabel:{}},setup(o){const e=o,t=y(()=>typeof e.icon=="object"?e.icon.svg:``);return(s,n)=>(a(),l("a",{class:"VPSocialLink no-icon",href:s.link,"aria-label":s.ariaLabel??(typeof s.icon=="string"?s.icon:""),target:"_blank",rel:"noopener",innerHTML:t.value},null,8,Xs))}}),xs=k(Zs,[["__scopeId","data-v-717b8b75"]]),eo={class:"VPSocialLinks"},to=b({__name:"VPSocialLinks",props:{links:{}},setup(o){return(e,t)=>(a(),l("div",eo,[(a(!0),l(M,null,B(e.links,({link:s,icon:n,ariaLabel:r})=>(a(),$(xs,{key:s,icon:n,link:s,ariaLabel:r},null,8,["icon","link","ariaLabel"]))),128))]))}}),se=k(to,[["__scopeId","data-v-ee7a9424"]]),no={key:0,class:"group translations"},so={class:"trans-title"},oo={key:1,class:"group"},ao={class:"item appearance"},ro={class:"label"},io={class:"appearance-action"},lo={key:2,class:"group"},co={class:"item social-links"},uo=b({__name:"VPNavBarExtra",setup(o){const{site:e,theme:t}=L(),{localeLinks:s,currentLang:n}=Y({correspondingLink:!0}),r=y(()=>s.value.length&&n.value.label||e.value.appearance||t.value.socialLinks);return(c,v)=>r.value?(a(),$($e,{key:0,class:"VPNavBarExtra",label:"extra navigation"},{default:f(()=>[i(s).length&&i(n).label?(a(),l("div",no,[p("p",so,w(i(n).label),1),(a(!0),l(M,null,B(i(s),d=>(a(),$(ne,{key:d.link,item:d},null,8,["item"]))),128))])):m("",!0),i(e).appearance&&i(e).appearance!=="force-dark"&&i(e).appearance!=="force-auto"?(a(),l("div",oo,[p("div",ao,[p("p",ro,w(i(t).darkModeSwitchLabel||"Appearance"),1),p("div",io,[g(ke)])])])):m("",!0),i(t).socialLinks?(a(),l("div",lo,[p("div",co,[g(se,{class:"social-links-list",links:i(t).socialLinks},null,8,["links"])])])):m("",!0)]),_:1})):m("",!0)}}),po=k(uo,[["__scopeId","data-v-925effce"]]),vo=["aria-expanded"],fo=b({__name:"VPNavBarHamburger",props:{active:{type:Boolean}},emits:["click"],setup(o){return(e,t)=>(a(),l("button",{type:"button",class:I(["VPNavBarHamburger",{active:e.active}]),"aria-label":"mobile navigation","aria-expanded":e.active,"aria-controls":"VPNavScreen",onClick:t[0]||(t[0]=s=>e.$emit("click"))},t[1]||(t[1]=[p("span",{class:"container"},[p("span",{class:"top"}),p("span",{class:"middle"}),p("span",{class:"bottom"})],-1)]),10,vo))}}),mo=k(fo,[["__scopeId","data-v-5dea55bf"]]),ho=["innerHTML"],_o=b({__name:"VPNavBarMenuLink",props:{item:{}},setup(o){const{page:e}=L();return(t,s)=>(a(),$(H,{class:I({VPNavBarMenuLink:!0,active:i(G)(i(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon,tabindex:"0"},{default:f(()=>[p("span",{innerHTML:t.item.text},null,8,ho)]),_:1},8,["class","href","target","rel","no-icon"]))}}),bo=k(_o,[["__scopeId","data-v-956ec74c"]]),Fe=b({__name:"VPNavBarMenuGroup",props:{item:{}},setup(o){const e=o,{page:t}=L(),s=r=>"component"in r?!1:"link"in r?G(t.value.relativePath,r.link,!!e.item.activeMatch):r.items.some(s),n=y(()=>s(e.item));return(r,c)=>(a(),$($e,{class:I({VPNavBarMenuGroup:!0,active:i(G)(i(t).relativePath,r.item.activeMatch,!!r.item.activeMatch)||n.value}),button:r.item.text,items:r.item.items},null,8,["class","button","items"]))}}),ko={key:0,"aria-labelledby":"main-nav-aria-label",class:"VPNavBarMenu"},go=b({__name:"VPNavBarMenu",setup(o){const{theme:e}=L();return(t,s)=>i(e).nav?(a(),l("nav",ko,[s[0]||(s[0]=p("span",{id:"main-nav-aria-label",class:"visually-hidden"}," Main Navigation ",-1)),(a(!0),l(M,null,B(i(e).nav,n=>(a(),l(M,{key:JSON.stringify(n)},["link"in n?(a(),$(bo,{key:0,item:n},null,8,["item"])):"component"in n?(a(),$(O(n.component),j({key:1,ref_for:!0},n.props),null,16)):(a(),$(Fe,{key:2,item:n},null,8,["item"]))],64))),128))])):m("",!0)}}),$o=k(go,[["__scopeId","data-v-e6d46098"]]);function yo(o){const{localeIndex:e,theme:t}=L();function s(n){var C,A,N;const r=n.split("."),c=(C=t.value.search)==null?void 0:C.options,v=c&&typeof c=="object",d=v&&((N=(A=c.locales)==null?void 0:A[e.value])==null?void 0:N.translations)||null,h=v&&c.translations||null;let P=d,_=h,V=o;const S=r.pop();for(const E of r){let z=null;const q=V==null?void 0:V[E];q&&(z=V=q);const oe=_==null?void 0:_[E];oe&&(z=_=oe);const ae=P==null?void 0:P[E];ae&&(z=P=ae),q||(V=z),oe||(_=z),ae||(P=z)}return(P==null?void 0:P[S])??(_==null?void 0:_[S])??(V==null?void 0:V[S])??""}return s}const Po=["aria-label"],Vo={class:"DocSearch-Button-Container"},So={class:"DocSearch-Button-Placeholder"},Pe=b({__name:"VPNavBarSearchButton",setup(o){const t=yo({button:{buttonText:"Search",buttonAriaLabel:"Search"}});return(s,n)=>(a(),l("button",{type:"button",class:"DocSearch DocSearch-Button","aria-label":i(t)("button.buttonAriaLabel")},[p("span",Vo,[n[0]||(n[0]=p("span",{class:"vp-icon DocSearch-Search-Icon"},null,-1)),p("span",So,w(i(t)("button.buttonText")),1)]),n[1]||(n[1]=p("span",{class:"DocSearch-Button-Keys"},[p("kbd",{class:"DocSearch-Button-Key"}),p("kbd",{class:"DocSearch-Button-Key"},"K")],-1))],8,Po))}}),Lo={class:"VPNavBarSearch"},To={id:"local-search"},wo={key:1,id:"docsearch"},No=b({__name:"VPNavBarSearch",setup(o){const e=Xe(()=>Ze(()=>import("./VPLocalSearchBox.CkYqsyE0.js"),__vite__mapDeps([0,1]))),t=()=>null,{theme:s}=L(),n=T(!1),r=T(!1);R(()=>{});function c(){n.value||(n.value=!0,setTimeout(v,16))}function v(){const _=new Event("keydown");_.key="k",_.metaKey=!0,window.dispatchEvent(_),setTimeout(()=>{document.querySelector(".DocSearch-Modal")||v()},16)}function d(_){const V=_.target,S=V.tagName;return V.isContentEditable||S==="INPUT"||S==="SELECT"||S==="TEXTAREA"}const h=T(!1);le("k",_=>{(_.ctrlKey||_.metaKey)&&(_.preventDefault(),h.value=!0)}),le("/",_=>{d(_)||(_.preventDefault(),h.value=!0)});const P="local";return(_,V)=>{var S;return a(),l("div",Lo,[i(P)==="local"?(a(),l(M,{key:0},[h.value?(a(),$(i(e),{key:0,onClose:V[0]||(V[0]=C=>h.value=!1)})):m("",!0),p("div",To,[g(Pe,{onClick:V[1]||(V[1]=C=>h.value=!0)})])],64)):i(P)==="algolia"?(a(),l(M,{key:1},[n.value?(a(),$(i(t),{key:0,algolia:((S=i(s).search)==null?void 0:S.options)??i(s).algolia,onVnodeBeforeMount:V[2]||(V[2]=C=>r.value=!0)},null,8,["algolia"])):m("",!0),r.value?m("",!0):(a(),l("div",wo,[g(Pe,{onClick:c})]))],64)):m("",!0)])}}}),Io=b({__name:"VPNavBarSocialLinks",setup(o){const{theme:e}=L();return(t,s)=>i(e).socialLinks?(a(),$(se,{key:0,class:"VPNavBarSocialLinks",links:i(e).socialLinks},null,8,["links"])):m("",!0)}}),Mo=k(Io,[["__scopeId","data-v-164c457f"]]),Co=["href","rel","target"],Ao=["innerHTML"],Bo={key:2},Eo=b({__name:"VPNavBarTitle",setup(o){const{site:e,theme:t}=L(),{hasSidebar:s}=U(),{currentLang:n}=Y(),r=y(()=>{var d;return typeof t.value.logoLink=="string"?t.value.logoLink:(d=t.value.logoLink)==null?void 0:d.link}),c=y(()=>{var d;return typeof t.value.logoLink=="string"||(d=t.value.logoLink)==null?void 0:d.rel}),v=y(()=>{var d;return typeof t.value.logoLink=="string"||(d=t.value.logoLink)==null?void 0:d.target});return(d,h)=>(a(),l("div",{class:I(["VPNavBarTitle",{"has-sidebar":i(s)}])},[p("a",{class:"title",href:r.value??i(_e)(i(n).link),rel:c.value,target:v.value},[u(d.$slots,"nav-bar-title-before",{},void 0,!0),i(t).logo?(a(),$(X,{key:0,class:"logo",image:i(t).logo},null,8,["image"])):m("",!0),i(t).siteTitle?(a(),l("span",{key:1,innerHTML:i(t).siteTitle},null,8,Ao)):i(t).siteTitle===void 0?(a(),l("span",Bo,w(i(e).title),1)):m("",!0),u(d.$slots,"nav-bar-title-after",{},void 0,!0)],8,Co)],2))}}),Ho=k(Eo,[["__scopeId","data-v-0f4f798b"]]),Oo={class:"items"},Do={class:"title"},Fo=b({__name:"VPNavBarTranslations",setup(o){const{theme:e}=L(),{localeLinks:t,currentLang:s}=Y({correspondingLink:!0});return(n,r)=>i(t).length&&i(s).label?(a(),$($e,{key:0,class:"VPNavBarTranslations",icon:"vpi-languages",label:i(e).langMenuLabel||"Change language"},{default:f(()=>[p("div",Oo,[p("p",Do,w(i(s).label),1),(a(!0),l(M,null,B(i(t),c=>(a(),$(ne,{key:c.link,item:c},null,8,["item"]))),128))])]),_:1},8,["label"])):m("",!0)}}),Ro=k(Fo,[["__scopeId","data-v-c80d9ad0"]]),Uo={class:"wrapper"},zo={class:"container"},jo={class:"title"},Go={class:"content"},Ko={class:"content-body"},qo=b({__name:"VPNavBar",props:{isScreenOpen:{type:Boolean}},emits:["toggle-screen"],setup(o){const e=o,{y:t}=Me(),{hasSidebar:s}=U(),{frontmatter:n}=L(),r=T({});return me(()=>{r.value={"has-sidebar":s.value,home:n.value.layout==="home",top:t.value===0,"screen-open":e.isScreenOpen}}),(c,v)=>(a(),l("div",{class:I(["VPNavBar",r.value])},[p("div",Uo,[p("div",zo,[p("div",jo,[g(Ho,null,{"nav-bar-title-before":f(()=>[u(c.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":f(()=>[u(c.$slots,"nav-bar-title-after",{},void 0,!0)]),_:3})]),p("div",Go,[p("div",Ko,[u(c.$slots,"nav-bar-content-before",{},void 0,!0),g(No,{class:"search"}),g($o,{class:"menu"}),g(Ro,{class:"translations"}),g(Is,{class:"appearance"}),g(Mo,{class:"social-links"}),g(po,{class:"extra"}),u(c.$slots,"nav-bar-content-after",{},void 0,!0),g(mo,{class:"hamburger",active:c.isScreenOpen,onClick:v[0]||(v[0]=d=>c.$emit("toggle-screen"))},null,8,["active"])])])])]),v[1]||(v[1]=p("div",{class:"divider"},[p("div",{class:"divider-line"})],-1))],2))}}),Wo=k(qo,[["__scopeId","data-v-822684d1"]]),Jo={key:0,class:"VPNavScreenAppearance"},Yo={class:"text"},Qo=b({__name:"VPNavScreenAppearance",setup(o){const{site:e,theme:t}=L();return(s,n)=>i(e).appearance&&i(e).appearance!=="force-dark"&&i(e).appearance!=="force-auto"?(a(),l("div",Jo,[p("p",Yo,w(i(t).darkModeSwitchLabel||"Appearance"),1),g(ke)])):m("",!0)}}),Xo=k(Qo,[["__scopeId","data-v-ffb44008"]]),Zo=["innerHTML"],xo=b({__name:"VPNavScreenMenuLink",props:{item:{}},setup(o){const e=W("close-screen");return(t,s)=>(a(),$(H,{class:"VPNavScreenMenuLink",href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon,onClick:i(e)},{default:f(()=>[p("span",{innerHTML:t.item.text},null,8,Zo)]),_:1},8,["href","target","rel","no-icon","onClick"]))}}),ea=k(xo,[["__scopeId","data-v-735512b8"]]),ta=["innerHTML"],na=b({__name:"VPNavScreenMenuGroupLink",props:{item:{}},setup(o){const e=W("close-screen");return(t,s)=>(a(),$(H,{class:"VPNavScreenMenuGroupLink",href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon,onClick:i(e)},{default:f(()=>[p("span",{innerHTML:t.item.text},null,8,ta)]),_:1},8,["href","target","rel","no-icon","onClick"]))}}),Re=k(na,[["__scopeId","data-v-372ae7c0"]]),sa={class:"VPNavScreenMenuGroupSection"},oa={key:0,class:"title"},aa=b({__name:"VPNavScreenMenuGroupSection",props:{text:{},items:{}},setup(o){return(e,t)=>(a(),l("div",sa,[e.text?(a(),l("p",oa,w(e.text),1)):m("",!0),(a(!0),l(M,null,B(e.items,s=>(a(),$(Re,{key:s.text,item:s},null,8,["item"]))),128))]))}}),ra=k(aa,[["__scopeId","data-v-4b8941ac"]]),ia=["aria-controls","aria-expanded"],la=["innerHTML"],ca=["id"],ua={key:0,class:"item"},da={key:1,class:"item"},pa={key:2,class:"group"},va=b({__name:"VPNavScreenMenuGroup",props:{text:{},items:{}},setup(o){const e=o,t=T(!1),s=y(()=>`NavScreenGroup-${e.text.replace(" ","-").toLowerCase()}`);function n(){t.value=!t.value}return(r,c)=>(a(),l("div",{class:I(["VPNavScreenMenuGroup",{open:t.value}])},[p("button",{class:"button","aria-controls":s.value,"aria-expanded":t.value,onClick:n},[p("span",{class:"button-text",innerHTML:r.text},null,8,la),c[0]||(c[0]=p("span",{class:"vpi-plus button-icon"},null,-1))],8,ia),p("div",{id:s.value,class:"items"},[(a(!0),l(M,null,B(r.items,v=>(a(),l(M,{key:JSON.stringify(v)},["link"in v?(a(),l("div",ua,[g(Re,{item:v},null,8,["item"])])):"component"in v?(a(),l("div",da,[(a(),$(O(v.component),j({ref_for:!0},v.props,{"screen-menu":""}),null,16))])):(a(),l("div",pa,[g(ra,{text:v.text,items:v.items},null,8,["text","items"])]))],64))),128))],8,ca)],2))}}),Ue=k(va,[["__scopeId","data-v-875057a5"]]),fa={key:0,class:"VPNavScreenMenu"},ma=b({__name:"VPNavScreenMenu",setup(o){const{theme:e}=L();return(t,s)=>i(e).nav?(a(),l("nav",fa,[(a(!0),l(M,null,B(i(e).nav,n=>(a(),l(M,{key:JSON.stringify(n)},["link"in n?(a(),$(ea,{key:0,item:n},null,8,["item"])):"component"in n?(a(),$(O(n.component),j({key:1,ref_for:!0},n.props,{"screen-menu":""}),null,16)):(a(),$(Ue,{key:2,text:n.text||"",items:n.items},null,8,["text","items"]))],64))),128))])):m("",!0)}}),ha=b({__name:"VPNavScreenSocialLinks",setup(o){const{theme:e}=L();return(t,s)=>i(e).socialLinks?(a(),$(se,{key:0,class:"VPNavScreenSocialLinks",links:i(e).socialLinks},null,8,["links"])):m("",!0)}}),_a={class:"list"},ba=b({__name:"VPNavScreenTranslations",setup(o){const{localeLinks:e,currentLang:t}=Y({correspondingLink:!0}),s=T(!1);function n(){s.value=!s.value}return(r,c)=>i(e).length&&i(t).label?(a(),l("div",{key:0,class:I(["VPNavScreenTranslations",{open:s.value}])},[p("button",{class:"title",onClick:n},[c[0]||(c[0]=p("span",{class:"vpi-languages icon lang"},null,-1)),F(" "+w(i(t).label)+" ",1),c[1]||(c[1]=p("span",{class:"vpi-chevron-down icon chevron"},null,-1))]),p("ul",_a,[(a(!0),l(M,null,B(i(e),v=>(a(),l("li",{key:v.link,class:"item"},[g(H,{class:"link",href:v.link},{default:f(()=>[F(w(v.text),1)]),_:2},1032,["href"])]))),128))])],2)):m("",!0)}}),ka=k(ba,[["__scopeId","data-v-362991c2"]]),ga={class:"container"},$a=b({__name:"VPNavScreen",props:{open:{type:Boolean}},setup(o){const e=T(null),t=Ce(te?document.body:null);return(s,n)=>(a(),$(pe,{name:"fade",onEnter:n[0]||(n[0]=r=>t.value=!0),onAfterLeave:n[1]||(n[1]=r=>t.value=!1)},{default:f(()=>[s.open?(a(),l("div",{key:0,class:"VPNavScreen",ref_key:"screen",ref:e,id:"VPNavScreen"},[p("div",ga,[u(s.$slots,"nav-screen-content-before",{},void 0,!0),g(ma,{class:"menu"}),g(ka,{class:"translations"}),g(Xo,{class:"appearance"}),g(ha,{class:"social-links"}),u(s.$slots,"nav-screen-content-after",{},void 0,!0)])],512)):m("",!0)]),_:3}))}}),ya=k($a,[["__scopeId","data-v-833aabba"]]),Pa={key:0,class:"VPNav"},Va=b({__name:"VPNav",setup(o){const{isScreenOpen:e,closeScreen:t,toggleScreen:s}=gs(),{frontmatter:n}=L(),r=y(()=>n.value.navbar!==!1);return he("close-screen",t),Z(()=>{te&&document.documentElement.classList.toggle("hide-nav",!r.value)}),(c,v)=>r.value?(a(),l("header",Pa,[g(Wo,{"is-screen-open":i(e),onToggleScreen:i(s)},{"nav-bar-title-before":f(()=>[u(c.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":f(()=>[u(c.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":f(()=>[u(c.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":f(()=>[u(c.$slots,"nav-bar-content-after",{},void 0,!0)]),_:3},8,["is-screen-open","onToggleScreen"]),g(ya,{open:i(e)},{"nav-screen-content-before":f(()=>[u(c.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":f(()=>[u(c.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3},8,["open"])])):m("",!0)}}),Sa=k(Va,[["__scopeId","data-v-f1e365da"]]),La=["role","tabindex"],Ta={key:1,class:"items"},wa=b({__name:"VPSidebarItem",props:{item:{},depth:{}},setup(o){const e=o,{collapsed:t,collapsible:s,isLink:n,isActiveLink:r,hasActiveLink:c,hasChildren:v,toggle:d}=Pt(y(()=>e.item)),h=y(()=>v.value?"section":"div"),P=y(()=>n.value?"a":"div"),_=y(()=>v.value?e.depth+2===7?"p":`h${e.depth+2}`:"p"),V=y(()=>n.value?void 0:"button"),S=y(()=>[[`level-${e.depth}`],{collapsible:s.value},{collapsed:t.value},{"is-link":n.value},{"is-active":r.value},{"has-active":c.value}]);function C(N){"key"in N&&N.key!=="Enter"||!e.item.link&&d()}function A(){e.item.link&&d()}return(N,E)=>{const z=K("VPSidebarItem",!0);return a(),$(O(h.value),{class:I(["VPSidebarItem",S.value])},{default:f(()=>[N.item.text?(a(),l("div",j({key:0,class:"item",role:V.value},et(N.item.items?{click:C,keydown:C}:{},!0),{tabindex:N.item.items&&0}),[E[1]||(E[1]=p("div",{class:"indicator"},null,-1)),N.item.link?(a(),$(H,{key:0,tag:P.value,class:"link",href:N.item.link,rel:N.item.rel,target:N.item.target},{default:f(()=>[(a(),$(O(_.value),{class:"text",innerHTML:N.item.text},null,8,["innerHTML"]))]),_:1},8,["tag","href","rel","target"])):(a(),$(O(_.value),{key:1,class:"text",innerHTML:N.item.text},null,8,["innerHTML"])),N.item.collapsed!=null&&N.item.items&&N.item.items.length?(a(),l("div",{key:2,class:"caret",role:"button","aria-label":"toggle section",onClick:A,onKeydown:xe(A,["enter"]),tabindex:"0"},E[0]||(E[0]=[p("span",{class:"vpi-chevron-right caret-icon"},null,-1)]),32)):m("",!0)],16,La)):m("",!0),N.item.items&&N.item.items.length?(a(),l("div",Ta,[N.depth<5?(a(!0),l(M,{key:0},B(N.item.items,q=>(a(),$(z,{key:q.text,item:q,depth:N.depth+1},null,8,["item","depth"]))),128)):m("",!0)])):m("",!0)]),_:1},8,["class"])}}}),Na=k(wa,[["__scopeId","data-v-196b2e5f"]]),Ia=b({__name:"VPSidebarGroup",props:{items:{}},setup(o){const e=T(!0);let t=null;return R(()=>{t=setTimeout(()=>{t=null,e.value=!1},300)}),tt(()=>{t!=null&&(clearTimeout(t),t=null)}),(s,n)=>(a(!0),l(M,null,B(s.items,r=>(a(),l("div",{key:r.text,class:I(["group",{"no-transition":e.value}])},[g(Na,{item:r,depth:0},null,8,["item"])],2))),128))}}),Ma=k(Ia,[["__scopeId","data-v-9e426adc"]]),Ca={class:"nav",id:"VPSidebarNav","aria-labelledby":"sidebar-aria-label",tabindex:"-1"},Aa=b({__name:"VPSidebar",props:{open:{type:Boolean}},setup(o){const{sidebarGroups:e,hasSidebar:t}=U(),s=o,n=T(null),r=Ce(te?document.body:null);D([s,n],()=>{var v;s.open?(r.value=!0,(v=n.value)==null||v.focus()):r.value=!1},{immediate:!0,flush:"post"});const c=T(0);return D(e,()=>{c.value+=1},{deep:!0}),(v,d)=>i(t)?(a(),l("aside",{key:0,class:I(["VPSidebar",{open:v.open}]),ref_key:"navEl",ref:n,onClick:d[0]||(d[0]=nt(()=>{},["stop"]))},[d[2]||(d[2]=p("div",{class:"curtain"},null,-1)),p("nav",Ca,[d[1]||(d[1]=p("span",{class:"visually-hidden",id:"sidebar-aria-label"}," Sidebar Navigation ",-1)),u(v.$slots,"sidebar-nav-before",{},void 0,!0),(a(),$(Ma,{items:i(e),key:c.value},null,8,["items"])),u(v.$slots,"sidebar-nav-after",{},void 0,!0)])],2)):m("",!0)}}),Ba=k(Aa,[["__scopeId","data-v-18756405"]]),Ea=b({__name:"VPSkipLink",setup(o){const e=ee(),t=T();D(()=>e.path,()=>t.value.focus());function s({target:n}){const r=document.getElementById(decodeURIComponent(n.hash).slice(1));if(r){const c=()=>{r.removeAttribute("tabindex"),r.removeEventListener("blur",c)};r.setAttribute("tabindex","-1"),r.addEventListener("blur",c),r.focus(),window.scrollTo(0,0)}}return(n,r)=>(a(),l(M,null,[p("span",{ref_key:"backToTop",ref:t,tabindex:"-1"},null,512),p("a",{href:"#VPContent",class:"VPSkipLink visually-hidden",onClick:s}," Skip to content ")],64))}}),Ha=k(Ea,[["__scopeId","data-v-c3508ec8"]]),Oa=b({__name:"Layout",setup(o){const{isOpen:e,open:t,close:s}=U(),n=ee();D(()=>n.path,s),yt(e,s);const{frontmatter:r}=L(),c=Ae(),v=y(()=>!!c["home-hero-image"]);return he("hero-image-slot-exists",v),(d,h)=>{const P=K("Content");return i(r).layout!==!1?(a(),l("div",{key:0,class:I(["Layout",i(r).pageClass])},[u(d.$slots,"layout-top",{},void 0,!0),g(Ha),g(ct,{class:"backdrop",show:i(e),onClick:i(s)},null,8,["show","onClick"]),g(Sa,null,{"nav-bar-title-before":f(()=>[u(d.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":f(()=>[u(d.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":f(()=>[u(d.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":f(()=>[u(d.$slots,"nav-bar-content-after",{},void 0,!0)]),"nav-screen-content-before":f(()=>[u(d.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":f(()=>[u(d.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3}),g(ks,{open:i(e),onOpenMenu:i(t)},null,8,["open","onOpenMenu"]),g(Ba,{open:i(e)},{"sidebar-nav-before":f(()=>[u(d.$slots,"sidebar-nav-before",{},void 0,!0)]),"sidebar-nav-after":f(()=>[u(d.$slots,"sidebar-nav-after",{},void 0,!0)]),_:3},8,["open"]),g(ss,null,{"page-top":f(()=>[u(d.$slots,"page-top",{},void 0,!0)]),"page-bottom":f(()=>[u(d.$slots,"page-bottom",{},void 0,!0)]),"not-found":f(()=>[u(d.$slots,"not-found",{},void 0,!0)]),"home-hero-before":f(()=>[u(d.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info-before":f(()=>[u(d.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":f(()=>[u(d.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":f(()=>[u(d.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":f(()=>[u(d.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":f(()=>[u(d.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":f(()=>[u(d.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":f(()=>[u(d.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":f(()=>[u(d.$slots,"home-features-after",{},void 0,!0)]),"doc-footer-before":f(()=>[u(d.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":f(()=>[u(d.$slots,"doc-before",{},void 0,!0)]),"doc-after":f(()=>[u(d.$slots,"doc-after",{},void 0,!0)]),"doc-top":f(()=>[u(d.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":f(()=>[u(d.$slots,"doc-bottom",{},void 0,!0)]),"aside-top":f(()=>[u(d.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":f(()=>[u(d.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":f(()=>[u(d.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":f(()=>[u(d.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":f(()=>[u(d.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":f(()=>[u(d.$slots,"aside-ads-after",{},void 0,!0)]),_:3}),g(ls),u(d.$slots,"layout-bottom",{},void 0,!0)],2)):(a(),$(P,{key:1}))}}}),Da=k(Oa,[["__scopeId","data-v-a9a9e638"]]),Fa={},Ra={class:"VPTeamPage"};function Ua(o,e){return a(),l("div",Ra,[u(o.$slots,"default")])}const Or=k(Fa,[["render",Ua],["__scopeId","data-v-c2f8e101"]]),za={},ja={class:"VPTeamPageTitle"},Ga={key:0,class:"title"},Ka={key:1,class:"lead"};function qa(o,e){return a(),l("div",ja,[o.$slots.title?(a(),l("h1",Ga,[u(o.$slots,"title",{},void 0,!0)])):m("",!0),o.$slots.lead?(a(),l("p",Ka,[u(o.$slots,"lead",{},void 0,!0)])):m("",!0)])}const Dr=k(za,[["render",qa],["__scopeId","data-v-e277e15c"]]),Wa={},Ja={class:"VPTeamPageSection"},Ya={class:"title"},Qa={key:0,class:"title-text"},Xa={key:0,class:"lead"},Za={key:1,class:"members"};function xa(o,e){return a(),l("section",Ja,[p("div",Ya,[e[0]||(e[0]=p("div",{class:"title-line"},null,-1)),o.$slots.title?(a(),l("h2",Qa,[u(o.$slots,"title",{},void 0,!0)])):m("",!0)]),o.$slots.lead?(a(),l("p",Xa,[u(o.$slots,"lead",{},void 0,!0)])):m("",!0),o.$slots.members?(a(),l("div",Za,[u(o.$slots,"members",{},void 0,!0)])):m("",!0)])}const Fr=k(Wa,[["render",xa],["__scopeId","data-v-d43bc49d"]]),er={class:"profile"},tr={class:"avatar"},nr=["src","alt"],sr={class:"data"},or={class:"name"},ar={key:0,class:"affiliation"},rr={key:0,class:"title"},ir={key:1,class:"at"},lr=["innerHTML"],cr={key:2,class:"links"},ur={key:0,class:"sp"},dr=b({__name:"VPTeamMembersItem",props:{size:{default:"medium"},member:{}},setup(o){return(e,t)=>(a(),l("article",{class:I(["VPTeamMembersItem",[e.size]])},[p("div",er,[p("figure",tr,[p("img",{class:"avatar-img",src:e.member.avatar,alt:e.member.name},null,8,nr)]),p("div",sr,[p("h1",or,w(e.member.name),1),e.member.title||e.member.org?(a(),l("p",ar,[e.member.title?(a(),l("span",rr,w(e.member.title),1)):m("",!0),e.member.title&&e.member.org?(a(),l("span",ir," @ ")):m("",!0),e.member.org?(a(),$(H,{key:2,class:I(["org",{link:e.member.orgLink}]),href:e.member.orgLink,"no-icon":""},{default:f(()=>[F(w(e.member.org),1)]),_:1},8,["class","href"])):m("",!0)])):m("",!0),e.member.desc?(a(),l("p",{key:1,class:"desc",innerHTML:e.member.desc},null,8,lr)):m("",!0),e.member.links?(a(),l("div",cr,[g(se,{links:e.member.links},null,8,["links"])])):m("",!0)])]),e.member.sponsor?(a(),l("div",ur,[g(H,{class:"sp-link",href:e.member.sponsor,"no-icon":""},{default:f(()=>[t[0]||(t[0]=p("span",{class:"vpi-heart sp-icon"},null,-1)),F(" "+w(e.member.actionText||"Sponsor"),1)]),_:1},8,["href"])])):m("",!0)],2))}}),pr=k(dr,[["__scopeId","data-v-f9987cb6"]]),vr={class:"container"},fr=b({__name:"VPTeamMembers",props:{size:{default:"medium"},members:{}},setup(o){const e=o,t=y(()=>[e.size,`count-${e.members.length}`]);return(s,n)=>(a(),l("div",{class:I(["VPTeamMembers",t.value])},[p("div",vr,[(a(!0),l(M,null,B(s.members,r=>(a(),l("div",{key:r.name,class:"item"},[g(pr,{size:s.size,member:r},null,8,["size","member"])]))),128))])],2))}}),Rr=k(fr,[["__scopeId","data-v-fba19bad"]]),Ve={Layout:Da,enhanceApp:({app:o})=>{o.component("Badge",rt)}},mr={};function hr(o,e){return e[0]||(e[0]=st('

    Trusted by

    Scientific Computing

    SciML.ai

    Machine Learning

    ',3))}const _r=k(mr,[["render",hr]]),br=b({__name:"VersionPicker",props:{screenMenu:{type:Boolean}},setup(o){const e=T([]),t=T("Versions"),s=T(!1);Le();const n=()=>typeof window<"u"&&(window.location.hostname==="localhost"||window.location.hostname==="127.0.0.1"),r=()=>{if(typeof window>"u")return"";const{origin:d,pathname:h}=window.location;if(d.includes("github.io")){const P=h.split("/").filter(Boolean),_=P.length>0?`/${P[0]}/`:"/";return`${d}${_}`}else return d},c=()=>new Promise(d=>{if(n()){d(!1);return}const h=setInterval(()=>{window.DOC_VERSIONS&&window.DOCUMENTER_CURRENT_VERSION&&(clearInterval(h),d(!0))},100);setTimeout(()=>{clearInterval(h),d(!1)},5e3)});return R(async()=>{if(!(typeof window>"u")){try{if(n()){const d=["dev"];e.value=d.map(h=>({text:h,link:"/"})),t.value="dev"}else{const d=await c(),h=y(()=>r());if(d&&window.DOC_VERSIONS&&window.DOCUMENTER_CURRENT_VERSION)e.value=window.DOC_VERSIONS.map(P=>({text:P,link:`${h.value}/${P}/`})),t.value=window.DOCUMENTER_CURRENT_VERSION;else{const P=["dev"];e.value=P.map(_=>({text:_,link:`${h.value}/${_}/`})),t.value="dev"}}}catch(d){console.warn("Error loading versions:",d);const h=["dev"],P=y(()=>r());e.value=h.map(_=>({text:_,link:`${P.value}/${_}/`})),t.value="dev"}s.value=!0}}),(d,h)=>s.value?(a(),l(M,{key:0},[!d.screenMenu&&e.value.length>0?(a(),$(Fe,{key:0,item:{text:t.value,items:e.value},class:"VPVersionPicker"},null,8,["item"])):d.screenMenu&&e.value.length>0?(a(),$(Ue,{key:1,text:t.value,items:e.value,class:"VPVersionPicker"},null,8,["text","items"])):m("",!0)],64)):m("",!0)}}),kr=k(br,[["__scopeId","data-v-d483b3a6"]]),gr=o=>{if(typeof document>"u")return{stabilizeScrollPosition:n=>async(...r)=>n(...r)};const e=document.documentElement;return{stabilizeScrollPosition:s=>async(...n)=>{const r=s(...n),c=o.value;if(!c)return r;const v=c.offsetTop-e.scrollTop;return await Ie(),e.scrollTop=c.offsetTop-v,r}}},ze="vitepress:tabSharedState",J=typeof localStorage<"u"?localStorage:null,je="vitepress:tabsSharedState",$r=()=>{const o=J==null?void 0:J.getItem(je);if(o)try{return JSON.parse(o)}catch{}return{}},yr=o=>{J&&J.setItem(je,JSON.stringify(o))},Pr=o=>{const e=ot({});D(()=>e.content,(t,s)=>{t&&s&&yr(t)},{deep:!0}),o.provide(ze,e)},Vr=(o,e)=>{const t=W(ze);if(!t)throw new Error("[vitepress-plugin-tabs] TabsSharedState should be injected");R(()=>{t.content||(t.content=$r())});const s=T(),n=y({get(){var d;const c=e.value,v=o.value;if(c){const h=(d=t.content)==null?void 0:d[c];if(h&&v.includes(h))return h}else{const h=s.value;if(h)return h}return v[0]},set(c){const v=e.value;v?t.content&&(t.content[v]=c):s.value=c}});return{selected:n,select:c=>{n.value=c}}};let Se=0;const Sr=()=>(Se++,""+Se);function Lr(){const o=Ae();return y(()=>{var s;const t=(s=o.default)==null?void 0:s.call(o);return t?t.filter(n=>typeof n.type=="object"&&"__name"in n.type&&n.type.__name==="PluginTabsTab"&&n.props).map(n=>{var r;return(r=n.props)==null?void 0:r.label}):[]})}const Ge="vitepress:tabSingleState",Tr=o=>{he(Ge,o)},wr=()=>{const o=W(Ge);if(!o)throw new Error("[vitepress-plugin-tabs] TabsSingleState should be injected");return o},Nr={class:"plugin-tabs"},Ir=["id","aria-selected","aria-controls","tabindex","onClick"],Mr=b({__name:"PluginTabs",props:{sharedStateKey:{}},setup(o){const e=o,t=Lr(),{selected:s,select:n}=Vr(t,at(e,"sharedStateKey")),r=T(),{stabilizeScrollPosition:c}=gr(r),v=c(n),d=T([]),h=_=>{var C;const V=t.value.indexOf(s.value);let S;_.key==="ArrowLeft"?S=V>=1?V-1:t.value.length-1:_.key==="ArrowRight"&&(S=V(a(),l("div",Nr,[p("div",{ref_key:"tablist",ref:r,class:"plugin-tabs--tab-list",role:"tablist",onKeydown:h},[(a(!0),l(M,null,B(i(t),S=>(a(),l("button",{id:`tab-${S}-${i(P)}`,ref_for:!0,ref_key:"buttonRefs",ref:d,key:S,role:"tab",class:"plugin-tabs--tab","aria-selected":S===i(s),"aria-controls":`panel-${S}-${i(P)}`,tabindex:S===i(s)?0:-1,onClick:()=>i(v)(S)},w(S),9,Ir))),128))],544),u(_.$slots,"default")]))}}),Cr=["id","aria-labelledby"],Ar=b({__name:"PluginTabsTab",props:{label:{}},setup(o){const{uid:e,selected:t}=wr();return(s,n)=>i(t)===s.label?(a(),l("div",{key:0,id:`panel-${s.label}-${i(e)}`,class:"plugin-tabs--content",role:"tabpanel",tabindex:"0","aria-labelledby":`tab-${s.label}-${i(e)}`},[u(s.$slots,"default",{},void 0,!0)],8,Cr)):m("",!0)}}),Br=k(Ar,[["__scopeId","data-v-9b0d03d2"]]),Er=o=>{Pr(o),o.component("PluginTabs",Mr),o.component("PluginTabsTab",Br)},Ur={extends:Ve,Layout(){return ye(Ve.Layout,null,{"aside-ads-before":()=>ye(_r)})},enhanceApp({app:o}){Er(o),o.component("VersionPicker",kr)}};export{Ur as R,Dr as V,Fr as a,Rr as b,Or as c,yo as d,L as u}; diff --git a/previews/PR1023/assets/ecosystem.md.CN8yStnf.js b/previews/PR1023/assets/ecosystem.md.CN8yStnf.js new file mode 100644 index 0000000000..b35b946dd1 --- /dev/null +++ b/previews/PR1023/assets/ecosystem.md.CN8yStnf.js @@ -0,0 +1 @@ +import{V as d,a as s,b as l,c as f}from"./chunks/theme.BkveSZIg.js";import{c as k,G as t,w as a,k as e,o as L,a as n}from"./chunks/framework.DFwXuivk.js";const x=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"page"},"headers":[],"relativePath":"ecosystem.md","filePath":"ecosystem.md","lastUpdated":null}'),j={name:"ecosystem.md"},J=Object.assign(j,{setup(v){const o=[{avatar:"https://github.com/SciML.png",name:"DiffEqFlux.jl",desc:"Universal neural differential equations with O(1) backprop, GPUs, and stiff+non-stiff DE solvers, demonstrating scientific machine learning (SciML) and physics-informed machine learning methods",links:[{icon:"github",link:"https://github.com/SciML/DiffEqFlux.jl"}]},{avatar:"https://github.com/SciML.png",name:"SciMLSensitivity.jl",desc:"A component of the DiffEq ecosystem for enabling sensitivity analysis for scientific machine learning (SciML). Optimize-then-discretize, discretize-then-optimize, adjoint methods, and more for ODEs, SDEs, DDEs, DAEs, etc.",links:[{icon:"github",link:"https://github.com/SciML/SciMLSensitivity.jl"}]},{avatar:"https://github.com/SciML.png",name:"NeuralPDE.jl",desc:"Physics-Informed Neural Networks (PINN) and Deep BSDE Solvers of Differential Equations for Scientific Machine Learning (SciML) accelerated simulation",links:[{icon:"github",link:"https://github.com/SciML/NeuralPDE.jl"}]},{avatar:"https://github.com/SciML.png",name:"NeuralLyapunov.jl",desc:"A library for searching for neural Lyapunov functions in Julia",links:[{icon:"github",link:"https://github.com/SciML/NeuralLyapunov.jl"}]},{avatar:"https://github.com/SciML.png",name:"DeepEquilibriumNetworks.jl",desc:"Implicit Layer Machine Learning via Deep Equilibrium Networks, O(1) backpropagation with accelerated convergence",links:[{icon:"github",link:"https://github.com/SciML/DeepEquilibriumNetworks.jl"}]},{avatar:"https://github.com/CosmologicalEmulators.png",name:"AbstractCosmologicalEmulators.jl",desc:"Repository containing the abstract interface to the emulators used in the CosmologicalEmulators organization",links:[{icon:"github",link:"https://github.com/CosmologicalEmulators/AbstractCosmologicalEmulators.jl"}]},{avatar:"https://github.com/impICNF.png",name:"ContinuousNormalizingFlows.jl",desc:"Implementations of Infinitesimal Continuous Normalizing Flows Algorithms in Julia",links:[{icon:"github",link:"https://github.com/impICNF/ContinuousNormalizingFlows.jl"}]},{avatar:"https://github.com/YichengDWu.png",name:"Sophon.jl",desc:"Efficient, Accurate, and Streamlined Training of Physics-Informed Neural Networks",links:[{icon:"github",link:"https://github.com/YichengDWu/Sophon.jl"}]},{avatar:"https://github.com/SciML.png",name:"DataDrivenDiffEq.jl",desc:"Data driven modeling and automated discovery of dynamical systems for the SciML Scientific Machine Learning organization",links:[{icon:"github",link:"https://github.com/SciML/DataDrivenDiffEq.jl"}]},{avatar:"https://github.com/YichengDWu.png",name:"NeuralGraphPDE.jl",desc:"Integrating Neural Ordinary Differential Equations, the Method of Lines, and Graph Neural Networks",links:[{icon:"github",link:"https://github.com/YichengDWu/NeuralGraphPDE.jl"}]},{avatar:"https://github.com/vavrines.png",name:"Solaris.jl",desc:"Lightweight module for fusing physical and neural models",links:[{icon:"github",link:"https://github.com/vavrines/Solaris.jl"}]},{avatar:"https://github.com/LuxDL.png",name:"Boltz.jl",desc:" Accelerate your ML research using pre-built Deep Learning Models with Lux",links:[{icon:"github",link:"https://github.com/LuxDL/Boltz.jl"}]},{avatar:"https://github.com/JuliaGNI.png",name:"GeometricMachineLearning.jl",desc:"Structure Preserving Machine Learning Models in Julia",links:[{icon:"github",link:"https://github.com/JuliaGNI/GeometricMachineLearning.jl"}]},{avatar:"https://as1.ftcdn.net/jpg/01/09/84/42/220_F_109844212_NnLGUrn3RgMHQIuqSiLGlc9d419eK2dX.jpg",name:"Want to Add Your Package?",desc:'Open a PR in LuxDL/Lux.jl'}],r=[{avatar:"https://github.com/FluxML.png",name:"Zygote.jl",desc:"Lux.jl default choice for AD",links:[{icon:"github",link:"https://github.com/FluxML/Zygote.jl"}]},{avatar:"https://github.com/FluxML.png",name:"Tracker.jl",desc:"Well tested and robust AD library (might fail on edge cases)",links:[{icon:"github",link:"https://github.com/FluxML/Tracker.jl"}]},{avatar:"https://github.com/JuliaDiff.png",name:"ForwardDiff.jl",desc:"For forward mode AD support",links:[{icon:"github",link:"https://github.com/JuliaDiff/ForwardDiff.jl"}]},{avatar:"https://github.com/JuliaDiff.png",name:"ReverseDiff.jl",desc:"Tape based reverse mode AD (might fail on edge cases and doesn't work on GPU)",links:[{icon:"github",link:"https://github.com/JuliaDiff/ReverseDiff.jl"}]},{avatar:"https://github.com/EnzymeAD.png",name:"Enzyme.jl",desc:"Experimental Support but will become the Future Default",links:[{icon:"github",link:"https://github.com/EnzymeAD/Enzyme.jl"}]}],u=[{avatar:"https://github.com/JuliaML.png",name:"MLUtils.jl",desc:"Utilities and abstractions for Machine Learning tasks",links:[{icon:"github",link:"https://github.com/JuliaML/MLUtils.jl"}]},{avatar:"https://github.com/JuliaML.png",name:"MLDatasets.jl",desc:"Utility package for accessing common Machine Learning datasets in Julia",links:[{icon:"github",link:"https://github.com/JuliaML/MLDatasets.jl"}]},{avatar:"https://github.com/JuliaImages.png",name:"Images.jl",desc:"An image library for Julia",links:[{icon:"github",link:"https://github.com/JuliaImages/Images.jl"}]},{avatar:"https://github.com/FluxML.png",name:"DataAugmentation.jl",desc:"Flexible data augmentation library for machine and deep learning",links:[{icon:"github",link:"https://github.com/FluxML/DataAugmentation.jl"}]}],m=[{avatar:"https://github.com/FluxML.png",name:"NNlib.jl",desc:"Neural Network primitives with multiple backends",links:[{icon:"github",link:"https://github.com/FluxML/NNlib.jl"}]},{avatar:"https://github.com/LuxDL.png",name:"LuxLib.jl",desc:"Backend for Lux.jl",links:[{icon:"github",link:"https://github.com/LuxDL/tree/main/lib/LuxLib.jl"}]}],c=[{avatar:"https://github.com/SciML.png",name:"Optimization.jl",desc:"Unified API for Optimization in Julia",links:[{icon:"github",link:"https://github.com/SciML/Optimization.jl"}]},{avatar:"https://github.com/FluxML.png",name:"Optimisers.jl",desc:"Optimisers.jl defines many standard optimisers and utilities for learning loops",links:[{icon:"github",link:"https://github.com/FluxML/Optimisers.jl"}]},{avatar:"https://github.com/FluxML.png",name:"ParameterSchedulers.jl",desc:"Common hyperparameter scheduling for ML",links:[{icon:"github",link:"https://github.com/FluxML/ParameterSchedulers.jl"}]}],g=[{avatar:"https://github.com/FluxML.png",name:"Functors.jl",desc:"Parameterise all the things",links:[{icon:"github",link:"https://github.com/FluxML/Functors.jl"}]},{avatar:"https://github.com/jonniedie.png",name:"ComponentArrays.jl",desc:"Arrays with arbitrarily nested named components",links:[{icon:"github",link:"https://github.com/jonniedie/ComponentArrays.jl"}]}],h=[{avatar:"https://github.com/JuliaLang.png",name:"Serialization.jl",desc:"Provides serialization of Julia objects",links:[{icon:"github",link:"https://github.com/JuliaLang/julia/tree/master/stdlib/Serialization"}]},{avatar:"https://github.com/JuliaIO.png",name:"JLD2.jl",desc:"HDF5-compatible file format in pure Julia",links:[{icon:"github",link:"https://github.com/JuliaIO/JLD2.jl"}]}],p=[{avatar:"https://github.com/JuliaDiff.png",name:"FiniteDiff.jl",desc:"Fast non-allocating calculations of gradients, Jacobians, and Hessians with sparsity support",links:[{icon:"github",link:"https://github.com/JuliaDiff/FiniteDiff.jl"}]},{avatar:"https://github.com/JuliaDiff.png",name:"FiniteDifferences.jl",desc:"High accuracy derivatives, estimated via numerical finite differences (formerly FDM.jl)",links:[{icon:"github",link:"https://github.com/JuliaDiff/FiniteDifferences.jl"}]},{avatar:"https://github.com/aviatesk.png",name:"JET.jl",desc:"JET employs Julia's type inference system to detect potential bugs and type instabilities",links:[{icon:"github",link:"https://github.com/aviatesk/JET.jl"}]},{avatar:"https://github.com/LuxDL.png",name:"LuxTestUtils.jl",desc:"Collection of Functions useful for testing various packages in the Lux Ecosystem",links:[{icon:"github",link:"https://github.com/LuxDL/tree/main/lib/LuxTestUtils"}]}],b=[{avatar:"https://github.com/JuliaAI.png",name:"MLFlowClient.jl",desc:"Julia client for MLFlow",links:[{icon:"github",link:"https://github.com/JuliaAI/MLFlowClient.jl"}]},{avatar:"https://github.com/JuliaLogging.png",name:"TensorBoardLogger.jl",desc:"Easy peasy logging to TensorBoard with Julia",links:[{icon:"github",link:"https://github.com/JuliaLogging/TensorBoardLogger.jl"}]},{avatar:"https://github.com/avik-pal.png",name:"Wandb.jl",desc:"Unofficial Julia bindings for logging experiments to wandb.ai",links:[{icon:"github",link:"https://github.com/avik-pal/Wandb.jl"}]}];return(D,i)=>(L(),k("div",null,[t(e(f),null,{default:a(()=>[t(e(d),null,{title:a(()=>i[0]||(i[0]=[n("Ecosystem")])),_:1}),t(e(s),null,{title:a(()=>i[1]||(i[1]=[n("Frameworks Extending Lux.jl")])),members:a(()=>[t(e(l),{size:"small",members:o})]),_:1}),t(e(s),null,{title:a(()=>i[2]||(i[2]=[n("Automatic Differentiation")])),members:a(()=>[t(e(l),{size:"small",members:r})]),_:1}),t(e(s),null,{title:a(()=>i[3]||(i[3]=[n("Data Manipulation, Data Loading & Datasets")])),members:a(()=>[t(e(l),{size:"small",members:u})]),_:1}),t(e(s),null,{title:a(()=>i[4]||(i[4]=[n("Neural Network Primitives")])),members:a(()=>[t(e(l),{size:"small",members:m})]),_:1}),t(e(s),null,{title:a(()=>i[5]||(i[5]=[n("Optimization")])),members:a(()=>[t(e(l),{size:"small",members:c})]),_:1}),t(e(s),null,{title:a(()=>i[6]||(i[6]=[n("Parameter Manipulation")])),members:a(()=>[t(e(l),{size:"small",members:g})]),_:1}),t(e(s),null,{title:a(()=>i[7]||(i[7]=[n("Serialization")])),members:a(()=>[t(e(l),{size:"small",members:h})]),_:1}),t(e(s),null,{title:a(()=>i[8]||(i[8]=[n("Testing Utilities")])),members:a(()=>[t(e(l),{size:"small",members:p})]),_:1}),t(e(s),null,{title:a(()=>i[9]||(i[9]=[n("Training Visualization & Logging")])),members:a(()=>[t(e(l),{size:"small",members:b})]),_:1})]),_:1})]))}});export{x as __pageData,J as default}; diff --git a/previews/PR1023/assets/ecosystem.md.CN8yStnf.lean.js b/previews/PR1023/assets/ecosystem.md.CN8yStnf.lean.js new file mode 100644 index 0000000000..b35b946dd1 --- /dev/null +++ b/previews/PR1023/assets/ecosystem.md.CN8yStnf.lean.js @@ -0,0 +1 @@ +import{V as d,a as s,b as l,c as f}from"./chunks/theme.BkveSZIg.js";import{c as k,G as t,w as a,k as e,o as L,a as n}from"./chunks/framework.DFwXuivk.js";const x=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"page"},"headers":[],"relativePath":"ecosystem.md","filePath":"ecosystem.md","lastUpdated":null}'),j={name:"ecosystem.md"},J=Object.assign(j,{setup(v){const o=[{avatar:"https://github.com/SciML.png",name:"DiffEqFlux.jl",desc:"Universal neural differential equations with O(1) backprop, GPUs, and stiff+non-stiff DE solvers, demonstrating scientific machine learning (SciML) and physics-informed machine learning methods",links:[{icon:"github",link:"https://github.com/SciML/DiffEqFlux.jl"}]},{avatar:"https://github.com/SciML.png",name:"SciMLSensitivity.jl",desc:"A component of the DiffEq ecosystem for enabling sensitivity analysis for scientific machine learning (SciML). Optimize-then-discretize, discretize-then-optimize, adjoint methods, and more for ODEs, SDEs, DDEs, DAEs, etc.",links:[{icon:"github",link:"https://github.com/SciML/SciMLSensitivity.jl"}]},{avatar:"https://github.com/SciML.png",name:"NeuralPDE.jl",desc:"Physics-Informed Neural Networks (PINN) and Deep BSDE Solvers of Differential Equations for Scientific Machine Learning (SciML) accelerated simulation",links:[{icon:"github",link:"https://github.com/SciML/NeuralPDE.jl"}]},{avatar:"https://github.com/SciML.png",name:"NeuralLyapunov.jl",desc:"A library for searching for neural Lyapunov functions in Julia",links:[{icon:"github",link:"https://github.com/SciML/NeuralLyapunov.jl"}]},{avatar:"https://github.com/SciML.png",name:"DeepEquilibriumNetworks.jl",desc:"Implicit Layer Machine Learning via Deep Equilibrium Networks, O(1) backpropagation with accelerated convergence",links:[{icon:"github",link:"https://github.com/SciML/DeepEquilibriumNetworks.jl"}]},{avatar:"https://github.com/CosmologicalEmulators.png",name:"AbstractCosmologicalEmulators.jl",desc:"Repository containing the abstract interface to the emulators used in the CosmologicalEmulators organization",links:[{icon:"github",link:"https://github.com/CosmologicalEmulators/AbstractCosmologicalEmulators.jl"}]},{avatar:"https://github.com/impICNF.png",name:"ContinuousNormalizingFlows.jl",desc:"Implementations of Infinitesimal Continuous Normalizing Flows Algorithms in Julia",links:[{icon:"github",link:"https://github.com/impICNF/ContinuousNormalizingFlows.jl"}]},{avatar:"https://github.com/YichengDWu.png",name:"Sophon.jl",desc:"Efficient, Accurate, and Streamlined Training of Physics-Informed Neural Networks",links:[{icon:"github",link:"https://github.com/YichengDWu/Sophon.jl"}]},{avatar:"https://github.com/SciML.png",name:"DataDrivenDiffEq.jl",desc:"Data driven modeling and automated discovery of dynamical systems for the SciML Scientific Machine Learning organization",links:[{icon:"github",link:"https://github.com/SciML/DataDrivenDiffEq.jl"}]},{avatar:"https://github.com/YichengDWu.png",name:"NeuralGraphPDE.jl",desc:"Integrating Neural Ordinary Differential Equations, the Method of Lines, and Graph Neural Networks",links:[{icon:"github",link:"https://github.com/YichengDWu/NeuralGraphPDE.jl"}]},{avatar:"https://github.com/vavrines.png",name:"Solaris.jl",desc:"Lightweight module for fusing physical and neural models",links:[{icon:"github",link:"https://github.com/vavrines/Solaris.jl"}]},{avatar:"https://github.com/LuxDL.png",name:"Boltz.jl",desc:" Accelerate your ML research using pre-built Deep Learning Models with Lux",links:[{icon:"github",link:"https://github.com/LuxDL/Boltz.jl"}]},{avatar:"https://github.com/JuliaGNI.png",name:"GeometricMachineLearning.jl",desc:"Structure Preserving Machine Learning Models in Julia",links:[{icon:"github",link:"https://github.com/JuliaGNI/GeometricMachineLearning.jl"}]},{avatar:"https://as1.ftcdn.net/jpg/01/09/84/42/220_F_109844212_NnLGUrn3RgMHQIuqSiLGlc9d419eK2dX.jpg",name:"Want to Add Your Package?",desc:'Open a PR in LuxDL/Lux.jl'}],r=[{avatar:"https://github.com/FluxML.png",name:"Zygote.jl",desc:"Lux.jl default choice for AD",links:[{icon:"github",link:"https://github.com/FluxML/Zygote.jl"}]},{avatar:"https://github.com/FluxML.png",name:"Tracker.jl",desc:"Well tested and robust AD library (might fail on edge cases)",links:[{icon:"github",link:"https://github.com/FluxML/Tracker.jl"}]},{avatar:"https://github.com/JuliaDiff.png",name:"ForwardDiff.jl",desc:"For forward mode AD support",links:[{icon:"github",link:"https://github.com/JuliaDiff/ForwardDiff.jl"}]},{avatar:"https://github.com/JuliaDiff.png",name:"ReverseDiff.jl",desc:"Tape based reverse mode AD (might fail on edge cases and doesn't work on GPU)",links:[{icon:"github",link:"https://github.com/JuliaDiff/ReverseDiff.jl"}]},{avatar:"https://github.com/EnzymeAD.png",name:"Enzyme.jl",desc:"Experimental Support but will become the Future Default",links:[{icon:"github",link:"https://github.com/EnzymeAD/Enzyme.jl"}]}],u=[{avatar:"https://github.com/JuliaML.png",name:"MLUtils.jl",desc:"Utilities and abstractions for Machine Learning tasks",links:[{icon:"github",link:"https://github.com/JuliaML/MLUtils.jl"}]},{avatar:"https://github.com/JuliaML.png",name:"MLDatasets.jl",desc:"Utility package for accessing common Machine Learning datasets in Julia",links:[{icon:"github",link:"https://github.com/JuliaML/MLDatasets.jl"}]},{avatar:"https://github.com/JuliaImages.png",name:"Images.jl",desc:"An image library for Julia",links:[{icon:"github",link:"https://github.com/JuliaImages/Images.jl"}]},{avatar:"https://github.com/FluxML.png",name:"DataAugmentation.jl",desc:"Flexible data augmentation library for machine and deep learning",links:[{icon:"github",link:"https://github.com/FluxML/DataAugmentation.jl"}]}],m=[{avatar:"https://github.com/FluxML.png",name:"NNlib.jl",desc:"Neural Network primitives with multiple backends",links:[{icon:"github",link:"https://github.com/FluxML/NNlib.jl"}]},{avatar:"https://github.com/LuxDL.png",name:"LuxLib.jl",desc:"Backend for Lux.jl",links:[{icon:"github",link:"https://github.com/LuxDL/tree/main/lib/LuxLib.jl"}]}],c=[{avatar:"https://github.com/SciML.png",name:"Optimization.jl",desc:"Unified API for Optimization in Julia",links:[{icon:"github",link:"https://github.com/SciML/Optimization.jl"}]},{avatar:"https://github.com/FluxML.png",name:"Optimisers.jl",desc:"Optimisers.jl defines many standard optimisers and utilities for learning loops",links:[{icon:"github",link:"https://github.com/FluxML/Optimisers.jl"}]},{avatar:"https://github.com/FluxML.png",name:"ParameterSchedulers.jl",desc:"Common hyperparameter scheduling for ML",links:[{icon:"github",link:"https://github.com/FluxML/ParameterSchedulers.jl"}]}],g=[{avatar:"https://github.com/FluxML.png",name:"Functors.jl",desc:"Parameterise all the things",links:[{icon:"github",link:"https://github.com/FluxML/Functors.jl"}]},{avatar:"https://github.com/jonniedie.png",name:"ComponentArrays.jl",desc:"Arrays with arbitrarily nested named components",links:[{icon:"github",link:"https://github.com/jonniedie/ComponentArrays.jl"}]}],h=[{avatar:"https://github.com/JuliaLang.png",name:"Serialization.jl",desc:"Provides serialization of Julia objects",links:[{icon:"github",link:"https://github.com/JuliaLang/julia/tree/master/stdlib/Serialization"}]},{avatar:"https://github.com/JuliaIO.png",name:"JLD2.jl",desc:"HDF5-compatible file format in pure Julia",links:[{icon:"github",link:"https://github.com/JuliaIO/JLD2.jl"}]}],p=[{avatar:"https://github.com/JuliaDiff.png",name:"FiniteDiff.jl",desc:"Fast non-allocating calculations of gradients, Jacobians, and Hessians with sparsity support",links:[{icon:"github",link:"https://github.com/JuliaDiff/FiniteDiff.jl"}]},{avatar:"https://github.com/JuliaDiff.png",name:"FiniteDifferences.jl",desc:"High accuracy derivatives, estimated via numerical finite differences (formerly FDM.jl)",links:[{icon:"github",link:"https://github.com/JuliaDiff/FiniteDifferences.jl"}]},{avatar:"https://github.com/aviatesk.png",name:"JET.jl",desc:"JET employs Julia's type inference system to detect potential bugs and type instabilities",links:[{icon:"github",link:"https://github.com/aviatesk/JET.jl"}]},{avatar:"https://github.com/LuxDL.png",name:"LuxTestUtils.jl",desc:"Collection of Functions useful for testing various packages in the Lux Ecosystem",links:[{icon:"github",link:"https://github.com/LuxDL/tree/main/lib/LuxTestUtils"}]}],b=[{avatar:"https://github.com/JuliaAI.png",name:"MLFlowClient.jl",desc:"Julia client for MLFlow",links:[{icon:"github",link:"https://github.com/JuliaAI/MLFlowClient.jl"}]},{avatar:"https://github.com/JuliaLogging.png",name:"TensorBoardLogger.jl",desc:"Easy peasy logging to TensorBoard with Julia",links:[{icon:"github",link:"https://github.com/JuliaLogging/TensorBoardLogger.jl"}]},{avatar:"https://github.com/avik-pal.png",name:"Wandb.jl",desc:"Unofficial Julia bindings for logging experiments to wandb.ai",links:[{icon:"github",link:"https://github.com/avik-pal/Wandb.jl"}]}];return(D,i)=>(L(),k("div",null,[t(e(f),null,{default:a(()=>[t(e(d),null,{title:a(()=>i[0]||(i[0]=[n("Ecosystem")])),_:1}),t(e(s),null,{title:a(()=>i[1]||(i[1]=[n("Frameworks Extending Lux.jl")])),members:a(()=>[t(e(l),{size:"small",members:o})]),_:1}),t(e(s),null,{title:a(()=>i[2]||(i[2]=[n("Automatic Differentiation")])),members:a(()=>[t(e(l),{size:"small",members:r})]),_:1}),t(e(s),null,{title:a(()=>i[3]||(i[3]=[n("Data Manipulation, Data Loading & Datasets")])),members:a(()=>[t(e(l),{size:"small",members:u})]),_:1}),t(e(s),null,{title:a(()=>i[4]||(i[4]=[n("Neural Network Primitives")])),members:a(()=>[t(e(l),{size:"small",members:m})]),_:1}),t(e(s),null,{title:a(()=>i[5]||(i[5]=[n("Optimization")])),members:a(()=>[t(e(l),{size:"small",members:c})]),_:1}),t(e(s),null,{title:a(()=>i[6]||(i[6]=[n("Parameter Manipulation")])),members:a(()=>[t(e(l),{size:"small",members:g})]),_:1}),t(e(s),null,{title:a(()=>i[7]||(i[7]=[n("Serialization")])),members:a(()=>[t(e(l),{size:"small",members:h})]),_:1}),t(e(s),null,{title:a(()=>i[8]||(i[8]=[n("Testing Utilities")])),members:a(()=>[t(e(l),{size:"small",members:p})]),_:1}),t(e(s),null,{title:a(()=>i[9]||(i[9]=[n("Training Visualization & Logging")])),members:a(()=>[t(e(l),{size:"small",members:b})]),_:1})]),_:1})]))}});export{x as __pageData,J as default}; diff --git a/previews/PR1023/assets/index.md.B7q9VhVT.js b/previews/PR1023/assets/index.md.B7q9VhVT.js new file mode 100644 index 0000000000..f54e7abfc6 --- /dev/null +++ b/previews/PR1023/assets/index.md.B7q9VhVT.js @@ -0,0 +1,27 @@ +import{_ as i,c as a,a2 as t,o as n}from"./chunks/framework.DFwXuivk.js";const o=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"home","hero":{"name":"LuxDL Docs","text":"Elegant & Performant Scientific Machine Learning in JuliaLang","tagline":"A Pure Julia Deep Learning Framework designed for Scientific Machine Learning","actions":[{"theme":"brand","text":"Tutorials","link":"/tutorials"},{"theme":"alt","text":"Ecosystem","link":"/ecosystem"},{"theme":"alt","text":"API Reference 📚","link":"/api/Lux/layers"},{"theme":"alt","text":"View on GitHub","link":"https://github.com/LuxDL/Lux.jl"}],"image":{"src":"/lux-logo.svg","alt":"Lux.jl"}},"features":[{"icon":"🚀","title":"Fast & Extendible","details":"Lux.jl is written in Julia itself, making it extremely extendible. CUDA and AMDGPU are supported first-class, with experimental support for Metal Hardware.","link":"/introduction"},{"icon":"🧑‍🔬","title":"SciML ❤️ Lux","details":"Lux is the default choice for many SciML packages, including DiffEqFlux.jl, NeuralPDE.jl, and more.","link":"https://sciml.ai/"},{"icon":"🧩","title":"Uniquely Composable","details":"Lux.jl natively supports Arbitrary Parameter Types, making it uniquely composable with other Julia packages (and even Non-Julia packages).","link":"/api/Lux/contrib#Training"},{"icon":"🧪","title":"Well Tested","details":"Lux.jl tests every supported Automatic Differentiation Framework with every supported hardware backend against Finite Differences to prevent sneaky 🐛 in your code.","link":"/api/Testing_Functionality/LuxTestUtils"}]},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":null}'),e={name:"index.md"};function l(p,s,h,k,d,r){return n(),a("div",null,s[0]||(s[0]=[t(`

    How to Install Lux.jl?

    Its easy to install Lux.jl. Since Lux.jl is registered in the Julia General registry, you can simply run the following command in the Julia REPL:

    julia
    julia> using Pkg
    +julia> Pkg.add("Lux")

    If you want to use the latest unreleased version of Lux.jl, you can run the following command: (in most cases the released version will be same as the version on github)

    julia
    julia> using Pkg
    +julia> Pkg.add(url="https://github.com/LuxDL/Lux.jl")

    Want GPU Support?

    Install the following package(s):

    julia
    using Pkg
    +Pkg.add("LuxCUDA")
    +# or
    +Pkg.add(["CUDA", "cuDNN"])
    julia
    using Pkg
    +Pkg.add("AMDGPU")
    julia
    using Pkg
    +Pkg.add("Metal")
    julia
    using Pkg
    +Pkg.add("oneAPI")

    Run the following to access a device:

    julia
    using Lux, LuxCUDA
    +
    +const dev = gpu_device()
    julia
    using Lux, AMDGPU
    +
    +const dev = gpu_device()
    julia
    using Lux, Metal
    +
    +const dev = gpu_device()
    julia
    using Lux, oneAPI
    +
    +const dev = gpu_device()

    Want XLA Support?

    Install the following package:

    julia
    using Pkg;
    +Pkg.add("Reactant")

    Run the following to access a device:

    julia
    using Reactant, Lux
    +Reactant.set_default_backend("cpu") # default
    +
    +const dev = xla_device()
    julia
    using Reactant, Lux
    +Reactant.set_default_backend("gpu")
    +
    +const dev = xla_device()
    julia
    using Reactant, Lux
    +Reactant.set_default_backend("tpu")
    +
    +const dev = xla_device()
    `,15)]))}const E=i(e,[["render",l]]);export{o as __pageData,E as default}; diff --git a/previews/PR1023/assets/index.md.B7q9VhVT.lean.js b/previews/PR1023/assets/index.md.B7q9VhVT.lean.js new file mode 100644 index 0000000000..f54e7abfc6 --- /dev/null +++ b/previews/PR1023/assets/index.md.B7q9VhVT.lean.js @@ -0,0 +1,27 @@ +import{_ as i,c as a,a2 as t,o as n}from"./chunks/framework.DFwXuivk.js";const o=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"home","hero":{"name":"LuxDL Docs","text":"Elegant & Performant Scientific Machine Learning in JuliaLang","tagline":"A Pure Julia Deep Learning Framework designed for Scientific Machine Learning","actions":[{"theme":"brand","text":"Tutorials","link":"/tutorials"},{"theme":"alt","text":"Ecosystem","link":"/ecosystem"},{"theme":"alt","text":"API Reference 📚","link":"/api/Lux/layers"},{"theme":"alt","text":"View on GitHub","link":"https://github.com/LuxDL/Lux.jl"}],"image":{"src":"/lux-logo.svg","alt":"Lux.jl"}},"features":[{"icon":"🚀","title":"Fast & Extendible","details":"Lux.jl is written in Julia itself, making it extremely extendible. CUDA and AMDGPU are supported first-class, with experimental support for Metal Hardware.","link":"/introduction"},{"icon":"🧑‍🔬","title":"SciML ❤️ Lux","details":"Lux is the default choice for many SciML packages, including DiffEqFlux.jl, NeuralPDE.jl, and more.","link":"https://sciml.ai/"},{"icon":"🧩","title":"Uniquely Composable","details":"Lux.jl natively supports Arbitrary Parameter Types, making it uniquely composable with other Julia packages (and even Non-Julia packages).","link":"/api/Lux/contrib#Training"},{"icon":"🧪","title":"Well Tested","details":"Lux.jl tests every supported Automatic Differentiation Framework with every supported hardware backend against Finite Differences to prevent sneaky 🐛 in your code.","link":"/api/Testing_Functionality/LuxTestUtils"}]},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":null}'),e={name:"index.md"};function l(p,s,h,k,d,r){return n(),a("div",null,s[0]||(s[0]=[t(`

    How to Install Lux.jl?

    Its easy to install Lux.jl. Since Lux.jl is registered in the Julia General registry, you can simply run the following command in the Julia REPL:

    julia
    julia> using Pkg
    +julia> Pkg.add("Lux")

    If you want to use the latest unreleased version of Lux.jl, you can run the following command: (in most cases the released version will be same as the version on github)

    julia
    julia> using Pkg
    +julia> Pkg.add(url="https://github.com/LuxDL/Lux.jl")

    Want GPU Support?

    Install the following package(s):

    julia
    using Pkg
    +Pkg.add("LuxCUDA")
    +# or
    +Pkg.add(["CUDA", "cuDNN"])
    julia
    using Pkg
    +Pkg.add("AMDGPU")
    julia
    using Pkg
    +Pkg.add("Metal")
    julia
    using Pkg
    +Pkg.add("oneAPI")

    Run the following to access a device:

    julia
    using Lux, LuxCUDA
    +
    +const dev = gpu_device()
    julia
    using Lux, AMDGPU
    +
    +const dev = gpu_device()
    julia
    using Lux, Metal
    +
    +const dev = gpu_device()
    julia
    using Lux, oneAPI
    +
    +const dev = gpu_device()

    Want XLA Support?

    Install the following package:

    julia
    using Pkg;
    +Pkg.add("Reactant")

    Run the following to access a device:

    julia
    using Reactant, Lux
    +Reactant.set_default_backend("cpu") # default
    +
    +const dev = xla_device()
    julia
    using Reactant, Lux
    +Reactant.set_default_backend("gpu")
    +
    +const dev = xla_device()
    julia
    using Reactant, Lux
    +Reactant.set_default_backend("tpu")
    +
    +const dev = xla_device()
    `,15)]))}const E=i(e,[["render",l]]);export{o as __pageData,E as default}; diff --git a/previews/PR1023/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 b/previews/PR1023/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 new file mode 100644 index 0000000000..b6b603d596 Binary files /dev/null and b/previews/PR1023/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 differ diff --git a/previews/PR1023/assets/inter-italic-cyrillic.By2_1cv3.woff2 b/previews/PR1023/assets/inter-italic-cyrillic.By2_1cv3.woff2 new file mode 100644 index 0000000000..def40a4f65 Binary files /dev/null and b/previews/PR1023/assets/inter-italic-cyrillic.By2_1cv3.woff2 differ diff --git a/previews/PR1023/assets/inter-italic-greek-ext.1u6EdAuj.woff2 b/previews/PR1023/assets/inter-italic-greek-ext.1u6EdAuj.woff2 new file mode 100644 index 0000000000..e070c3d309 Binary files /dev/null and b/previews/PR1023/assets/inter-italic-greek-ext.1u6EdAuj.woff2 differ diff --git a/previews/PR1023/assets/inter-italic-greek.DJ8dCoTZ.woff2 b/previews/PR1023/assets/inter-italic-greek.DJ8dCoTZ.woff2 new file mode 100644 index 0000000000..a3c16ca40b Binary files /dev/null and b/previews/PR1023/assets/inter-italic-greek.DJ8dCoTZ.woff2 differ diff --git a/previews/PR1023/assets/inter-italic-latin-ext.CN1xVJS-.woff2 b/previews/PR1023/assets/inter-italic-latin-ext.CN1xVJS-.woff2 new file mode 100644 index 0000000000..2210a899ed Binary files /dev/null and b/previews/PR1023/assets/inter-italic-latin-ext.CN1xVJS-.woff2 differ diff --git a/previews/PR1023/assets/inter-italic-latin.C2AdPX0b.woff2 b/previews/PR1023/assets/inter-italic-latin.C2AdPX0b.woff2 new file mode 100644 index 0000000000..790d62dc7b Binary files /dev/null and b/previews/PR1023/assets/inter-italic-latin.C2AdPX0b.woff2 differ diff --git a/previews/PR1023/assets/inter-italic-vietnamese.BSbpV94h.woff2 b/previews/PR1023/assets/inter-italic-vietnamese.BSbpV94h.woff2 new file mode 100644 index 0000000000..1eec0775a6 Binary files /dev/null and b/previews/PR1023/assets/inter-italic-vietnamese.BSbpV94h.woff2 differ diff --git a/previews/PR1023/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 b/previews/PR1023/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 new file mode 100644 index 0000000000..2cfe61536e Binary files /dev/null and b/previews/PR1023/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 differ diff --git a/previews/PR1023/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 b/previews/PR1023/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 new file mode 100644 index 0000000000..e3886dd141 Binary files /dev/null and b/previews/PR1023/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 differ diff --git a/previews/PR1023/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 b/previews/PR1023/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 new file mode 100644 index 0000000000..36d67487dc Binary files /dev/null and b/previews/PR1023/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 differ diff --git a/previews/PR1023/assets/inter-roman-greek.BBVDIX6e.woff2 b/previews/PR1023/assets/inter-roman-greek.BBVDIX6e.woff2 new file mode 100644 index 0000000000..2bed1e85e8 Binary files /dev/null and b/previews/PR1023/assets/inter-roman-greek.BBVDIX6e.woff2 differ diff --git a/previews/PR1023/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 b/previews/PR1023/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 new file mode 100644 index 0000000000..9a8d1e2b5e Binary files /dev/null and b/previews/PR1023/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 differ diff --git a/previews/PR1023/assets/inter-roman-latin.Di8DUHzh.woff2 b/previews/PR1023/assets/inter-roman-latin.Di8DUHzh.woff2 new file mode 100644 index 0000000000..07d3c53aef Binary files /dev/null and b/previews/PR1023/assets/inter-roman-latin.Di8DUHzh.woff2 differ diff --git a/previews/PR1023/assets/inter-roman-vietnamese.BjW4sHH5.woff2 b/previews/PR1023/assets/inter-roman-vietnamese.BjW4sHH5.woff2 new file mode 100644 index 0000000000..57bdc22ae8 Binary files /dev/null and b/previews/PR1023/assets/inter-roman-vietnamese.BjW4sHH5.woff2 differ diff --git a/previews/PR1023/assets/introduction_citation.md.CC7Ayz4q.js b/previews/PR1023/assets/introduction_citation.md.CC7Ayz4q.js new file mode 100644 index 0000000000..a88aabaee5 --- /dev/null +++ b/previews/PR1023/assets/introduction_citation.md.CC7Ayz4q.js @@ -0,0 +1,16 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const F=JSON.parse('{"title":"Citation","description":"","frontmatter":{},"headers":[],"relativePath":"introduction/citation.md","filePath":"introduction/citation.md","lastUpdated":null}'),h={name:"introduction/citation.md"};function k(l,s,p,e,E,r){return t(),a("div",null,s[0]||(s[0]=[n(`

    Citation

    If you found this library to be useful in academic work, then please cite:

    bibtex
    @software{pal2023lux,
    +  author    = {Pal, Avik},
    +  title     = {{Lux: Explicit Parameterization of Deep Neural Networks in Julia}},
    +  month     = {April},
    +  year      = 2023,
    +  note      = {If you use this software, please cite it as below.},
    +  publisher = {Zenodo},
    +  version   = {v0.5.0},
    +  doi       = {10.5281/zenodo.7808904},
    +  url       = {https://doi.org/10.5281/zenodo.7808904}
    +}
    bibtex
    @thesis{pal2023efficient,
    +  title     = {{On Efficient Training \\& Inference of Neural Differential Equations}},
    +  author    = {Pal, Avik},
    +  year      = {2023},
    +  school    = {Massachusetts Institute of Technology}
    +}
    `,4)]))}const g=i(h,[["render",k]]);export{F as __pageData,g as default}; diff --git a/previews/PR1023/assets/introduction_citation.md.CC7Ayz4q.lean.js b/previews/PR1023/assets/introduction_citation.md.CC7Ayz4q.lean.js new file mode 100644 index 0000000000..a88aabaee5 --- /dev/null +++ b/previews/PR1023/assets/introduction_citation.md.CC7Ayz4q.lean.js @@ -0,0 +1,16 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const F=JSON.parse('{"title":"Citation","description":"","frontmatter":{},"headers":[],"relativePath":"introduction/citation.md","filePath":"introduction/citation.md","lastUpdated":null}'),h={name:"introduction/citation.md"};function k(l,s,p,e,E,r){return t(),a("div",null,s[0]||(s[0]=[n(`

    Citation

    If you found this library to be useful in academic work, then please cite:

    bibtex
    @software{pal2023lux,
    +  author    = {Pal, Avik},
    +  title     = {{Lux: Explicit Parameterization of Deep Neural Networks in Julia}},
    +  month     = {April},
    +  year      = 2023,
    +  note      = {If you use this software, please cite it as below.},
    +  publisher = {Zenodo},
    +  version   = {v0.5.0},
    +  doi       = {10.5281/zenodo.7808904},
    +  url       = {https://doi.org/10.5281/zenodo.7808904}
    +}
    bibtex
    @thesis{pal2023efficient,
    +  title     = {{On Efficient Training \\& Inference of Neural Differential Equations}},
    +  author    = {Pal, Avik},
    +  year      = {2023},
    +  school    = {Massachusetts Institute of Technology}
    +}
    `,4)]))}const g=i(h,[["render",k]]);export{F as __pageData,g as default}; diff --git a/previews/PR1023/assets/introduction_index.md.Do6486F0.js b/previews/PR1023/assets/introduction_index.md.Do6486F0.js new file mode 100644 index 0000000000..18d8e8c3bc --- /dev/null +++ b/previews/PR1023/assets/introduction_index.md.Do6486F0.js @@ -0,0 +1,111 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const E=JSON.parse('{"title":"Getting Started","description":"","frontmatter":{},"headers":[],"relativePath":"introduction/index.md","filePath":"introduction/index.md","lastUpdated":null}'),l={name:"introduction/index.md"};function e(p,s,h,k,r,d){return t(),a("div",null,s[0]||(s[0]=[n(`

    Getting Started

    Installation

    Install Julia v1.10 or above. Lux.jl is available through the Julia package manager. You can enter it by pressing ] in the REPL and then typing add Lux. Alternatively, you can also do

    julia
    import Pkg
    +Pkg.add("Lux")

    Update to v1

    If you are using a pre-v1 version of Lux.jl, please see the Updating to v1 section for instructions on how to update.

    Quickstart

    Pre-Requisites

    You need to install Optimisers and Zygote if not done already. Pkg.add(["Optimisers", "Zygote"])

    julia
    using Lux, Random, Optimisers, Zygote
    +using LuxCUDA # For CUDA support
    +# using AMDGPU, Metal, oneAPI # Other pptional packages for GPU support

    We take randomness very seriously

    julia
    # Seeding
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    Random.TaskLocalRNG()

    Build the model

    julia
    # Construct the layer
    +model = Chain(Dense(128, 256, tanh), Chain(Dense(256, 1, tanh), Dense(1, 10)))
    Chain(
    +    layer_1 = Dense(128 => 256, tanh),  # 33_024 parameters
    +    layer_2 = Chain(
    +        layer_1 = Dense(256 => 1, tanh),  # 257 parameters
    +        layer_2 = Dense(1 => 10),       # 20 parameters
    +    ),
    +)         # Total: 33_301 parameters,
    +          #        plus 0 states.

    Models don't hold parameters and states so initialize them. From there on, we can just use our standard AD and Optimisers API. However, here we will show how to use Lux's Training API that provides an uniform API over all supported AD systems.

    julia
    # Get the device determined by Lux
    +dev = gpu_device()
    +
    +# Parameter and State Variables
    +ps, st = Lux.setup(rng, model) |> dev
    +
    +# Dummy Input
    +x = rand(rng, Float32, 128, 2) |> dev
    +
    +# Run the model
    +y, st = Lux.apply(model, x, ps, st)
    +
    +# Gradients
    +## First construct a TrainState
    +train_state = Lux.Training.TrainState(model, ps, st, Adam(0.0001f0))
    +
    +## We can compute the gradients using Training.compute_gradients
    +gs, loss, stats, train_state = Lux.Training.compute_gradients(AutoZygote(), MSELoss(),
    +    (x, dev(rand(rng, Float32, 10, 2))), train_state)
    +
    +## Optimization
    +train_state = Training.apply_gradients!(train_state, gs) # or Training.apply_gradients (no \`!\` at the end)
    +
    +# Both these steps can be combined into a single call
    +gs, loss, stats, train_state = Training.single_train_step!(AutoZygote(), MSELoss(),
    +    (x, dev(rand(rng, Float32, 10, 2))), train_state)
    ((layer_1 = (weight = Float32[0.004144425 0.0027955552 … 0.004169049 0.0031376407; 0.002106787 0.0018510937 … 0.0024323382 0.001973281; … ; -0.0017369908 -0.0014175134 … -0.0019262917 -0.0015313211; 0.005014097 0.0012843215 … 0.00351666 0.0019504696], bias = Float32[0.0067729075, 0.0037725805, 0.0044189203, -0.008870317, 0.0024971329, 0.0034101289, 0.011739168, 0.0100971125, -0.012522168, -0.006184267  …  -0.0019153744, -0.0021203319, -0.006736353, -0.0061099795, -0.0017900232, 0.0053856913, 0.0022308934, -0.004047669, -0.003027094, 0.0065859724]), layer_2 = (layer_1 = (weight = Float32[0.009578831 3.793463f-5 … -0.047356773 0.04226003], bias = Float32[0.073442355]), layer_2 = (weight = Float32[-0.098861866; -0.09785451; … ; -0.022434518; -0.07412187;;], bias = Float32[-0.226381, -0.22459084, -0.2545935, -0.24099025, -0.07057328, -0.17239982, -0.17449912, 0.07704306, -0.050089, -0.16909766]))), 0.87143785f0, NamedTuple(), Lux.Training.TrainState{Nothing, Nothing, Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Nothing}, @NamedTuple{layer_1::@NamedTuple{weight::CuArray{Float32, 2, CUDA.DeviceMemory}, bias::CuArray{Float32, 1, CUDA.DeviceMemory}}, layer_2::@NamedTuple{layer_1::@NamedTuple{weight::CuArray{Float32, 2, CUDA.DeviceMemory}, bias::CuArray{Float32, 1, CUDA.DeviceMemory}}, layer_2::@NamedTuple{weight::CuArray{Float32, 2, CUDA.DeviceMemory}, bias::CuArray{Float32, 1, CUDA.DeviceMemory}}}}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}}}, Adam, @NamedTuple{layer_1::@NamedTuple{weight::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 2, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}, bias::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}}, layer_2::@NamedTuple{layer_1::@NamedTuple{weight::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 2, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}, bias::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}}, layer_2::@NamedTuple{weight::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 2, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}, bias::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}}}}}(nothing, nothing, Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Nothing}((layer_1 = Dense(128 => 256, tanh), layer_2 = Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}((layer_1 = Dense(256 => 1, tanh), layer_2 = Dense(1 => 10)), nothing)), nothing), (layer_1 = (weight = Float32[-0.22543387 0.2237958 … 0.19975941 -0.018701272; -0.023031702 0.15451166 … -0.065317236 0.181208; … ; 0.03804328 -0.07125676 … -0.03306928 0.039132368; -0.18811704 -0.09692798 … -0.18102339 0.019236464], bias = Float32[0.03094203, -0.06026962, 0.08456781, 0.0003920444, -0.06550143, -0.08526564, -0.026516732, 0.063480526, 0.04224006, 0.027702922  …  -0.06053336, 0.0350433, -0.028251555, 0.067872316, 0.0027386106, -0.06942138, 0.006432486, 0.014100174, -0.029290024, 0.011734666]), layer_2 = (layer_1 = (weight = Float32[0.11984776 0.060364496 … -0.07058401 0.1577715], bias = Float32[0.026851978]), layer_2 = (weight = Float32[0.5345716; -0.28289196; … ; -0.32984197; -0.45298263;;], bias = Float32[-0.5975106, -0.70330536, -0.84576, -0.5378918, -0.3147238, 0.1746128, -0.82945824, 0.6784163, 0.35836592, -0.14941669]))), (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple())), Adam(0.0001, (0.9, 0.999), 1.0e-8), (layer_1 = (weight = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.00139126 0.00077649 … 0.00128162 0.000910802; 0.000699265 0.000510198 … 0.000731462 0.000563284; … ; -0.000574894 -0.000391076 … -0.000580705 -0.000438132; 0.00170922 0.000374875 … 0.00115296 0.000609521], Float32[1.34855f-7 3.8271f-8 … 1.09599f-7 5.38068f-8; 3.38798f-8 1.64605f-8 … 3.53144f-8 2.04108f-8; … ; 2.28682f-8 9.67595f-9 … 2.22846f-8 1.23626f-8; 2.05058f-7 9.13988f-9 … 9.15542f-8 2.49913f-8], (0.729, 0.997003))), bias = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.00214946, 0.00117228, 0.00145586, -0.00270753, 0.00077338, 0.00106574, 0.00364828, 0.00306169, -0.0038745, -0.00198767  …  -0.000612726, -0.000689046, -0.00209504, -0.00187748, -0.000554918, 0.00175152, 0.000667028, -0.00126273, -0.000942026, 0.00219681], Float32[3.13168f-7, 9.21856f-8, 1.46327f-7, 4.87431f-7, 4.00564f-8, 7.64058f-8, 8.929f-7, 6.21252f-7, 1.00488f-6, 2.69472f-7  …  2.55476f-8, 3.25587f-8, 2.94557f-7, 2.35152f-7, 2.06325f-8, 2.10458f-7, 2.92832f-8, 1.07167f-7, 5.9572f-8, 3.35188f-7], (0.729, 0.997003)))), layer_2 = (layer_1 = (weight = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.0018058 -0.000936727 … -0.0146587 0.0123139], Float32[1.80423f-7 1.09098f-7 … 1.43866f-5 9.85344f-6], (0.729, 0.997003))), bias = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.0227737], Float32[3.47551f-5], (0.729, 0.997003)))), layer_2 = (weight = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[-0.0207926; -0.0231775; … ; -0.00706411; -0.0158726;;], Float32[2.44439f-5; 3.16946f-5; … ; 3.36938f-6; 1.4322f-5;;], (0.729, 0.997003))), bias = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[-0.0435721, -0.0480501, -0.0540537, -0.0420834, -0.0105465, -0.0302464, -0.0315817, 0.0244214, -0.0142814, -0.0330944], Float32[0.000105296, 0.00013121, 0.000165657, 9.79656f-5, 6.48203f-6, 5.0585f-5, 5.50798f-5, 4.04019f-5, 1.31128f-5, 6.08993f-5], (0.729, 0.997003)))))), 2))

    Defining Custom Layers

    julia
    using Lux, Random, Optimisers, Zygote
    +using LuxCUDA # For CUDA support
    +# using AMDGPU, Metal, oneAPI # Other pptional packages for GPU support
    +using Printf # For pretty printing
    +
    +dev = gpu_device()
    (::CUDADevice{Nothing}) (generic function with 4 methods)

    We will define a custom MLP using the @compact macro. The macro takes in a list of parameters, layers and states, and a function defining the forward pass of the neural network.

    julia
    n_in = 1
    +n_out = 1
    +nlayers = 3
    +
    +model = @compact(w1=Dense(n_in => 32),
    +    w2=[Dense(32 => 32) for i in 1:nlayers],
    +    w3=Dense(32 => n_out),
    +    act=relu) do x
    +    embed = act(w1(x))
    +    for w in w2
    +        embed = act(w(embed))
    +    end
    +    out = w3(embed)
    +    @return out
    +end
    @compact(
    +    w1 = Dense(1 => 32),                # 64 parameters
    +    w2 = NamedTuple(
    +        1 = Dense(32 => 32),            # 1_056 parameters
    +        2 = Dense(32 => 32),            # 1_056 parameters
    +        3 = Dense(32 => 32),            # 1_056 parameters
    +    ),
    +    w3 = Dense(32 => 1),                # 33 parameters
    +    act = relu,
    +) do x 
    +    embed = act(w1(x))
    +    for w = w2
    +        embed = act(w(embed))
    +    end
    +    out = w3(embed)
    +    return out
    +end       # Total: 3_265 parameters,
    +          #        plus 1 states.

    We can initialize the model and train it with the same code as before!

    julia
    rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +ps, st = Lux.setup(Xoshiro(0), model) |> dev
    +
    +x = rand(rng, Float32, n_in, 32) |> dev
    +
    +model(x, ps, st)  # 1×32 Matrix and updated state as output.
    +
    +x_data = reshape(collect(-2.0f0:0.1f0:2.0f0), 1, :) |> dev
    +y_data = 2 .* x_data .- x_data .^ 3
    +
    +function train_model!(model, ps, st, x_data, y_data)
    +    train_state = Lux.Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    for iter in 1:1000
    +        _, loss, _, train_state = Lux.Training.single_train_step!(AutoZygote(), MSELoss(),
    +            (x_data, y_data), train_state)
    +        if iter % 100 == 1 || iter == 1000
    +            @printf "Iteration: %04d \\t Loss: %10.9g\\n" iter loss
    +        end
    +    end
    +
    +    return model, ps, st
    +end
    +
    +train_model!(model, ps, st, x_data, y_data)
    Iteration: 0001 	 Loss: 2.08085155
    +Iteration: 0101 	 Loss: 0.131583631
    +Iteration: 0201 	 Loss: 0.00390526722
    +Iteration: 0301 	 Loss: 0.000871024327
    +Iteration: 0401 	 Loss: 0.000441076729
    +Iteration: 0501 	 Loss: 0.000454922556
    +Iteration: 0601 	 Loss: 0.00036629336
    +Iteration: 0701 	 Loss: 0.00015113852
    +Iteration: 0801 	 Loss: 0.000239130808
    +Iteration: 0901 	 Loss: 0.00140763051
    +Iteration: 1000 	 Loss: 0.000214067404

    Training with Optimization.jl

    If you are coming from the SciML ecosystem and want to use Optimization.jl, please refer to the Optimization.jl Tutorial.

    Additional Packages

    LuxDL hosts various packages that provide additional functionality for Lux.jl. All packages mentioned in this documentation are available via the Julia General Registry.

    You can install all those packages via import Pkg; Pkg.add(<package name>).

    GPU Support

    GPU Support for Lux.jl requires loading additional packages:

    `,33)]))}const o=i(l,[["render",e]]);export{E as __pageData,o as default}; diff --git a/previews/PR1023/assets/introduction_index.md.Do6486F0.lean.js b/previews/PR1023/assets/introduction_index.md.Do6486F0.lean.js new file mode 100644 index 0000000000..18d8e8c3bc --- /dev/null +++ b/previews/PR1023/assets/introduction_index.md.Do6486F0.lean.js @@ -0,0 +1,111 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const E=JSON.parse('{"title":"Getting Started","description":"","frontmatter":{},"headers":[],"relativePath":"introduction/index.md","filePath":"introduction/index.md","lastUpdated":null}'),l={name:"introduction/index.md"};function e(p,s,h,k,r,d){return t(),a("div",null,s[0]||(s[0]=[n(`

    Getting Started

    Installation

    Install Julia v1.10 or above. Lux.jl is available through the Julia package manager. You can enter it by pressing ] in the REPL and then typing add Lux. Alternatively, you can also do

    julia
    import Pkg
    +Pkg.add("Lux")

    Update to v1

    If you are using a pre-v1 version of Lux.jl, please see the Updating to v1 section for instructions on how to update.

    Quickstart

    Pre-Requisites

    You need to install Optimisers and Zygote if not done already. Pkg.add(["Optimisers", "Zygote"])

    julia
    using Lux, Random, Optimisers, Zygote
    +using LuxCUDA # For CUDA support
    +# using AMDGPU, Metal, oneAPI # Other pptional packages for GPU support

    We take randomness very seriously

    julia
    # Seeding
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    Random.TaskLocalRNG()

    Build the model

    julia
    # Construct the layer
    +model = Chain(Dense(128, 256, tanh), Chain(Dense(256, 1, tanh), Dense(1, 10)))
    Chain(
    +    layer_1 = Dense(128 => 256, tanh),  # 33_024 parameters
    +    layer_2 = Chain(
    +        layer_1 = Dense(256 => 1, tanh),  # 257 parameters
    +        layer_2 = Dense(1 => 10),       # 20 parameters
    +    ),
    +)         # Total: 33_301 parameters,
    +          #        plus 0 states.

    Models don't hold parameters and states so initialize them. From there on, we can just use our standard AD and Optimisers API. However, here we will show how to use Lux's Training API that provides an uniform API over all supported AD systems.

    julia
    # Get the device determined by Lux
    +dev = gpu_device()
    +
    +# Parameter and State Variables
    +ps, st = Lux.setup(rng, model) |> dev
    +
    +# Dummy Input
    +x = rand(rng, Float32, 128, 2) |> dev
    +
    +# Run the model
    +y, st = Lux.apply(model, x, ps, st)
    +
    +# Gradients
    +## First construct a TrainState
    +train_state = Lux.Training.TrainState(model, ps, st, Adam(0.0001f0))
    +
    +## We can compute the gradients using Training.compute_gradients
    +gs, loss, stats, train_state = Lux.Training.compute_gradients(AutoZygote(), MSELoss(),
    +    (x, dev(rand(rng, Float32, 10, 2))), train_state)
    +
    +## Optimization
    +train_state = Training.apply_gradients!(train_state, gs) # or Training.apply_gradients (no \`!\` at the end)
    +
    +# Both these steps can be combined into a single call
    +gs, loss, stats, train_state = Training.single_train_step!(AutoZygote(), MSELoss(),
    +    (x, dev(rand(rng, Float32, 10, 2))), train_state)
    ((layer_1 = (weight = Float32[0.004144425 0.0027955552 … 0.004169049 0.0031376407; 0.002106787 0.0018510937 … 0.0024323382 0.001973281; … ; -0.0017369908 -0.0014175134 … -0.0019262917 -0.0015313211; 0.005014097 0.0012843215 … 0.00351666 0.0019504696], bias = Float32[0.0067729075, 0.0037725805, 0.0044189203, -0.008870317, 0.0024971329, 0.0034101289, 0.011739168, 0.0100971125, -0.012522168, -0.006184267  …  -0.0019153744, -0.0021203319, -0.006736353, -0.0061099795, -0.0017900232, 0.0053856913, 0.0022308934, -0.004047669, -0.003027094, 0.0065859724]), layer_2 = (layer_1 = (weight = Float32[0.009578831 3.793463f-5 … -0.047356773 0.04226003], bias = Float32[0.073442355]), layer_2 = (weight = Float32[-0.098861866; -0.09785451; … ; -0.022434518; -0.07412187;;], bias = Float32[-0.226381, -0.22459084, -0.2545935, -0.24099025, -0.07057328, -0.17239982, -0.17449912, 0.07704306, -0.050089, -0.16909766]))), 0.87143785f0, NamedTuple(), Lux.Training.TrainState{Nothing, Nothing, Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Nothing}, @NamedTuple{layer_1::@NamedTuple{weight::CuArray{Float32, 2, CUDA.DeviceMemory}, bias::CuArray{Float32, 1, CUDA.DeviceMemory}}, layer_2::@NamedTuple{layer_1::@NamedTuple{weight::CuArray{Float32, 2, CUDA.DeviceMemory}, bias::CuArray{Float32, 1, CUDA.DeviceMemory}}, layer_2::@NamedTuple{weight::CuArray{Float32, 2, CUDA.DeviceMemory}, bias::CuArray{Float32, 1, CUDA.DeviceMemory}}}}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}}}, Adam, @NamedTuple{layer_1::@NamedTuple{weight::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 2, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}, bias::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}}, layer_2::@NamedTuple{layer_1::@NamedTuple{weight::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 2, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}, bias::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}}, layer_2::@NamedTuple{weight::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 2, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}, bias::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}}}}}(nothing, nothing, Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Nothing}((layer_1 = Dense(128 => 256, tanh), layer_2 = Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}((layer_1 = Dense(256 => 1, tanh), layer_2 = Dense(1 => 10)), nothing)), nothing), (layer_1 = (weight = Float32[-0.22543387 0.2237958 … 0.19975941 -0.018701272; -0.023031702 0.15451166 … -0.065317236 0.181208; … ; 0.03804328 -0.07125676 … -0.03306928 0.039132368; -0.18811704 -0.09692798 … -0.18102339 0.019236464], bias = Float32[0.03094203, -0.06026962, 0.08456781, 0.0003920444, -0.06550143, -0.08526564, -0.026516732, 0.063480526, 0.04224006, 0.027702922  …  -0.06053336, 0.0350433, -0.028251555, 0.067872316, 0.0027386106, -0.06942138, 0.006432486, 0.014100174, -0.029290024, 0.011734666]), layer_2 = (layer_1 = (weight = Float32[0.11984776 0.060364496 … -0.07058401 0.1577715], bias = Float32[0.026851978]), layer_2 = (weight = Float32[0.5345716; -0.28289196; … ; -0.32984197; -0.45298263;;], bias = Float32[-0.5975106, -0.70330536, -0.84576, -0.5378918, -0.3147238, 0.1746128, -0.82945824, 0.6784163, 0.35836592, -0.14941669]))), (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple())), Adam(0.0001, (0.9, 0.999), 1.0e-8), (layer_1 = (weight = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.00139126 0.00077649 … 0.00128162 0.000910802; 0.000699265 0.000510198 … 0.000731462 0.000563284; … ; -0.000574894 -0.000391076 … -0.000580705 -0.000438132; 0.00170922 0.000374875 … 0.00115296 0.000609521], Float32[1.34855f-7 3.8271f-8 … 1.09599f-7 5.38068f-8; 3.38798f-8 1.64605f-8 … 3.53144f-8 2.04108f-8; … ; 2.28682f-8 9.67595f-9 … 2.22846f-8 1.23626f-8; 2.05058f-7 9.13988f-9 … 9.15542f-8 2.49913f-8], (0.729, 0.997003))), bias = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.00214946, 0.00117228, 0.00145586, -0.00270753, 0.00077338, 0.00106574, 0.00364828, 0.00306169, -0.0038745, -0.00198767  …  -0.000612726, -0.000689046, -0.00209504, -0.00187748, -0.000554918, 0.00175152, 0.000667028, -0.00126273, -0.000942026, 0.00219681], Float32[3.13168f-7, 9.21856f-8, 1.46327f-7, 4.87431f-7, 4.00564f-8, 7.64058f-8, 8.929f-7, 6.21252f-7, 1.00488f-6, 2.69472f-7  …  2.55476f-8, 3.25587f-8, 2.94557f-7, 2.35152f-7, 2.06325f-8, 2.10458f-7, 2.92832f-8, 1.07167f-7, 5.9572f-8, 3.35188f-7], (0.729, 0.997003)))), layer_2 = (layer_1 = (weight = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.0018058 -0.000936727 … -0.0146587 0.0123139], Float32[1.80423f-7 1.09098f-7 … 1.43866f-5 9.85344f-6], (0.729, 0.997003))), bias = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.0227737], Float32[3.47551f-5], (0.729, 0.997003)))), layer_2 = (weight = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[-0.0207926; -0.0231775; … ; -0.00706411; -0.0158726;;], Float32[2.44439f-5; 3.16946f-5; … ; 3.36938f-6; 1.4322f-5;;], (0.729, 0.997003))), bias = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[-0.0435721, -0.0480501, -0.0540537, -0.0420834, -0.0105465, -0.0302464, -0.0315817, 0.0244214, -0.0142814, -0.0330944], Float32[0.000105296, 0.00013121, 0.000165657, 9.79656f-5, 6.48203f-6, 5.0585f-5, 5.50798f-5, 4.04019f-5, 1.31128f-5, 6.08993f-5], (0.729, 0.997003)))))), 2))

    Defining Custom Layers

    julia
    using Lux, Random, Optimisers, Zygote
    +using LuxCUDA # For CUDA support
    +# using AMDGPU, Metal, oneAPI # Other pptional packages for GPU support
    +using Printf # For pretty printing
    +
    +dev = gpu_device()
    (::CUDADevice{Nothing}) (generic function with 4 methods)

    We will define a custom MLP using the @compact macro. The macro takes in a list of parameters, layers and states, and a function defining the forward pass of the neural network.

    julia
    n_in = 1
    +n_out = 1
    +nlayers = 3
    +
    +model = @compact(w1=Dense(n_in => 32),
    +    w2=[Dense(32 => 32) for i in 1:nlayers],
    +    w3=Dense(32 => n_out),
    +    act=relu) do x
    +    embed = act(w1(x))
    +    for w in w2
    +        embed = act(w(embed))
    +    end
    +    out = w3(embed)
    +    @return out
    +end
    @compact(
    +    w1 = Dense(1 => 32),                # 64 parameters
    +    w2 = NamedTuple(
    +        1 = Dense(32 => 32),            # 1_056 parameters
    +        2 = Dense(32 => 32),            # 1_056 parameters
    +        3 = Dense(32 => 32),            # 1_056 parameters
    +    ),
    +    w3 = Dense(32 => 1),                # 33 parameters
    +    act = relu,
    +) do x 
    +    embed = act(w1(x))
    +    for w = w2
    +        embed = act(w(embed))
    +    end
    +    out = w3(embed)
    +    return out
    +end       # Total: 3_265 parameters,
    +          #        plus 1 states.

    We can initialize the model and train it with the same code as before!

    julia
    rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +ps, st = Lux.setup(Xoshiro(0), model) |> dev
    +
    +x = rand(rng, Float32, n_in, 32) |> dev
    +
    +model(x, ps, st)  # 1×32 Matrix and updated state as output.
    +
    +x_data = reshape(collect(-2.0f0:0.1f0:2.0f0), 1, :) |> dev
    +y_data = 2 .* x_data .- x_data .^ 3
    +
    +function train_model!(model, ps, st, x_data, y_data)
    +    train_state = Lux.Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    for iter in 1:1000
    +        _, loss, _, train_state = Lux.Training.single_train_step!(AutoZygote(), MSELoss(),
    +            (x_data, y_data), train_state)
    +        if iter % 100 == 1 || iter == 1000
    +            @printf "Iteration: %04d \\t Loss: %10.9g\\n" iter loss
    +        end
    +    end
    +
    +    return model, ps, st
    +end
    +
    +train_model!(model, ps, st, x_data, y_data)
    Iteration: 0001 	 Loss: 2.08085155
    +Iteration: 0101 	 Loss: 0.131583631
    +Iteration: 0201 	 Loss: 0.00390526722
    +Iteration: 0301 	 Loss: 0.000871024327
    +Iteration: 0401 	 Loss: 0.000441076729
    +Iteration: 0501 	 Loss: 0.000454922556
    +Iteration: 0601 	 Loss: 0.00036629336
    +Iteration: 0701 	 Loss: 0.00015113852
    +Iteration: 0801 	 Loss: 0.000239130808
    +Iteration: 0901 	 Loss: 0.00140763051
    +Iteration: 1000 	 Loss: 0.000214067404

    Training with Optimization.jl

    If you are coming from the SciML ecosystem and want to use Optimization.jl, please refer to the Optimization.jl Tutorial.

    Additional Packages

    LuxDL hosts various packages that provide additional functionality for Lux.jl. All packages mentioned in this documentation are available via the Julia General Registry.

    You can install all those packages via import Pkg; Pkg.add(<package name>).

    GPU Support

    GPU Support for Lux.jl requires loading additional packages:

    `,33)]))}const o=i(l,[["render",e]]);export{E as __pageData,o as default}; diff --git a/previews/PR1023/assets/introduction_overview.md.DDk7R0pj.js b/previews/PR1023/assets/introduction_overview.md.DDk7R0pj.js new file mode 100644 index 0000000000..c7838a2575 --- /dev/null +++ b/previews/PR1023/assets/introduction_overview.md.DDk7R0pj.js @@ -0,0 +1 @@ +import{_ as t,c as r,a2 as a,o as s}from"./chunks/framework.DFwXuivk.js";const m=JSON.parse('{"title":"Why we wrote Lux?","description":"","frontmatter":{},"headers":[],"relativePath":"introduction/overview.md","filePath":"introduction/overview.md","lastUpdated":null}'),i={name:"introduction/overview.md"};function o(n,e,l,u,d,p){return s(),r("div",null,e[0]||(e[0]=[a('

    Why we wrote Lux?

    Julia already has quite a few well established Neural Network Frameworks – Flux & KNet. However, certain design elements – Coupled Model and Parameters & Internal Mutations – associated with these frameworks make them less compiler and user friendly. Making changes to address these problems in the respective frameworks would be too disruptive for users. Here comes in Lux: a neural network framework built completely using pure functions to make it both compiler and autodiff friendly.

    Design Principles

    • Layers must be immutable – cannot store any parameter/state but rather store the information to construct them

    • Layers are pure functions

    • Layers return a Tuple containing the result and the updated state

    • Given same inputs the outputs must be same – yes this must hold true even for stochastic functions. Randomness must be controlled using rngs passed in the state.

    • Easily extensible

    • Extensive Testing – All layers and features are tested across all supported AD backends across all supported hardware backends.

    Why use Lux over Flux?

    • Neural Networks for SciML: For SciML Applications (Neural ODEs, Deep Equilibrium Models) solvers typically expect a monolithic parameter vector. Flux enables this via its destructure mechanism, but destructure comes with various edge cases and limitations. Lux forces users to make an explicit distinction between state variables and parameter variables to avoid these issues. Also, it comes battery-included for distributed training.

    • Sensible display of Custom Layers – Ever wanted to see Pytorch like Network printouts or wondered how to extend the pretty printing of Flux's layers? Lux handles all of that by default.

    • Truly immutable models - No unexpected internal mutations since all layers are implemented as pure functions. All layers are also deterministic given the parameters and state: if a layer is supposed to be stochastic (say Dropout), the state must contain a seed which is then updated after the function call.

    • Easy Parameter Manipulation – By separating parameter data and layer structures, Lux makes implementing WeightNorm, SpectralNorm, etc. downright trivial. Without this separation, it is much harder to pass such parameters around without mutations which AD systems don't like.

    • Wider AD Support – Lux has extensive support for most AD systems in julia, while Flux is mostly tied to Zygote (with some initial support for Enzyme).

    • Small Neural Networks on CPU – Lux is developed for training large neural networks. For smaller architectures, we recommend using SimpleChains.jl or even better use it in conjunction with Lux via ToSimpleChainsAdaptor.

    • Reliability – We have learned from the mistakes of the past with Flux and everything in our core framework is extensively tested, along with downstream CI to ensure that everything works as expected.

    Revising Previous Recommendation about Large Models

    Previously we recommended not using Lux for very large models. But we have been making a lot of head-way with Reactant.jl and it would be worthwhile to test larger models with Lux. See compiling Lux models for more information.

    ',7)]))}const h=t(i,[["render",o]]);export{m as __pageData,h as default}; diff --git a/previews/PR1023/assets/introduction_overview.md.DDk7R0pj.lean.js b/previews/PR1023/assets/introduction_overview.md.DDk7R0pj.lean.js new file mode 100644 index 0000000000..c7838a2575 --- /dev/null +++ b/previews/PR1023/assets/introduction_overview.md.DDk7R0pj.lean.js @@ -0,0 +1 @@ +import{_ as t,c as r,a2 as a,o as s}from"./chunks/framework.DFwXuivk.js";const m=JSON.parse('{"title":"Why we wrote Lux?","description":"","frontmatter":{},"headers":[],"relativePath":"introduction/overview.md","filePath":"introduction/overview.md","lastUpdated":null}'),i={name:"introduction/overview.md"};function o(n,e,l,u,d,p){return s(),r("div",null,e[0]||(e[0]=[a('

    Why we wrote Lux?

    Julia already has quite a few well established Neural Network Frameworks – Flux & KNet. However, certain design elements – Coupled Model and Parameters & Internal Mutations – associated with these frameworks make them less compiler and user friendly. Making changes to address these problems in the respective frameworks would be too disruptive for users. Here comes in Lux: a neural network framework built completely using pure functions to make it both compiler and autodiff friendly.

    Design Principles

    • Layers must be immutable – cannot store any parameter/state but rather store the information to construct them

    • Layers are pure functions

    • Layers return a Tuple containing the result and the updated state

    • Given same inputs the outputs must be same – yes this must hold true even for stochastic functions. Randomness must be controlled using rngs passed in the state.

    • Easily extensible

    • Extensive Testing – All layers and features are tested across all supported AD backends across all supported hardware backends.

    Why use Lux over Flux?

    • Neural Networks for SciML: For SciML Applications (Neural ODEs, Deep Equilibrium Models) solvers typically expect a monolithic parameter vector. Flux enables this via its destructure mechanism, but destructure comes with various edge cases and limitations. Lux forces users to make an explicit distinction between state variables and parameter variables to avoid these issues. Also, it comes battery-included for distributed training.

    • Sensible display of Custom Layers – Ever wanted to see Pytorch like Network printouts or wondered how to extend the pretty printing of Flux's layers? Lux handles all of that by default.

    • Truly immutable models - No unexpected internal mutations since all layers are implemented as pure functions. All layers are also deterministic given the parameters and state: if a layer is supposed to be stochastic (say Dropout), the state must contain a seed which is then updated after the function call.

    • Easy Parameter Manipulation – By separating parameter data and layer structures, Lux makes implementing WeightNorm, SpectralNorm, etc. downright trivial. Without this separation, it is much harder to pass such parameters around without mutations which AD systems don't like.

    • Wider AD Support – Lux has extensive support for most AD systems in julia, while Flux is mostly tied to Zygote (with some initial support for Enzyme).

    • Small Neural Networks on CPU – Lux is developed for training large neural networks. For smaller architectures, we recommend using SimpleChains.jl or even better use it in conjunction with Lux via ToSimpleChainsAdaptor.

    • Reliability – We have learned from the mistakes of the past with Flux and everything in our core framework is extensively tested, along with downstream CI to ensure that everything works as expected.

    Revising Previous Recommendation about Large Models

    Previously we recommended not using Lux for very large models. But we have been making a lot of head-way with Reactant.jl and it would be worthwhile to test larger models with Lux. See compiling Lux models for more information.

    ',7)]))}const h=t(i,[["render",o]]);export{m as __pageData,h as default}; diff --git a/previews/PR1023/assets/introduction_resources.md.JKo7XfzJ.js b/previews/PR1023/assets/introduction_resources.md.JKo7XfzJ.js new file mode 100644 index 0000000000..76f92e8f9b --- /dev/null +++ b/previews/PR1023/assets/introduction_resources.md.JKo7XfzJ.js @@ -0,0 +1 @@ +import{_ as t,c as r,a2 as s,o as a}from"./chunks/framework.DFwXuivk.js";const h=JSON.parse('{"title":"Resources to Get Started","description":"","frontmatter":{},"headers":[],"relativePath":"introduction/resources.md","filePath":"introduction/resources.md","lastUpdated":null}'),o={name:"introduction/resources.md"};function i(u,e,n,l,d,c){return a(),r("div",null,e[0]||(e[0]=[s('

    Resources to Get Started

    • Go through the Quickstart Example.

    • Read the introductory tutorials on Julia and Lux.

    • Go through the examples sorted based on their complexity in the documentation.

    Have More Questions?

    For usage related questions, please use Github Discussions which allows questions and answers to be indexed. To report bugs use Github Issues or even better send in a Pull Request.

    ',3)]))}const g=t(o,[["render",i]]);export{h as __pageData,g as default}; diff --git a/previews/PR1023/assets/introduction_resources.md.JKo7XfzJ.lean.js b/previews/PR1023/assets/introduction_resources.md.JKo7XfzJ.lean.js new file mode 100644 index 0000000000..76f92e8f9b --- /dev/null +++ b/previews/PR1023/assets/introduction_resources.md.JKo7XfzJ.lean.js @@ -0,0 +1 @@ +import{_ as t,c as r,a2 as s,o as a}from"./chunks/framework.DFwXuivk.js";const h=JSON.parse('{"title":"Resources to Get Started","description":"","frontmatter":{},"headers":[],"relativePath":"introduction/resources.md","filePath":"introduction/resources.md","lastUpdated":null}'),o={name:"introduction/resources.md"};function i(u,e,n,l,d,c){return a(),r("div",null,e[0]||(e[0]=[s('

    Resources to Get Started

    • Go through the Quickstart Example.

    • Read the introductory tutorials on Julia and Lux.

    • Go through the examples sorted based on their complexity in the documentation.

    Have More Questions?

    For usage related questions, please use Github Discussions which allows questions and answers to be indexed. To report bugs use Github Issues or even better send in a Pull Request.

    ',3)]))}const g=t(o,[["render",i]]);export{h as __pageData,g as default}; diff --git a/previews/PR1023/assets/introduction_updating_to_v1.md.BI71nsoN.js b/previews/PR1023/assets/introduction_updating_to_v1.md.BI71nsoN.js new file mode 100644 index 0000000000..78918500b7 --- /dev/null +++ b/previews/PR1023/assets/introduction_updating_to_v1.md.BI71nsoN.js @@ -0,0 +1 @@ +import{_ as a,c as o,a2 as i,o as t}from"./chunks/framework.DFwXuivk.js";const h=JSON.parse('{"title":"Updating to Lux v1","description":"","frontmatter":{},"headers":[],"relativePath":"introduction/updating_to_v1.md","filePath":"introduction/updating_to_v1.md","lastUpdated":null}'),r={name:"introduction/updating_to_v1.md"};function n(d,e,s,l,c,u){return t(),o("div",null,e[0]||(e[0]=[i('

    Updating to Lux v1

    Lux v1 is a Major Release, mostly to signify the stability of the API. In this page, we list out a concrete set of changes that need to be made to your code to update to Lux v1. We also list out some new exciting features that were added as part of this release.

    LuxLib.jl

    Breaking Changes

    • Old deprecated API with keyword arguments has been removed. See the new docs in LuxLib API for more details.

    • Default for layernorm dims has been changed to exclude the batch dimension.

    New Major Features

    • Dense layers now support CUDA backend for Enzyme (starting v1.1). Wider support for other operations with Enzyme + CUDA is being actively worked on.

    LuxCore.jl

    Breaking Changes

    • AbstractExplicitLayer has been renamed to AbstractLuxLayer.

    • AbstractExplicitContainerLayer behaviour

      • This has been renamed to AbstractLuxContainerLayer.

      • Previously, AbstractExplicitContainerLayer{(:a,)} (i.e. singleton containers) would produce default initial parameters and states without wrapping them in a NamedTuple{(:a,)}. This was inconsistent with non-singleton containers, and was a source of confusion. With v we return (; a = <parameters>) and (; a = <states>) by default. See AbstractLuxWrapperLayer for a replacement of this functionality.

    • inputsize has been removed since it was ambiguous and not used anywhere.

    • Changes to outputsize:

      • Single argument version has been removed. See LuxCore.jl Pull Request 43 for more details on the rationale behind this change.

      • Fallback implementation has been moved to Lux.jl. (i.e. users using Lux shouldn't see a difference, but if Lux.jl isn't loaded, this function has error.)

        • Internally this uses a NilArray that is able to compute sizes without actually running the computation.
    • Functors and Setfield have been made into optional dependencies. Certain LuxCore functionality that rely on these functions, will throw an error if these packages are not loaded.

    New Major Features

    • Introduction of AbstractLuxWrapperLayer. This behaves exactly like the old singleton container. For example, the old AbstractExplicitContainerLayer{(:a,)} is equivalent to AbstractLuxWrapperLayer{:a}.

    WeightInitializers.jl

    This was a major release to signify the stability of the API. There were no breaking changes. We do support a wider range of RNG types, see Supported RNG Types for more details.

    MLDataDevices.jl

    This is the most aggressive change that was made. We renamed the LuxDeviceUtils.jl package to MLDataDevices.jl, to allow for non-Lux packages to use this shared device management abstraction.

    Deprecation of LuxDeviceUtils.jl

    This also marks the deprecation of the LuxDeviceUtils.jl package. We won't be making any updates to that package, including fixing any bugs. All users should switch to MLDataDevices.jl instead.

    Breaking Changes

    • Lux(___)Device objects have been renamed to (___)Device. For example, LuxCUDADevice has been renamed to CUDADevice.

    • Lux(___)Adaptor objects have been removed. The corresponding Device objects should be used directly instead.

    New Major Features

    • DeviceIterator provides a generalization of CUDA.CuIterator and works for all backends and more data types (using Functors.jl). MLUtils.DataLoader |> gdev now returns a DeviceIterator instead of being a no-op.

    Lux.jl

    Breaking Changes (Removed Functionality)

    • Direct reexport of NNlib has been removed. We reexport selected functionality from NNlib. Direactly load NNlib if you need to use the other functions.

    • Flattening of Chain layers has been removed, and the corresponding disable_optimizations kwarg has been removed.

    • Some layers overloaded Base.keys, these have been removed. These were mostly un-documented and weren't supposed to be used outside of the Lux.jl package.

    • Training.TrainState construction with rng has been removed.

    • Older versions of Preferences have been removed.

    • disable_stacktrace_truncation! has been removed. From Julia 1.9 onwards, stacktrace truncation is enabled by default.

    • Certain Experimental features were present outside the Lux.Experimental module. These have been removed, use them via Lux.Experimental instead. Run Julia with with depwarn as error and Lux v0.5 to see the deprecations.

    • Lux.Experimental.@layer_map is not longer needed and has been removed. The name of the variable prevents writing generic functions and is no longer pre-pended to the KeyPath. See the docstring of Lux.Experimental.layer_map for more details.

    • allow_fast_activation kwarg has been removed completely. Pass an anonymous function as the activation to prevent internal modivations to the activation function.

    Breaking Changes (Moved Functionality)

    • Lux.Experimental.Training has been moved to Lux.Training. We guarantee SemVar on this new module.

    • Lux.cpu and Lux.gpu have been removed. Use cpu_device and gpu_device instead.

    • Experimental.@compact can be directly used via @compact now.

    • Experimental.StatefulLuxLayer has been moved to Lux.StatefulLuxLayer.

    • st_fixed_path kwarg has been removed from Lux.StatefulLuxLayer, instead use it as StatefulLuxLayer{st_fixed_path}(...).

    • Strings as inputs to Lux.Experimental.layer_map and Lux.Experimental.@debug_mode are removed, use Functors.KeyPath instead.

    • CrossCor has been removed. Use Conv(args...; kwargs..., cross_correlation=true) instead.

    Breaking Changes (Changes in Defaults)

    • Conv and ConvTranspose use an initialization based on the activation function, taken from Pytorch. Pytorch assumes the activation function is leakyrelu to compute the gain, however, we compute the gain based on the activation function passed in to the layer.

    • Upsample now has an align_corners keyword argument, which defaults to false. Previously this was always true.

    • Dense and Bilinear have updated default initializations to align with the defaults from Pytorch. See the documentation for more details.

    • InstanceNorm now defaults to affine=false instead of affine=true.

    • Embedding now defaults to init_weight=rand32 instead of init_weight=randn32.

    • Recurrent Cells - RNNCell, LSTMCell, and GRUCell now have different default initializations. See the documentation for more details.

    New Features

    • InstanceNorm now supports tracking statistics.

    • RNNCell and LSTMCell add bias_ih and bias_hh to the parameters to align with Pytorch. Both are controlled using init_bias and use_bias.

    • ConvTranspose allows flipkernel=true via cross_correlation=true. This makes it efficient for MIOpen.

    • ConvTranspose now has an outpad keyword argument, which is used to increase the size of the output in the desired dimensions.

    • Pooling Layers based on lpnorm have been added – LPPool, GlobalLPPool, and AdaptiveLPPool.

    ',30)]))}const L=a(r,[["render",n]]);export{h as __pageData,L as default}; diff --git a/previews/PR1023/assets/introduction_updating_to_v1.md.BI71nsoN.lean.js b/previews/PR1023/assets/introduction_updating_to_v1.md.BI71nsoN.lean.js new file mode 100644 index 0000000000..78918500b7 --- /dev/null +++ b/previews/PR1023/assets/introduction_updating_to_v1.md.BI71nsoN.lean.js @@ -0,0 +1 @@ +import{_ as a,c as o,a2 as i,o as t}from"./chunks/framework.DFwXuivk.js";const h=JSON.parse('{"title":"Updating to Lux v1","description":"","frontmatter":{},"headers":[],"relativePath":"introduction/updating_to_v1.md","filePath":"introduction/updating_to_v1.md","lastUpdated":null}'),r={name:"introduction/updating_to_v1.md"};function n(d,e,s,l,c,u){return t(),o("div",null,e[0]||(e[0]=[i('

    Updating to Lux v1

    Lux v1 is a Major Release, mostly to signify the stability of the API. In this page, we list out a concrete set of changes that need to be made to your code to update to Lux v1. We also list out some new exciting features that were added as part of this release.

    LuxLib.jl

    Breaking Changes

    • Old deprecated API with keyword arguments has been removed. See the new docs in LuxLib API for more details.

    • Default for layernorm dims has been changed to exclude the batch dimension.

    New Major Features

    • Dense layers now support CUDA backend for Enzyme (starting v1.1). Wider support for other operations with Enzyme + CUDA is being actively worked on.

    LuxCore.jl

    Breaking Changes

    • AbstractExplicitLayer has been renamed to AbstractLuxLayer.

    • AbstractExplicitContainerLayer behaviour

      • This has been renamed to AbstractLuxContainerLayer.

      • Previously, AbstractExplicitContainerLayer{(:a,)} (i.e. singleton containers) would produce default initial parameters and states without wrapping them in a NamedTuple{(:a,)}. This was inconsistent with non-singleton containers, and was a source of confusion. With v we return (; a = <parameters>) and (; a = <states>) by default. See AbstractLuxWrapperLayer for a replacement of this functionality.

    • inputsize has been removed since it was ambiguous and not used anywhere.

    • Changes to outputsize:

      • Single argument version has been removed. See LuxCore.jl Pull Request 43 for more details on the rationale behind this change.

      • Fallback implementation has been moved to Lux.jl. (i.e. users using Lux shouldn't see a difference, but if Lux.jl isn't loaded, this function has error.)

        • Internally this uses a NilArray that is able to compute sizes without actually running the computation.
    • Functors and Setfield have been made into optional dependencies. Certain LuxCore functionality that rely on these functions, will throw an error if these packages are not loaded.

    New Major Features

    • Introduction of AbstractLuxWrapperLayer. This behaves exactly like the old singleton container. For example, the old AbstractExplicitContainerLayer{(:a,)} is equivalent to AbstractLuxWrapperLayer{:a}.

    WeightInitializers.jl

    This was a major release to signify the stability of the API. There were no breaking changes. We do support a wider range of RNG types, see Supported RNG Types for more details.

    MLDataDevices.jl

    This is the most aggressive change that was made. We renamed the LuxDeviceUtils.jl package to MLDataDevices.jl, to allow for non-Lux packages to use this shared device management abstraction.

    Deprecation of LuxDeviceUtils.jl

    This also marks the deprecation of the LuxDeviceUtils.jl package. We won't be making any updates to that package, including fixing any bugs. All users should switch to MLDataDevices.jl instead.

    Breaking Changes

    • Lux(___)Device objects have been renamed to (___)Device. For example, LuxCUDADevice has been renamed to CUDADevice.

    • Lux(___)Adaptor objects have been removed. The corresponding Device objects should be used directly instead.

    New Major Features

    • DeviceIterator provides a generalization of CUDA.CuIterator and works for all backends and more data types (using Functors.jl). MLUtils.DataLoader |> gdev now returns a DeviceIterator instead of being a no-op.

    Lux.jl

    Breaking Changes (Removed Functionality)

    • Direct reexport of NNlib has been removed. We reexport selected functionality from NNlib. Direactly load NNlib if you need to use the other functions.

    • Flattening of Chain layers has been removed, and the corresponding disable_optimizations kwarg has been removed.

    • Some layers overloaded Base.keys, these have been removed. These were mostly un-documented and weren't supposed to be used outside of the Lux.jl package.

    • Training.TrainState construction with rng has been removed.

    • Older versions of Preferences have been removed.

    • disable_stacktrace_truncation! has been removed. From Julia 1.9 onwards, stacktrace truncation is enabled by default.

    • Certain Experimental features were present outside the Lux.Experimental module. These have been removed, use them via Lux.Experimental instead. Run Julia with with depwarn as error and Lux v0.5 to see the deprecations.

    • Lux.Experimental.@layer_map is not longer needed and has been removed. The name of the variable prevents writing generic functions and is no longer pre-pended to the KeyPath. See the docstring of Lux.Experimental.layer_map for more details.

    • allow_fast_activation kwarg has been removed completely. Pass an anonymous function as the activation to prevent internal modivations to the activation function.

    Breaking Changes (Moved Functionality)

    • Lux.Experimental.Training has been moved to Lux.Training. We guarantee SemVar on this new module.

    • Lux.cpu and Lux.gpu have been removed. Use cpu_device and gpu_device instead.

    • Experimental.@compact can be directly used via @compact now.

    • Experimental.StatefulLuxLayer has been moved to Lux.StatefulLuxLayer.

    • st_fixed_path kwarg has been removed from Lux.StatefulLuxLayer, instead use it as StatefulLuxLayer{st_fixed_path}(...).

    • Strings as inputs to Lux.Experimental.layer_map and Lux.Experimental.@debug_mode are removed, use Functors.KeyPath instead.

    • CrossCor has been removed. Use Conv(args...; kwargs..., cross_correlation=true) instead.

    Breaking Changes (Changes in Defaults)

    • Conv and ConvTranspose use an initialization based on the activation function, taken from Pytorch. Pytorch assumes the activation function is leakyrelu to compute the gain, however, we compute the gain based on the activation function passed in to the layer.

    • Upsample now has an align_corners keyword argument, which defaults to false. Previously this was always true.

    • Dense and Bilinear have updated default initializations to align with the defaults from Pytorch. See the documentation for more details.

    • InstanceNorm now defaults to affine=false instead of affine=true.

    • Embedding now defaults to init_weight=rand32 instead of init_weight=randn32.

    • Recurrent Cells - RNNCell, LSTMCell, and GRUCell now have different default initializations. See the documentation for more details.

    New Features

    • InstanceNorm now supports tracking statistics.

    • RNNCell and LSTMCell add bias_ih and bias_hh to the parameters to align with Pytorch. Both are controlled using init_bias and use_bias.

    • ConvTranspose allows flipkernel=true via cross_correlation=true. This makes it efficient for MIOpen.

    • ConvTranspose now has an outpad keyword argument, which is used to increase the size of the output in the desired dimensions.

    • Pooling Layers based on lpnorm have been added – LPPool, GlobalLPPool, and AdaptiveLPPool.

    ',30)]))}const L=a(r,[["render",n]]);export{h as __pageData,L as default}; diff --git a/previews/PR1023/assets/manual_autodiff.md.Ba7AkbE9.js b/previews/PR1023/assets/manual_autodiff.md.Ba7AkbE9.js new file mode 100644 index 0000000000..d243f85d1f --- /dev/null +++ b/previews/PR1023/assets/manual_autodiff.md.Ba7AkbE9.js @@ -0,0 +1 @@ +import{_ as t,c as a,a2 as l,o}from"./chunks/framework.DFwXuivk.js";const p=JSON.parse('{"title":"Automatic Differentiation","description":"","frontmatter":{},"headers":[],"relativePath":"manual/autodiff.md","filePath":"manual/autodiff.md","lastUpdated":null}'),r={name:"manual/autodiff.md"};function s(i,e,f,n,d,c){return o(),a("div",null,e[0]||(e[0]=[l('

    Automatic Differentiation

    Lux is not an AD package, but it composes well with most of the AD packages available in the Julia ecosystem. This document lists the current level of support for various AD packages in Lux. Additionally, we provide some convenience functions for working with AD.

    Overview

    AD PackageModeCPUGPUNested 2nd Order ADSupport Class
    ChainRules.jl[1]Reverse✔️✔️✔️Tier I
    Enzyme.jlReverse✔️[2][2:1]Tier I[3]
    Zygote.jlReverse✔️✔️✔️Tier I
    ForwardDiff.jlForward✔️✔️✔️Tier I
    ReverseDiff.jlReverse✔️Tier II
    Tracker.jlReverse✔️✔️Tier II
    Mooncake.jlReverse[2:2]Tier III
    Diffractor.jlForward[2:3][2:4][2:5]Tier III

    Recommendations

    • For CPU Usacases:

      1. Use Zygote.jl for the best performance. This is the most reliable and fastest option for CPU for the time-being. (We are working on faster Enzyme support for CPU)

      2. Use Enzyme.jl, if there are mutations in the code and/or Zygote.jl fails.

      3. If Enzyme.jl fails for some reason, (open an issue and) try ReverseDiff.jl (possibly with compiled mode).

    • For GPU Usacases:

      1. Use Zygote.jl for the best performance. This is the most reliable and fastest option for GPU for the time-being. We are working on supporting Enzyme.jl for GPU as well.

    Support Class

    1. Tier I: These packages are fully supported and have been tested extensively. Often have special rules to enhance performance. Issues for these backends take the highest priority.

    2. Tier II: These packages are supported and extensively tested but often don't have the best performance. Issues against these backends are less critical, but we fix them when possible. (Some specific edge cases, especially with AMDGPU, are known to fail here)

    3. Tier III: We don't know if these packages currently work with Lux. We'd love to add tests for these backends, but currently these are not our priority.

    Footnotes


    1. Note that ChainRules.jl is not really an AD package, but we have first-class support for packages that use rrules. ↩︎

    2. This feature is supported downstream, but we don't extensively test it to ensure that it works with Lux. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

    3. Currently Enzyme outperforms other AD packages in terms of CPU performance. However, there are some edge cases where it might not work with Lux. We are working on improving the compatibility. Please report any issues you encounter. ↩︎

    ',11)]))}const u=t(r,[["render",s]]);export{p as __pageData,u as default}; diff --git a/previews/PR1023/assets/manual_autodiff.md.Ba7AkbE9.lean.js b/previews/PR1023/assets/manual_autodiff.md.Ba7AkbE9.lean.js new file mode 100644 index 0000000000..d243f85d1f --- /dev/null +++ b/previews/PR1023/assets/manual_autodiff.md.Ba7AkbE9.lean.js @@ -0,0 +1 @@ +import{_ as t,c as a,a2 as l,o}from"./chunks/framework.DFwXuivk.js";const p=JSON.parse('{"title":"Automatic Differentiation","description":"","frontmatter":{},"headers":[],"relativePath":"manual/autodiff.md","filePath":"manual/autodiff.md","lastUpdated":null}'),r={name:"manual/autodiff.md"};function s(i,e,f,n,d,c){return o(),a("div",null,e[0]||(e[0]=[l('

    Automatic Differentiation

    Lux is not an AD package, but it composes well with most of the AD packages available in the Julia ecosystem. This document lists the current level of support for various AD packages in Lux. Additionally, we provide some convenience functions for working with AD.

    Overview

    AD PackageModeCPUGPUNested 2nd Order ADSupport Class
    ChainRules.jl[1]Reverse✔️✔️✔️Tier I
    Enzyme.jlReverse✔️[2][2:1]Tier I[3]
    Zygote.jlReverse✔️✔️✔️Tier I
    ForwardDiff.jlForward✔️✔️✔️Tier I
    ReverseDiff.jlReverse✔️Tier II
    Tracker.jlReverse✔️✔️Tier II
    Mooncake.jlReverse[2:2]Tier III
    Diffractor.jlForward[2:3][2:4][2:5]Tier III

    Recommendations

    • For CPU Usacases:

      1. Use Zygote.jl for the best performance. This is the most reliable and fastest option for CPU for the time-being. (We are working on faster Enzyme support for CPU)

      2. Use Enzyme.jl, if there are mutations in the code and/or Zygote.jl fails.

      3. If Enzyme.jl fails for some reason, (open an issue and) try ReverseDiff.jl (possibly with compiled mode).

    • For GPU Usacases:

      1. Use Zygote.jl for the best performance. This is the most reliable and fastest option for GPU for the time-being. We are working on supporting Enzyme.jl for GPU as well.

    Support Class

    1. Tier I: These packages are fully supported and have been tested extensively. Often have special rules to enhance performance. Issues for these backends take the highest priority.

    2. Tier II: These packages are supported and extensively tested but often don't have the best performance. Issues against these backends are less critical, but we fix them when possible. (Some specific edge cases, especially with AMDGPU, are known to fail here)

    3. Tier III: We don't know if these packages currently work with Lux. We'd love to add tests for these backends, but currently these are not our priority.

    Footnotes


    1. Note that ChainRules.jl is not really an AD package, but we have first-class support for packages that use rrules. ↩︎

    2. This feature is supported downstream, but we don't extensively test it to ensure that it works with Lux. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

    3. Currently Enzyme outperforms other AD packages in terms of CPU performance. However, there are some edge cases where it might not work with Lux. We are working on improving the compatibility. Please report any issues you encounter. ↩︎

    ',11)]))}const u=t(r,[["render",s]]);export{p as __pageData,u as default}; diff --git a/previews/PR1023/assets/manual_compiling_lux_models.md.CpD3KwNd.js b/previews/PR1023/assets/manual_compiling_lux_models.md.CpD3KwNd.js new file mode 100644 index 0000000000..21aa5a8301 --- /dev/null +++ b/previews/PR1023/assets/manual_compiling_lux_models.md.CpD3KwNd.js @@ -0,0 +1,75 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const g=JSON.parse('{"title":"Compiling Lux Models using Reactant.jl","description":"","frontmatter":{},"headers":[],"relativePath":"manual/compiling_lux_models.md","filePath":"manual/compiling_lux_models.md","lastUpdated":null}'),e={name:"manual/compiling_lux_models.md"};function l(p,s,h,k,d,r){return t(),a("div",null,s[0]||(s[0]=[n(`

    Compiling Lux Models using Reactant.jl

    Quoting the Reactant.jl Readme:

    Reactant takes Julia function and compile it into MLIR and run fancy optimizations on top of it, including using EnzymeMLIR for automatic differentiation, and create relevant executables for CPU/GPU/TPU via XLA. It presently operates as a tracing system. Compiled functions will assume the same control flow pattern as was original taken by objects used at compile time, and control flow (e.g. if, for) as well as any type instabilities will be removed. The benefits of this approach is immediately making all such code available for advanced optimization with little developer effort.

    Experimental

    Reactant compilation is a very new feature and is currently experimental. Certain models might not be compilable yet, but we are actively working on it. Open an issue if you encounter any problems.

    julia
    using Lux, Reactant, Enzyme, Random, Zygote
    +using Functors, Optimisers, Printf

    Using the TrainState API

    If you are using the Training.TrainState API, skip to the bottom of this page to see how to train the model without any of this boilerplate.

    We start by defining a simple MLP model:

    julia
    model = Chain(
    +    Dense(2 => 32, gelu),
    +    Dense(32 => 32, gelu),
    +    Dense(32 => 2)
    +)
    +ps, st = Lux.setup(Random.default_rng(), model)
    ((layer_1 = (weight = Float32[-1.2228831 -0.87702435; 0.5031421 -0.15133555; … ; -0.31550723 -0.7672513; 0.111552626 0.6064619], bias = Float32[-0.63795453, 0.62450767, -0.014877922, 0.25385493, -0.20188306, 0.21950458, 0.109203495, 0.23021114, -0.26657984, 0.16187939  …  -0.6409691, 0.4391564, 0.14488737, 0.49998975, -0.04566476, -0.56069607, -0.33442986, -0.1549292, -0.42669478, 0.636308]), layer_2 = (weight = Float32[0.293211 0.19084926 … 0.2464001 0.2913357; -0.116796836 0.09926938 … -0.26311737 -0.15802455; … ; -0.2042089 -0.22406094 … 0.13504265 0.09289699; 0.25389904 0.28355134 … 0.28725442 0.13343152], bias = Float32[0.12992674, 0.14568081, -0.10754459, -0.15686738, -0.14118214, 0.088205874, -0.06301335, 0.06027697, 0.14445141, 0.08791955  …  0.053627778, -0.06618893, 0.1124609, 0.037500158, 0.12827216, -0.13913931, -0.17048413, -0.1032465, -0.15493166, -0.0069942693]), layer_3 = (weight = Float32[-0.031503614 -0.23162955 … 0.097182155 -0.099906564; 0.05729505 0.28042415 … 0.1293236 -0.18089005], bias = Float32[-0.16409892, 0.042256515])), (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()))

    We then create a random input and output data:

    julia
    x = randn(Float32, 2, 32)
    +y = x .^ 2
    2×32 Matrix{Float32}:
    + 0.203036   0.362593  0.354464   0.0320963  …  0.0954186  0.713316  0.438519
    + 0.0155126  1.13864   0.0187668  0.142251      2.24169    4.16407   0.415858

    We will use xla_device similar to gpu_device to move the arrays to Reactant.

    julia
    const xdev = xla_device()
    +
    +x_ra = x |> xdev
    +y_ra = y |> xdev
    +ps_ra = ps |> xdev
    +st_ra = st |> xdev
    +nothing

    First let's run the model as we would normally:

    julia
    pred_lux, _ = model(x, ps, Lux.testmode(st))
    (Float32[-0.20053944 -0.8147778 … -2.3903124 -0.15544322; 0.1585735 0.4981351 … 1.2586653 0.27545732], (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()))

    To run it using XLA we need to compile the model. We can do this using the Reactant.@compile macro. Note that the inputs need to be moved to the device using xla_device first.

    julia
    model_compiled = @compile model(x_ra, ps_ra, Lux.testmode(st_ra))
    Reactant.Compiler.Thunk{Symbol("##Chain{@NamedTuple{layer_1::Dense{typeof(gelu), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(gelu), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}((layer_1 = Dense(2 => 32, gelu), layer_2 = Dense(32 => 32, gelu), layer_3 = Dense(32 => 2)), nothing)_reactant#1069")}()

    Now we can test the difference between the results:

    julia
    pred_compiled, _ = model_compiled(x_ra, ps_ra, Lux.testmode(st_ra))
    +
    +pred_lux .- Array(pred_compiled)
    2×32 Matrix{Float32}:
    + 0.0  -1.19209f-7  -2.98023f-8  2.98023f-8  …  2.98023f-8  0.0  -1.49012f-8
    + 0.0   1.19209f-7   8.9407f-8   1.78814f-7     1.49012f-8  0.0   2.98023f-8

    The difference is very small as we would expect. Now, let's try to differentiate the output of the model. We need to use Enzyme.jl to do this.

    julia
    function loss_function(model, ps, st, x, y)
    +    pred, _ = model(x, ps, st)
    +    return MSELoss()(pred, y)
    +end
    loss_function (generic function with 1 method)

    We will use Zygote.jl to compute the gradient of the loss function for the vanilla model.

    julia
    loss_function(model, ps, st, x, y)
    +
    +∂ps_zyg = only(Zygote.gradient(ps -> loss_function(model, ps, st, x, y), ps))
    (layer_1 = (weight = Float32[-0.011611392 -0.12556516; -0.09724939 0.11515345; … ; 0.08667634 -0.2689521; -0.09643307 0.030881835], bias = Float32[0.048133414, -0.106884085, 0.097701035, 0.105524555, -0.039647065, -0.018338889, -0.019115759, -0.15107606, 0.013992601, -0.014150472  …  0.0041674753, 0.032615878, 0.031403527, 0.13760866, -0.04225484, 0.049417753, -0.00059220614, -0.03242131, 0.18807876, -0.07640441]), layer_2 = (weight = Float32[-0.004287243 0.028275706 … -0.0073489705 0.0028297475; 0.016479947 0.030926052 … -0.0036810301 0.019791333; … ; 0.010637202 -0.002057937 … 0.010218928 -0.047897488; 0.13518015 0.25378025 … 0.0903271 0.048811335], bias = Float32[0.018884761, 0.053747915, -0.17435724, -0.059518166, -0.10950818, 0.13725635, -0.048533253, -0.11365668, -0.3891182, 0.26477236  …  0.2236399, 0.1377298, -0.027226413, -0.09919551, -0.12902719, 0.0072498624, -0.012183794, 0.066751055, -0.017432783, 0.26700422]), layer_3 = (weight = Float32[-2.5994074 0.07425845 … 0.08953094 -0.9130077; -1.1187928 0.0062888456 … -0.032405674 -0.4112945], bias = Float32[-1.6541586, -0.61384505]))

    Now we will compile the gradient function using Reactant.@compile.

    julia
    function enzyme_gradient(model, ps, st, x, y)
    +    return Enzyme.gradient(Enzyme.Reverse, Const(loss_function), Const(model),
    +        ps, Const(st), Const(x), Const(y))[2]
    +end
    +
    +enzyme_gradient_compiled = @compile enzyme_gradient(model, ps_ra, st_ra, x_ra, y_ra)
    +
    +∂ps_enzyme = enzyme_gradient_compiled(model, ps_ra, st_ra, x_ra, y_ra)
    (layer_1 = (weight = Float32[-0.011611394 -0.12556516; -0.09724942 0.11515346; … ; 0.08667634 -0.2689521; -0.09643307 0.030881835], bias = Float32[0.048133414, -0.10688411, 0.097701035, 0.10552457, -0.039647065, -0.018338893, -0.01911576, -0.15107603, 0.013992591, -0.01415047  …  0.0041674743, 0.03261588, 0.031403534, 0.13760868, -0.042254835, 0.049417756, -0.0005922087, -0.0324213, 0.18807876, -0.076404385]), layer_2 = (weight = Float32[-0.004287243 0.02827571 … -0.0073489705 0.0028297466; 0.016479947 0.030926049 … -0.0036810287 0.019791335; … ; 0.010637204 -0.0020579377 … 0.0102189295 -0.047897488; 0.13518013 0.25378025 … 0.0903271 0.048811335], bias = Float32[0.018884756, 0.053747915, -0.17435724, -0.059518166, -0.1095082, 0.13725637, -0.04853325, -0.11365668, -0.38911813, 0.26477236  …  0.22363997, 0.1377298, -0.027226416, -0.0991955, -0.12902719, 0.007249862, -0.012183795, 0.06675106, -0.017432783, 0.26700416]), layer_3 = (weight = Float32[-2.5994072 0.07425846 … 0.089530945 -0.9130077; -1.1187928 0.006288857 … -0.032405667 -0.4112944], bias = Float32[-1.6541584, -0.6138451]))

    Now we check the difference:

    julia
    fmap(Broadcast.BroadcastFunction(-), ∂ps_zyg, ∂ps_enzyme)
    (layer_1 = (weight = Float32[1.8626451f-9 0.0; 2.9802322f-8 -1.4901161f-8; … ; 0.0 0.0; 0.0 0.0], bias = Float32[0.0, 2.2351742f-8, 0.0, -1.4901161f-8, 0.0, 3.7252903f-9, 1.8626451f-9, -2.9802322f-8, 1.0244548f-8, -2.7939677f-9  …  9.313226f-10, -3.7252903f-9, -7.450581f-9, -1.4901161f-8, -3.7252903f-9, -3.7252903f-9, 2.561137f-9, -1.1175871f-8, 0.0, -2.2351742f-8]), layer_2 = (weight = Float32[0.0 -3.7252903f-9 … 0.0 9.313226f-10; 0.0 3.7252903f-9 … -1.3969839f-9 -1.8626451f-9; … ; -1.8626451f-9 6.9849193f-10 … -1.8626451f-9 0.0; 1.4901161f-8 0.0 … 0.0 0.0], bias = Float32[5.5879354f-9, 0.0, 0.0, 0.0, 2.2351742f-8, -1.4901161f-8, -3.7252903f-9, 0.0, -5.9604645f-8, 0.0  …  -5.9604645f-8, 0.0, 3.7252903f-9, -7.450581f-9, 0.0, 4.656613f-10, 9.313226f-10, -7.450581f-9, 0.0, 5.9604645f-8]), layer_3 = (weight = Float32[-2.3841858f-7 -1.4901161f-8 … -7.450581f-9 0.0; 0.0 -1.1641532f-8 … -7.450581f-9 -8.940697f-8], bias = Float32[-2.3841858f-7, 5.9604645f-8]))

    Using the TrainState API

    Now that we saw the low-level API let's see how to train the model without any of this boilerplate. Simply follow the following steps:

    1. Create a device using xla_device. Remember to load Reactant.jl before doing this.

    2. Similar to other device functions move the model, parameters, states and data to the device. Note that you might want to use DeviceIterator to move the data loader to the device with an iterator.

    3. Construct a TrainState using Training.TrainState.

    4. And most importantly use AutoEnzyme while calling Training.single_train_step! or Training.single_train_step.

    julia
    model = Chain(
    +    Dense(2 => 4, gelu),
    +    Dense(4 => 4, gelu),
    +    Dense(4 => 2)
    +)
    +ps, st = Lux.setup(Random.default_rng(), model)
    +
    +x_ra = [randn(Float32, 2, 32) for _ in 1:32]
    +y_ra = [xᵢ .^ 2 for xᵢ in x_ra]
    +ps_ra = ps |> xdev
    +st_ra = st |> xdev
    +
    +dataloader = DeviceIterator(xdev, zip(x_ra, y_ra))
    +
    +function train_model(model, ps, st, dataloader)
    +    train_state = Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    for iteration in 1:1000
    +        for (xᵢ, yᵢ) in dataloader
    +            grads, loss, stats, train_state = Training.single_train_step!(
    +                AutoEnzyme(), MSELoss(), (xᵢ, yᵢ), train_state)
    +        end
    +        if iteration % 100 == 0 || iteration == 1
    +            # We need to do this since scalar outputs are currently expressed as a zero-dim
    +            # array
    +            loss = Array(loss)[]
    +            @printf("Iter: [%4d/%4d]\\tLoss: %.8f\\n", iteration, 1000, loss)
    +        end
    +    end
    +
    +    return train_state
    +end
    +
    +train_model(model, ps_ra, st_ra, dataloader)
    Iter: [   1/1000]	Loss: 3.07964921
    +Iter: [ 100/1000]	Loss: 1.06519687
    +Iter: [ 200/1000]	Loss: 0.44807646
    +Iter: [ 300/1000]	Loss: 0.24150778
    +Iter: [ 400/1000]	Loss: 0.14340512
    +Iter: [ 500/1000]	Loss: 0.09299411
    +Iter: [ 600/1000]	Loss: 0.06612328
    +Iter: [ 700/1000]	Loss: 0.04551310
    +Iter: [ 800/1000]	Loss: 0.03070261
    +Iter: [ 900/1000]	Loss: 0.02143306
    +Iter: [1000/1000]	Loss: 0.01542492
    `,40)]))}const E=i(e,[["render",l]]);export{g as __pageData,E as default}; diff --git a/previews/PR1023/assets/manual_compiling_lux_models.md.CpD3KwNd.lean.js b/previews/PR1023/assets/manual_compiling_lux_models.md.CpD3KwNd.lean.js new file mode 100644 index 0000000000..21aa5a8301 --- /dev/null +++ b/previews/PR1023/assets/manual_compiling_lux_models.md.CpD3KwNd.lean.js @@ -0,0 +1,75 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const g=JSON.parse('{"title":"Compiling Lux Models using Reactant.jl","description":"","frontmatter":{},"headers":[],"relativePath":"manual/compiling_lux_models.md","filePath":"manual/compiling_lux_models.md","lastUpdated":null}'),e={name:"manual/compiling_lux_models.md"};function l(p,s,h,k,d,r){return t(),a("div",null,s[0]||(s[0]=[n(`

    Compiling Lux Models using Reactant.jl

    Quoting the Reactant.jl Readme:

    Reactant takes Julia function and compile it into MLIR and run fancy optimizations on top of it, including using EnzymeMLIR for automatic differentiation, and create relevant executables for CPU/GPU/TPU via XLA. It presently operates as a tracing system. Compiled functions will assume the same control flow pattern as was original taken by objects used at compile time, and control flow (e.g. if, for) as well as any type instabilities will be removed. The benefits of this approach is immediately making all such code available for advanced optimization with little developer effort.

    Experimental

    Reactant compilation is a very new feature and is currently experimental. Certain models might not be compilable yet, but we are actively working on it. Open an issue if you encounter any problems.

    julia
    using Lux, Reactant, Enzyme, Random, Zygote
    +using Functors, Optimisers, Printf

    Using the TrainState API

    If you are using the Training.TrainState API, skip to the bottom of this page to see how to train the model without any of this boilerplate.

    We start by defining a simple MLP model:

    julia
    model = Chain(
    +    Dense(2 => 32, gelu),
    +    Dense(32 => 32, gelu),
    +    Dense(32 => 2)
    +)
    +ps, st = Lux.setup(Random.default_rng(), model)
    ((layer_1 = (weight = Float32[-1.2228831 -0.87702435; 0.5031421 -0.15133555; … ; -0.31550723 -0.7672513; 0.111552626 0.6064619], bias = Float32[-0.63795453, 0.62450767, -0.014877922, 0.25385493, -0.20188306, 0.21950458, 0.109203495, 0.23021114, -0.26657984, 0.16187939  …  -0.6409691, 0.4391564, 0.14488737, 0.49998975, -0.04566476, -0.56069607, -0.33442986, -0.1549292, -0.42669478, 0.636308]), layer_2 = (weight = Float32[0.293211 0.19084926 … 0.2464001 0.2913357; -0.116796836 0.09926938 … -0.26311737 -0.15802455; … ; -0.2042089 -0.22406094 … 0.13504265 0.09289699; 0.25389904 0.28355134 … 0.28725442 0.13343152], bias = Float32[0.12992674, 0.14568081, -0.10754459, -0.15686738, -0.14118214, 0.088205874, -0.06301335, 0.06027697, 0.14445141, 0.08791955  …  0.053627778, -0.06618893, 0.1124609, 0.037500158, 0.12827216, -0.13913931, -0.17048413, -0.1032465, -0.15493166, -0.0069942693]), layer_3 = (weight = Float32[-0.031503614 -0.23162955 … 0.097182155 -0.099906564; 0.05729505 0.28042415 … 0.1293236 -0.18089005], bias = Float32[-0.16409892, 0.042256515])), (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()))

    We then create a random input and output data:

    julia
    x = randn(Float32, 2, 32)
    +y = x .^ 2
    2×32 Matrix{Float32}:
    + 0.203036   0.362593  0.354464   0.0320963  …  0.0954186  0.713316  0.438519
    + 0.0155126  1.13864   0.0187668  0.142251      2.24169    4.16407   0.415858

    We will use xla_device similar to gpu_device to move the arrays to Reactant.

    julia
    const xdev = xla_device()
    +
    +x_ra = x |> xdev
    +y_ra = y |> xdev
    +ps_ra = ps |> xdev
    +st_ra = st |> xdev
    +nothing

    First let's run the model as we would normally:

    julia
    pred_lux, _ = model(x, ps, Lux.testmode(st))
    (Float32[-0.20053944 -0.8147778 … -2.3903124 -0.15544322; 0.1585735 0.4981351 … 1.2586653 0.27545732], (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()))

    To run it using XLA we need to compile the model. We can do this using the Reactant.@compile macro. Note that the inputs need to be moved to the device using xla_device first.

    julia
    model_compiled = @compile model(x_ra, ps_ra, Lux.testmode(st_ra))
    Reactant.Compiler.Thunk{Symbol("##Chain{@NamedTuple{layer_1::Dense{typeof(gelu), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(gelu), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}((layer_1 = Dense(2 => 32, gelu), layer_2 = Dense(32 => 32, gelu), layer_3 = Dense(32 => 2)), nothing)_reactant#1069")}()

    Now we can test the difference between the results:

    julia
    pred_compiled, _ = model_compiled(x_ra, ps_ra, Lux.testmode(st_ra))
    +
    +pred_lux .- Array(pred_compiled)
    2×32 Matrix{Float32}:
    + 0.0  -1.19209f-7  -2.98023f-8  2.98023f-8  …  2.98023f-8  0.0  -1.49012f-8
    + 0.0   1.19209f-7   8.9407f-8   1.78814f-7     1.49012f-8  0.0   2.98023f-8

    The difference is very small as we would expect. Now, let's try to differentiate the output of the model. We need to use Enzyme.jl to do this.

    julia
    function loss_function(model, ps, st, x, y)
    +    pred, _ = model(x, ps, st)
    +    return MSELoss()(pred, y)
    +end
    loss_function (generic function with 1 method)

    We will use Zygote.jl to compute the gradient of the loss function for the vanilla model.

    julia
    loss_function(model, ps, st, x, y)
    +
    +∂ps_zyg = only(Zygote.gradient(ps -> loss_function(model, ps, st, x, y), ps))
    (layer_1 = (weight = Float32[-0.011611392 -0.12556516; -0.09724939 0.11515345; … ; 0.08667634 -0.2689521; -0.09643307 0.030881835], bias = Float32[0.048133414, -0.106884085, 0.097701035, 0.105524555, -0.039647065, -0.018338889, -0.019115759, -0.15107606, 0.013992601, -0.014150472  …  0.0041674753, 0.032615878, 0.031403527, 0.13760866, -0.04225484, 0.049417753, -0.00059220614, -0.03242131, 0.18807876, -0.07640441]), layer_2 = (weight = Float32[-0.004287243 0.028275706 … -0.0073489705 0.0028297475; 0.016479947 0.030926052 … -0.0036810301 0.019791333; … ; 0.010637202 -0.002057937 … 0.010218928 -0.047897488; 0.13518015 0.25378025 … 0.0903271 0.048811335], bias = Float32[0.018884761, 0.053747915, -0.17435724, -0.059518166, -0.10950818, 0.13725635, -0.048533253, -0.11365668, -0.3891182, 0.26477236  …  0.2236399, 0.1377298, -0.027226413, -0.09919551, -0.12902719, 0.0072498624, -0.012183794, 0.066751055, -0.017432783, 0.26700422]), layer_3 = (weight = Float32[-2.5994074 0.07425845 … 0.08953094 -0.9130077; -1.1187928 0.0062888456 … -0.032405674 -0.4112945], bias = Float32[-1.6541586, -0.61384505]))

    Now we will compile the gradient function using Reactant.@compile.

    julia
    function enzyme_gradient(model, ps, st, x, y)
    +    return Enzyme.gradient(Enzyme.Reverse, Const(loss_function), Const(model),
    +        ps, Const(st), Const(x), Const(y))[2]
    +end
    +
    +enzyme_gradient_compiled = @compile enzyme_gradient(model, ps_ra, st_ra, x_ra, y_ra)
    +
    +∂ps_enzyme = enzyme_gradient_compiled(model, ps_ra, st_ra, x_ra, y_ra)
    (layer_1 = (weight = Float32[-0.011611394 -0.12556516; -0.09724942 0.11515346; … ; 0.08667634 -0.2689521; -0.09643307 0.030881835], bias = Float32[0.048133414, -0.10688411, 0.097701035, 0.10552457, -0.039647065, -0.018338893, -0.01911576, -0.15107603, 0.013992591, -0.01415047  …  0.0041674743, 0.03261588, 0.031403534, 0.13760868, -0.042254835, 0.049417756, -0.0005922087, -0.0324213, 0.18807876, -0.076404385]), layer_2 = (weight = Float32[-0.004287243 0.02827571 … -0.0073489705 0.0028297466; 0.016479947 0.030926049 … -0.0036810287 0.019791335; … ; 0.010637204 -0.0020579377 … 0.0102189295 -0.047897488; 0.13518013 0.25378025 … 0.0903271 0.048811335], bias = Float32[0.018884756, 0.053747915, -0.17435724, -0.059518166, -0.1095082, 0.13725637, -0.04853325, -0.11365668, -0.38911813, 0.26477236  …  0.22363997, 0.1377298, -0.027226416, -0.0991955, -0.12902719, 0.007249862, -0.012183795, 0.06675106, -0.017432783, 0.26700416]), layer_3 = (weight = Float32[-2.5994072 0.07425846 … 0.089530945 -0.9130077; -1.1187928 0.006288857 … -0.032405667 -0.4112944], bias = Float32[-1.6541584, -0.6138451]))

    Now we check the difference:

    julia
    fmap(Broadcast.BroadcastFunction(-), ∂ps_zyg, ∂ps_enzyme)
    (layer_1 = (weight = Float32[1.8626451f-9 0.0; 2.9802322f-8 -1.4901161f-8; … ; 0.0 0.0; 0.0 0.0], bias = Float32[0.0, 2.2351742f-8, 0.0, -1.4901161f-8, 0.0, 3.7252903f-9, 1.8626451f-9, -2.9802322f-8, 1.0244548f-8, -2.7939677f-9  …  9.313226f-10, -3.7252903f-9, -7.450581f-9, -1.4901161f-8, -3.7252903f-9, -3.7252903f-9, 2.561137f-9, -1.1175871f-8, 0.0, -2.2351742f-8]), layer_2 = (weight = Float32[0.0 -3.7252903f-9 … 0.0 9.313226f-10; 0.0 3.7252903f-9 … -1.3969839f-9 -1.8626451f-9; … ; -1.8626451f-9 6.9849193f-10 … -1.8626451f-9 0.0; 1.4901161f-8 0.0 … 0.0 0.0], bias = Float32[5.5879354f-9, 0.0, 0.0, 0.0, 2.2351742f-8, -1.4901161f-8, -3.7252903f-9, 0.0, -5.9604645f-8, 0.0  …  -5.9604645f-8, 0.0, 3.7252903f-9, -7.450581f-9, 0.0, 4.656613f-10, 9.313226f-10, -7.450581f-9, 0.0, 5.9604645f-8]), layer_3 = (weight = Float32[-2.3841858f-7 -1.4901161f-8 … -7.450581f-9 0.0; 0.0 -1.1641532f-8 … -7.450581f-9 -8.940697f-8], bias = Float32[-2.3841858f-7, 5.9604645f-8]))

    Using the TrainState API

    Now that we saw the low-level API let's see how to train the model without any of this boilerplate. Simply follow the following steps:

    1. Create a device using xla_device. Remember to load Reactant.jl before doing this.

    2. Similar to other device functions move the model, parameters, states and data to the device. Note that you might want to use DeviceIterator to move the data loader to the device with an iterator.

    3. Construct a TrainState using Training.TrainState.

    4. And most importantly use AutoEnzyme while calling Training.single_train_step! or Training.single_train_step.

    julia
    model = Chain(
    +    Dense(2 => 4, gelu),
    +    Dense(4 => 4, gelu),
    +    Dense(4 => 2)
    +)
    +ps, st = Lux.setup(Random.default_rng(), model)
    +
    +x_ra = [randn(Float32, 2, 32) for _ in 1:32]
    +y_ra = [xᵢ .^ 2 for xᵢ in x_ra]
    +ps_ra = ps |> xdev
    +st_ra = st |> xdev
    +
    +dataloader = DeviceIterator(xdev, zip(x_ra, y_ra))
    +
    +function train_model(model, ps, st, dataloader)
    +    train_state = Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    for iteration in 1:1000
    +        for (xᵢ, yᵢ) in dataloader
    +            grads, loss, stats, train_state = Training.single_train_step!(
    +                AutoEnzyme(), MSELoss(), (xᵢ, yᵢ), train_state)
    +        end
    +        if iteration % 100 == 0 || iteration == 1
    +            # We need to do this since scalar outputs are currently expressed as a zero-dim
    +            # array
    +            loss = Array(loss)[]
    +            @printf("Iter: [%4d/%4d]\\tLoss: %.8f\\n", iteration, 1000, loss)
    +        end
    +    end
    +
    +    return train_state
    +end
    +
    +train_model(model, ps_ra, st_ra, dataloader)
    Iter: [   1/1000]	Loss: 3.07964921
    +Iter: [ 100/1000]	Loss: 1.06519687
    +Iter: [ 200/1000]	Loss: 0.44807646
    +Iter: [ 300/1000]	Loss: 0.24150778
    +Iter: [ 400/1000]	Loss: 0.14340512
    +Iter: [ 500/1000]	Loss: 0.09299411
    +Iter: [ 600/1000]	Loss: 0.06612328
    +Iter: [ 700/1000]	Loss: 0.04551310
    +Iter: [ 800/1000]	Loss: 0.03070261
    +Iter: [ 900/1000]	Loss: 0.02143306
    +Iter: [1000/1000]	Loss: 0.01542492
    `,40)]))}const E=i(e,[["render",l]]);export{g as __pageData,E as default}; diff --git a/previews/PR1023/assets/manual_debugging.md.DPbHDP8E.js b/previews/PR1023/assets/manual_debugging.md.DPbHDP8E.js new file mode 100644 index 0000000000..22e620765e --- /dev/null +++ b/previews/PR1023/assets/manual_debugging.md.DPbHDP8E.js @@ -0,0 +1,120 @@ +import{_ as a,c as i,a2 as n,o as e}from"./chunks/framework.DFwXuivk.js";const g=JSON.parse('{"title":"Debugging Lux Models","description":"","frontmatter":{},"headers":[],"relativePath":"manual/debugging.md","filePath":"manual/debugging.md","lastUpdated":null}'),t={name:"manual/debugging.md"};function l(p,s,h,k,r,d){return e(),i("div",null,s[0]||(s[0]=[n(`

    Debugging Lux Models

    Debugging DNNs can be very painful. Especially with the gigantic stacktraces for Lux, it is even harder to pin-point to which particular layer errored out. This page describes some useful tools that ship with Lux, that can help you debug your models.

    TL;DR

    Simply wrap your model with Lux.Experimental.@debug_mode!!

    Don't Forget

    Remember to use the non Debug mode model after you finish debugging. Debug mode models are way slower.

    Let us construct a model which has an obviously incorrect dimension. In this example, you will see how easy it is to pin-point the problematic layer.

    Incorrect Model Specification: Dimension Mismatch Problems

    julia
    using Lux, Random
    +
    +model = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 3), Dense(1 => 1)), BatchNorm(1))
    +
    +model_debug = Lux.Experimental.@debug_mode model
    Chain(
    +    layer_1 = DebugLayer(
    +        layer = Dense(1 => 16, relu),   # 32 parameters
    +    ),
    +    layer_2 = Chain(
    +        layer_1 = DebugLayer(
    +            layer = Dense(16 => 3),     # 51 parameters
    +        ),
    +        layer_2 = DebugLayer(
    +            layer = Dense(1 => 1),      # 2 parameters
    +        ),
    +    ),
    +    layer_3 = DebugLayer(
    +        layer = BatchNorm(1, affine=true, track_stats=true),  # 2 parameters, plus 3
    +    ),
    +)         # Total: 87 parameters,
    +          #        plus 3 states.

    Note that we can use the parameters and states for model itself in model_debug, no need to make any changes. If you ran the original model this is the kind of error you would see:

    julia
    rng = Xoshiro(0)
    +
    +ps, st = Lux.setup(rng, model)
    +x = randn(rng, Float32, 1, 2)
    +
    +try
    +    model(x, ps, st)
    +catch e
    +    println(e)
    +end
    DimensionMismatch("A has shape (1, 1) but B has shape (3, 2)")

    Ofcourse, this error will come with a detailed stacktrace, but it is still not very useful. Now let's try using the debug mode model:

    julia
    try
    +    model_debug(x, ps, st)
    +catch e
    +    println(e)
    +end
    [ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 16, relu) at location KeyPath(:model, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (16, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (16, 2).
    +[ Info: Running Layer: Dense(16 => 3) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (3, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (3, 2).
    +[ Info: Running Layer: Dense(1 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2)!
    +┌ Error: Layer Dense(1 => 1) failed!! This layer is present at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2).
    +└ @ Lux.Experimental /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/src/contrib/debug.jl:102
    +DimensionMismatch("A has shape (1, 1) but B has shape (3, 2)")

    See now we know that model.layers.layer_2.layers.layer_2 is the problematic layer. Let us fix that layer and see what happens:

    julia
    model = Chain(Dense(1 => 16, relu),
    +    Chain(
    +        Dense(16 => 3),  
    +        Dense(16 => 1),  
    +        Dense(1 => 1)),
    +    BatchNorm(1))
    julia
    model_fixed = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 1), Dense(1 => 1)),
    +    BatchNorm(1))
    +
    +ps, st = Lux.setup(rng, model_fixed)
    +
    +model_fixed(x, ps, st)
    (Float32[-0.99998605 0.999986], (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_3 = (running_mean = Float32[0.07133968], running_var = Float32[0.971899], training = Val{true}())))

    Voila!! We have tracked down and fixed the problem.

    Tracking down NaNs

    Have you encountered those pesky little NaNs in your training? They are very hard to track down. We will create an artificially simulate NaNs in our model and see how we can track the offending layer.

    We can set nan_check to :forward, :backward or :both to check for NaNs in the debug model. (or even disable it by setting it to :none)

    julia
    model = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 1), Dense(1 => 1)),
    +    BatchNorm(1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model_debug = Lux.Experimental.@debug_mode model nan_check=:both
    Chain(
    +    layer_1 = DebugLayer(
    +        layer = Dense(1 => 16, relu),   # 32 parameters
    +    ),
    +    layer_2 = Chain(
    +        layer_1 = DebugLayer(
    +            layer = Dense(16 => 1),     # 17 parameters
    +        ),
    +        layer_2 = DebugLayer(
    +            layer = Dense(1 => 1),      # 2 parameters
    +        ),
    +    ),
    +    layer_3 = DebugLayer(
    +        layer = BatchNorm(1, affine=true, track_stats=true),  # 2 parameters, plus 3
    +    ),
    +)         # Total: 53 parameters,
    +          #        plus 3 states.

    Let us set a value in the parameter to NaN:

    julia
    ps.layer_2.layer_2.weight[1, 1] = NaN
    NaN

    Now let us run the model

    julia
    model(x, ps, st)
    (Float32[NaN NaN], (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_3 = (running_mean = Float32[NaN], running_var = Float32[NaN], training = Val{true}())))

    Ah as expected our output is NaN. But is is not very clear how to track where the first NaN occurred. Let's run the debug model and check:

    julia
    try
    +    model_debug(x, ps, st)
    +catch e
    +    println(e)
    +end
    [ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 16, relu) at location KeyPath(:model, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (16, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (16, 2).
    +[ Info: Running Layer: Dense(16 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2)!
    +DomainError(Float32[NaN;;], "NaNs detected in parameters (@ KeyPath(:weight,))  of layer Dense(1 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2).")

    And we have figured it out! The first NaN occurred in the parameters of model.layers.layer_2.layers.layer_2! But what if NaN occurs in the reverse pass! Let us define a custom layer and introduce a fake NaN in the backward pass.

    julia
    using ChainRulesCore, Zygote
    +
    +const CRC = ChainRulesCore
    +
    +offending_layer(x) = 2 .* x
    offending_layer (generic function with 1 method)
    julia
    model = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 1), offending_layer), BatchNorm(1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(x, ps, st)
    (Float32[0.9999881 -0.9999881], (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_3 = (running_mean = Float32[0.0026271285], running_var = Float32[0.98396176], training = Val{true}())))

    Let us define a custom backward pass to introduce some NaNs:

    julia
    function CRC.rrule(::typeof(offending_layer), x)
    +    y = offending_layer(x)
    +    function ∇offending_layer(Δ)
    +        Δ[1] = NaN
    +        return NoTangent(), Δ
    +    end
    +    return y, ∇offending_layer
    +end

    Let us compute the gradient of the layer now:

    julia
    Zygote.gradient(ps -> sum(first(model(x, ps, st))), ps)
    ((layer_1 = (weight = Float32[0.0; 0.0; … ; 0.0; 0.0;;], bias = Float32[0.0, 0.0, 0.0, 0.0, NaN, 0.0, NaN, NaN, 0.0, 0.0, 0.0, NaN, NaN, NaN, 0.0, 0.0]), layer_2 = (layer_1 = (weight = Float32[NaN NaN … NaN NaN], bias = Float32[NaN]), layer_2 = nothing), layer_3 = (scale = Float32[0.0], bias = Float32[2.0])),)

    Oh no!! A NaN is present in the gradient of ps. Let us run the debug model and see where the NaN occurred:

    julia
    model_debug = Lux.Experimental.@debug_mode model nan_check=:both
    +
    +try
    +    Zygote.gradient(ps -> sum(first(model_debug(x, ps, st))), ps)
    +catch e
    +    println(e)
    +end
    [ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 16, relu) at location KeyPath(:model, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (16, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (16, 2).
    +[ Info: Running Layer: Dense(16 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: WrappedFunction(offending_layer) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: BatchNorm(1, affine=true, track_stats=true) at location KeyPath(:model, :layers, :layer_3)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +DomainError(Float32[NaN 0.0], "NaNs detected in pullback output (x)  of layer WrappedFunction(offending_layer) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2).")

    And there you go our debug layer prints that the problem is in WrappedFunction(offending_layer) at location model.layers.layer_2.layers.layer_2! Once we fix the pullback of the layer, we will fix the NaNs.

    Conclusion

    In this manual section, we have discussed tracking down errors in Lux models. We have covered tracking incorrect model specifications and NaNs in forward and backward passes. However, remember that this is an Experimental feature, and there might be edge cases that don't work correctly. If you find any such cases, please open an issue on GitHub!

    `,49)]))}const c=a(t,[["render",l]]);export{g as __pageData,c as default}; diff --git a/previews/PR1023/assets/manual_debugging.md.DPbHDP8E.lean.js b/previews/PR1023/assets/manual_debugging.md.DPbHDP8E.lean.js new file mode 100644 index 0000000000..22e620765e --- /dev/null +++ b/previews/PR1023/assets/manual_debugging.md.DPbHDP8E.lean.js @@ -0,0 +1,120 @@ +import{_ as a,c as i,a2 as n,o as e}from"./chunks/framework.DFwXuivk.js";const g=JSON.parse('{"title":"Debugging Lux Models","description":"","frontmatter":{},"headers":[],"relativePath":"manual/debugging.md","filePath":"manual/debugging.md","lastUpdated":null}'),t={name:"manual/debugging.md"};function l(p,s,h,k,r,d){return e(),i("div",null,s[0]||(s[0]=[n(`

    Debugging Lux Models

    Debugging DNNs can be very painful. Especially with the gigantic stacktraces for Lux, it is even harder to pin-point to which particular layer errored out. This page describes some useful tools that ship with Lux, that can help you debug your models.

    TL;DR

    Simply wrap your model with Lux.Experimental.@debug_mode!!

    Don't Forget

    Remember to use the non Debug mode model after you finish debugging. Debug mode models are way slower.

    Let us construct a model which has an obviously incorrect dimension. In this example, you will see how easy it is to pin-point the problematic layer.

    Incorrect Model Specification: Dimension Mismatch Problems

    julia
    using Lux, Random
    +
    +model = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 3), Dense(1 => 1)), BatchNorm(1))
    +
    +model_debug = Lux.Experimental.@debug_mode model
    Chain(
    +    layer_1 = DebugLayer(
    +        layer = Dense(1 => 16, relu),   # 32 parameters
    +    ),
    +    layer_2 = Chain(
    +        layer_1 = DebugLayer(
    +            layer = Dense(16 => 3),     # 51 parameters
    +        ),
    +        layer_2 = DebugLayer(
    +            layer = Dense(1 => 1),      # 2 parameters
    +        ),
    +    ),
    +    layer_3 = DebugLayer(
    +        layer = BatchNorm(1, affine=true, track_stats=true),  # 2 parameters, plus 3
    +    ),
    +)         # Total: 87 parameters,
    +          #        plus 3 states.

    Note that we can use the parameters and states for model itself in model_debug, no need to make any changes. If you ran the original model this is the kind of error you would see:

    julia
    rng = Xoshiro(0)
    +
    +ps, st = Lux.setup(rng, model)
    +x = randn(rng, Float32, 1, 2)
    +
    +try
    +    model(x, ps, st)
    +catch e
    +    println(e)
    +end
    DimensionMismatch("A has shape (1, 1) but B has shape (3, 2)")

    Ofcourse, this error will come with a detailed stacktrace, but it is still not very useful. Now let's try using the debug mode model:

    julia
    try
    +    model_debug(x, ps, st)
    +catch e
    +    println(e)
    +end
    [ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 16, relu) at location KeyPath(:model, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (16, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (16, 2).
    +[ Info: Running Layer: Dense(16 => 3) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (3, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (3, 2).
    +[ Info: Running Layer: Dense(1 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2)!
    +┌ Error: Layer Dense(1 => 1) failed!! This layer is present at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2).
    +└ @ Lux.Experimental /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/src/contrib/debug.jl:102
    +DimensionMismatch("A has shape (1, 1) but B has shape (3, 2)")

    See now we know that model.layers.layer_2.layers.layer_2 is the problematic layer. Let us fix that layer and see what happens:

    julia
    model = Chain(Dense(1 => 16, relu),
    +    Chain(
    +        Dense(16 => 3),  
    +        Dense(16 => 1),  
    +        Dense(1 => 1)),
    +    BatchNorm(1))
    julia
    model_fixed = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 1), Dense(1 => 1)),
    +    BatchNorm(1))
    +
    +ps, st = Lux.setup(rng, model_fixed)
    +
    +model_fixed(x, ps, st)
    (Float32[-0.99998605 0.999986], (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_3 = (running_mean = Float32[0.07133968], running_var = Float32[0.971899], training = Val{true}())))

    Voila!! We have tracked down and fixed the problem.

    Tracking down NaNs

    Have you encountered those pesky little NaNs in your training? They are very hard to track down. We will create an artificially simulate NaNs in our model and see how we can track the offending layer.

    We can set nan_check to :forward, :backward or :both to check for NaNs in the debug model. (or even disable it by setting it to :none)

    julia
    model = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 1), Dense(1 => 1)),
    +    BatchNorm(1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model_debug = Lux.Experimental.@debug_mode model nan_check=:both
    Chain(
    +    layer_1 = DebugLayer(
    +        layer = Dense(1 => 16, relu),   # 32 parameters
    +    ),
    +    layer_2 = Chain(
    +        layer_1 = DebugLayer(
    +            layer = Dense(16 => 1),     # 17 parameters
    +        ),
    +        layer_2 = DebugLayer(
    +            layer = Dense(1 => 1),      # 2 parameters
    +        ),
    +    ),
    +    layer_3 = DebugLayer(
    +        layer = BatchNorm(1, affine=true, track_stats=true),  # 2 parameters, plus 3
    +    ),
    +)         # Total: 53 parameters,
    +          #        plus 3 states.

    Let us set a value in the parameter to NaN:

    julia
    ps.layer_2.layer_2.weight[1, 1] = NaN
    NaN

    Now let us run the model

    julia
    model(x, ps, st)
    (Float32[NaN NaN], (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_3 = (running_mean = Float32[NaN], running_var = Float32[NaN], training = Val{true}())))

    Ah as expected our output is NaN. But is is not very clear how to track where the first NaN occurred. Let's run the debug model and check:

    julia
    try
    +    model_debug(x, ps, st)
    +catch e
    +    println(e)
    +end
    [ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 16, relu) at location KeyPath(:model, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (16, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (16, 2).
    +[ Info: Running Layer: Dense(16 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2)!
    +DomainError(Float32[NaN;;], "NaNs detected in parameters (@ KeyPath(:weight,))  of layer Dense(1 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2).")

    And we have figured it out! The first NaN occurred in the parameters of model.layers.layer_2.layers.layer_2! But what if NaN occurs in the reverse pass! Let us define a custom layer and introduce a fake NaN in the backward pass.

    julia
    using ChainRulesCore, Zygote
    +
    +const CRC = ChainRulesCore
    +
    +offending_layer(x) = 2 .* x
    offending_layer (generic function with 1 method)
    julia
    model = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 1), offending_layer), BatchNorm(1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(x, ps, st)
    (Float32[0.9999881 -0.9999881], (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_3 = (running_mean = Float32[0.0026271285], running_var = Float32[0.98396176], training = Val{true}())))

    Let us define a custom backward pass to introduce some NaNs:

    julia
    function CRC.rrule(::typeof(offending_layer), x)
    +    y = offending_layer(x)
    +    function ∇offending_layer(Δ)
    +        Δ[1] = NaN
    +        return NoTangent(), Δ
    +    end
    +    return y, ∇offending_layer
    +end

    Let us compute the gradient of the layer now:

    julia
    Zygote.gradient(ps -> sum(first(model(x, ps, st))), ps)
    ((layer_1 = (weight = Float32[0.0; 0.0; … ; 0.0; 0.0;;], bias = Float32[0.0, 0.0, 0.0, 0.0, NaN, 0.0, NaN, NaN, 0.0, 0.0, 0.0, NaN, NaN, NaN, 0.0, 0.0]), layer_2 = (layer_1 = (weight = Float32[NaN NaN … NaN NaN], bias = Float32[NaN]), layer_2 = nothing), layer_3 = (scale = Float32[0.0], bias = Float32[2.0])),)

    Oh no!! A NaN is present in the gradient of ps. Let us run the debug model and see where the NaN occurred:

    julia
    model_debug = Lux.Experimental.@debug_mode model nan_check=:both
    +
    +try
    +    Zygote.gradient(ps -> sum(first(model_debug(x, ps, st))), ps)
    +catch e
    +    println(e)
    +end
    [ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 16, relu) at location KeyPath(:model, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (16, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (16, 2).
    +[ Info: Running Layer: Dense(16 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: WrappedFunction(offending_layer) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: BatchNorm(1, affine=true, track_stats=true) at location KeyPath(:model, :layers, :layer_3)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +DomainError(Float32[NaN 0.0], "NaNs detected in pullback output (x)  of layer WrappedFunction(offending_layer) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2).")

    And there you go our debug layer prints that the problem is in WrappedFunction(offending_layer) at location model.layers.layer_2.layers.layer_2! Once we fix the pullback of the layer, we will fix the NaNs.

    Conclusion

    In this manual section, we have discussed tracking down errors in Lux models. We have covered tracking incorrect model specifications and NaNs in forward and backward passes. However, remember that this is an Experimental feature, and there might be edge cases that don't work correctly. If you find any such cases, please open an issue on GitHub!

    `,49)]))}const c=a(t,[["render",l]]);export{g as __pageData,c as default}; diff --git a/previews/PR1023/assets/manual_dispatch_custom_input.md.C-fcTpBz.js b/previews/PR1023/assets/manual_dispatch_custom_input.md.C-fcTpBz.js new file mode 100644 index 0000000000..9627765afb --- /dev/null +++ b/previews/PR1023/assets/manual_dispatch_custom_input.md.C-fcTpBz.js @@ -0,0 +1,61 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const g=JSON.parse('{"title":"Dispatching on Custom Input Types","description":"","frontmatter":{},"headers":[],"relativePath":"manual/dispatch_custom_input.md","filePath":"manual/dispatch_custom_input.md","lastUpdated":null}'),h={name:"manual/dispatch_custom_input.md"};function p(l,s,e,k,r,d){return t(),a("div",null,s[0]||(s[0]=[n(`

    Dispatching on Custom Input Types

    Which function should participate in dispatch?

    • Defining a dispatch on (::Layer)(x::MyInputType, ps, st::NamedTuple) is inconvenient, since it requires the user to define a new method for every layer type.

    • (::AbstractLuxLayer)(x::MyInputType, ps, st::NamedTuple) doesn't work.

    • Instead, we need to define the dispatch on Lux.apply(::AbstractLuxLayer, x::MyInputType, ps, st::NamedTuple).

    Concrete Example

    Consider Neural ODEs. In these models, often time we want to every iteration of the neural network to take the current time as input. Here, we won't go through implementing an entire Neural ODE model. Instead we will define a time dependent version of Chain.

    Time-Dependent Chain Implementation

    julia
    using Lux, Random
    +
    +struct TDChain{L <: NamedTuple} <: Lux.AbstractLuxWrapperLayer{:layers}
    +    layers::L
    +end
    +
    +function (l::TDChain)((x, t)::Tuple, ps, st::NamedTuple)
    +    # Concatenate along the 2nd last dimension
    +    sz = ntuple(i -> i == ndims(x) - 1 ? 1 : size(x, i), ndims(x))
    +    t_ = ones(eltype(x), sz) .* t  # Needs to be modified for GPU
    +    for name in keys(l.layers)
    +        x, st_ = Lux.apply(getfield(l.layers, name), cat(x, t_; dims=ndims(x) - 1),
    +                           getfield(ps, name), getfield(st, name))
    +        st = merge(st, NamedTuple{(name,)}((st_,)))
    +    end
    +    return x, st
    +end
    +
    +model = Chain(Dense(3, 4), TDChain((; d1=Dense(5, 4), d2=Dense(5, 4))), Dense(4, 1))
    Chain(
    +    layer_1 = Dense(3 => 4),            # 16 parameters
    +    layer_2 = TDChain(
    +        d1 = Dense(5 => 4),             # 24 parameters
    +        d2 = Dense(5 => 4),             # 24 parameters
    +    ),
    +    layer_3 = Dense(4 => 1),            # 5 parameters
    +)         # Total: 69 parameters,
    +          #        plus 0 states.

    Running the TDChain

    julia
    rng = MersenneTwister(0)
    +ps, st = Lux.setup(rng, model)
    +x = randn(rng, Float32, 3, 2)
    +
    +try
    +    model(x, ps, st)
    +catch e
    +    Base.showerror(stdout, e)
    +end
    MethodError: no method matching apply(::@NamedTuple{d1::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}, d2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, ::Matrix{Float32}, ::@NamedTuple{d1::@NamedTuple{weight::Matrix{Float32}, bias::Vector{Float32}}, d2::@NamedTuple{weight::Matrix{Float32}, bias::Vector{Float32}}}, ::@NamedTuple{d1::@NamedTuple{}, d2::@NamedTuple{}})
    +
    +Closest candidates are:
    +  apply(!Matched::AbstractLuxLayer, ::Any, ::Any, ::Any)
    +   @ LuxCore /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxCore/src/LuxCore.jl:154
    +  apply(!Matched::AbstractLuxLayer, !Matched::Tracker.TrackedArray, ::Any, ::Any)
    +   @ LuxCoreArrayInterfaceTrackerExt /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxCore/ext/LuxCoreArrayInterfaceTrackerExt.jl:19
    +  apply(!Matched::AbstractLuxLayer, !Matched::ReverseDiff.TrackedArray, ::Any, ::Any)
    +   @ LuxCoreArrayInterfaceReverseDiffExt /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxCore/ext/LuxCoreArrayInterfaceReverseDiffExt.jl:20
    +  ...

    Writing the Correct Dispatch Rules

    • Create a Custom Layer storing the time.
    julia
    struct ArrayAndTime{A <: AbstractArray, T <: Real}
    +    array::A
    +    time::T
    +end
    • Define the dispatch on Lux.apply(::AbstractLuxLayer, x::ArrayAndTime, ps, st::NamedTuple).
    julia
    function Lux.apply(layer::Lux.AbstractLuxLayer, x::ArrayAndTime, ps, st::NamedTuple)
    +    y, st = layer(x.array, ps, st)
    +    return ArrayAndTime(y, x.time), st
    +end
    +
    +function Lux.apply(layer::TDChain, x::ArrayAndTime, ps, st::NamedTuple)
    +    y, st = layer((x.array, x.time), ps, st)
    +    return ArrayAndTime(y, x.time), st
    +end
    • Run the model.
    julia
    xt = ArrayAndTime(x, 10.0f0)
    +
    +model(xt, ps, st)[1]
    Main.ArrayAndTime{Matrix{Float32}, Float32}(Float32[-2.1488175 -2.401215], 10.0f0)

    Using the Same Input for Non-TD Models

    Writing proper dispatch means we can simply replace the TDChain with a Chain (of course with dimension corrections) and the pipeline still works.

    julia
    model = Chain(Dense(3, 4), Chain((; d1=Dense(4, 4), d2=Dense(4, 4))), Dense(4, 1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(xt, ps, st)[1]
    Main.ArrayAndTime{Matrix{Float32}, Float32}(Float32[0.33758628 -0.079208925], 10.0f0)
    `,23)]))}const y=i(h,[["render",p]]);export{g as __pageData,y as default}; diff --git a/previews/PR1023/assets/manual_dispatch_custom_input.md.C-fcTpBz.lean.js b/previews/PR1023/assets/manual_dispatch_custom_input.md.C-fcTpBz.lean.js new file mode 100644 index 0000000000..9627765afb --- /dev/null +++ b/previews/PR1023/assets/manual_dispatch_custom_input.md.C-fcTpBz.lean.js @@ -0,0 +1,61 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const g=JSON.parse('{"title":"Dispatching on Custom Input Types","description":"","frontmatter":{},"headers":[],"relativePath":"manual/dispatch_custom_input.md","filePath":"manual/dispatch_custom_input.md","lastUpdated":null}'),h={name:"manual/dispatch_custom_input.md"};function p(l,s,e,k,r,d){return t(),a("div",null,s[0]||(s[0]=[n(`

    Dispatching on Custom Input Types

    Which function should participate in dispatch?

    • Defining a dispatch on (::Layer)(x::MyInputType, ps, st::NamedTuple) is inconvenient, since it requires the user to define a new method for every layer type.

    • (::AbstractLuxLayer)(x::MyInputType, ps, st::NamedTuple) doesn't work.

    • Instead, we need to define the dispatch on Lux.apply(::AbstractLuxLayer, x::MyInputType, ps, st::NamedTuple).

    Concrete Example

    Consider Neural ODEs. In these models, often time we want to every iteration of the neural network to take the current time as input. Here, we won't go through implementing an entire Neural ODE model. Instead we will define a time dependent version of Chain.

    Time-Dependent Chain Implementation

    julia
    using Lux, Random
    +
    +struct TDChain{L <: NamedTuple} <: Lux.AbstractLuxWrapperLayer{:layers}
    +    layers::L
    +end
    +
    +function (l::TDChain)((x, t)::Tuple, ps, st::NamedTuple)
    +    # Concatenate along the 2nd last dimension
    +    sz = ntuple(i -> i == ndims(x) - 1 ? 1 : size(x, i), ndims(x))
    +    t_ = ones(eltype(x), sz) .* t  # Needs to be modified for GPU
    +    for name in keys(l.layers)
    +        x, st_ = Lux.apply(getfield(l.layers, name), cat(x, t_; dims=ndims(x) - 1),
    +                           getfield(ps, name), getfield(st, name))
    +        st = merge(st, NamedTuple{(name,)}((st_,)))
    +    end
    +    return x, st
    +end
    +
    +model = Chain(Dense(3, 4), TDChain((; d1=Dense(5, 4), d2=Dense(5, 4))), Dense(4, 1))
    Chain(
    +    layer_1 = Dense(3 => 4),            # 16 parameters
    +    layer_2 = TDChain(
    +        d1 = Dense(5 => 4),             # 24 parameters
    +        d2 = Dense(5 => 4),             # 24 parameters
    +    ),
    +    layer_3 = Dense(4 => 1),            # 5 parameters
    +)         # Total: 69 parameters,
    +          #        plus 0 states.

    Running the TDChain

    julia
    rng = MersenneTwister(0)
    +ps, st = Lux.setup(rng, model)
    +x = randn(rng, Float32, 3, 2)
    +
    +try
    +    model(x, ps, st)
    +catch e
    +    Base.showerror(stdout, e)
    +end
    MethodError: no method matching apply(::@NamedTuple{d1::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}, d2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, ::Matrix{Float32}, ::@NamedTuple{d1::@NamedTuple{weight::Matrix{Float32}, bias::Vector{Float32}}, d2::@NamedTuple{weight::Matrix{Float32}, bias::Vector{Float32}}}, ::@NamedTuple{d1::@NamedTuple{}, d2::@NamedTuple{}})
    +
    +Closest candidates are:
    +  apply(!Matched::AbstractLuxLayer, ::Any, ::Any, ::Any)
    +   @ LuxCore /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxCore/src/LuxCore.jl:154
    +  apply(!Matched::AbstractLuxLayer, !Matched::Tracker.TrackedArray, ::Any, ::Any)
    +   @ LuxCoreArrayInterfaceTrackerExt /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxCore/ext/LuxCoreArrayInterfaceTrackerExt.jl:19
    +  apply(!Matched::AbstractLuxLayer, !Matched::ReverseDiff.TrackedArray, ::Any, ::Any)
    +   @ LuxCoreArrayInterfaceReverseDiffExt /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxCore/ext/LuxCoreArrayInterfaceReverseDiffExt.jl:20
    +  ...

    Writing the Correct Dispatch Rules

    • Create a Custom Layer storing the time.
    julia
    struct ArrayAndTime{A <: AbstractArray, T <: Real}
    +    array::A
    +    time::T
    +end
    • Define the dispatch on Lux.apply(::AbstractLuxLayer, x::ArrayAndTime, ps, st::NamedTuple).
    julia
    function Lux.apply(layer::Lux.AbstractLuxLayer, x::ArrayAndTime, ps, st::NamedTuple)
    +    y, st = layer(x.array, ps, st)
    +    return ArrayAndTime(y, x.time), st
    +end
    +
    +function Lux.apply(layer::TDChain, x::ArrayAndTime, ps, st::NamedTuple)
    +    y, st = layer((x.array, x.time), ps, st)
    +    return ArrayAndTime(y, x.time), st
    +end
    • Run the model.
    julia
    xt = ArrayAndTime(x, 10.0f0)
    +
    +model(xt, ps, st)[1]
    Main.ArrayAndTime{Matrix{Float32}, Float32}(Float32[-2.1488175 -2.401215], 10.0f0)

    Using the Same Input for Non-TD Models

    Writing proper dispatch means we can simply replace the TDChain with a Chain (of course with dimension corrections) and the pipeline still works.

    julia
    model = Chain(Dense(3, 4), Chain((; d1=Dense(4, 4), d2=Dense(4, 4))), Dense(4, 1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(xt, ps, st)[1]
    Main.ArrayAndTime{Matrix{Float32}, Float32}(Float32[0.33758628 -0.079208925], 10.0f0)
    `,23)]))}const y=i(h,[["render",p]]);export{g as __pageData,y as default}; diff --git a/previews/PR1023/assets/manual_distributed_utils.md.CYDIHMTo.js b/previews/PR1023/assets/manual_distributed_utils.md.CYDIHMTo.js new file mode 100644 index 0000000000..f4ec00994e --- /dev/null +++ b/previews/PR1023/assets/manual_distributed_utils.md.CYDIHMTo.js @@ -0,0 +1,4 @@ +import{_ as e,c as t,a2 as s,o as a}from"./chunks/framework.DFwXuivk.js";const c=JSON.parse('{"title":"Distributed Data Parallel Training","description":"","frontmatter":{},"headers":[],"relativePath":"manual/distributed_utils.md","filePath":"manual/distributed_utils.md","lastUpdated":null}'),n={name:"manual/distributed_utils.md"};function l(r,i,d,o,h,p){return a(),t("div",null,i[0]||(i[0]=[s(`

    Distributed Data Parallel Training

    Tip

    For a fully functional example, see the ImageNet Training Example.

    DDP Training using Lux.DistributedUtils is a spiritual successor to FluxMPI.jl, but has some key differences.

    Guide to Integrating DistributedUtils into your code

    • Initialize the respective backend with DistributedUtils.initialize, by passing in a backend type. It is important that you pass in the type, i.e. NCCLBackend and not the object NCCLBackend().
    julia
    DistributedUtils.initialize(NCCLBackend)
    julia
    backend = DistributedUtils.get_distributed_backend(NCCLBackend)

    It is important that you use this function instead of directly constructing the backend, since there are certain internal states that need to be synchronized.

    • Next synchronize the parameters and states of the model. This is done by calling DistributedUtils.synchronize!! with the backend and the respective input.
    julia
    ps = DistributedUtils.synchronize!!(backend, ps)
    +st = DistributedUtils.synchronize!!(backend, st)
    julia
    data = DistributedUtils.DistributedDataContainer(backend, data)
    • Wrap the optimizer in DistributedUtils.DistributedOptimizer to ensure that the optimizer is correctly synchronized across all processes before parameter updates. After initializing the state of the optimizer, synchronize the state across all processes.
    julia
    opt = DistributedUtils.DistributedOptimizer(backend, opt)
    +opt_state = Optimisers.setup(opt, ps)
    +opt_state = DistributedUtils.synchronize!!(backend, opt_state)
    • Finally change all logging and serialization code to trigger on local_rank(backend) == 0. This ensures that only the master process logs and serializes the model.

    Migration Guide from FluxMPI.jl

    Let's compare the changes we need to make wrt the FluxMPI.jl integration guide.

    1. FluxMPI.Init is now DistributedUtils.initialize.

    2. FluxMPI.synchronize!(x) needs to be changed to x_new = DistributedUtils.synchronize!!(backend, x).

    3. DistributedUtils.DistributedDataContainer, DistributedUtils.local_rank, and DistributedUtils.DistributedOptimizer need backend as the first input.

    And that's pretty much it!

    Removed Functionality

    1. FluxMPI.allreduce_gradients no longer exists. Previously this was needed when CUDA communication was flaky, with NCCL.jl this is no longer the case.

    2. FluxMPIFluxModel has been removed. DistributedUtils no longer works with Flux.

    Key Differences

    1. FluxMPI.synchronize! is now DistributedUtils.synchronize!! to highlight the fact that some of the inputs are not updated in-place.

    2. All of the functions now require a communication backend as input.

    3. We don't automatically determine if the MPI Implementation is CUDA or ROCM aware. See GPU-aware MPI for more information.

    4. Older (now non-existent) Lux.gpu implementations used to "just work" with FluxMPI.jl. We expect gpu_device to continue working as expected, however, we recommend using gpu_device after calling DistributedUtils.initialize to avoid any mismatch between the device set via DistributedUtils and the device stores in CUDADevice or AMDGPUDevice.

    Known Shortcomings

    1. Currently we don't run tests with CUDA or ROCM aware MPI, use those features at your own risk. We are working on adding tests for these features.

    2. AMDGPU support is mostly experimental and causes deadlocks in certain situations, this is being investigated. If you have a minimal reproducer for this, please open an issue.

    `,26)]))}const k=e(n,[["render",l]]);export{c as __pageData,k as default}; diff --git a/previews/PR1023/assets/manual_distributed_utils.md.CYDIHMTo.lean.js b/previews/PR1023/assets/manual_distributed_utils.md.CYDIHMTo.lean.js new file mode 100644 index 0000000000..f4ec00994e --- /dev/null +++ b/previews/PR1023/assets/manual_distributed_utils.md.CYDIHMTo.lean.js @@ -0,0 +1,4 @@ +import{_ as e,c as t,a2 as s,o as a}from"./chunks/framework.DFwXuivk.js";const c=JSON.parse('{"title":"Distributed Data Parallel Training","description":"","frontmatter":{},"headers":[],"relativePath":"manual/distributed_utils.md","filePath":"manual/distributed_utils.md","lastUpdated":null}'),n={name:"manual/distributed_utils.md"};function l(r,i,d,o,h,p){return a(),t("div",null,i[0]||(i[0]=[s(`

    Distributed Data Parallel Training

    Tip

    For a fully functional example, see the ImageNet Training Example.

    DDP Training using Lux.DistributedUtils is a spiritual successor to FluxMPI.jl, but has some key differences.

    Guide to Integrating DistributedUtils into your code

    • Initialize the respective backend with DistributedUtils.initialize, by passing in a backend type. It is important that you pass in the type, i.e. NCCLBackend and not the object NCCLBackend().
    julia
    DistributedUtils.initialize(NCCLBackend)
    julia
    backend = DistributedUtils.get_distributed_backend(NCCLBackend)

    It is important that you use this function instead of directly constructing the backend, since there are certain internal states that need to be synchronized.

    • Next synchronize the parameters and states of the model. This is done by calling DistributedUtils.synchronize!! with the backend and the respective input.
    julia
    ps = DistributedUtils.synchronize!!(backend, ps)
    +st = DistributedUtils.synchronize!!(backend, st)
    julia
    data = DistributedUtils.DistributedDataContainer(backend, data)
    • Wrap the optimizer in DistributedUtils.DistributedOptimizer to ensure that the optimizer is correctly synchronized across all processes before parameter updates. After initializing the state of the optimizer, synchronize the state across all processes.
    julia
    opt = DistributedUtils.DistributedOptimizer(backend, opt)
    +opt_state = Optimisers.setup(opt, ps)
    +opt_state = DistributedUtils.synchronize!!(backend, opt_state)
    • Finally change all logging and serialization code to trigger on local_rank(backend) == 0. This ensures that only the master process logs and serializes the model.

    Migration Guide from FluxMPI.jl

    Let's compare the changes we need to make wrt the FluxMPI.jl integration guide.

    1. FluxMPI.Init is now DistributedUtils.initialize.

    2. FluxMPI.synchronize!(x) needs to be changed to x_new = DistributedUtils.synchronize!!(backend, x).

    3. DistributedUtils.DistributedDataContainer, DistributedUtils.local_rank, and DistributedUtils.DistributedOptimizer need backend as the first input.

    And that's pretty much it!

    Removed Functionality

    1. FluxMPI.allreduce_gradients no longer exists. Previously this was needed when CUDA communication was flaky, with NCCL.jl this is no longer the case.

    2. FluxMPIFluxModel has been removed. DistributedUtils no longer works with Flux.

    Key Differences

    1. FluxMPI.synchronize! is now DistributedUtils.synchronize!! to highlight the fact that some of the inputs are not updated in-place.

    2. All of the functions now require a communication backend as input.

    3. We don't automatically determine if the MPI Implementation is CUDA or ROCM aware. See GPU-aware MPI for more information.

    4. Older (now non-existent) Lux.gpu implementations used to "just work" with FluxMPI.jl. We expect gpu_device to continue working as expected, however, we recommend using gpu_device after calling DistributedUtils.initialize to avoid any mismatch between the device set via DistributedUtils and the device stores in CUDADevice or AMDGPUDevice.

    Known Shortcomings

    1. Currently we don't run tests with CUDA or ROCM aware MPI, use those features at your own risk. We are working on adding tests for these features.

    2. AMDGPU support is mostly experimental and causes deadlocks in certain situations, this is being investigated. If you have a minimal reproducer for this, please open an issue.

    `,26)]))}const k=e(n,[["render",l]]);export{c as __pageData,k as default}; diff --git a/previews/PR1023/assets/manual_freezing_model_parameters.md.0i6pMVyg.js b/previews/PR1023/assets/manual_freezing_model_parameters.md.0i6pMVyg.js new file mode 100644 index 0000000000..27d88d34c9 --- /dev/null +++ b/previews/PR1023/assets/manual_freezing_model_parameters.md.0i6pMVyg.js @@ -0,0 +1,51 @@ +import{_ as i,c as a,a2 as n,o as e}from"./chunks/framework.DFwXuivk.js";const g=JSON.parse('{"title":"Freezing Model Parameters","description":"","frontmatter":{},"headers":[],"relativePath":"manual/freezing_model_parameters.md","filePath":"manual/freezing_model_parameters.md","lastUpdated":null}'),h={name:"manual/freezing_model_parameters.md"};function l(t,s,p,k,r,d){return e(),a("div",null,s[0]||(s[0]=[n(`

    Freezing Model Parameters

    Warning

    API for freezing parameters should be considered experimental at this point.

    In this manual entry, we will go over how to freeze certain parameters in a model.

    Freezing Layers of a Particular Kind

    To freeze a particular kind of layer, let's say Dense in the following example. We can use Lux.Experimental.layer_map and freeze layers if they are of type Dense.

    julia
    using Lux, Random, Functors
    +
    +rng = Xoshiro(0)
    +
    +model = Chain(Dense(3, 4), Chain(Dense(4, 4), Dropout(0.5f0), BatchNorm(4)), Dense(4, 1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +x = randn(rng, Float32, 3, 2)
    +
    +model(x, ps, st)
    +
    +function freeze_dense(d::Lux.Dense, ps, st, path)
    +    return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +end
    +freeze_dense(l, ps, st, path) = (l, ps, st)
    +
    +model_frozen, ps_frozen, st_frozen = Lux.Experimental.layer_map(freeze_dense, model, ps, st)
    +
    +model_frozen(x, ps_frozen, st_frozen)
    (Float32[0.6886741 -1.2361472], (layer_1 = (frozen_params = (weight = Float32[-0.028461456 -0.5999714 -0.3850993; -0.18860114 0.72428167 0.32322538; -0.965117 -0.4585489 -0.32623518; -0.86290836 -0.82805836 -0.7673453], bias = Float32[0.4216236, -0.4510427, -0.097253, 0.23325463]), states = NamedTuple()), layer_2 = (layer_1 = (frozen_params = (weight = Float32[-0.680748 0.1764085 0.34383082 0.6469914; -0.13819042 -0.109261915 -0.6143286 -0.21672015; -0.20881107 0.70390546 0.48137343 0.25662464; 0.38187847 0.05779423 -0.35181466 -0.096988946], bias = Float32[0.41246277, 0.4318977, -0.4305781, 0.3367505]), states = NamedTuple()), layer_2 = (rng = Random.Xoshiro(0x4fa3403dd074e603, 0x12c522b8034ae186, 0x8e0c3a65079041bb, 0x21617f7747d97206, 0x22a21880af5dc689), training = Val{true}()), layer_3 = (running_mean = Float32[0.01965834, 0.0, 0.0, 0.015937408], running_var = Float32[0.90772897, 0.9, 0.9, 0.90508], training = Val{true}())), layer_3 = (frozen_params = (weight = Float32[0.7794657 0.8337032 0.6323408 -0.18308182], bias = Float32[-0.27373654]), states = NamedTuple())))

    Freezing by Layer Name

    When the function in layer_map is called, the 4th argument is the name of the layer. For example, if you want to freeze the 1st layer inside the inner Chain. The name for this would be layer_2.layer_1.

    julia
    
    +function freeze_by_name(d, ps, st, name::KeyPath)
    +    name == KeyPath(:layer_2, :layer_1) &&
    +        return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +    return d, ps, st
    +end
    julia
    
    +function freeze_dense(d::Dense, ps, st, _)
    +    return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +end
    +freeze_dense(l, ps, st, _) = (l, ps, st)

    Freezing Part of the Parameters

    Instead of freezing all the parameters, we can simply specify (:weight,) to freeze only the weight parameter while training the bias parameter.

    julia
    
    +function freeze_by_name(d, ps, st, name::KeyPath)
    +    name == KeyPath(:layer_2, :layer_1) &&
    +        return Lux.Experimental.freeze(d, ps, st, (:weight,))
    +    return d, ps, st
    +end
    julia
    
    +function freeze_by_name(d, ps, st, name::KeyPath)
    +    name == KeyPath(:layer_2, :layer_1) &&
    +        return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +    return d, ps, st
    +end

    Freezing Part of a Chain

    julia
    using Lux, Random
    +
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +model = Chain(Dense(3, 4), Dense(4, 4), Dropout(0.5f0), BatchNorm(4), Dense(4, 1))
    +
    +model_frozen = Chain(model[1:2], Lux.Experimental.freeze(model[3:4]), model[5])
    +ps, st = Lux.setup(rng, model_frozen)
    +
    +x = randn(rng, Float32, 3, 2)
    +
    +model_frozen(x, ps, st)
    (Float32[0.7429947 -1.2904677], (layer_1 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_2 = (frozen_params = (layer_3 = NamedTuple(), layer_4 = (scale = Float32[1.0, 1.0, 1.0, 1.0], bias = Float32[0.0, 0.0, 0.0, 0.0])), states = (layer_3 = (rng = Random.TaskLocalRNG(), training = Val{true}()), layer_4 = (running_mean = Float32[0.0, 0.048522998, 0.0, 0.015937408], running_var = Float32[0.9, 0.9470896, 0.9, 0.90508], training = Val{true}()))), layer_3 = NamedTuple()))
    `,16)]))}const y=i(h,[["render",l]]);export{g as __pageData,y as default}; diff --git a/previews/PR1023/assets/manual_freezing_model_parameters.md.0i6pMVyg.lean.js b/previews/PR1023/assets/manual_freezing_model_parameters.md.0i6pMVyg.lean.js new file mode 100644 index 0000000000..27d88d34c9 --- /dev/null +++ b/previews/PR1023/assets/manual_freezing_model_parameters.md.0i6pMVyg.lean.js @@ -0,0 +1,51 @@ +import{_ as i,c as a,a2 as n,o as e}from"./chunks/framework.DFwXuivk.js";const g=JSON.parse('{"title":"Freezing Model Parameters","description":"","frontmatter":{},"headers":[],"relativePath":"manual/freezing_model_parameters.md","filePath":"manual/freezing_model_parameters.md","lastUpdated":null}'),h={name:"manual/freezing_model_parameters.md"};function l(t,s,p,k,r,d){return e(),a("div",null,s[0]||(s[0]=[n(`

    Freezing Model Parameters

    Warning

    API for freezing parameters should be considered experimental at this point.

    In this manual entry, we will go over how to freeze certain parameters in a model.

    Freezing Layers of a Particular Kind

    To freeze a particular kind of layer, let's say Dense in the following example. We can use Lux.Experimental.layer_map and freeze layers if they are of type Dense.

    julia
    using Lux, Random, Functors
    +
    +rng = Xoshiro(0)
    +
    +model = Chain(Dense(3, 4), Chain(Dense(4, 4), Dropout(0.5f0), BatchNorm(4)), Dense(4, 1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +x = randn(rng, Float32, 3, 2)
    +
    +model(x, ps, st)
    +
    +function freeze_dense(d::Lux.Dense, ps, st, path)
    +    return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +end
    +freeze_dense(l, ps, st, path) = (l, ps, st)
    +
    +model_frozen, ps_frozen, st_frozen = Lux.Experimental.layer_map(freeze_dense, model, ps, st)
    +
    +model_frozen(x, ps_frozen, st_frozen)
    (Float32[0.6886741 -1.2361472], (layer_1 = (frozen_params = (weight = Float32[-0.028461456 -0.5999714 -0.3850993; -0.18860114 0.72428167 0.32322538; -0.965117 -0.4585489 -0.32623518; -0.86290836 -0.82805836 -0.7673453], bias = Float32[0.4216236, -0.4510427, -0.097253, 0.23325463]), states = NamedTuple()), layer_2 = (layer_1 = (frozen_params = (weight = Float32[-0.680748 0.1764085 0.34383082 0.6469914; -0.13819042 -0.109261915 -0.6143286 -0.21672015; -0.20881107 0.70390546 0.48137343 0.25662464; 0.38187847 0.05779423 -0.35181466 -0.096988946], bias = Float32[0.41246277, 0.4318977, -0.4305781, 0.3367505]), states = NamedTuple()), layer_2 = (rng = Random.Xoshiro(0x4fa3403dd074e603, 0x12c522b8034ae186, 0x8e0c3a65079041bb, 0x21617f7747d97206, 0x22a21880af5dc689), training = Val{true}()), layer_3 = (running_mean = Float32[0.01965834, 0.0, 0.0, 0.015937408], running_var = Float32[0.90772897, 0.9, 0.9, 0.90508], training = Val{true}())), layer_3 = (frozen_params = (weight = Float32[0.7794657 0.8337032 0.6323408 -0.18308182], bias = Float32[-0.27373654]), states = NamedTuple())))

    Freezing by Layer Name

    When the function in layer_map is called, the 4th argument is the name of the layer. For example, if you want to freeze the 1st layer inside the inner Chain. The name for this would be layer_2.layer_1.

    julia
    
    +function freeze_by_name(d, ps, st, name::KeyPath)
    +    name == KeyPath(:layer_2, :layer_1) &&
    +        return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +    return d, ps, st
    +end
    julia
    
    +function freeze_dense(d::Dense, ps, st, _)
    +    return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +end
    +freeze_dense(l, ps, st, _) = (l, ps, st)

    Freezing Part of the Parameters

    Instead of freezing all the parameters, we can simply specify (:weight,) to freeze only the weight parameter while training the bias parameter.

    julia
    
    +function freeze_by_name(d, ps, st, name::KeyPath)
    +    name == KeyPath(:layer_2, :layer_1) &&
    +        return Lux.Experimental.freeze(d, ps, st, (:weight,))
    +    return d, ps, st
    +end
    julia
    
    +function freeze_by_name(d, ps, st, name::KeyPath)
    +    name == KeyPath(:layer_2, :layer_1) &&
    +        return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +    return d, ps, st
    +end

    Freezing Part of a Chain

    julia
    using Lux, Random
    +
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +model = Chain(Dense(3, 4), Dense(4, 4), Dropout(0.5f0), BatchNorm(4), Dense(4, 1))
    +
    +model_frozen = Chain(model[1:2], Lux.Experimental.freeze(model[3:4]), model[5])
    +ps, st = Lux.setup(rng, model_frozen)
    +
    +x = randn(rng, Float32, 3, 2)
    +
    +model_frozen(x, ps, st)
    (Float32[0.7429947 -1.2904677], (layer_1 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_2 = (frozen_params = (layer_3 = NamedTuple(), layer_4 = (scale = Float32[1.0, 1.0, 1.0, 1.0], bias = Float32[0.0, 0.0, 0.0, 0.0])), states = (layer_3 = (rng = Random.TaskLocalRNG(), training = Val{true}()), layer_4 = (running_mean = Float32[0.0, 0.048522998, 0.0, 0.015937408], running_var = Float32[0.9, 0.9470896, 0.9, 0.90508], training = Val{true}()))), layer_3 = NamedTuple()))
    `,16)]))}const y=i(h,[["render",l]]);export{g as __pageData,y as default}; diff --git a/previews/PR1023/assets/manual_gpu_management.md.DNTD4_pe.js b/previews/PR1023/assets/manual_gpu_management.md.DNTD4_pe.js new file mode 100644 index 0000000000..93afb6f8f3 --- /dev/null +++ b/previews/PR1023/assets/manual_gpu_management.md.DNTD4_pe.js @@ -0,0 +1,20 @@ +import{_ as a,c as i,a2 as e,o as n}from"./chunks/framework.DFwXuivk.js";const r=JSON.parse('{"title":"GPU Management","description":"","frontmatter":{},"headers":[],"relativePath":"manual/gpu_management.md","filePath":"manual/gpu_management.md","lastUpdated":null}'),t={name:"manual/gpu_management.md"};function p(l,s,h,c,d,k){return n(),i("div",null,s[0]||(s[0]=[e(`

    GPU Management

    Info

    Starting from v0.5, Lux has transitioned to a new GPU management system. The old system using cpu and gpu functions is still in place but will be removed in v1. Using the old functions might lead to performance regressions if used inside performance critical code.

    Lux.jl can handle multiple GPU backends. Currently, the following backends are supported:

    julia
    # Important to load trigger packages
    +using Lux, LuxCUDA #, AMDGPU, Metal, oneAPI
    +
    +supported_gpu_backends()
    ("CUDA", "AMDGPU", "Metal", "oneAPI")

    Metal Support

    Support for Metal GPUs should be considered extremely experimental at this point.

    Automatic Backend Management (Recommended Approach)

    Automatic Backend Management is done by two simple functions: cpu_device and gpu_device.

    • cpu_device: This is a simple function and just returns a CPUDevice object. @example gpu_management cdev = cpu_device()@example gpu_management x_cpu = randn(Float32, 3, 2)

    • gpu_device: This function performs automatic GPU device selection and returns an object.

      1. If no GPU is available, it returns a CPUDevice object.

      2. If a LocalPreferences file is present, then the backend specified in the file is used. To set a backend, use Lux.gpu_backend!(<backend_name>). (a) If the trigger package corresponding to the device is not loaded, then a warning is displayed. (b) If no LocalPreferences file is present, then the first working GPU with loaded trigger package is used.

      @example
      x_gpu = x_cpu |&gt; gdev  \`\`\`
      +\`@example gpu_management  (x_gpu |> cdev) ≈ x_cpu\`

    Manual Backend Management

    Automatic Device Selection can be circumvented by directly using CPUDevice and AbstractGPUDevice objects.

    julia
    cdev = cpu_device()
    +
    +x_cpu = randn(Float32, 3, 2)
    +
    +if MLDataDevices.functional(CUDADevice)
    +    gdev = CUDADevice()
    +    x_gpu = x_cpu |> gdev
    +elseif MLDataDevices.functional(AMDGPUDevice)
    +    gdev = AMDGPUDevice()
    +    x_gpu = x_cpu |> gdev
    +else
    +    @info "No GPU is available. Using CPU."
    +    x_gpu = x_cpu
    +end
    +
    +(x_gpu |> cdev)  x_cpu
    true
    `,13)]))}const g=a(t,[["render",p]]);export{r as __pageData,g as default}; diff --git a/previews/PR1023/assets/manual_gpu_management.md.DNTD4_pe.lean.js b/previews/PR1023/assets/manual_gpu_management.md.DNTD4_pe.lean.js new file mode 100644 index 0000000000..93afb6f8f3 --- /dev/null +++ b/previews/PR1023/assets/manual_gpu_management.md.DNTD4_pe.lean.js @@ -0,0 +1,20 @@ +import{_ as a,c as i,a2 as e,o as n}from"./chunks/framework.DFwXuivk.js";const r=JSON.parse('{"title":"GPU Management","description":"","frontmatter":{},"headers":[],"relativePath":"manual/gpu_management.md","filePath":"manual/gpu_management.md","lastUpdated":null}'),t={name:"manual/gpu_management.md"};function p(l,s,h,c,d,k){return n(),i("div",null,s[0]||(s[0]=[e(`

    GPU Management

    Info

    Starting from v0.5, Lux has transitioned to a new GPU management system. The old system using cpu and gpu functions is still in place but will be removed in v1. Using the old functions might lead to performance regressions if used inside performance critical code.

    Lux.jl can handle multiple GPU backends. Currently, the following backends are supported:

    julia
    # Important to load trigger packages
    +using Lux, LuxCUDA #, AMDGPU, Metal, oneAPI
    +
    +supported_gpu_backends()
    ("CUDA", "AMDGPU", "Metal", "oneAPI")

    Metal Support

    Support for Metal GPUs should be considered extremely experimental at this point.

    Automatic Backend Management (Recommended Approach)

    Automatic Backend Management is done by two simple functions: cpu_device and gpu_device.

    • cpu_device: This is a simple function and just returns a CPUDevice object. @example gpu_management cdev = cpu_device()@example gpu_management x_cpu = randn(Float32, 3, 2)

    • gpu_device: This function performs automatic GPU device selection and returns an object.

      1. If no GPU is available, it returns a CPUDevice object.

      2. If a LocalPreferences file is present, then the backend specified in the file is used. To set a backend, use Lux.gpu_backend!(<backend_name>). (a) If the trigger package corresponding to the device is not loaded, then a warning is displayed. (b) If no LocalPreferences file is present, then the first working GPU with loaded trigger package is used.

      @example
      x_gpu = x_cpu |&gt; gdev  \`\`\`
      +\`@example gpu_management  (x_gpu |> cdev) ≈ x_cpu\`

    Manual Backend Management

    Automatic Device Selection can be circumvented by directly using CPUDevice and AbstractGPUDevice objects.

    julia
    cdev = cpu_device()
    +
    +x_cpu = randn(Float32, 3, 2)
    +
    +if MLDataDevices.functional(CUDADevice)
    +    gdev = CUDADevice()
    +    x_gpu = x_cpu |> gdev
    +elseif MLDataDevices.functional(AMDGPUDevice)
    +    gdev = AMDGPUDevice()
    +    x_gpu = x_cpu |> gdev
    +else
    +    @info "No GPU is available. Using CPU."
    +    x_gpu = x_cpu
    +end
    +
    +(x_gpu |> cdev)  x_cpu
    true
    `,13)]))}const g=a(t,[["render",p]]);export{r as __pageData,g as default}; diff --git a/previews/PR1023/assets/manual_interface.md.D86uezLQ.js b/previews/PR1023/assets/manual_interface.md.D86uezLQ.js new file mode 100644 index 0000000000..76849093d6 --- /dev/null +++ b/previews/PR1023/assets/manual_interface.md.D86uezLQ.js @@ -0,0 +1,91 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const o=JSON.parse('{"title":"Lux Interface","description":"","frontmatter":{},"headers":[],"relativePath":"manual/interface.md","filePath":"manual/interface.md","lastUpdated":null}'),e={name:"manual/interface.md"};function h(l,s,p,k,r,d){return t(),a("div",null,s[0]||(s[0]=[n(`

    Lux Interface

    Lux.jl vs LuxCore.jl

    If you just want to define compatibility with Lux without actually using any of the other functionality provided by Lux (like layers), it is recommended to depend on LuxCore.jl instead of Lux.jl. LuxCore.jl is a significantly lighter dependency.

    Following this interface provides the ability for frameworks built on top of Lux to be cross compatible. Additionally, any new functionality built into Lux, will just work for your framework.

    @compact macro

    While writing out a custom struct and defining dispatches manually is a good way to understand the interface, it is not the most concise way. We recommend using the Lux.@compact macro to define layers which makes handling the states and parameters downright trivial.

    Layer Interface

    Singular Layer

    If the layer doesn't contain any other Lux layer, then it is a Singular Layer. This means it should optionally subtype Lux.AbstractLuxLayer but mandatorily define all the necessary functions mentioned in the docstrings. Consider a simplified version of Dense called Linear.

    First, setup the architectural details for this layer. Note, that the architecture doesn't contain any mutable structure like arrays. When in doubt, remember, once constructed a model architecture cannot change.

    Tip

    For people coming from Flux.jl background, this might be weird. We recommend checking out the Flux to Lux migration guide first before proceeding.

    julia
    using LuxCore, Random, WeightInitializers # Importing \`Lux\` also gives you access to \`LuxCore\`
    +
    +struct Linear{F1, F2} <: LuxCore.AbstractLuxLayer
    +    in_dims::Int
    +    out_dims::Int
    +    init_weight::F1
    +    init_bias::F2
    +end
    +
    +function Linear(in_dims::Int, out_dims::Int; init_weight=glorot_uniform, init_bias=zeros32)
    +    return Linear{typeof(init_weight), typeof(init_bias)}(in_dims, out_dims, init_weight,
    +        init_bias)
    +end
    +
    +l = Linear(2, 4)
    Main.Linear{typeof(glorot_uniform), typeof(zeros32)}(2, 4, WeightInitializers.glorot_uniform, WeightInitializers.zeros32)

    Next, we need to implement functions which return the parameters and states for the layer. In case of Linear, the parameters are weight and bias while the states are empty. States become important when defining layers like BatchNorm, WeightNorm, etc. The recommended data structure for returning parameters is a NamedTuple, though anything satisfying the Parameter Interface is valid.

    julia
    function LuxCore.initialparameters(rng::AbstractRNG, l::Linear)
    +    return (weight=l.init_weight(rng, l.out_dims, l.in_dims),
    +            bias=l.init_bias(rng, l.out_dims, 1))
    +end
    +
    +LuxCore.initialstates(::AbstractRNG, ::Linear) = NamedTuple()

    You could also implement LuxCore.parameterlength and LuxCore.statelength to prevent wasteful reconstruction of the parameters and states.

    julia
    # This works
    +println("Parameter Length: ", LuxCore.parameterlength(l), "; State Length: ",
    +    LuxCore.statelength(l))
    +
    +# But still recommended to define these
    +LuxCore.parameterlength(l::Linear) = l.out_dims * l.in_dims + l.out_dims
    +
    +LuxCore.statelength(::Linear) = 0
    Parameter Length: 12; State Length: 0

    No RNG in initialparameters and initialstates

    You might notice that we don't pass in a RNG for these functions. If your parameter length and/or state length depend on a random number generator, you should think really hard about what you are trying to do and why.

    Now, we need to define how the layer works. For this you make your layer a function with exactly 3 arguments – x the input, ps the parameters, and st the states. This function must return two things – y the output, and st_new the updated state.

    julia
    function (l::Linear)(x::AbstractMatrix, ps, st::NamedTuple)
    +    y = ps.weight * x .+ ps.bias
    +    return y, st
    +end

    Finally, let's run this layer. If you have made this far into the documentation, we don't feel you need a refresher on that.

    julia
    rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +ps, st = LuxCore.setup(rng, l)
    +
    +println("Parameter Length: ", LuxCore.parameterlength(l), "; State Length: ",
    +    LuxCore.statelength(l))
    +
    +x = randn(rng, Float32, 2, 1)
    +
    +LuxCore.apply(l, x, ps, st) # or \`l(x, ps, st)\`
    (Float32[-0.15276335; 0.45325348; 1.0207279; 0.78226817;;], NamedTuple())

    Container Layer

    If your layer comprises of other Lux layers, then it is a Container Layer. Note that you could treat it as a Singular Layer, and it is still fine. FWIW, if you cannot subtype your layer with LuxCore.AbstractLuxContainerLayer then you should go down the Singular Layer route. But subtyping allows us to bypass some of these common definitions. Let us now define a layer, which is basically a composition of two linear layers.

    Wrapper Layer

    If you are defining a layer that is a wrapper around another layer, then you should subtype LuxCore.AbstractLuxWrapperLayer instead of LuxCore.AbstractLuxContainerLayer. The only difference from a container layer is that it can wrap a single layer and the parameter/state structure is exactly the same as the wrapped layer.

    julia
    struct ComposedLinear{L1, L2} <: LuxCore.AbstractLuxContainerLayer{(:linear_1, :linear_2)}
    +    linear_1::L1
    +    linear_2::L2
    +end
    +
    +function (cl::ComposedLinear)(x::AbstractMatrix, ps, st::NamedTuple)
    +    # To access the parameters and states for \`linear_1\` we do \`ps.linear_1\` and
    +    # \`st.linear_1\`. Similarly for \`linear_2\`
    +    y, st_l1 = cl.linear_1(x, ps.linear_1, st.linear_1)
    +    y, st_l2 = cl.linear_2(y, ps.linear_2, st.linear_2)
    +    # Finally, we need to return the new state which has the exact structure as \`st\`
    +    return y, (linear_1 = st_l1, linear_2 = st_l2)
    +end

    Here, you will notice we have passed (:linear_1, :linear_2) to the supertype. It essentially informs the type that, <obj>.linear_1 and <obj>.linear_2 are Lux layers and we need to construct parameters and states for those. Let's construct these and see:

    julia
    model = ComposedLinear(Linear(2, 4), Linear(4, 2))
    +display(model)
    +
    +ps, st = LuxCore.setup(rng, model)
    +
    +println("Parameters: ", ps)
    +println("States: ", st)
    +
    +println("Parameter Length: ", LuxCore.parameterlength(model), "; State Length: ",
    +    LuxCore.statelength(model))
    +
    +x = randn(rng, Float32, 2, 1)
    +
    +LuxCore.apply(model, x, ps, st) # or \`model(x, ps, st)\`
    (Float32[1.3410565; 0.78000563;;], (linear_1 = NamedTuple(), linear_2 = NamedTuple()))

    Parameter Interface

    We accept any parameter type as long as we can fetch the parameters using getproperty(obj, :parameter_name). This allows us to simultaneously support NamedTuples and ComponentArrays. Let us go through a concrete example of what it means. Consider Dense which expects two parameters named weight and bias.

    Automatic Differentiation

    If you are defining your own parameter type, it is your responsibility to make sure that it works with the AutoDiff System you are using.

    julia
    using Lux, Random
    +
    +d = Dense(2, 3)
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +ps_default, st = LuxCore.setup(rng, d)
    +
    +x = randn(rng, Float32, 2, 1)
    +
    +println("Result with \`NamedTuple\` parameters: ", first(d(x, ps_default, st)))
    Result with \`NamedTuple\` parameters: Float32[-0.08713347; -0.4851346; -0.8490221;;]

    Let, us define a custom parameter type with fields myweight and mybias but if we try to access weight we get back myweight, similar for bias.

    Beware!

    This is for demonstrative purposes, don't try this at home!

    julia
    struct DenseLayerParameters{W, B}
    +    myweight::W
    +    mybias::B
    +end
    +
    +function Base.getproperty(ps::DenseLayerParameters, x::Symbol)
    +    if x == :weight
    +        return getfield(ps, :myweight)
    +    elseif x == :bias
    +        return getfield(ps, :mybias)
    +    end
    +    return getfield(ps, x)
    +end
    +
    +ps = DenseLayerParameters(ps_default.weight, ps_default.bias)
    +
    +println("Result with \`DenseLayerParameters\` parameters: ", first(d(x, ps, st)))
    Result with \`DenseLayerParameters\` parameters: Float32[0.23710957; 0.1003911; -0.57671577;;]

    The takeaway from this shouldn't be – lets define weird parameter types. Simply because you can do weird things like this doesn't mean you should, since it only leads to bugs.

    Instead this shows the flexibility you have for how your parameters can be structured.

    State Interface

    States are always type constrained to be NamedTuple. The structure of the input state must match that of the output state, i.e. keys(st_in) == keys(st_out). This doesn't imply that types of the input and output state match. To generate efficient code, we often do dispatch on the state, for example, Dropout, BatchNorm, etc.

    `,42)]))}const g=i(e,[["render",h]]);export{o as __pageData,g as default}; diff --git a/previews/PR1023/assets/manual_interface.md.D86uezLQ.lean.js b/previews/PR1023/assets/manual_interface.md.D86uezLQ.lean.js new file mode 100644 index 0000000000..76849093d6 --- /dev/null +++ b/previews/PR1023/assets/manual_interface.md.D86uezLQ.lean.js @@ -0,0 +1,91 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const o=JSON.parse('{"title":"Lux Interface","description":"","frontmatter":{},"headers":[],"relativePath":"manual/interface.md","filePath":"manual/interface.md","lastUpdated":null}'),e={name:"manual/interface.md"};function h(l,s,p,k,r,d){return t(),a("div",null,s[0]||(s[0]=[n(`

    Lux Interface

    Lux.jl vs LuxCore.jl

    If you just want to define compatibility with Lux without actually using any of the other functionality provided by Lux (like layers), it is recommended to depend on LuxCore.jl instead of Lux.jl. LuxCore.jl is a significantly lighter dependency.

    Following this interface provides the ability for frameworks built on top of Lux to be cross compatible. Additionally, any new functionality built into Lux, will just work for your framework.

    @compact macro

    While writing out a custom struct and defining dispatches manually is a good way to understand the interface, it is not the most concise way. We recommend using the Lux.@compact macro to define layers which makes handling the states and parameters downright trivial.

    Layer Interface

    Singular Layer

    If the layer doesn't contain any other Lux layer, then it is a Singular Layer. This means it should optionally subtype Lux.AbstractLuxLayer but mandatorily define all the necessary functions mentioned in the docstrings. Consider a simplified version of Dense called Linear.

    First, setup the architectural details for this layer. Note, that the architecture doesn't contain any mutable structure like arrays. When in doubt, remember, once constructed a model architecture cannot change.

    Tip

    For people coming from Flux.jl background, this might be weird. We recommend checking out the Flux to Lux migration guide first before proceeding.

    julia
    using LuxCore, Random, WeightInitializers # Importing \`Lux\` also gives you access to \`LuxCore\`
    +
    +struct Linear{F1, F2} <: LuxCore.AbstractLuxLayer
    +    in_dims::Int
    +    out_dims::Int
    +    init_weight::F1
    +    init_bias::F2
    +end
    +
    +function Linear(in_dims::Int, out_dims::Int; init_weight=glorot_uniform, init_bias=zeros32)
    +    return Linear{typeof(init_weight), typeof(init_bias)}(in_dims, out_dims, init_weight,
    +        init_bias)
    +end
    +
    +l = Linear(2, 4)
    Main.Linear{typeof(glorot_uniform), typeof(zeros32)}(2, 4, WeightInitializers.glorot_uniform, WeightInitializers.zeros32)

    Next, we need to implement functions which return the parameters and states for the layer. In case of Linear, the parameters are weight and bias while the states are empty. States become important when defining layers like BatchNorm, WeightNorm, etc. The recommended data structure for returning parameters is a NamedTuple, though anything satisfying the Parameter Interface is valid.

    julia
    function LuxCore.initialparameters(rng::AbstractRNG, l::Linear)
    +    return (weight=l.init_weight(rng, l.out_dims, l.in_dims),
    +            bias=l.init_bias(rng, l.out_dims, 1))
    +end
    +
    +LuxCore.initialstates(::AbstractRNG, ::Linear) = NamedTuple()

    You could also implement LuxCore.parameterlength and LuxCore.statelength to prevent wasteful reconstruction of the parameters and states.

    julia
    # This works
    +println("Parameter Length: ", LuxCore.parameterlength(l), "; State Length: ",
    +    LuxCore.statelength(l))
    +
    +# But still recommended to define these
    +LuxCore.parameterlength(l::Linear) = l.out_dims * l.in_dims + l.out_dims
    +
    +LuxCore.statelength(::Linear) = 0
    Parameter Length: 12; State Length: 0

    No RNG in initialparameters and initialstates

    You might notice that we don't pass in a RNG for these functions. If your parameter length and/or state length depend on a random number generator, you should think really hard about what you are trying to do and why.

    Now, we need to define how the layer works. For this you make your layer a function with exactly 3 arguments – x the input, ps the parameters, and st the states. This function must return two things – y the output, and st_new the updated state.

    julia
    function (l::Linear)(x::AbstractMatrix, ps, st::NamedTuple)
    +    y = ps.weight * x .+ ps.bias
    +    return y, st
    +end

    Finally, let's run this layer. If you have made this far into the documentation, we don't feel you need a refresher on that.

    julia
    rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +ps, st = LuxCore.setup(rng, l)
    +
    +println("Parameter Length: ", LuxCore.parameterlength(l), "; State Length: ",
    +    LuxCore.statelength(l))
    +
    +x = randn(rng, Float32, 2, 1)
    +
    +LuxCore.apply(l, x, ps, st) # or \`l(x, ps, st)\`
    (Float32[-0.15276335; 0.45325348; 1.0207279; 0.78226817;;], NamedTuple())

    Container Layer

    If your layer comprises of other Lux layers, then it is a Container Layer. Note that you could treat it as a Singular Layer, and it is still fine. FWIW, if you cannot subtype your layer with LuxCore.AbstractLuxContainerLayer then you should go down the Singular Layer route. But subtyping allows us to bypass some of these common definitions. Let us now define a layer, which is basically a composition of two linear layers.

    Wrapper Layer

    If you are defining a layer that is a wrapper around another layer, then you should subtype LuxCore.AbstractLuxWrapperLayer instead of LuxCore.AbstractLuxContainerLayer. The only difference from a container layer is that it can wrap a single layer and the parameter/state structure is exactly the same as the wrapped layer.

    julia
    struct ComposedLinear{L1, L2} <: LuxCore.AbstractLuxContainerLayer{(:linear_1, :linear_2)}
    +    linear_1::L1
    +    linear_2::L2
    +end
    +
    +function (cl::ComposedLinear)(x::AbstractMatrix, ps, st::NamedTuple)
    +    # To access the parameters and states for \`linear_1\` we do \`ps.linear_1\` and
    +    # \`st.linear_1\`. Similarly for \`linear_2\`
    +    y, st_l1 = cl.linear_1(x, ps.linear_1, st.linear_1)
    +    y, st_l2 = cl.linear_2(y, ps.linear_2, st.linear_2)
    +    # Finally, we need to return the new state which has the exact structure as \`st\`
    +    return y, (linear_1 = st_l1, linear_2 = st_l2)
    +end

    Here, you will notice we have passed (:linear_1, :linear_2) to the supertype. It essentially informs the type that, <obj>.linear_1 and <obj>.linear_2 are Lux layers and we need to construct parameters and states for those. Let's construct these and see:

    julia
    model = ComposedLinear(Linear(2, 4), Linear(4, 2))
    +display(model)
    +
    +ps, st = LuxCore.setup(rng, model)
    +
    +println("Parameters: ", ps)
    +println("States: ", st)
    +
    +println("Parameter Length: ", LuxCore.parameterlength(model), "; State Length: ",
    +    LuxCore.statelength(model))
    +
    +x = randn(rng, Float32, 2, 1)
    +
    +LuxCore.apply(model, x, ps, st) # or \`model(x, ps, st)\`
    (Float32[1.3410565; 0.78000563;;], (linear_1 = NamedTuple(), linear_2 = NamedTuple()))

    Parameter Interface

    We accept any parameter type as long as we can fetch the parameters using getproperty(obj, :parameter_name). This allows us to simultaneously support NamedTuples and ComponentArrays. Let us go through a concrete example of what it means. Consider Dense which expects two parameters named weight and bias.

    Automatic Differentiation

    If you are defining your own parameter type, it is your responsibility to make sure that it works with the AutoDiff System you are using.

    julia
    using Lux, Random
    +
    +d = Dense(2, 3)
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +ps_default, st = LuxCore.setup(rng, d)
    +
    +x = randn(rng, Float32, 2, 1)
    +
    +println("Result with \`NamedTuple\` parameters: ", first(d(x, ps_default, st)))
    Result with \`NamedTuple\` parameters: Float32[-0.08713347; -0.4851346; -0.8490221;;]

    Let, us define a custom parameter type with fields myweight and mybias but if we try to access weight we get back myweight, similar for bias.

    Beware!

    This is for demonstrative purposes, don't try this at home!

    julia
    struct DenseLayerParameters{W, B}
    +    myweight::W
    +    mybias::B
    +end
    +
    +function Base.getproperty(ps::DenseLayerParameters, x::Symbol)
    +    if x == :weight
    +        return getfield(ps, :myweight)
    +    elseif x == :bias
    +        return getfield(ps, :mybias)
    +    end
    +    return getfield(ps, x)
    +end
    +
    +ps = DenseLayerParameters(ps_default.weight, ps_default.bias)
    +
    +println("Result with \`DenseLayerParameters\` parameters: ", first(d(x, ps, st)))
    Result with \`DenseLayerParameters\` parameters: Float32[0.23710957; 0.1003911; -0.57671577;;]

    The takeaway from this shouldn't be – lets define weird parameter types. Simply because you can do weird things like this doesn't mean you should, since it only leads to bugs.

    Instead this shows the flexibility you have for how your parameters can be structured.

    State Interface

    States are always type constrained to be NamedTuple. The structure of the input state must match that of the output state, i.e. keys(st_in) == keys(st_out). This doesn't imply that types of the input and output state match. To generate efficient code, we often do dispatch on the state, for example, Dropout, BatchNorm, etc.

    `,42)]))}const g=i(e,[["render",h]]);export{o as __pageData,g as default}; diff --git a/previews/PR1023/assets/manual_migrate_from_flux.md.UjjC2Rl6.js b/previews/PR1023/assets/manual_migrate_from_flux.md.UjjC2Rl6.js new file mode 100644 index 0000000000..874d628ea3 --- /dev/null +++ b/previews/PR1023/assets/manual_migrate_from_flux.md.UjjC2Rl6.js @@ -0,0 +1,75 @@ +import{_ as e,c as a,a2 as l,j as s,a as n,o as t}from"./chunks/framework.DFwXuivk.js";const x=JSON.parse('{"title":"Migrating from Flux to Lux","description":"","frontmatter":{},"headers":[],"relativePath":"manual/migrate_from_flux.md","filePath":"manual/migrate_from_flux.md","lastUpdated":null}'),h={name:"manual/migrate_from_flux.md"},p={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},k={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"10.24ex",height:"1.645ex",role:"img",focusable:"false",viewBox:"0 -716 4525.9 727","aria-hidden":"true"},r={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},d={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"0"},xmlns:"http://www.w3.org/2000/svg",width:"1.697ex",height:"1.62ex",role:"img",focusable:"false",viewBox:"0 -716 750 716","aria-hidden":"true"},E={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},g={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"0"},xmlns:"http://www.w3.org/2000/svg",width:"1.717ex",height:"1.545ex",role:"img",focusable:"false",viewBox:"0 -683 759 683","aria-hidden":"true"};function o(y,i,c,u,F,m){return t(),a("div",null,[i[10]||(i[10]=l(`

    Migrating from Flux to Lux

    For the core library layers like Dense, Conv, etc. we have intentionally kept the API very similar to Flux. In most cases, replacing using Flux with using Lux should be enough to get you started. We cover the additional changes that you will have to make in the following example.

    julia
    using Lux, Random, NNlib, Zygote
    +
    +model = Chain(Dense(2 => 4), BatchNorm(4, relu), Dense(4 => 2))
    +rng = Random.default_rng()
    +x = randn(rng, Float32, 2, 4)
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(x, ps, st)
    +
    +gradient(ps -> sum(first(model(x, ps, st))), ps)
    julia
    using Flux, Random, NNlib, Zygote
    +
    +model = Chain(Dense(2 => 4), BatchNorm(4, relu), Dense(4 => 2))
    +rng = Random.default_rng()
    +x = randn(rng, Float32, 2, 4)
    +
    +
    +
    +model(x)
    +
    +gradient(model -> sum(model(x)), model)

    Implementing Custom Layers

    Flux and Lux operate under extremely different design philosophies regarding how layers should be implemented. A summary of the differences would be:

    • Flux stores everything in a single struct and relies on Functors.@functor and Flux.trainable to distinguish between trainable and non-trainable parameters.

    • Lux relies on the user to define Lux.initialparameters and Lux.initialstates to distinguish between trainable parameters (called "parameters") and non-trainable parameters (called "states"). Additionally, Lux layers define the model architecture, hence device transfer utilities like gpu_device, cpu_device, etc. cannot be applied on Lux layers, instead they need to be applied on the parameters and states.

    `,6)),s("p",null,[i[6]||(i[6]=n("Let's work through a concrete example to demonstrate this. We will implement a very simple layer that computes ")),s("mjx-container",p,[(t(),a("svg",k,i[0]||(i[0]=[l('',1)]))),i[1]||(i[1]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"A"),s("mo",null,"×"),s("mi",null,"B"),s("mo",null,"×"),s("mi",null,"x")])],-1))]),i[7]||(i[7]=n(" where ")),s("mjx-container",r,[(t(),a("svg",d,i[2]||(i[2]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D434",d:"M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z",style:{"stroke-width":"3"}})])])],-1)]))),i[3]||(i[3]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"A")])],-1))]),i[8]||(i[8]=n(" is not trainable and ")),s("mjx-container",E,[(t(),a("svg",g,i[4]||(i[4]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D435",d:"M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z",style:{"stroke-width":"3"}})])])],-1)]))),i[5]||(i[5]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"B")])],-1))]),i[9]||(i[9]=n(" is trainable."))]),i[11]||(i[11]=l(`
    julia
    using Lux, Random, NNlib, Zygote
    +
    +struct LuxLinear <: Lux.AbstractLuxLayer
    +    init_A
    +    init_B
    +end
    +
    +function LuxLinear(A::AbstractArray, B::AbstractArray)
    +    # Storing Arrays or any mutable structure inside a Lux Layer is not recommended
    +    # instead we will convert this to a function to perform lazy initialization
    +    return LuxLinear(() -> copy(A), () -> copy(B))
    +end
    +
    +# \`B\` is a parameter
    +Lux.initialparameters(::AbstractRNG, layer::LuxLinear) = (B=layer.init_B(),)
    +
    +# \`A\` is a state
    +Lux.initialstates(::AbstractRNG, layer::LuxLinear) = (A=layer.init_A(),)
    +
    +(l::LuxLinear)(x, ps, st) = st.A * ps.B * x, st
    julia
    using Flux, Random, NNlib, Zygote, Optimisers
    +
    +struct FluxLinear
    +    A
    +    B
    +end
    +
    +
    +
    +
    +
    +
    +
    +# \`A\` is not trainable
    +Optimisers.trainable(f::FluxLinear) = (B=f.B,)
    +
    +# Needed so that both \`A\` and \`B\` can be transferred between devices
    +Flux.@functor FluxLinear
    +
    +(l::FluxLinear)(x) = l.A * l.B * x

    Now let us run the model.

    julia
    rng = Random.default_rng()
    +model = LuxLinear(randn(rng, 2, 4), randn(rng, 4, 2))
    +x = randn(rng, 2, 1)
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(x, ps, st)
    +
    +gradient(ps -> sum(first(model(x, ps, st))), ps)
    julia
    rng = Random.default_rng()
    +model = FluxLinear(randn(rng, 2, 4), randn(rng, 4, 2))
    +x = randn(rng, 2, 1)
    +
    +
    +
    +model(x)
    +
    +gradient(model -> sum(model(x)), model)

    To reiterate some important points:

    • Don't store mutables like Arrays inside a Lux Layer.

    • Parameters and States should be constructured inside the respective initial* functions.

    Certain Important Implementation Details

    Training/Inference Mode

    Flux supports a mode called :auto which automatically decides if the user is training the model or running inference. This is the default mode for Flux.BatchNorm, Flux.GroupNorm, Flux.Dropout, etc. Lux doesn't support this mode (specifically to keep code simple and do exactly what the user wants), hence our default mode is training. This can be changed using Lux.testmode.

    Can we still use Flux Layers?

    If you have Flux loaded in your code, you can use the function FromFluxAdaptor to automatically convert your model to Lux. Note that in case a native Lux counterpart isn't available, we fallback to using Optimisers.destructure.

    `,10))])}const Q=e(h,[["render",o]]);export{x as __pageData,Q as default}; diff --git a/previews/PR1023/assets/manual_migrate_from_flux.md.UjjC2Rl6.lean.js b/previews/PR1023/assets/manual_migrate_from_flux.md.UjjC2Rl6.lean.js new file mode 100644 index 0000000000..874d628ea3 --- /dev/null +++ b/previews/PR1023/assets/manual_migrate_from_flux.md.UjjC2Rl6.lean.js @@ -0,0 +1,75 @@ +import{_ as e,c as a,a2 as l,j as s,a as n,o as t}from"./chunks/framework.DFwXuivk.js";const x=JSON.parse('{"title":"Migrating from Flux to Lux","description":"","frontmatter":{},"headers":[],"relativePath":"manual/migrate_from_flux.md","filePath":"manual/migrate_from_flux.md","lastUpdated":null}'),h={name:"manual/migrate_from_flux.md"},p={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},k={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"10.24ex",height:"1.645ex",role:"img",focusable:"false",viewBox:"0 -716 4525.9 727","aria-hidden":"true"},r={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},d={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"0"},xmlns:"http://www.w3.org/2000/svg",width:"1.697ex",height:"1.62ex",role:"img",focusable:"false",viewBox:"0 -716 750 716","aria-hidden":"true"},E={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},g={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"0"},xmlns:"http://www.w3.org/2000/svg",width:"1.717ex",height:"1.545ex",role:"img",focusable:"false",viewBox:"0 -683 759 683","aria-hidden":"true"};function o(y,i,c,u,F,m){return t(),a("div",null,[i[10]||(i[10]=l(`

    Migrating from Flux to Lux

    For the core library layers like Dense, Conv, etc. we have intentionally kept the API very similar to Flux. In most cases, replacing using Flux with using Lux should be enough to get you started. We cover the additional changes that you will have to make in the following example.

    julia
    using Lux, Random, NNlib, Zygote
    +
    +model = Chain(Dense(2 => 4), BatchNorm(4, relu), Dense(4 => 2))
    +rng = Random.default_rng()
    +x = randn(rng, Float32, 2, 4)
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(x, ps, st)
    +
    +gradient(ps -> sum(first(model(x, ps, st))), ps)
    julia
    using Flux, Random, NNlib, Zygote
    +
    +model = Chain(Dense(2 => 4), BatchNorm(4, relu), Dense(4 => 2))
    +rng = Random.default_rng()
    +x = randn(rng, Float32, 2, 4)
    +
    +
    +
    +model(x)
    +
    +gradient(model -> sum(model(x)), model)

    Implementing Custom Layers

    Flux and Lux operate under extremely different design philosophies regarding how layers should be implemented. A summary of the differences would be:

    • Flux stores everything in a single struct and relies on Functors.@functor and Flux.trainable to distinguish between trainable and non-trainable parameters.

    • Lux relies on the user to define Lux.initialparameters and Lux.initialstates to distinguish between trainable parameters (called "parameters") and non-trainable parameters (called "states"). Additionally, Lux layers define the model architecture, hence device transfer utilities like gpu_device, cpu_device, etc. cannot be applied on Lux layers, instead they need to be applied on the parameters and states.

    `,6)),s("p",null,[i[6]||(i[6]=n("Let's work through a concrete example to demonstrate this. We will implement a very simple layer that computes ")),s("mjx-container",p,[(t(),a("svg",k,i[0]||(i[0]=[l('',1)]))),i[1]||(i[1]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"A"),s("mo",null,"×"),s("mi",null,"B"),s("mo",null,"×"),s("mi",null,"x")])],-1))]),i[7]||(i[7]=n(" where ")),s("mjx-container",r,[(t(),a("svg",d,i[2]||(i[2]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D434",d:"M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z",style:{"stroke-width":"3"}})])])],-1)]))),i[3]||(i[3]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"A")])],-1))]),i[8]||(i[8]=n(" is not trainable and ")),s("mjx-container",E,[(t(),a("svg",g,i[4]||(i[4]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D435",d:"M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z",style:{"stroke-width":"3"}})])])],-1)]))),i[5]||(i[5]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"B")])],-1))]),i[9]||(i[9]=n(" is trainable."))]),i[11]||(i[11]=l(`
    julia
    using Lux, Random, NNlib, Zygote
    +
    +struct LuxLinear <: Lux.AbstractLuxLayer
    +    init_A
    +    init_B
    +end
    +
    +function LuxLinear(A::AbstractArray, B::AbstractArray)
    +    # Storing Arrays or any mutable structure inside a Lux Layer is not recommended
    +    # instead we will convert this to a function to perform lazy initialization
    +    return LuxLinear(() -> copy(A), () -> copy(B))
    +end
    +
    +# \`B\` is a parameter
    +Lux.initialparameters(::AbstractRNG, layer::LuxLinear) = (B=layer.init_B(),)
    +
    +# \`A\` is a state
    +Lux.initialstates(::AbstractRNG, layer::LuxLinear) = (A=layer.init_A(),)
    +
    +(l::LuxLinear)(x, ps, st) = st.A * ps.B * x, st
    julia
    using Flux, Random, NNlib, Zygote, Optimisers
    +
    +struct FluxLinear
    +    A
    +    B
    +end
    +
    +
    +
    +
    +
    +
    +
    +# \`A\` is not trainable
    +Optimisers.trainable(f::FluxLinear) = (B=f.B,)
    +
    +# Needed so that both \`A\` and \`B\` can be transferred between devices
    +Flux.@functor FluxLinear
    +
    +(l::FluxLinear)(x) = l.A * l.B * x

    Now let us run the model.

    julia
    rng = Random.default_rng()
    +model = LuxLinear(randn(rng, 2, 4), randn(rng, 4, 2))
    +x = randn(rng, 2, 1)
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(x, ps, st)
    +
    +gradient(ps -> sum(first(model(x, ps, st))), ps)
    julia
    rng = Random.default_rng()
    +model = FluxLinear(randn(rng, 2, 4), randn(rng, 4, 2))
    +x = randn(rng, 2, 1)
    +
    +
    +
    +model(x)
    +
    +gradient(model -> sum(model(x)), model)

    To reiterate some important points:

    • Don't store mutables like Arrays inside a Lux Layer.

    • Parameters and States should be constructured inside the respective initial* functions.

    Certain Important Implementation Details

    Training/Inference Mode

    Flux supports a mode called :auto which automatically decides if the user is training the model or running inference. This is the default mode for Flux.BatchNorm, Flux.GroupNorm, Flux.Dropout, etc. Lux doesn't support this mode (specifically to keep code simple and do exactly what the user wants), hence our default mode is training. This can be changed using Lux.testmode.

    Can we still use Flux Layers?

    If you have Flux loaded in your code, you can use the function FromFluxAdaptor to automatically convert your model to Lux. Note that in case a native Lux counterpart isn't available, we fallback to using Optimisers.destructure.

    `,10))])}const Q=e(h,[["render",o]]);export{x as __pageData,Q as default}; diff --git a/previews/PR1023/assets/manual_nested_autodiff.md.BllOXIU5.js b/previews/PR1023/assets/manual_nested_autodiff.md.BllOXIU5.js new file mode 100644 index 0000000000..87e3ab6ab9 --- /dev/null +++ b/previews/PR1023/assets/manual_nested_autodiff.md.BllOXIU5.js @@ -0,0 +1,119 @@ +import{_ as e,c as n,a2 as t,j as s,a,o as l}from"./chunks/framework.DFwXuivk.js";const j=JSON.parse('{"title":"Nested Automatic Differentiation","description":"","frontmatter":{},"headers":[],"relativePath":"manual/nested_autodiff.md","filePath":"manual/nested_autodiff.md","lastUpdated":null}'),h={name:"manual/nested_autodiff.md"},p={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},k={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.09ex"},xmlns:"http://www.w3.org/2000/svg",width:"10.178ex",height:"2.004ex",role:"img",focusable:"false",viewBox:"0 -846 4498.7 886","aria-hidden":"true"},d={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},r={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.09ex"},xmlns:"http://www.w3.org/2000/svg",width:"7.009ex",height:"2.004ex",role:"img",focusable:"false",viewBox:"0 -846 3098 886","aria-hidden":"true"},o={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},g={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"11.439ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 5056 1199","aria-hidden":"true"},Q={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},E={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.819ex"},xmlns:"http://www.w3.org/2000/svg",width:"33.692ex",height:"6.74ex",role:"img",focusable:"false",viewBox:"0 -1733 14891.7 2978.9","aria-hidden":"true"},T={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},c={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.09ex"},xmlns:"http://www.w3.org/2000/svg",width:"9.913ex",height:"2.004ex",role:"img",focusable:"false",viewBox:"0 -846 4381.7 886","aria-hidden":"true"},y={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},m={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.819ex"},xmlns:"http://www.w3.org/2000/svg",width:"21.167ex",height:"6.74ex",role:"img",focusable:"false",viewBox:"0 -1733 9355.6 2978.9","aria-hidden":"true"},u={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},F={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.661ex"},xmlns:"http://www.w3.org/2000/svg",width:"3.843ex",height:"2.565ex",role:"img",focusable:"false",viewBox:"0 -841.7 1698.8 1133.9","aria-hidden":"true"},C={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},f={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"3.269ex",height:"1.902ex",role:"img",focusable:"false",viewBox:"0 -683 1445 840.8","aria-hidden":"true"},b={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},x={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.837ex",height:"1.359ex",role:"img",focusable:"false",viewBox:"0 -443 812 600.8","aria-hidden":"true"};function v(w,i,H,D,B,L){return l(),n("div",null,[i[32]||(i[32]=t(`

    Nested Automatic Differentiation

    Note

    This is a relatively new feature in Lux, so there might be some rough edges. If you encounter any issues, please let us know by opening an issue on the GitHub repository.

    In this manual, we will explore how to use automatic differentiation (AD) inside your layers or loss functions and have Lux automatically switch the AD backend with a faster one when needed.

    Tip

    Don't wan't Lux to do this switching for you? You can disable it by setting the automatic_nested_ad_switching Preference to false.

    Remember that if you are using ForwardDiff inside a Zygote call, it will drop gradients (with a warning message), so it is not recommended to use this combination.

    Let's explore this using some questions that were posted on the Julia Discourse forum.

    julia
    using ADTypes, Lux, LinearAlgebra, Zygote, ForwardDiff, Random, StableRNGs
    +using ComponentArrays, FiniteDiff

    First let's set the stage using some minor changes that need to be made for this feature to work:

    • Switching only works if a StatefulLuxLayer is being used, with the following function calls:

      • For operations on the inputs:

        • (<some-function> ∘ <StatefulLuxLayer>)(x::AbstractArray)

        • (<StatefulLuxLayer> ∘ <some-function>)(x::AbstractArray)

        • (<StatefulLuxLayer>)(x::AbstractArray)

      • For operations on the parameters:

        • (<some-function> ∘ Base.Fix1(<StatefulLuxLayer>, x))(ps)

        • (Base.Fix1(<StatefulLuxLayer>, x) ∘ <some-function>)(ps)

        • (Base.Fix1(<StatefulLuxLayer>, x))(ps)

    • Currently we have custom routines implemented for:

    • Switching only happens for ChainRules compatible AD libraries.

    We plan to capture DifferentiationInterface, and Enzyme.autodiff calls in the future (PRs are welcome).

    Tip

    @compact uses StatefulLuxLayers internally, so you can directly use these features inside a layer generated by @compact.

    Loss Function containing Jacobian Computation

    This problem comes from @facusapienza on Discourse. In this case, we want to add a regularization term to the neural DE based on first-order derivatives. The neural DE part is not important here and we can demonstrate this easily with a standard neural network.

    julia
    function loss_function1(model, x, ps, st, y)
    +    # Make it a stateful layer
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    += smodel(x)
    +    loss_emp = sum(abs2, ŷ .- y)
    +    # You can use \`Zygote.jacobian\` as well but ForwardDiff tends to be more efficient here
    +    J = ForwardDiff.jacobian(smodel, x)
    +    loss_reg = abs2(norm(J .* 0.01f0))
    +    return loss_emp + loss_reg
    +end
    +
    +# Using Batchnorm to show that it is possible
    +model = Chain(Dense(2 => 4, tanh), BatchNorm(4), Dense(4 => 2))
    +ps, st = Lux.setup(StableRNG(0), model)
    +x = randn(StableRNG(0), Float32, 2, 10)
    +y = randn(StableRNG(11), Float32, 2, 10)
    +
    +loss_function1(model, x, ps, st, y)
    14.883664f0

    So our loss function works, let's take the gradient (forward diff doesn't nest nicely here):

    julia
    _, ∂x, ∂ps, _, _ = Zygote.gradient(loss_function1, model, x, ps, st, y)
    (nothing, Float32[-1.6702257 0.9043228 … 0.16094846 -4.992662; -8.010404 0.8541596 … 3.3928175 -7.1936812], (layer_1 = (weight = Float32[-4.3707023 -4.9076533; 22.199387 1.867202; 0.47872233 -0.9734574; -0.36428708 0.31861955], bias = Float32[-1.0168695, -0.16566901, 1.0829282, 1.4810884]), layer_2 = (scale = Float32[4.2774315, 3.1984668, 6.840588, 3.7018592], bias = Float32[-2.6477456, 4.9094505, -4.987689, -0.7292344]), layer_3 = (weight = Float32[11.395306 1.9206433 9.744489 -7.6726513; 2.5979974 7.106069 -7.869632 -1.787159], bias = Float32[0.041031003, 7.928609])), nothing, Float32[0.48193252 1.4007905 … -0.19124654 -1.7181164; 1.7811481 0.6913705 … -1.5627227 1.4397957])

    Now let's verify the gradients using finite differences:

    julia
    ∂x_fd = FiniteDiff.finite_difference_gradient(x -> loss_function1(model, x, ps, st, y), x)
    +∂ps_fd = FiniteDiff.finite_difference_gradient(ps -> loss_function1(model, x, ps, st, y),
    +    ComponentArray(ps))
    +
    +println("∞-norm(∂x - ∂x_fd): ", norm(∂x .- ∂x_fd, Inf))
    +println("∞-norm(∂ps - ∂ps_fd): ", norm(ComponentArray(∂ps) .- ∂ps_fd, Inf))
    ┌ Warning: \`training\` is set to \`Val{true}()\` but is not being used within an autodiff call (gradient, jacobian, etc...). This will be slow. If you are using a \`Lux.jl\` model, set it to inference (test) mode using \`LuxCore.testmode\`. Reliance on this behavior is discouraged, and is not guaranteed by Semantic Versioning, and might be removed without a deprecation cycle. It is recommended to fix this issue in your code.
    +└ @ LuxLib.Utils /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxLib/src/utils.jl:309
    +┌ Warning: \`training\` is set to \`Val{true}()\` but is not being used within an autodiff call (gradient, jacobian, etc...). This will be slow. If you are using a \`Lux.jl\` model, set it to inference (test) mode using \`LuxCore.testmode\`. Reliance on this behavior is discouraged, and is not guaranteed by Semantic Versioning, and might be removed without a deprecation cycle. It is recommended to fix this issue in your code.
    +└ @ LuxLib.Utils /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxLib/src/utils.jl:309
    +∞-norm(∂x - ∂x_fd): 0.00046014786
    +∞-norm(∂ps - ∂ps_fd): 0.00068473816

    That's pretty good, of course you will have some error from the finite differences calculation.

    Using Batched Jacobian for Multiple Inputs

    Notice that in this example the Jacobian J consists on the full matrix of derivatives of smodel with respect the different inputs in x. In many cases, we are interested in computing the Jacobian with respect to each input individually, avoiding the unnecessary calculation of zero entries of the Jacobian. This can be achieved with batched_jacobian to parse the calculation of the Jacobian per each single input. Using the same example from the previous section:

    julia
    model = Chain(Dense(2 => 4, tanh), Dense(4 => 2))
    +ps, st = Lux.setup(StableRNG(0), model)
    +x = randn(StableRNG(0), Float32, 2, 10)
    +y = randn(StableRNG(11), Float32, 2, 10)
    +
    +function loss_function_batched(model, x, ps, st, y)
    +    # Make it a stateful layer
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    += smodel(x)
    +    loss_emp = sum(abs2, ŷ .- y)
    +    # You can use \`AutoZygote()\` as well but \`AutoForwardDiff()\` tends to be more efficient here
    +    J = batched_jacobian(smodel, AutoForwardDiff(), x)
    +    loss_reg = abs2(norm(J .* 0.01f0))
    +    return loss_emp + loss_reg
    +end
    +
    +loss_function_batched(model, x, ps, st, y)
    11.380777f0

    Notice that in this last example we removed BatchNorm() from the neural network. This is done so outputs corresponding to differern inputs don't have an algebraic dependency due to the batch normalization happening in the neural network. We can now verify again the value of the Jacobian:

    julia
    ∂x_fd = FiniteDiff.finite_difference_gradient(x -> loss_function_batched(model, x, ps, st, y), x)
    +∂ps_fd = FiniteDiff.finite_difference_gradient(ps -> loss_function_batched(model, x, ps, st, y),
    +    ComponentArray(ps))
    +
    +_, ∂x_b, ∂ps_b, _, _ = Zygote.gradient(loss_function_batched, model, x, ps, st, y)
    +println("∞-norm(∂x_b - ∂x_fd): ", norm(∂x_b .- ∂x_fd, Inf))
    +println("∞-norm(∂ps_b - ∂ps_fd): ", norm(ComponentArray(∂ps_b) .- ∂ps_fd, Inf))
    ∞-norm(∂x_b - ∂x_fd): 0.00020849705
    +∞-norm(∂ps_b - ∂ps_fd): 0.00025326014

    In this example, it is important to remark that now batched_jacobian returns a 3D array with the Jacobian calculation for each independent input value in x.

    Loss Function contains Gradient Computation

    Ok here I am going to cheat a bit. This comes from a discussion on nested AD for PINNs on Discourse. As the consensus there, we shouldn't use nested AD for 3rd or higher order differentiation. Note that in the example there, the user uses ForwardDiff.derivative but we will use ForwardDiff.gradient instead, as we typically deal with array inputs and outputs.

    julia
    function loss_function2(model, t, ps, st)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    += only(Zygote.gradient(Base.Fix1(sum, abs2)  smodel, t)) # Zygote returns a tuple
    +    return sum(abs2, ŷ .- cos.(t))
    +end
    +
    +model = Chain(Dense(1 => 12,tanh), Dense(12 => 12,tanh), Dense(12 => 12,tanh),
    +    Dense(12 => 1))
    +ps, st = Lux.setup(StableRNG(0), model)
    +t = rand(StableRNG(0), Float32, 1, 16)
    1×16 Matrix{Float32}:
    + 0.420698  0.488105  0.267644  0.784768  …  0.305844  0.131726  0.859405

    Now the moment of truth:

    julia
    _, ∂t, ∂ps, _ = Zygote.gradient(loss_function2, model, t, ps, st)
    (nothing, Float32[-0.5530689 0.15707001 … -8.553631 0.075135306], (layer_1 = (weight = Float32[-1.3108876; -2.4101033; … ; 0.43676835; 1.9626998;;], bias = Float32[-1.77037, 1.7834251, -7.1079326, -3.4437156, 3.2615936, -1.9511775, 11.52717, -1.8003627, 6.751377, -4.7700396, -3.183307, 6.5878153]), layer_2 = (weight = Float32[-0.23921265 -0.20668754 … -0.63838756 -2.23242; -1.666682 1.0425432 … -1.6409345 -3.4007292; … ; -0.3602331 -0.086429894 … -0.7054554 -2.1921258; 3.1173706 -1.9727281 … 3.0402095 6.1137304], bias = Float32[0.3729234, -2.9340093, 3.6637242, -0.72471225, -0.79250443, -1.1245008, -0.89858943, -0.032846544, -2.7296474, -8.446214, 0.062079933, 5.5367613]), layer_3 = (weight = Float32[-0.7262075 1.0381727 … -1.5016017 -1.6798847; 2.2896142 0.43350348 … -1.6663244 -1.8067698; … ; -2.185124 -0.6424197 … 1.9577397 2.1489007; 0.36542922 -0.09699093 … 0.02535769 0.028738942], bias = Float32[1.1350521, -2.1769385, 4.114975, 3.2842, 0.35638642, 3.7911112, -0.007984845, -2.0338569, -1.1642133, -2.9500444, 2.0285962, -0.41238892]), layer_4 = (weight = Float32[15.794908 -20.65178 … -7.798027 -9.910251], bias = Float32[11.4614])), nothing)

    Boom that worked! Let's verify the gradient using forward diff:

    julia
    ∂t_fd = ForwardDiff.gradient(t -> loss_function2(model, t, ps, st), t)
    +∂ps_fd = ForwardDiff.gradient(ps -> loss_function2(model, t, ps, st), ComponentArray(ps))
    +
    +println("∞-norm(∂t - ∂t_fd): ", norm(∂t .- ∂t_fd, Inf))
    +println("∞-norm(∂ps - ∂ps_fd): ", norm(ComponentArray(∂ps) .- ∂ps_fd, Inf))
    ∞-norm(∂t - ∂t_fd): 3.8146973e-6
    +∞-norm(∂ps - ∂ps_fd): 3.8146973e-6

    Loss Function computing the Jacobian of the Parameters

    The above example shows how to compute the gradient/jacobian wrt the inputs in the loss function. However, what if we want to compute the jacobian wrt the parameters? This problem has been taken from Issue 610.

    We resolve these setups by using the Base.Fix1 wrapper around the stateful layer and fixing the input to the stateful layer.

    julia
    function loss_function3(model, x, ps, st)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    J = only(Zygote.jacobian(Base.Fix1(smodel, x), ps)) # Zygote returns a tuple
    +    return sum(abs2, J)
    +end
    +
    +model = Chain(Dense(1 => 12,tanh), Dense(12 => 12,tanh), Dense(12 => 12,tanh),
    +    Dense(12 => 1))
    +ps, st = Lux.setup(StableRNG(0), model)
    +ps = ComponentArray(ps)  # needs to be an AbstractArray for most jacobian functions
    +x = rand(StableRNG(0), Float32, 1, 16)
    1×16 Matrix{Float32}:
    + 0.420698  0.488105  0.267644  0.784768  …  0.305844  0.131726  0.859405

    We can as usual compute the gradient/jacobian of the loss function:

    julia
    _, ∂x, ∂ps, _ = Zygote.gradient(loss_function3, model, x, ps, st)
    (nothing, Float32[6.846457 6.2111273 … 1.9693878 -1.959182], (layer_1 = (weight = Float32[-3.6867142; -1.6853896; … ; 2.9501405; -6.6372185;;], bias = Float32[-6.488623, -7.066128, 1.3344351, 2.6049256, 0.72908926, -15.730941, -5.4314566, 7.4604845, -1.186451, 15.522139, 0.44571686, -15.376383]), layer_2 = (weight = Float32[0.39800483 -4.3071294 … -1.0914626 -4.759412; 0.8852221 -2.2523673 … 0.3977319 0.1306755; … ; -2.2192001 0.88214725 … -0.55989707 1.3939896; -3.1545162 4.594261 … -1.7649314 -0.38242024], bias = Float32[7.524781, 4.252925, -17.252985, 3.2606924, -7.4066515, 1.1126356, 2.847106, 6.754463, -9.815336, 0.18652338, -4.5365157, -10.048109]), layer_3 = (weight = Float32[1.0462954 4.8999977 … 1.1557574 -2.2849667; -2.3719285 8.687264 … -3.1904755 -8.841231; … ; -10.298787 -2.9139614 … -9.754747 -4.0381317; 1.2221465 -0.4687857 … 1.0469301 0.90910274], bias = Float32[2.837991, 8.345025, 2.9214196, -2.2415948, -11.139433, -3.8340728, -2.8454118, -7.9164896, 4.222528, -1.2864522, 6.9338737, -1.4144732]), layer_4 = (weight = Float32[-59.44397 -12.688665 … 99.77207 -3.339079], bias = Float32[0.0])), nothing)

    Now let's verify the gradient using forward diff:

    julia
    ∂x_fd = ForwardDiff.gradient(x -> loss_function3(model, x, ps, st), x)
    +∂ps_fd = ForwardDiff.gradient(ps -> loss_function3(model, x, ps, st), ComponentArray(ps))
    +
    +println("∞-norm(∂x - ∂x_fd): ", norm(∂x .- ∂x_fd, Inf))
    +println("∞-norm(∂ps - ∂ps_fd): ", norm(ComponentArray(∂ps) .- ∂ps_fd, Inf))
    ∞-norm(∂x - ∂x_fd): 4.172325e-6
    +∞-norm(∂ps - ∂ps_fd): 4.5776367e-5

    Hutchinson Trace Estimation

    `,51)),s("p",null,[i[6]||(i[6]=a("Hutchinson Trace Estimation often shows up in machine learning literature to provide a fast estimate of the trace of a Jacobian Matrix. This is based off of ")),i[7]||(i[7]=s("a",{href:"https://www.nowozin.net/sebastian/blog/thoughts-on-trace-estimation-in-deep-learning.html",target:"_blank",rel:"noreferrer"},"Hutchinson 1990",-1)),i[8]||(i[8]=a(" which computes the estimated trace of a matrix ")),s("mjx-container",p,[(l(),n("svg",k,i[0]||(i[0]=[t('',1)]))),i[1]||(i[1]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"A"),s("mo",null,"∈"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"R")]),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"D"),s("mo",null,"×"),s("mi",null,"D")])])])],-1))]),i[9]||(i[9]=a(" using random vectors ")),s("mjx-container",d,[(l(),n("svg",r,i[2]||(i[2]=[t('',1)]))),i[3]||(i[3]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"v"),s("mo",null,"∈"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"R")]),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"D")])])])],-1))]),i[10]||(i[10]=a(" s.t. ")),s("mjx-container",o,[(l(),n("svg",g,i[4]||(i[4]=[t('',1)]))),i[5]||(i[5]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"E")]),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"["),s("mi",null,"v"),s("msup",null,[s("mi",null,"v"),s("mi",null,"T")]),s("mo",{"data-mjx-texclass":"CLOSE"},"]")]),s("mo",null,"="),s("mi",null,"I")])],-1))]),i[11]||(i[11]=a("."))]),s("mjx-container",Q,[(l(),n("svg",E,i[12]||(i[12]=[t('',1)]))),i[13]||(i[13]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"Tr"),s("mo",{stretchy:"false"},"("),s("mi",null,"A"),s("mo",{stretchy:"false"},")"),s("mo",null,"="),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"E")]),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"["),s("msup",null,[s("mi",null,"v"),s("mi",null,"T")]),s("mi",null,"A"),s("mi",null,"v"),s("mo",{"data-mjx-texclass":"CLOSE"},"]")]),s("mo",null,"="),s("mfrac",null,[s("mn",null,"1"),s("mi",null,"V")]),s("munderover",null,[s("mo",{"data-mjx-texclass":"OP"},"∑"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"i"),s("mo",null,"="),s("mn",null,"1")]),s("mi",null,"V")]),s("msubsup",null,[s("mi",null,"v"),s("mi",null,"i"),s("mi",null,"T")]),s("mi",null,"A"),s("msub",null,[s("mi",null,"v"),s("mi",null,"i")])])],-1))]),s("p",null,[i[16]||(i[16]=a("We can use this to compute the trace of a Jacobian Matrix ")),s("mjx-container",T,[(l(),n("svg",c,i[14]||(i[14]=[t('',1)]))),i[15]||(i[15]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"J"),s("mo",null,"∈"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"R")]),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"D"),s("mo",null,"×"),s("mi",null,"D")])])])],-1))]),i[17]||(i[17]=a(" using the following algorithm:"))]),s("mjx-container",y,[(l(),n("svg",m,i[18]||(i[18]=[t('',1)]))),i[19]||(i[19]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"Tr"),s("mo",{stretchy:"false"},"("),s("mi",null,"J"),s("mo",{stretchy:"false"},")"),s("mo",null,"="),s("mfrac",null,[s("mn",null,"1"),s("mi",null,"V")]),s("munderover",null,[s("mo",{"data-mjx-texclass":"OP"},"∑"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"i"),s("mo",null,"="),s("mn",null,"1")]),s("mi",null,"V")]),s("msubsup",null,[s("mi",null,"v"),s("mi",null,"i"),s("mi",null,"T")]),s("mi",null,"J"),s("msub",null,[s("mi",null,"v"),s("mi",null,"i")])])],-1))]),i[33]||(i[33]=s("p",null,"Note that we can compute this using two methods:",-1)),s("ol",null,[s("li",null,[s("p",null,[i[22]||(i[22]=a("Compute ")),s("mjx-container",u,[(l(),n("svg",F,i[20]||(i[20]=[t('',1)]))),i[21]||(i[21]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("msubsup",null,[s("mi",null,"v"),s("mi",null,"i"),s("mi",null,"T")]),s("mi",null,"J")])],-1))]),i[23]||(i[23]=a(" using a Vector-Jacobian product and then do a matrix-vector product to get the trace."))])]),s("li",null,[s("p",null,[i[26]||(i[26]=a("Compute ")),s("mjx-container",C,[(l(),n("svg",f,i[24]||(i[24]=[t('',1)]))),i[25]||(i[25]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"J"),s("msub",null,[s("mi",null,"v"),s("mi",null,"i")])])],-1))]),i[27]||(i[27]=a(" using a Jacobian-Vector product and then do a matrix-vector product to get the trace."))])])]),s("p",null,[i[30]||(i[30]=a("For simplicity, we will use a single sample of ")),s("mjx-container",b,[(l(),n("svg",x,i[28]||(i[28]=[t('',1)]))),i[29]||(i[29]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("msub",null,[s("mi",null,"v"),s("mi",null,"i")])])],-1))]),i[31]||(i[31]=a(" to compute the trace. Additionally, we will fix the sample to ensure that our tests against the finite difference implementation are not affected by the randomness in the sample."))]),i[34]||(i[34]=t(`

    Computing using the Vector-Jacobian Product

    julia
    function hutchinson_trace_vjp(model, x, ps, st, v)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    vjp = vector_jacobian_product(smodel, AutoZygote(), x, v)
    +    return sum(batched_matmul(reshape(vjp, 1, :, size(vjp, ndims(vjp))),
    +               reshape(v, :, 1, size(v, ndims(v)))))
    +end
    hutchinson_trace_vjp (generic function with 1 method)

    This vjp version will be the fastest and most scalable and hence is the recommended way for computing hutchinson trace.

    Computing using the Jacobian-Vector Product

    julia
    function hutchinson_trace_jvp(model, x, ps, st, v)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    jvp = jacobian_vector_product(smodel, AutoForwardDiff(), x, v)
    +    return sum(batched_matmul(reshape(v, 1, :, size(v, ndims(v))),
    +               reshape(jvp, :, 1, size(jvp, ndims(jvp)))))
    +end
    hutchinson_trace_jvp (generic function with 1 method)

    Computing using the Full Jacobian

    This is definitely not recommended, but we are showing it for completeness.

    julia
    function hutchinson_trace_full_jacobian(model, x, ps, st, v)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    J = ForwardDiff.jacobian(smodel, x)
    +    return vec(v)' * J * vec(v)
    +end
    hutchinson_trace_full_jacobian (generic function with 1 method)

    Now let's compute the trace and compare the results:

    julia
    model = Chain(Dense(4 => 12,tanh), Dense(12 => 12,tanh), Dense(12 => 12,tanh),
    +    Dense(12 => 4))
    +ps, st = Lux.setup(StableRNG(0), model)
    +x = rand(StableRNG(0), Float32, 4, 12)
    +v = (rand(StableRNG(12), Float32, 4, 12) .> 0.5f0) * 2.0f0 .- 1.0f0  # rademacher sample
    julia
    tr_vjp = hutchinson_trace_vjp(model, x, ps, st, v)
    +tr_jvp = hutchinson_trace_jvp(model, x, ps, st, v)
    +tr_full_jacobian = hutchinson_trace_full_jacobian(model, x, ps, st, v)
    +println("Tr(J) using vjp: ", tr_vjp)
    +println("Tr(J) using jvp: ", tr_jvp)
    +println("Tr(J) using full jacobian: ", tr_full_jacobian)
    Tr(J) using vjp: 4.9127817
    +Tr(J) using jvp: 4.912782
    +Tr(J) using full jacobian: 4.912781

    Now that we have verified that the results are the same, let's try to differentiate the trace estimate. This often shows up as a regularization term in neural networks.

    julia
    _, ∂x_vjp, ∂ps_vjp, _, _ = Zygote.gradient(hutchinson_trace_vjp, model, x, ps, st, v)
    +_, ∂x_jvp, ∂ps_jvp, _, _ = Zygote.gradient(hutchinson_trace_jvp, model, x, ps, st, v)
    +_, ∂x_full_jacobian, ∂ps_full_jacobian, _, _ = Zygote.gradient(hutchinson_trace_full_jacobian,
    +    model, x, ps, st, v)

    For sanity check, let's verify that the gradients are the same:

    julia
    println("∞-norm(∂x using vjp): ", norm(∂x_vjp .- ∂x_jvp, Inf))
    +println("∞-norm(∂ps using vjp): ",
    +    norm(ComponentArray(∂ps_vjp) .- ComponentArray(∂ps_jvp), Inf))
    +println("∞-norm(∂x using full jacobian): ", norm(∂x_full_jacobian .- ∂x_vjp, Inf))
    +println("∞-norm(∂ps using full jacobian): ",
    +    norm(ComponentArray(∂ps_full_jacobian) .- ComponentArray(∂ps_vjp), Inf))
    ∞-norm(∂x using vjp): 0.0
    +∞-norm(∂ps using vjp): 0.0
    +∞-norm(∂x using full jacobian): 9.536743e-7
    +∞-norm(∂ps using full jacobian): 1.4305115e-6
    `,20))])}const _=e(h,[["render",v]]);export{j as __pageData,_ as default}; diff --git a/previews/PR1023/assets/manual_nested_autodiff.md.BllOXIU5.lean.js b/previews/PR1023/assets/manual_nested_autodiff.md.BllOXIU5.lean.js new file mode 100644 index 0000000000..87e3ab6ab9 --- /dev/null +++ b/previews/PR1023/assets/manual_nested_autodiff.md.BllOXIU5.lean.js @@ -0,0 +1,119 @@ +import{_ as e,c as n,a2 as t,j as s,a,o as l}from"./chunks/framework.DFwXuivk.js";const j=JSON.parse('{"title":"Nested Automatic Differentiation","description":"","frontmatter":{},"headers":[],"relativePath":"manual/nested_autodiff.md","filePath":"manual/nested_autodiff.md","lastUpdated":null}'),h={name:"manual/nested_autodiff.md"},p={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},k={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.09ex"},xmlns:"http://www.w3.org/2000/svg",width:"10.178ex",height:"2.004ex",role:"img",focusable:"false",viewBox:"0 -846 4498.7 886","aria-hidden":"true"},d={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},r={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.09ex"},xmlns:"http://www.w3.org/2000/svg",width:"7.009ex",height:"2.004ex",role:"img",focusable:"false",viewBox:"0 -846 3098 886","aria-hidden":"true"},o={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},g={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.791ex"},xmlns:"http://www.w3.org/2000/svg",width:"11.439ex",height:"2.713ex",role:"img",focusable:"false",viewBox:"0 -849.5 5056 1199","aria-hidden":"true"},Q={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},E={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.819ex"},xmlns:"http://www.w3.org/2000/svg",width:"33.692ex",height:"6.74ex",role:"img",focusable:"false",viewBox:"0 -1733 14891.7 2978.9","aria-hidden":"true"},T={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},c={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.09ex"},xmlns:"http://www.w3.org/2000/svg",width:"9.913ex",height:"2.004ex",role:"img",focusable:"false",viewBox:"0 -846 4381.7 886","aria-hidden":"true"},y={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},m={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.819ex"},xmlns:"http://www.w3.org/2000/svg",width:"21.167ex",height:"6.74ex",role:"img",focusable:"false",viewBox:"0 -1733 9355.6 2978.9","aria-hidden":"true"},u={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},F={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.661ex"},xmlns:"http://www.w3.org/2000/svg",width:"3.843ex",height:"2.565ex",role:"img",focusable:"false",viewBox:"0 -841.7 1698.8 1133.9","aria-hidden":"true"},C={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},f={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"3.269ex",height:"1.902ex",role:"img",focusable:"false",viewBox:"0 -683 1445 840.8","aria-hidden":"true"},b={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},x={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.357ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.837ex",height:"1.359ex",role:"img",focusable:"false",viewBox:"0 -443 812 600.8","aria-hidden":"true"};function v(w,i,H,D,B,L){return l(),n("div",null,[i[32]||(i[32]=t(`

    Nested Automatic Differentiation

    Note

    This is a relatively new feature in Lux, so there might be some rough edges. If you encounter any issues, please let us know by opening an issue on the GitHub repository.

    In this manual, we will explore how to use automatic differentiation (AD) inside your layers or loss functions and have Lux automatically switch the AD backend with a faster one when needed.

    Tip

    Don't wan't Lux to do this switching for you? You can disable it by setting the automatic_nested_ad_switching Preference to false.

    Remember that if you are using ForwardDiff inside a Zygote call, it will drop gradients (with a warning message), so it is not recommended to use this combination.

    Let's explore this using some questions that were posted on the Julia Discourse forum.

    julia
    using ADTypes, Lux, LinearAlgebra, Zygote, ForwardDiff, Random, StableRNGs
    +using ComponentArrays, FiniteDiff

    First let's set the stage using some minor changes that need to be made for this feature to work:

    • Switching only works if a StatefulLuxLayer is being used, with the following function calls:

      • For operations on the inputs:

        • (<some-function> ∘ <StatefulLuxLayer>)(x::AbstractArray)

        • (<StatefulLuxLayer> ∘ <some-function>)(x::AbstractArray)

        • (<StatefulLuxLayer>)(x::AbstractArray)

      • For operations on the parameters:

        • (<some-function> ∘ Base.Fix1(<StatefulLuxLayer>, x))(ps)

        • (Base.Fix1(<StatefulLuxLayer>, x) ∘ <some-function>)(ps)

        • (Base.Fix1(<StatefulLuxLayer>, x))(ps)

    • Currently we have custom routines implemented for:

    • Switching only happens for ChainRules compatible AD libraries.

    We plan to capture DifferentiationInterface, and Enzyme.autodiff calls in the future (PRs are welcome).

    Tip

    @compact uses StatefulLuxLayers internally, so you can directly use these features inside a layer generated by @compact.

    Loss Function containing Jacobian Computation

    This problem comes from @facusapienza on Discourse. In this case, we want to add a regularization term to the neural DE based on first-order derivatives. The neural DE part is not important here and we can demonstrate this easily with a standard neural network.

    julia
    function loss_function1(model, x, ps, st, y)
    +    # Make it a stateful layer
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    += smodel(x)
    +    loss_emp = sum(abs2, ŷ .- y)
    +    # You can use \`Zygote.jacobian\` as well but ForwardDiff tends to be more efficient here
    +    J = ForwardDiff.jacobian(smodel, x)
    +    loss_reg = abs2(norm(J .* 0.01f0))
    +    return loss_emp + loss_reg
    +end
    +
    +# Using Batchnorm to show that it is possible
    +model = Chain(Dense(2 => 4, tanh), BatchNorm(4), Dense(4 => 2))
    +ps, st = Lux.setup(StableRNG(0), model)
    +x = randn(StableRNG(0), Float32, 2, 10)
    +y = randn(StableRNG(11), Float32, 2, 10)
    +
    +loss_function1(model, x, ps, st, y)
    14.883664f0

    So our loss function works, let's take the gradient (forward diff doesn't nest nicely here):

    julia
    _, ∂x, ∂ps, _, _ = Zygote.gradient(loss_function1, model, x, ps, st, y)
    (nothing, Float32[-1.6702257 0.9043228 … 0.16094846 -4.992662; -8.010404 0.8541596 … 3.3928175 -7.1936812], (layer_1 = (weight = Float32[-4.3707023 -4.9076533; 22.199387 1.867202; 0.47872233 -0.9734574; -0.36428708 0.31861955], bias = Float32[-1.0168695, -0.16566901, 1.0829282, 1.4810884]), layer_2 = (scale = Float32[4.2774315, 3.1984668, 6.840588, 3.7018592], bias = Float32[-2.6477456, 4.9094505, -4.987689, -0.7292344]), layer_3 = (weight = Float32[11.395306 1.9206433 9.744489 -7.6726513; 2.5979974 7.106069 -7.869632 -1.787159], bias = Float32[0.041031003, 7.928609])), nothing, Float32[0.48193252 1.4007905 … -0.19124654 -1.7181164; 1.7811481 0.6913705 … -1.5627227 1.4397957])

    Now let's verify the gradients using finite differences:

    julia
    ∂x_fd = FiniteDiff.finite_difference_gradient(x -> loss_function1(model, x, ps, st, y), x)
    +∂ps_fd = FiniteDiff.finite_difference_gradient(ps -> loss_function1(model, x, ps, st, y),
    +    ComponentArray(ps))
    +
    +println("∞-norm(∂x - ∂x_fd): ", norm(∂x .- ∂x_fd, Inf))
    +println("∞-norm(∂ps - ∂ps_fd): ", norm(ComponentArray(∂ps) .- ∂ps_fd, Inf))
    ┌ Warning: \`training\` is set to \`Val{true}()\` but is not being used within an autodiff call (gradient, jacobian, etc...). This will be slow. If you are using a \`Lux.jl\` model, set it to inference (test) mode using \`LuxCore.testmode\`. Reliance on this behavior is discouraged, and is not guaranteed by Semantic Versioning, and might be removed without a deprecation cycle. It is recommended to fix this issue in your code.
    +└ @ LuxLib.Utils /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxLib/src/utils.jl:309
    +┌ Warning: \`training\` is set to \`Val{true}()\` but is not being used within an autodiff call (gradient, jacobian, etc...). This will be slow. If you are using a \`Lux.jl\` model, set it to inference (test) mode using \`LuxCore.testmode\`. Reliance on this behavior is discouraged, and is not guaranteed by Semantic Versioning, and might be removed without a deprecation cycle. It is recommended to fix this issue in your code.
    +└ @ LuxLib.Utils /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxLib/src/utils.jl:309
    +∞-norm(∂x - ∂x_fd): 0.00046014786
    +∞-norm(∂ps - ∂ps_fd): 0.00068473816

    That's pretty good, of course you will have some error from the finite differences calculation.

    Using Batched Jacobian for Multiple Inputs

    Notice that in this example the Jacobian J consists on the full matrix of derivatives of smodel with respect the different inputs in x. In many cases, we are interested in computing the Jacobian with respect to each input individually, avoiding the unnecessary calculation of zero entries of the Jacobian. This can be achieved with batched_jacobian to parse the calculation of the Jacobian per each single input. Using the same example from the previous section:

    julia
    model = Chain(Dense(2 => 4, tanh), Dense(4 => 2))
    +ps, st = Lux.setup(StableRNG(0), model)
    +x = randn(StableRNG(0), Float32, 2, 10)
    +y = randn(StableRNG(11), Float32, 2, 10)
    +
    +function loss_function_batched(model, x, ps, st, y)
    +    # Make it a stateful layer
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    += smodel(x)
    +    loss_emp = sum(abs2, ŷ .- y)
    +    # You can use \`AutoZygote()\` as well but \`AutoForwardDiff()\` tends to be more efficient here
    +    J = batched_jacobian(smodel, AutoForwardDiff(), x)
    +    loss_reg = abs2(norm(J .* 0.01f0))
    +    return loss_emp + loss_reg
    +end
    +
    +loss_function_batched(model, x, ps, st, y)
    11.380777f0

    Notice that in this last example we removed BatchNorm() from the neural network. This is done so outputs corresponding to differern inputs don't have an algebraic dependency due to the batch normalization happening in the neural network. We can now verify again the value of the Jacobian:

    julia
    ∂x_fd = FiniteDiff.finite_difference_gradient(x -> loss_function_batched(model, x, ps, st, y), x)
    +∂ps_fd = FiniteDiff.finite_difference_gradient(ps -> loss_function_batched(model, x, ps, st, y),
    +    ComponentArray(ps))
    +
    +_, ∂x_b, ∂ps_b, _, _ = Zygote.gradient(loss_function_batched, model, x, ps, st, y)
    +println("∞-norm(∂x_b - ∂x_fd): ", norm(∂x_b .- ∂x_fd, Inf))
    +println("∞-norm(∂ps_b - ∂ps_fd): ", norm(ComponentArray(∂ps_b) .- ∂ps_fd, Inf))
    ∞-norm(∂x_b - ∂x_fd): 0.00020849705
    +∞-norm(∂ps_b - ∂ps_fd): 0.00025326014

    In this example, it is important to remark that now batched_jacobian returns a 3D array with the Jacobian calculation for each independent input value in x.

    Loss Function contains Gradient Computation

    Ok here I am going to cheat a bit. This comes from a discussion on nested AD for PINNs on Discourse. As the consensus there, we shouldn't use nested AD for 3rd or higher order differentiation. Note that in the example there, the user uses ForwardDiff.derivative but we will use ForwardDiff.gradient instead, as we typically deal with array inputs and outputs.

    julia
    function loss_function2(model, t, ps, st)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    += only(Zygote.gradient(Base.Fix1(sum, abs2)  smodel, t)) # Zygote returns a tuple
    +    return sum(abs2, ŷ .- cos.(t))
    +end
    +
    +model = Chain(Dense(1 => 12,tanh), Dense(12 => 12,tanh), Dense(12 => 12,tanh),
    +    Dense(12 => 1))
    +ps, st = Lux.setup(StableRNG(0), model)
    +t = rand(StableRNG(0), Float32, 1, 16)
    1×16 Matrix{Float32}:
    + 0.420698  0.488105  0.267644  0.784768  …  0.305844  0.131726  0.859405

    Now the moment of truth:

    julia
    _, ∂t, ∂ps, _ = Zygote.gradient(loss_function2, model, t, ps, st)
    (nothing, Float32[-0.5530689 0.15707001 … -8.553631 0.075135306], (layer_1 = (weight = Float32[-1.3108876; -2.4101033; … ; 0.43676835; 1.9626998;;], bias = Float32[-1.77037, 1.7834251, -7.1079326, -3.4437156, 3.2615936, -1.9511775, 11.52717, -1.8003627, 6.751377, -4.7700396, -3.183307, 6.5878153]), layer_2 = (weight = Float32[-0.23921265 -0.20668754 … -0.63838756 -2.23242; -1.666682 1.0425432 … -1.6409345 -3.4007292; … ; -0.3602331 -0.086429894 … -0.7054554 -2.1921258; 3.1173706 -1.9727281 … 3.0402095 6.1137304], bias = Float32[0.3729234, -2.9340093, 3.6637242, -0.72471225, -0.79250443, -1.1245008, -0.89858943, -0.032846544, -2.7296474, -8.446214, 0.062079933, 5.5367613]), layer_3 = (weight = Float32[-0.7262075 1.0381727 … -1.5016017 -1.6798847; 2.2896142 0.43350348 … -1.6663244 -1.8067698; … ; -2.185124 -0.6424197 … 1.9577397 2.1489007; 0.36542922 -0.09699093 … 0.02535769 0.028738942], bias = Float32[1.1350521, -2.1769385, 4.114975, 3.2842, 0.35638642, 3.7911112, -0.007984845, -2.0338569, -1.1642133, -2.9500444, 2.0285962, -0.41238892]), layer_4 = (weight = Float32[15.794908 -20.65178 … -7.798027 -9.910251], bias = Float32[11.4614])), nothing)

    Boom that worked! Let's verify the gradient using forward diff:

    julia
    ∂t_fd = ForwardDiff.gradient(t -> loss_function2(model, t, ps, st), t)
    +∂ps_fd = ForwardDiff.gradient(ps -> loss_function2(model, t, ps, st), ComponentArray(ps))
    +
    +println("∞-norm(∂t - ∂t_fd): ", norm(∂t .- ∂t_fd, Inf))
    +println("∞-norm(∂ps - ∂ps_fd): ", norm(ComponentArray(∂ps) .- ∂ps_fd, Inf))
    ∞-norm(∂t - ∂t_fd): 3.8146973e-6
    +∞-norm(∂ps - ∂ps_fd): 3.8146973e-6

    Loss Function computing the Jacobian of the Parameters

    The above example shows how to compute the gradient/jacobian wrt the inputs in the loss function. However, what if we want to compute the jacobian wrt the parameters? This problem has been taken from Issue 610.

    We resolve these setups by using the Base.Fix1 wrapper around the stateful layer and fixing the input to the stateful layer.

    julia
    function loss_function3(model, x, ps, st)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    J = only(Zygote.jacobian(Base.Fix1(smodel, x), ps)) # Zygote returns a tuple
    +    return sum(abs2, J)
    +end
    +
    +model = Chain(Dense(1 => 12,tanh), Dense(12 => 12,tanh), Dense(12 => 12,tanh),
    +    Dense(12 => 1))
    +ps, st = Lux.setup(StableRNG(0), model)
    +ps = ComponentArray(ps)  # needs to be an AbstractArray for most jacobian functions
    +x = rand(StableRNG(0), Float32, 1, 16)
    1×16 Matrix{Float32}:
    + 0.420698  0.488105  0.267644  0.784768  …  0.305844  0.131726  0.859405

    We can as usual compute the gradient/jacobian of the loss function:

    julia
    _, ∂x, ∂ps, _ = Zygote.gradient(loss_function3, model, x, ps, st)
    (nothing, Float32[6.846457 6.2111273 … 1.9693878 -1.959182], (layer_1 = (weight = Float32[-3.6867142; -1.6853896; … ; 2.9501405; -6.6372185;;], bias = Float32[-6.488623, -7.066128, 1.3344351, 2.6049256, 0.72908926, -15.730941, -5.4314566, 7.4604845, -1.186451, 15.522139, 0.44571686, -15.376383]), layer_2 = (weight = Float32[0.39800483 -4.3071294 … -1.0914626 -4.759412; 0.8852221 -2.2523673 … 0.3977319 0.1306755; … ; -2.2192001 0.88214725 … -0.55989707 1.3939896; -3.1545162 4.594261 … -1.7649314 -0.38242024], bias = Float32[7.524781, 4.252925, -17.252985, 3.2606924, -7.4066515, 1.1126356, 2.847106, 6.754463, -9.815336, 0.18652338, -4.5365157, -10.048109]), layer_3 = (weight = Float32[1.0462954 4.8999977 … 1.1557574 -2.2849667; -2.3719285 8.687264 … -3.1904755 -8.841231; … ; -10.298787 -2.9139614 … -9.754747 -4.0381317; 1.2221465 -0.4687857 … 1.0469301 0.90910274], bias = Float32[2.837991, 8.345025, 2.9214196, -2.2415948, -11.139433, -3.8340728, -2.8454118, -7.9164896, 4.222528, -1.2864522, 6.9338737, -1.4144732]), layer_4 = (weight = Float32[-59.44397 -12.688665 … 99.77207 -3.339079], bias = Float32[0.0])), nothing)

    Now let's verify the gradient using forward diff:

    julia
    ∂x_fd = ForwardDiff.gradient(x -> loss_function3(model, x, ps, st), x)
    +∂ps_fd = ForwardDiff.gradient(ps -> loss_function3(model, x, ps, st), ComponentArray(ps))
    +
    +println("∞-norm(∂x - ∂x_fd): ", norm(∂x .- ∂x_fd, Inf))
    +println("∞-norm(∂ps - ∂ps_fd): ", norm(ComponentArray(∂ps) .- ∂ps_fd, Inf))
    ∞-norm(∂x - ∂x_fd): 4.172325e-6
    +∞-norm(∂ps - ∂ps_fd): 4.5776367e-5

    Hutchinson Trace Estimation

    `,51)),s("p",null,[i[6]||(i[6]=a("Hutchinson Trace Estimation often shows up in machine learning literature to provide a fast estimate of the trace of a Jacobian Matrix. This is based off of ")),i[7]||(i[7]=s("a",{href:"https://www.nowozin.net/sebastian/blog/thoughts-on-trace-estimation-in-deep-learning.html",target:"_blank",rel:"noreferrer"},"Hutchinson 1990",-1)),i[8]||(i[8]=a(" which computes the estimated trace of a matrix ")),s("mjx-container",p,[(l(),n("svg",k,i[0]||(i[0]=[t('',1)]))),i[1]||(i[1]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"A"),s("mo",null,"∈"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"R")]),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"D"),s("mo",null,"×"),s("mi",null,"D")])])])],-1))]),i[9]||(i[9]=a(" using random vectors ")),s("mjx-container",d,[(l(),n("svg",r,i[2]||(i[2]=[t('',1)]))),i[3]||(i[3]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"v"),s("mo",null,"∈"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"R")]),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"D")])])])],-1))]),i[10]||(i[10]=a(" s.t. ")),s("mjx-container",o,[(l(),n("svg",g,i[4]||(i[4]=[t('',1)]))),i[5]||(i[5]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"E")]),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"["),s("mi",null,"v"),s("msup",null,[s("mi",null,"v"),s("mi",null,"T")]),s("mo",{"data-mjx-texclass":"CLOSE"},"]")]),s("mo",null,"="),s("mi",null,"I")])],-1))]),i[11]||(i[11]=a("."))]),s("mjx-container",Q,[(l(),n("svg",E,i[12]||(i[12]=[t('',1)]))),i[13]||(i[13]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"Tr"),s("mo",{stretchy:"false"},"("),s("mi",null,"A"),s("mo",{stretchy:"false"},")"),s("mo",null,"="),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"E")]),s("mrow",{"data-mjx-texclass":"INNER"},[s("mo",{"data-mjx-texclass":"OPEN"},"["),s("msup",null,[s("mi",null,"v"),s("mi",null,"T")]),s("mi",null,"A"),s("mi",null,"v"),s("mo",{"data-mjx-texclass":"CLOSE"},"]")]),s("mo",null,"="),s("mfrac",null,[s("mn",null,"1"),s("mi",null,"V")]),s("munderover",null,[s("mo",{"data-mjx-texclass":"OP"},"∑"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"i"),s("mo",null,"="),s("mn",null,"1")]),s("mi",null,"V")]),s("msubsup",null,[s("mi",null,"v"),s("mi",null,"i"),s("mi",null,"T")]),s("mi",null,"A"),s("msub",null,[s("mi",null,"v"),s("mi",null,"i")])])],-1))]),s("p",null,[i[16]||(i[16]=a("We can use this to compute the trace of a Jacobian Matrix ")),s("mjx-container",T,[(l(),n("svg",c,i[14]||(i[14]=[t('',1)]))),i[15]||(i[15]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"J"),s("mo",null,"∈"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"R")]),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"D"),s("mo",null,"×"),s("mi",null,"D")])])])],-1))]),i[17]||(i[17]=a(" using the following algorithm:"))]),s("mjx-container",y,[(l(),n("svg",m,i[18]||(i[18]=[t('',1)]))),i[19]||(i[19]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mtext",null,"Tr"),s("mo",{stretchy:"false"},"("),s("mi",null,"J"),s("mo",{stretchy:"false"},")"),s("mo",null,"="),s("mfrac",null,[s("mn",null,"1"),s("mi",null,"V")]),s("munderover",null,[s("mo",{"data-mjx-texclass":"OP"},"∑"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"i"),s("mo",null,"="),s("mn",null,"1")]),s("mi",null,"V")]),s("msubsup",null,[s("mi",null,"v"),s("mi",null,"i"),s("mi",null,"T")]),s("mi",null,"J"),s("msub",null,[s("mi",null,"v"),s("mi",null,"i")])])],-1))]),i[33]||(i[33]=s("p",null,"Note that we can compute this using two methods:",-1)),s("ol",null,[s("li",null,[s("p",null,[i[22]||(i[22]=a("Compute ")),s("mjx-container",u,[(l(),n("svg",F,i[20]||(i[20]=[t('',1)]))),i[21]||(i[21]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("msubsup",null,[s("mi",null,"v"),s("mi",null,"i"),s("mi",null,"T")]),s("mi",null,"J")])],-1))]),i[23]||(i[23]=a(" using a Vector-Jacobian product and then do a matrix-vector product to get the trace."))])]),s("li",null,[s("p",null,[i[26]||(i[26]=a("Compute ")),s("mjx-container",C,[(l(),n("svg",f,i[24]||(i[24]=[t('',1)]))),i[25]||(i[25]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"J"),s("msub",null,[s("mi",null,"v"),s("mi",null,"i")])])],-1))]),i[27]||(i[27]=a(" using a Jacobian-Vector product and then do a matrix-vector product to get the trace."))])])]),s("p",null,[i[30]||(i[30]=a("For simplicity, we will use a single sample of ")),s("mjx-container",b,[(l(),n("svg",x,i[28]||(i[28]=[t('',1)]))),i[29]||(i[29]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("msub",null,[s("mi",null,"v"),s("mi",null,"i")])])],-1))]),i[31]||(i[31]=a(" to compute the trace. Additionally, we will fix the sample to ensure that our tests against the finite difference implementation are not affected by the randomness in the sample."))]),i[34]||(i[34]=t(`

    Computing using the Vector-Jacobian Product

    julia
    function hutchinson_trace_vjp(model, x, ps, st, v)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    vjp = vector_jacobian_product(smodel, AutoZygote(), x, v)
    +    return sum(batched_matmul(reshape(vjp, 1, :, size(vjp, ndims(vjp))),
    +               reshape(v, :, 1, size(v, ndims(v)))))
    +end
    hutchinson_trace_vjp (generic function with 1 method)

    This vjp version will be the fastest and most scalable and hence is the recommended way for computing hutchinson trace.

    Computing using the Jacobian-Vector Product

    julia
    function hutchinson_trace_jvp(model, x, ps, st, v)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    jvp = jacobian_vector_product(smodel, AutoForwardDiff(), x, v)
    +    return sum(batched_matmul(reshape(v, 1, :, size(v, ndims(v))),
    +               reshape(jvp, :, 1, size(jvp, ndims(jvp)))))
    +end
    hutchinson_trace_jvp (generic function with 1 method)

    Computing using the Full Jacobian

    This is definitely not recommended, but we are showing it for completeness.

    julia
    function hutchinson_trace_full_jacobian(model, x, ps, st, v)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    J = ForwardDiff.jacobian(smodel, x)
    +    return vec(v)' * J * vec(v)
    +end
    hutchinson_trace_full_jacobian (generic function with 1 method)

    Now let's compute the trace and compare the results:

    julia
    model = Chain(Dense(4 => 12,tanh), Dense(12 => 12,tanh), Dense(12 => 12,tanh),
    +    Dense(12 => 4))
    +ps, st = Lux.setup(StableRNG(0), model)
    +x = rand(StableRNG(0), Float32, 4, 12)
    +v = (rand(StableRNG(12), Float32, 4, 12) .> 0.5f0) * 2.0f0 .- 1.0f0  # rademacher sample
    julia
    tr_vjp = hutchinson_trace_vjp(model, x, ps, st, v)
    +tr_jvp = hutchinson_trace_jvp(model, x, ps, st, v)
    +tr_full_jacobian = hutchinson_trace_full_jacobian(model, x, ps, st, v)
    +println("Tr(J) using vjp: ", tr_vjp)
    +println("Tr(J) using jvp: ", tr_jvp)
    +println("Tr(J) using full jacobian: ", tr_full_jacobian)
    Tr(J) using vjp: 4.9127817
    +Tr(J) using jvp: 4.912782
    +Tr(J) using full jacobian: 4.912781

    Now that we have verified that the results are the same, let's try to differentiate the trace estimate. This often shows up as a regularization term in neural networks.

    julia
    _, ∂x_vjp, ∂ps_vjp, _, _ = Zygote.gradient(hutchinson_trace_vjp, model, x, ps, st, v)
    +_, ∂x_jvp, ∂ps_jvp, _, _ = Zygote.gradient(hutchinson_trace_jvp, model, x, ps, st, v)
    +_, ∂x_full_jacobian, ∂ps_full_jacobian, _, _ = Zygote.gradient(hutchinson_trace_full_jacobian,
    +    model, x, ps, st, v)

    For sanity check, let's verify that the gradients are the same:

    julia
    println("∞-norm(∂x using vjp): ", norm(∂x_vjp .- ∂x_jvp, Inf))
    +println("∞-norm(∂ps using vjp): ",
    +    norm(ComponentArray(∂ps_vjp) .- ComponentArray(∂ps_jvp), Inf))
    +println("∞-norm(∂x using full jacobian): ", norm(∂x_full_jacobian .- ∂x_vjp, Inf))
    +println("∞-norm(∂ps using full jacobian): ",
    +    norm(ComponentArray(∂ps_full_jacobian) .- ComponentArray(∂ps_vjp), Inf))
    ∞-norm(∂x using vjp): 0.0
    +∞-norm(∂ps using vjp): 0.0
    +∞-norm(∂x using full jacobian): 9.536743e-7
    +∞-norm(∂ps using full jacobian): 1.4305115e-6
    `,20))])}const _=e(h,[["render",v]]);export{j as __pageData,_ as default}; diff --git a/previews/PR1023/assets/manual_nn_inside_gpu_kernels.md.egqCePx_.js b/previews/PR1023/assets/manual_nn_inside_gpu_kernels.md.egqCePx_.js new file mode 100644 index 0000000000..2ae34d5b5f --- /dev/null +++ b/previews/PR1023/assets/manual_nn_inside_gpu_kernels.md.egqCePx_.js @@ -0,0 +1,103 @@ +import{_ as a,c as i,a2 as n,o as p}from"./chunks/framework.DFwXuivk.js";const E=JSON.parse('{"title":"Neural Networks Inside GPU Kernels","description":"","frontmatter":{},"headers":[],"relativePath":"manual/nn_inside_gpu_kernels.md","filePath":"manual/nn_inside_gpu_kernels.md","lastUpdated":null}'),l={name:"manual/nn_inside_gpu_kernels.md"};function e(t,s,h,k,r,d){return p(),i("div",null,s[0]||(s[0]=[n(`

    Neural Networks Inside GPU Kernels

    In this page, we will describe how to embed neural networks inside GPU kernels. We will use KernelAbstractions.jl to do this, making it compatible with multiple GPU backends.

    Experimental Feature

    This is a relatively new and experimental feature. Expect edge cases and open issues on GitHub if you find any.

    Inference Only

    Currently this works only for inference. We will eventually test automatic differentiation using Enzyme.jl

    Batching

    In most usecases, this form of batching via embedding the neural network inside a GPU kernel is not recommended and will lead to suboptimal performance. Instead, batch the input data and let Lux handle the batching internally.

    julia
    using Lux, LuxCUDA, Random
    +using KernelAbstractions, StaticArrays

    First thing to remember is that we can't use regular high-level operations inside the kernels, instead we will use Static Arrays. Leveraging Julia's multiple dispatch Lux will use specialized operations that are compatible with GPU kernels.

    julia
    @kernel function nn_eval_single_batch!(output, model, input, ps, st)
    +    i = @index(Global, Linear)
    +    y, st_ = Lux.apply(model, input[i], ps, st)
    +    output[i] = y
    +end
    nn_eval_single_batch! (generic function with 4 methods)

    We define and initialize the neural network as usual, but we need to additionally convert the Arrays into SArrays.

    julia
    nn = Chain(Dense(4, 4, relu), Dense(4, 4))
    +ps, st = Lux.setup(Xoshiro(123), nn)
    +
    +to_sarray(x) = SArray{Tuple{size(x)...}}(x)
    +ps_static = Lux.recursive_map(to_sarray, ps)
    +st_static = Lux.recursive_map(to_sarray, st)
    (layer_1 = NamedTuple(), layer_2 = NamedTuple())

    First we will run it on CPU.

    Warning

    Currently due to a minor bug, we cannot call the Lux models with vector input. As a workaround we make them into Matrix with batch size 1.

    julia
    input = [@SArray(rand(Float64, 4, 1)) for i in 1:1024]
    +output = [@SArray(zeros(Float64, 4, 1)) for i in 1:1024] # Allocate the output
    1024-element Vector{StaticArraysCore.SMatrix{4, 1, Float64, 4}}:
    + [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.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; 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.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; 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.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; 0.0;;]

    Now run the model using KernelAbstractions.jl

    julia
    backend = KernelAbstractions.get_backend(output)
    +cpu_kernel! = nn_eval_single_batch!(backend)
    +cpu_kernel!(output, nn, input, ps_static, st_static; ndrange=length(output))
    +KernelAbstractions.synchronize(backend)
    +output
    1024-element Vector{StaticArraysCore.SMatrix{4, 1, Float64, 4}}:
    + [2.0564903986057956; 1.1188200246206075; -1.2227837233928576; -0.8173783982243132;;]
    + [1.9721554734769875; 1.3940224213371761; -1.297959481822617; -0.7195462169922175;;]
    + [2.5680085614623662; 1.713567516238075; -1.7165512278088038; -1.009963844931984;;]
    + [1.800792614736468; 0.36222499022985155; -1.1204217935313214; -1.1836515766351254;;]
    + [1.486550215883336; 0.32839986131789933; -0.9019142280758281; -0.9452923791531558;;]
    + [2.716134755899883; 1.1617228180412864; -1.902982902377702; -1.5865265807660498;;]
    + [1.0228109822209213; 0.2525357728685884; -0.4376572711003852; -0.4500963619011972;;]
    + [2.2771862617010155; 0.5381101016248151; -1.4730743722547668; -1.488028235902512;;]
    + [3.2791573282471997; 1.3436353225087703; -2.4619778701480337; -2.1239749674027375;;]
    + [1.2290224145974982; 0.4158693023143286; -0.6370531107315014; -0.5779067839062536;;]
    +
    + [1.8674763752817416; 1.6423511984038721; -1.1477053709248992; -0.3834447782571344;;]
    + [2.091359335844565; 1.0621559246995447; -1.4763277207638008; -1.142470881033475;;]
    + [2.712979078066394; 0.42005835019799886; -1.717863343114228; -1.8601870861800127;;]
    + [0.7701346738750905; 0.2869913410456831; -0.1586047939092094; -0.10140238162746013;;]
    + [1.611584190904272; 1.2797048270773437; -0.923950547913545; -0.3558193508137715;;]
    + [2.0884834705765853; 0.862480861009647; -1.3942307655311696; -1.179584495291061;;]
    + [2.390200114697191; 0.5267549745189349; -1.657670184695808; -1.7089496198123055;;]
    + [2.1846486482317626; -0.031414255389526885; -1.3279041356366077; -1.6909446526419574;;]
    + [1.3650193059617517; 0.5210742834996898; -0.7689272356710357; -0.6642563709240284;;]

    Now we will run the same model on GPU.

    julia
    gdev = gpu_device()
    +
    +input_gpu = input |> gdev
    +output_gpu = [@SArray(zeros(Float64, 4, 1)) for i in 1:1024] |> gdev
    1024-element CuArray{StaticArraysCore.SMatrix{4, 1, Float64, 4}, 1, CUDA.DeviceMemory}:
    + [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.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; 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.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; 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.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; 0.0;;]
    julia
    backend = KernelAbstractions.get_backend(output_gpu)
    +gpu_kernel! = nn_eval_single_batch!(backend)
    +gpu_kernel!(output_gpu, nn, input_gpu, ps_static, st_static; ndrange=length(output_gpu))
    +KernelAbstractions.synchronize(backend)
    +output_gpu
    1024-element CuArray{StaticArraysCore.SMatrix{4, 1, Float64, 4}, 1, CUDA.DeviceMemory}:
    + [2.0564903986057956; 1.1188200246206075; -1.2227837233928576; -0.8173783982243132;;]
    + [1.9721554734769875; 1.3940224213371761; -1.297959481822617; -0.7195462169922173;;]
    + [2.5680085614623662; 1.713567516238075; -1.7165512278088038; -1.009963844931984;;]
    + [1.800792614736468; 0.36222499022985155; -1.1204217935313214; -1.1836515766351254;;]
    + [1.486550215883336; 0.32839986131789933; -0.9019142280758281; -0.9452923791531558;;]
    + [2.716134755899883; 1.1617228180412864; -1.902982902377702; -1.5865265807660498;;]
    + [1.0228109822209213; 0.2525357728685884; -0.4376572711003852; -0.4500963619011972;;]
    + [2.2771862617010155; 0.5381101016248151; -1.4730743722547668; -1.488028235902512;;]
    + [3.2791573282471997; 1.3436353225087703; -2.4619778701480337; -2.1239749674027375;;]
    + [1.2290224145974982; 0.4158693023143286; -0.6370531107315014; -0.5779067839062536;;]
    +
    + [1.8674763752817414; 1.6423511984038721; -1.147705370924899; -0.3834447782571341;;]
    + [2.0913593358445652; 1.062155924699545; -1.4763277207638013; -1.142470881033475;;]
    + [2.712979078066394; 0.420058350197999; -1.717863343114228; -1.8601870861800127;;]
    + [0.7701346738750905; 0.2869913410456831; -0.1586047939092094; -0.10140238162746013;;]
    + [1.611584190904272; 1.2797048270773437; -0.923950547913545; -0.3558193508137715;;]
    + [2.0884834705765853; 0.862480861009647; -1.3942307655311696; -1.179584495291061;;]
    + [2.390200114697191; 0.5267549745189349; -1.657670184695808; -1.7089496198123055;;]
    + [2.1846486482317626; -0.031414255389526885; -1.3279041356366077; -1.6909446526419574;;]
    + [1.3650193059617517; 0.5210742834996898; -0.7689272356710357; -0.6642563709240284;;]
    `,24)]))}const g=a(l,[["render",e]]);export{E as __pageData,g as default}; diff --git a/previews/PR1023/assets/manual_nn_inside_gpu_kernels.md.egqCePx_.lean.js b/previews/PR1023/assets/manual_nn_inside_gpu_kernels.md.egqCePx_.lean.js new file mode 100644 index 0000000000..2ae34d5b5f --- /dev/null +++ b/previews/PR1023/assets/manual_nn_inside_gpu_kernels.md.egqCePx_.lean.js @@ -0,0 +1,103 @@ +import{_ as a,c as i,a2 as n,o as p}from"./chunks/framework.DFwXuivk.js";const E=JSON.parse('{"title":"Neural Networks Inside GPU Kernels","description":"","frontmatter":{},"headers":[],"relativePath":"manual/nn_inside_gpu_kernels.md","filePath":"manual/nn_inside_gpu_kernels.md","lastUpdated":null}'),l={name:"manual/nn_inside_gpu_kernels.md"};function e(t,s,h,k,r,d){return p(),i("div",null,s[0]||(s[0]=[n(`

    Neural Networks Inside GPU Kernels

    In this page, we will describe how to embed neural networks inside GPU kernels. We will use KernelAbstractions.jl to do this, making it compatible with multiple GPU backends.

    Experimental Feature

    This is a relatively new and experimental feature. Expect edge cases and open issues on GitHub if you find any.

    Inference Only

    Currently this works only for inference. We will eventually test automatic differentiation using Enzyme.jl

    Batching

    In most usecases, this form of batching via embedding the neural network inside a GPU kernel is not recommended and will lead to suboptimal performance. Instead, batch the input data and let Lux handle the batching internally.

    julia
    using Lux, LuxCUDA, Random
    +using KernelAbstractions, StaticArrays

    First thing to remember is that we can't use regular high-level operations inside the kernels, instead we will use Static Arrays. Leveraging Julia's multiple dispatch Lux will use specialized operations that are compatible with GPU kernels.

    julia
    @kernel function nn_eval_single_batch!(output, model, input, ps, st)
    +    i = @index(Global, Linear)
    +    y, st_ = Lux.apply(model, input[i], ps, st)
    +    output[i] = y
    +end
    nn_eval_single_batch! (generic function with 4 methods)

    We define and initialize the neural network as usual, but we need to additionally convert the Arrays into SArrays.

    julia
    nn = Chain(Dense(4, 4, relu), Dense(4, 4))
    +ps, st = Lux.setup(Xoshiro(123), nn)
    +
    +to_sarray(x) = SArray{Tuple{size(x)...}}(x)
    +ps_static = Lux.recursive_map(to_sarray, ps)
    +st_static = Lux.recursive_map(to_sarray, st)
    (layer_1 = NamedTuple(), layer_2 = NamedTuple())

    First we will run it on CPU.

    Warning

    Currently due to a minor bug, we cannot call the Lux models with vector input. As a workaround we make them into Matrix with batch size 1.

    julia
    input = [@SArray(rand(Float64, 4, 1)) for i in 1:1024]
    +output = [@SArray(zeros(Float64, 4, 1)) for i in 1:1024] # Allocate the output
    1024-element Vector{StaticArraysCore.SMatrix{4, 1, Float64, 4}}:
    + [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.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; 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.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; 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.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; 0.0;;]

    Now run the model using KernelAbstractions.jl

    julia
    backend = KernelAbstractions.get_backend(output)
    +cpu_kernel! = nn_eval_single_batch!(backend)
    +cpu_kernel!(output, nn, input, ps_static, st_static; ndrange=length(output))
    +KernelAbstractions.synchronize(backend)
    +output
    1024-element Vector{StaticArraysCore.SMatrix{4, 1, Float64, 4}}:
    + [2.0564903986057956; 1.1188200246206075; -1.2227837233928576; -0.8173783982243132;;]
    + [1.9721554734769875; 1.3940224213371761; -1.297959481822617; -0.7195462169922175;;]
    + [2.5680085614623662; 1.713567516238075; -1.7165512278088038; -1.009963844931984;;]
    + [1.800792614736468; 0.36222499022985155; -1.1204217935313214; -1.1836515766351254;;]
    + [1.486550215883336; 0.32839986131789933; -0.9019142280758281; -0.9452923791531558;;]
    + [2.716134755899883; 1.1617228180412864; -1.902982902377702; -1.5865265807660498;;]
    + [1.0228109822209213; 0.2525357728685884; -0.4376572711003852; -0.4500963619011972;;]
    + [2.2771862617010155; 0.5381101016248151; -1.4730743722547668; -1.488028235902512;;]
    + [3.2791573282471997; 1.3436353225087703; -2.4619778701480337; -2.1239749674027375;;]
    + [1.2290224145974982; 0.4158693023143286; -0.6370531107315014; -0.5779067839062536;;]
    +
    + [1.8674763752817416; 1.6423511984038721; -1.1477053709248992; -0.3834447782571344;;]
    + [2.091359335844565; 1.0621559246995447; -1.4763277207638008; -1.142470881033475;;]
    + [2.712979078066394; 0.42005835019799886; -1.717863343114228; -1.8601870861800127;;]
    + [0.7701346738750905; 0.2869913410456831; -0.1586047939092094; -0.10140238162746013;;]
    + [1.611584190904272; 1.2797048270773437; -0.923950547913545; -0.3558193508137715;;]
    + [2.0884834705765853; 0.862480861009647; -1.3942307655311696; -1.179584495291061;;]
    + [2.390200114697191; 0.5267549745189349; -1.657670184695808; -1.7089496198123055;;]
    + [2.1846486482317626; -0.031414255389526885; -1.3279041356366077; -1.6909446526419574;;]
    + [1.3650193059617517; 0.5210742834996898; -0.7689272356710357; -0.6642563709240284;;]

    Now we will run the same model on GPU.

    julia
    gdev = gpu_device()
    +
    +input_gpu = input |> gdev
    +output_gpu = [@SArray(zeros(Float64, 4, 1)) for i in 1:1024] |> gdev
    1024-element CuArray{StaticArraysCore.SMatrix{4, 1, Float64, 4}, 1, CUDA.DeviceMemory}:
    + [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.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; 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.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; 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.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; 0.0;;]
    julia
    backend = KernelAbstractions.get_backend(output_gpu)
    +gpu_kernel! = nn_eval_single_batch!(backend)
    +gpu_kernel!(output_gpu, nn, input_gpu, ps_static, st_static; ndrange=length(output_gpu))
    +KernelAbstractions.synchronize(backend)
    +output_gpu
    1024-element CuArray{StaticArraysCore.SMatrix{4, 1, Float64, 4}, 1, CUDA.DeviceMemory}:
    + [2.0564903986057956; 1.1188200246206075; -1.2227837233928576; -0.8173783982243132;;]
    + [1.9721554734769875; 1.3940224213371761; -1.297959481822617; -0.7195462169922173;;]
    + [2.5680085614623662; 1.713567516238075; -1.7165512278088038; -1.009963844931984;;]
    + [1.800792614736468; 0.36222499022985155; -1.1204217935313214; -1.1836515766351254;;]
    + [1.486550215883336; 0.32839986131789933; -0.9019142280758281; -0.9452923791531558;;]
    + [2.716134755899883; 1.1617228180412864; -1.902982902377702; -1.5865265807660498;;]
    + [1.0228109822209213; 0.2525357728685884; -0.4376572711003852; -0.4500963619011972;;]
    + [2.2771862617010155; 0.5381101016248151; -1.4730743722547668; -1.488028235902512;;]
    + [3.2791573282471997; 1.3436353225087703; -2.4619778701480337; -2.1239749674027375;;]
    + [1.2290224145974982; 0.4158693023143286; -0.6370531107315014; -0.5779067839062536;;]
    +
    + [1.8674763752817414; 1.6423511984038721; -1.147705370924899; -0.3834447782571341;;]
    + [2.0913593358445652; 1.062155924699545; -1.4763277207638013; -1.142470881033475;;]
    + [2.712979078066394; 0.420058350197999; -1.717863343114228; -1.8601870861800127;;]
    + [0.7701346738750905; 0.2869913410456831; -0.1586047939092094; -0.10140238162746013;;]
    + [1.611584190904272; 1.2797048270773437; -0.923950547913545; -0.3558193508137715;;]
    + [2.0884834705765853; 0.862480861009647; -1.3942307655311696; -1.179584495291061;;]
    + [2.390200114697191; 0.5267549745189349; -1.657670184695808; -1.7089496198123055;;]
    + [2.1846486482317626; -0.031414255389526885; -1.3279041356366077; -1.6909446526419574;;]
    + [1.3650193059617517; 0.5210742834996898; -0.7689272356710357; -0.6642563709240284;;]
    `,24)]))}const g=a(l,[["render",e]]);export{E as __pageData,g as default}; diff --git a/previews/PR1023/assets/manual_performance_pitfalls.md.s_yX8yPE.js b/previews/PR1023/assets/manual_performance_pitfalls.md.s_yX8yPE.js new file mode 100644 index 0000000000..6e3474163b --- /dev/null +++ b/previews/PR1023/assets/manual_performance_pitfalls.md.s_yX8yPE.js @@ -0,0 +1,28 @@ +import{_ as s,c as a,a2 as e,o as t}from"./chunks/framework.DFwXuivk.js";const c=JSON.parse('{"title":"Performance Pitfalls & How to Catch Them","description":"","frontmatter":{},"headers":[],"relativePath":"manual/performance_pitfalls.md","filePath":"manual/performance_pitfalls.md","lastUpdated":null}'),n={name:"manual/performance_pitfalls.md"};function l(p,i,h,r,o,d){return t(),a("div",null,i[0]||(i[0]=[e(`

    Performance Pitfalls & How to Catch Them

    Go through the following documentations for general performance tips:

    1. Official Julia Performance Tips.

    2. Recommendations for selecting AD packages.

    Spurious Type-Promotion

    Lux by-default uses Julia semantics for type-promotions, while this means that we do the "correct" numerical thing, this can often come as a surprise to users coming from a more deep learning background. For example, consider the following code:

    julia
    using Lux, Random
    +
    +rng = Xoshiro(0)
    +
    +model = Dense(2 => 2, gelu)
    +ps, st = Lux.setup(rng, model)
    +Lux.recursive_eltype((ps, st))
    Float32

    As we can see that ps and st are structures with the highest precision being Float32. Now let's run the model using some random data:

    julia
    x = rand(rng, 2, 4)
    +
    +eltype(first(model(x, ps, st)))
    Float64

    Oops our output became Float64. This will be bad on CPUs but an absolute performance disaster on GPUs. The reason this happened is that our input x was Float64. Instead, we should have used Float32 input:

    julia
    x = rand(rng, Float32, 2, 4)
    +
    +eltype(first(model(x, ps, st)))
    Float32

    This was easy to fix for a small model. But certain layers might incorrectly promote objects to a higher precision. This will cause a regression in performance. There are 2 recommendations to fix this or track them down:

    1. Use Lux.Experimental.@debug_mode to see which layer is causing the type-promotion.

    2. Alternatively to control the global behavior of eltypes in Lux and allow it to auto-correct the precision use match_eltype and the eltype_mismatch_handling preference.

    Scalar Indexing on GPU Arrays

    When running code on GPUs, it is recommended to disallow scalar indexing. Note that this is disabled by default except in REPL. You can disable it even in REPL mode using:

    julia
    using GPUArraysCore
    +GPUArraysCore.allowscalar(false)

    Type Instabilities

    Lux.jl is integrated with DispatchDoctor.jl to catch type instabilities. You can easily enable it by setting the instability_check preference. This will help you catch type instabilities in your code. For more information on how to set preferences, check out Lux.set_dispatch_doctor_preferences!.

    Faster Primitives

    Prefer to use deep learning primitives and their fused variants from LuxLib.jl instead of NNlib.jl. Some of the alternatives are:

    1. Replace NNlib.batched_mul with LuxLib.batched_matmul.

    2. Replace NNlib.conv with bias and activation with LuxLib.fused_conv_bias_activation.

    3. Replace σ.(w * x .+ b) with LuxLib.fused_dense_bias_activation.

    4. Replace uses of σ.(x) with LuxLib.fast_activation or LuxLib.fast_activation!! (the latter one is often faster).

    5. Replace uses of σ.(x .+ b) with LuxLib.bias_activation or LuxLib.bias_activation!! (the latter one is often faster).

    Optional Dependencies for Performance

    For faster performance on CPUs load the following packages:

    1. LoopVectorization.jl

    2. Octavian.jl

    If these are available, we automatically use optimized versions of the layers. Though there are cases where this might be an issue (see #980 and disabling loop vectorization).

    Data Loading and Device Transfer

    A common pattern for loading data and transferring data to GPUs looks like this:

    julia
    dataloader = DataLoader(dataset; parallel=true, batchsize=12)  # from MLUtils.jl
    +gdev = gpu_device()
    +
    +for (X, y) in dataloader
    +    X = X |> gdev
    +    y = y |> gdev
    +    # ...
    +    # do some computation
    +    # ...
    +end

    This is typically fast enough, but the data transfer to the device is happening in main process, not exploiting the parallelism in the dataloader. Instead, we can do this:

    julia
    dataloader = DataLoader(dataset; parallel=true, batchsize=12)  # from MLUtils.jl
    +gdev = gpu_device()
    +
    +for (X, y) in gdev(dataloader)
    +    # ...
    +    # do some computation
    +    # ...
    +end

    Here, X and y are on the gpu device gdev and the data transfer happens in the worker processes. Additionally, it behaves similar to CuIterator from CUDA.jl and eagerly frees the data after every iteration (this is device agnostic and works on all supported GPU backends).

    `,33)]))}const g=s(n,[["render",l]]);export{c as __pageData,g as default}; diff --git a/previews/PR1023/assets/manual_performance_pitfalls.md.s_yX8yPE.lean.js b/previews/PR1023/assets/manual_performance_pitfalls.md.s_yX8yPE.lean.js new file mode 100644 index 0000000000..6e3474163b --- /dev/null +++ b/previews/PR1023/assets/manual_performance_pitfalls.md.s_yX8yPE.lean.js @@ -0,0 +1,28 @@ +import{_ as s,c as a,a2 as e,o as t}from"./chunks/framework.DFwXuivk.js";const c=JSON.parse('{"title":"Performance Pitfalls & How to Catch Them","description":"","frontmatter":{},"headers":[],"relativePath":"manual/performance_pitfalls.md","filePath":"manual/performance_pitfalls.md","lastUpdated":null}'),n={name:"manual/performance_pitfalls.md"};function l(p,i,h,r,o,d){return t(),a("div",null,i[0]||(i[0]=[e(`

    Performance Pitfalls & How to Catch Them

    Go through the following documentations for general performance tips:

    1. Official Julia Performance Tips.

    2. Recommendations for selecting AD packages.

    Spurious Type-Promotion

    Lux by-default uses Julia semantics for type-promotions, while this means that we do the "correct" numerical thing, this can often come as a surprise to users coming from a more deep learning background. For example, consider the following code:

    julia
    using Lux, Random
    +
    +rng = Xoshiro(0)
    +
    +model = Dense(2 => 2, gelu)
    +ps, st = Lux.setup(rng, model)
    +Lux.recursive_eltype((ps, st))
    Float32

    As we can see that ps and st are structures with the highest precision being Float32. Now let's run the model using some random data:

    julia
    x = rand(rng, 2, 4)
    +
    +eltype(first(model(x, ps, st)))
    Float64

    Oops our output became Float64. This will be bad on CPUs but an absolute performance disaster on GPUs. The reason this happened is that our input x was Float64. Instead, we should have used Float32 input:

    julia
    x = rand(rng, Float32, 2, 4)
    +
    +eltype(first(model(x, ps, st)))
    Float32

    This was easy to fix for a small model. But certain layers might incorrectly promote objects to a higher precision. This will cause a regression in performance. There are 2 recommendations to fix this or track them down:

    1. Use Lux.Experimental.@debug_mode to see which layer is causing the type-promotion.

    2. Alternatively to control the global behavior of eltypes in Lux and allow it to auto-correct the precision use match_eltype and the eltype_mismatch_handling preference.

    Scalar Indexing on GPU Arrays

    When running code on GPUs, it is recommended to disallow scalar indexing. Note that this is disabled by default except in REPL. You can disable it even in REPL mode using:

    julia
    using GPUArraysCore
    +GPUArraysCore.allowscalar(false)

    Type Instabilities

    Lux.jl is integrated with DispatchDoctor.jl to catch type instabilities. You can easily enable it by setting the instability_check preference. This will help you catch type instabilities in your code. For more information on how to set preferences, check out Lux.set_dispatch_doctor_preferences!.

    Faster Primitives

    Prefer to use deep learning primitives and their fused variants from LuxLib.jl instead of NNlib.jl. Some of the alternatives are:

    1. Replace NNlib.batched_mul with LuxLib.batched_matmul.

    2. Replace NNlib.conv with bias and activation with LuxLib.fused_conv_bias_activation.

    3. Replace σ.(w * x .+ b) with LuxLib.fused_dense_bias_activation.

    4. Replace uses of σ.(x) with LuxLib.fast_activation or LuxLib.fast_activation!! (the latter one is often faster).

    5. Replace uses of σ.(x .+ b) with LuxLib.bias_activation or LuxLib.bias_activation!! (the latter one is often faster).

    Optional Dependencies for Performance

    For faster performance on CPUs load the following packages:

    1. LoopVectorization.jl

    2. Octavian.jl

    If these are available, we automatically use optimized versions of the layers. Though there are cases where this might be an issue (see #980 and disabling loop vectorization).

    Data Loading and Device Transfer

    A common pattern for loading data and transferring data to GPUs looks like this:

    julia
    dataloader = DataLoader(dataset; parallel=true, batchsize=12)  # from MLUtils.jl
    +gdev = gpu_device()
    +
    +for (X, y) in dataloader
    +    X = X |> gdev
    +    y = y |> gdev
    +    # ...
    +    # do some computation
    +    # ...
    +end

    This is typically fast enough, but the data transfer to the device is happening in main process, not exploiting the parallelism in the dataloader. Instead, we can do this:

    julia
    dataloader = DataLoader(dataset; parallel=true, batchsize=12)  # from MLUtils.jl
    +gdev = gpu_device()
    +
    +for (X, y) in gdev(dataloader)
    +    # ...
    +    # do some computation
    +    # ...
    +end

    Here, X and y are on the gpu device gdev and the data transfer happens in the worker processes. Additionally, it behaves similar to CuIterator from CUDA.jl and eagerly frees the data after every iteration (this is device agnostic and works on all supported GPU backends).

    `,33)]))}const g=s(n,[["render",l]]);export{c as __pageData,g as default}; diff --git a/previews/PR1023/assets/manual_preferences.md.CiGO9gyg.js b/previews/PR1023/assets/manual_preferences.md.CiGO9gyg.js new file mode 100644 index 0000000000..dff7287856 --- /dev/null +++ b/previews/PR1023/assets/manual_preferences.md.CiGO9gyg.js @@ -0,0 +1,3 @@ +import{_ as a,c as i,a2 as t,o as s}from"./chunks/framework.DFwXuivk.js";const u=JSON.parse('{"title":"Preferences for Lux.jl","description":"","frontmatter":{},"headers":[],"relativePath":"manual/preferences.md","filePath":"manual/preferences.md","lastUpdated":null}'),o={name:"manual/preferences.md"};function n(r,e,l,c,p,d){return s(),i("div",null,e[0]||(e[0]=[t(`

    Preferences for Lux.jl

    How to set Preferences

    PreferenceTools.jl provides an interactive way to set preferences. First run the following command:

    julia
    using PreferenceTools

    Then in the pkg mode (press ] in the REPL), run the following command:

    julia
    pkg> preference add Lux <preference-name>=<value>
    +pkg> preference add LuxLib <preference-name>=<value>
    +pkg> preference add LuxCore <preference-name>=<value>

    Lux.jl relies on several preferences to make decision on how to run your code. Here is an exhaustive list of preferences that Lux.jl uses.

    Nested Automatic Differentiation

    1. automatic_nested_ad_switching - Set this to false to disable automatic switching of backends for nested automatic differentiation. See the manual section on nested automatic differentiation for more details.

    GPU-Aware MPI Support

    If you are using a custom MPI build that supports CUDA or ROCM, you can use the following preferences with Preferences.jl:

    1. cuda_aware_mpi - Set this to true if your MPI build is CUDA aware.

    2. rocm_aware_mpi - Set this to true if your MPI build is ROCM aware.

    By default, both of these preferences are set to false.

    GPU Backend Selection

    1. gpu_backend - Set this to bypass the automatic backend selection and use a specific gpu backend. Valid options are "cuda", "rocm", "metal", and "oneapi". This preference needs to be set for MLDataDevices package. It is recommended to use MLDataDevices.gpu_backend! to set this preference.

    Automatic Eltype Conversion

    1. eltype_mismatch_handling - Preference controlling what happens when layers get different eltypes as input. See the documentation on match_eltype for more details.

    Dispatch Doctor

    1. instability_check - Preference controlling the dispatch doctor. See the documentation on Lux.set_dispatch_doctor_preferences! for more details. The preferences need to be set for LuxCore and LuxLib packages. Both of them default to disable.
    • Setting the LuxCore preference sets the check at the level of LuxCore.apply. This essentially activates the dispatch doctor for all Lux layers.

    • Setting the LuxLib preference sets the check at the level of functional layer of Lux, for example, fused_dense_bias_activation. These functions are supposed to be type stable for common input types and can be used to guarantee type stability.

    Disabling Loop Vectorization / Octavian

    LoopVectorization.jl and Octavian.jl are optional dependencies that are used to accelerate certain CPU operations. However, these packages are tightly coupled with julia and might not work with all julia versions and systems. If these packages are loaded in any form LuxLib will use the optimized versions of the functions. But it might be desirable to disable these packages and use the default implementations instead. This can be done by setting the disable_loop_vectorization preference to true for LuxLib.

    `,18)]))}const k=a(o,[["render",n]]);export{u as __pageData,k as default}; diff --git a/previews/PR1023/assets/manual_preferences.md.CiGO9gyg.lean.js b/previews/PR1023/assets/manual_preferences.md.CiGO9gyg.lean.js new file mode 100644 index 0000000000..dff7287856 --- /dev/null +++ b/previews/PR1023/assets/manual_preferences.md.CiGO9gyg.lean.js @@ -0,0 +1,3 @@ +import{_ as a,c as i,a2 as t,o as s}from"./chunks/framework.DFwXuivk.js";const u=JSON.parse('{"title":"Preferences for Lux.jl","description":"","frontmatter":{},"headers":[],"relativePath":"manual/preferences.md","filePath":"manual/preferences.md","lastUpdated":null}'),o={name:"manual/preferences.md"};function n(r,e,l,c,p,d){return s(),i("div",null,e[0]||(e[0]=[t(`

    Preferences for Lux.jl

    How to set Preferences

    PreferenceTools.jl provides an interactive way to set preferences. First run the following command:

    julia
    using PreferenceTools

    Then in the pkg mode (press ] in the REPL), run the following command:

    julia
    pkg> preference add Lux <preference-name>=<value>
    +pkg> preference add LuxLib <preference-name>=<value>
    +pkg> preference add LuxCore <preference-name>=<value>

    Lux.jl relies on several preferences to make decision on how to run your code. Here is an exhaustive list of preferences that Lux.jl uses.

    Nested Automatic Differentiation

    1. automatic_nested_ad_switching - Set this to false to disable automatic switching of backends for nested automatic differentiation. See the manual section on nested automatic differentiation for more details.

    GPU-Aware MPI Support

    If you are using a custom MPI build that supports CUDA or ROCM, you can use the following preferences with Preferences.jl:

    1. cuda_aware_mpi - Set this to true if your MPI build is CUDA aware.

    2. rocm_aware_mpi - Set this to true if your MPI build is ROCM aware.

    By default, both of these preferences are set to false.

    GPU Backend Selection

    1. gpu_backend - Set this to bypass the automatic backend selection and use a specific gpu backend. Valid options are "cuda", "rocm", "metal", and "oneapi". This preference needs to be set for MLDataDevices package. It is recommended to use MLDataDevices.gpu_backend! to set this preference.

    Automatic Eltype Conversion

    1. eltype_mismatch_handling - Preference controlling what happens when layers get different eltypes as input. See the documentation on match_eltype for more details.

    Dispatch Doctor

    1. instability_check - Preference controlling the dispatch doctor. See the documentation on Lux.set_dispatch_doctor_preferences! for more details. The preferences need to be set for LuxCore and LuxLib packages. Both of them default to disable.
    • Setting the LuxCore preference sets the check at the level of LuxCore.apply. This essentially activates the dispatch doctor for all Lux layers.

    • Setting the LuxLib preference sets the check at the level of functional layer of Lux, for example, fused_dense_bias_activation. These functions are supposed to be type stable for common input types and can be used to guarantee type stability.

    Disabling Loop Vectorization / Octavian

    LoopVectorization.jl and Octavian.jl are optional dependencies that are used to accelerate certain CPU operations. However, these packages are tightly coupled with julia and might not work with all julia versions and systems. If these packages are loaded in any form LuxLib will use the optimized versions of the functions. But it might be desirable to disable these packages and use the default implementations instead. This can be done by setting the disable_loop_vectorization preference to true for LuxLib.

    `,18)]))}const k=a(o,[["render",n]]);export{u as __pageData,k as default}; diff --git a/previews/PR1023/assets/manual_weight_initializers.md.kYS4Pm9l.js b/previews/PR1023/assets/manual_weight_initializers.md.kYS4Pm9l.js new file mode 100644 index 0000000000..70d75a4c03 --- /dev/null +++ b/previews/PR1023/assets/manual_weight_initializers.md.kYS4Pm9l.js @@ -0,0 +1,30 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const c=JSON.parse('{"title":"Initializing Weights","description":"","frontmatter":{},"headers":[],"relativePath":"manual/weight_initializers.md","filePath":"manual/weight_initializers.md","lastUpdated":null}'),e={name:"manual/weight_initializers.md"};function l(p,s,h,k,d,g){return t(),a("div",null,s[0]||(s[0]=[n(`

    Initializing Weights

    WeightInitializers.jl provides common weight initialization schemes for deep learning models.

    julia
    using WeightInitializers, Random
    +
    +# Fixing rng
    +rng = Random.MersenneTwister(42)
    Random.MersenneTwister(42)
    julia
    # Explicit rng call
    +weights = kaiming_normal(rng, 2, 5)
    2×5 Matrix{Float32}:
    + -0.351662   0.0171745   1.12442   -0.296372   -1.67094
    + -0.281053  -0.18941    -0.724099   0.0987538   0.634549
    julia
    # Default rng call
    +weights = kaiming_normal(2, 5)
    2×5 Matrix{Float32}:
    + -0.227513  -0.265372   0.265788  1.29955  -0.192836
    +  0.687611   0.454679  -0.433656  0.20548   0.292002
    julia
    # Passing kwargs (if needed) with explicit rng call
    +weights_cl = kaiming_normal(rng; gain=1.0)
    +weights = weights_cl(2, 5)
    2×5 Matrix{Float32}:
    + 0.484056   0.231723   0.164379   0.306147   0.18365
    + 0.0836414  0.666965  -0.396323  -0.711329  -0.382971
    julia
    # Passing kwargs (if needed) with default rng call
    +weights_cl = kaiming_normal(; gain=1.0)
    +weights = weights_cl(2, 5)
    2×5 Matrix{Float32}:
    + -0.160876  -0.187646   0.18794   0.918918  -0.136356
    +  0.486214   0.321506  -0.306641  0.145296   0.206476

    To generate weights directly on GPU, pass in a CUDA.RNG. For a complete list of supported RNG types, see Supported RNG Types.

    julia
    using LuxCUDA
    +
    +weights = kaiming_normal(CUDA.default_rng(), 2, 5)
    2×5 CuArray{Float32, 2, CUDA.DeviceMemory}:
    + -0.0722369  -0.00913097  -0.200837  -0.200958  -0.39841
    +  0.131664   -0.634591     0.577344  -0.738118   0.502413

    You can also generate Complex Numbers:

    julia
    weights = kaiming_normal(CUDA.default_rng(), ComplexF32, 2, 5)
    2×5 CuArray{ComplexF32, 2, CUDA.DeviceMemory}:
    +   1.38353+0.0474757im   0.303938-0.0469896im  …   -1.46088-0.283445im
    + 0.0479814-0.435768im   -0.427741-0.0129954im     -0.910244+0.175707im

    Quick examples

    The package is meant to be working with deep learning libraries such as (F)Lux. All the methods take as input the chosen rng type and the dimension for the array.

    julia
    weights = init(rng, dims...)

    The rng is optional, if not specified a default one will be used.

    julia
    weights = init(dims...)

    If there is the need to use keyword arguments the methods can be called with just the rng (optionally) and the keywords to get in return a function behaving like the two examples above.

    julia
    weights_init = init(rng; kwargs...)
    +weights = weights_init(rng, dims...)
    +
    +# Or
    +
    +weights_init = init(; kwargs...)
    +weights = weights_init(dims...)
    `,25)]))}const o=i(e,[["render",l]]);export{c as __pageData,o as default}; diff --git a/previews/PR1023/assets/manual_weight_initializers.md.kYS4Pm9l.lean.js b/previews/PR1023/assets/manual_weight_initializers.md.kYS4Pm9l.lean.js new file mode 100644 index 0000000000..70d75a4c03 --- /dev/null +++ b/previews/PR1023/assets/manual_weight_initializers.md.kYS4Pm9l.lean.js @@ -0,0 +1,30 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const c=JSON.parse('{"title":"Initializing Weights","description":"","frontmatter":{},"headers":[],"relativePath":"manual/weight_initializers.md","filePath":"manual/weight_initializers.md","lastUpdated":null}'),e={name:"manual/weight_initializers.md"};function l(p,s,h,k,d,g){return t(),a("div",null,s[0]||(s[0]=[n(`

    Initializing Weights

    WeightInitializers.jl provides common weight initialization schemes for deep learning models.

    julia
    using WeightInitializers, Random
    +
    +# Fixing rng
    +rng = Random.MersenneTwister(42)
    Random.MersenneTwister(42)
    julia
    # Explicit rng call
    +weights = kaiming_normal(rng, 2, 5)
    2×5 Matrix{Float32}:
    + -0.351662   0.0171745   1.12442   -0.296372   -1.67094
    + -0.281053  -0.18941    -0.724099   0.0987538   0.634549
    julia
    # Default rng call
    +weights = kaiming_normal(2, 5)
    2×5 Matrix{Float32}:
    + -0.227513  -0.265372   0.265788  1.29955  -0.192836
    +  0.687611   0.454679  -0.433656  0.20548   0.292002
    julia
    # Passing kwargs (if needed) with explicit rng call
    +weights_cl = kaiming_normal(rng; gain=1.0)
    +weights = weights_cl(2, 5)
    2×5 Matrix{Float32}:
    + 0.484056   0.231723   0.164379   0.306147   0.18365
    + 0.0836414  0.666965  -0.396323  -0.711329  -0.382971
    julia
    # Passing kwargs (if needed) with default rng call
    +weights_cl = kaiming_normal(; gain=1.0)
    +weights = weights_cl(2, 5)
    2×5 Matrix{Float32}:
    + -0.160876  -0.187646   0.18794   0.918918  -0.136356
    +  0.486214   0.321506  -0.306641  0.145296   0.206476

    To generate weights directly on GPU, pass in a CUDA.RNG. For a complete list of supported RNG types, see Supported RNG Types.

    julia
    using LuxCUDA
    +
    +weights = kaiming_normal(CUDA.default_rng(), 2, 5)
    2×5 CuArray{Float32, 2, CUDA.DeviceMemory}:
    + -0.0722369  -0.00913097  -0.200837  -0.200958  -0.39841
    +  0.131664   -0.634591     0.577344  -0.738118   0.502413

    You can also generate Complex Numbers:

    julia
    weights = kaiming_normal(CUDA.default_rng(), ComplexF32, 2, 5)
    2×5 CuArray{ComplexF32, 2, CUDA.DeviceMemory}:
    +   1.38353+0.0474757im   0.303938-0.0469896im  …   -1.46088-0.283445im
    + 0.0479814-0.435768im   -0.427741-0.0129954im     -0.910244+0.175707im

    Quick examples

    The package is meant to be working with deep learning libraries such as (F)Lux. All the methods take as input the chosen rng type and the dimension for the array.

    julia
    weights = init(rng, dims...)

    The rng is optional, if not specified a default one will be used.

    julia
    weights = init(dims...)

    If there is the need to use keyword arguments the methods can be called with just the rng (optionally) and the keywords to get in return a function behaving like the two examples above.

    julia
    weights_init = init(rng; kwargs...)
    +weights = weights_init(rng, dims...)
    +
    +# Or
    +
    +weights_init = init(; kwargs...)
    +weights = weights_init(dims...)
    `,25)]))}const o=i(e,[["render",l]]);export{c as __pageData,o as default}; diff --git a/previews/PR1023/assets/pinn_nested_ad.B__JnolW.gif b/previews/PR1023/assets/pinn_nested_ad.B__JnolW.gif new file mode 100644 index 0000000000..efb0cc6668 Binary files /dev/null and b/previews/PR1023/assets/pinn_nested_ad.B__JnolW.gif differ diff --git a/previews/PR1023/assets/results.Dm2mgseg.gif b/previews/PR1023/assets/results.Dm2mgseg.gif new file mode 100644 index 0000000000..b111af2fad Binary files /dev/null and b/previews/PR1023/assets/results.Dm2mgseg.gif differ diff --git a/previews/PR1023/assets/style.C8dKrHz3.css b/previews/PR1023/assets/style.C8dKrHz3.css new file mode 100644 index 0000000000..124f76bace --- /dev/null +++ b/previews/PR1023/assets/style.C8dKrHz3.css @@ -0,0 +1 @@ +@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-roman-cyrillic.C5lxZ8CY.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-roman-greek-ext.CqjqNYQ-.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-roman-greek.BBVDIX6e.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-roman-vietnamese.BjW4sHH5.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-roman-latin-ext.4ZJIpNVo.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-roman-latin.Di8DUHzh.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-italic-cyrillic-ext.r48I6akx.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-italic-cyrillic.By2_1cv3.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-italic-greek-ext.1u6EdAuj.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-italic-greek.DJ8dCoTZ.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-italic-vietnamese.BSbpV94h.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-italic-latin-ext.CN1xVJS-.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/previews/PR1023/assets/inter-italic-latin.C2AdPX0b.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Punctuation SC;font-weight:400;src:local("PingFang SC Regular"),local("Noto Sans CJK SC"),local("Microsoft YaHei");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:500;src:local("PingFang SC Medium"),local("Noto Sans CJK SC"),local("Microsoft YaHei");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:600;src:local("PingFang SC Semibold"),local("Noto Sans CJK SC Bold"),local("Microsoft YaHei Bold");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:700;src:local("PingFang SC Semibold"),local("Noto Sans CJK SC Bold"),local("Microsoft YaHei Bold");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}:root{--vp-c-white: #ffffff;--vp-c-black: #000000;--vp-c-neutral: var(--vp-c-black);--vp-c-neutral-inverse: var(--vp-c-white)}.dark{--vp-c-neutral: var(--vp-c-white);--vp-c-neutral-inverse: var(--vp-c-black)}:root{--vp-c-gray-1: #dddde3;--vp-c-gray-2: #e4e4e9;--vp-c-gray-3: #ebebef;--vp-c-gray-soft: rgba(142, 150, 170, .14);--vp-c-indigo-1: #3451b2;--vp-c-indigo-2: #3a5ccc;--vp-c-indigo-3: #5672cd;--vp-c-indigo-soft: rgba(100, 108, 255, .14);--vp-c-purple-1: #6f42c1;--vp-c-purple-2: #7e4cc9;--vp-c-purple-3: #8e5cd9;--vp-c-purple-soft: rgba(159, 122, 234, .14);--vp-c-green-1: #18794e;--vp-c-green-2: #299764;--vp-c-green-3: #30a46c;--vp-c-green-soft: rgba(16, 185, 129, .14);--vp-c-yellow-1: #915930;--vp-c-yellow-2: #946300;--vp-c-yellow-3: #9f6a00;--vp-c-yellow-soft: rgba(234, 179, 8, .14);--vp-c-red-1: #b8272c;--vp-c-red-2: #d5393e;--vp-c-red-3: #e0575b;--vp-c-red-soft: rgba(244, 63, 94, .14);--vp-c-sponsor: #db2777}.dark{--vp-c-gray-1: #515c67;--vp-c-gray-2: #414853;--vp-c-gray-3: #32363f;--vp-c-gray-soft: rgba(101, 117, 133, .16);--vp-c-indigo-1: #a8b1ff;--vp-c-indigo-2: #5c73e7;--vp-c-indigo-3: #3e63dd;--vp-c-indigo-soft: rgba(100, 108, 255, .16);--vp-c-purple-1: #c8abfa;--vp-c-purple-2: #a879e6;--vp-c-purple-3: #8e5cd9;--vp-c-purple-soft: rgba(159, 122, 234, .16);--vp-c-green-1: #3dd68c;--vp-c-green-2: #30a46c;--vp-c-green-3: #298459;--vp-c-green-soft: rgba(16, 185, 129, .16);--vp-c-yellow-1: #f9b44e;--vp-c-yellow-2: #da8b17;--vp-c-yellow-3: #a46a0a;--vp-c-yellow-soft: rgba(234, 179, 8, .16);--vp-c-red-1: #f66f81;--vp-c-red-2: #f14158;--vp-c-red-3: #b62a3c;--vp-c-red-soft: rgba(244, 63, 94, .16)}:root{--vp-c-bg: #ffffff;--vp-c-bg-alt: #f6f6f7;--vp-c-bg-elv: #ffffff;--vp-c-bg-soft: #f6f6f7}.dark{--vp-c-bg: #1b1b1f;--vp-c-bg-alt: #161618;--vp-c-bg-elv: #202127;--vp-c-bg-soft: #202127}:root{--vp-c-border: #c2c2c4;--vp-c-divider: #e2e2e3;--vp-c-gutter: #e2e2e3}.dark{--vp-c-border: #3c3f44;--vp-c-divider: #2e2e32;--vp-c-gutter: #000000}:root{--vp-c-text-1: rgba(60, 60, 67);--vp-c-text-2: rgba(60, 60, 67, .78);--vp-c-text-3: rgba(60, 60, 67, .56)}.dark{--vp-c-text-1: rgba(255, 255, 245, .86);--vp-c-text-2: rgba(235, 235, 245, .6);--vp-c-text-3: rgba(235, 235, 245, .38)}:root{--vp-c-default-1: var(--vp-c-gray-1);--vp-c-default-2: var(--vp-c-gray-2);--vp-c-default-3: var(--vp-c-gray-3);--vp-c-default-soft: var(--vp-c-gray-soft);--vp-c-brand-1: var(--vp-c-indigo-1);--vp-c-brand-2: var(--vp-c-indigo-2);--vp-c-brand-3: var(--vp-c-indigo-3);--vp-c-brand-soft: var(--vp-c-indigo-soft);--vp-c-brand: var(--vp-c-brand-1);--vp-c-tip-1: var(--vp-c-brand-1);--vp-c-tip-2: var(--vp-c-brand-2);--vp-c-tip-3: var(--vp-c-brand-3);--vp-c-tip-soft: var(--vp-c-brand-soft);--vp-c-note-1: var(--vp-c-brand-1);--vp-c-note-2: var(--vp-c-brand-2);--vp-c-note-3: var(--vp-c-brand-3);--vp-c-note-soft: var(--vp-c-brand-soft);--vp-c-success-1: var(--vp-c-green-1);--vp-c-success-2: var(--vp-c-green-2);--vp-c-success-3: var(--vp-c-green-3);--vp-c-success-soft: var(--vp-c-green-soft);--vp-c-important-1: var(--vp-c-purple-1);--vp-c-important-2: var(--vp-c-purple-2);--vp-c-important-3: var(--vp-c-purple-3);--vp-c-important-soft: var(--vp-c-purple-soft);--vp-c-warning-1: var(--vp-c-yellow-1);--vp-c-warning-2: var(--vp-c-yellow-2);--vp-c-warning-3: var(--vp-c-yellow-3);--vp-c-warning-soft: var(--vp-c-yellow-soft);--vp-c-danger-1: var(--vp-c-red-1);--vp-c-danger-2: var(--vp-c-red-2);--vp-c-danger-3: var(--vp-c-red-3);--vp-c-danger-soft: var(--vp-c-red-soft);--vp-c-caution-1: var(--vp-c-red-1);--vp-c-caution-2: var(--vp-c-red-2);--vp-c-caution-3: var(--vp-c-red-3);--vp-c-caution-soft: var(--vp-c-red-soft)}:root{--vp-font-family-base: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--vp-font-family-mono: ui-monospace, "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace;font-optical-sizing:auto}:root:where(:lang(zh)){--vp-font-family-base: "Punctuation SC", "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"}:root{--vp-shadow-1: 0 1px 2px rgba(0, 0, 0, .04), 0 1px 2px rgba(0, 0, 0, .06);--vp-shadow-2: 0 3px 12px rgba(0, 0, 0, .07), 0 1px 4px rgba(0, 0, 0, .07);--vp-shadow-3: 0 12px 32px rgba(0, 0, 0, .1), 0 2px 6px rgba(0, 0, 0, .08);--vp-shadow-4: 0 14px 44px rgba(0, 0, 0, .12), 0 3px 9px rgba(0, 0, 0, .12);--vp-shadow-5: 0 18px 56px rgba(0, 0, 0, .16), 0 4px 12px rgba(0, 0, 0, .16)}:root{--vp-z-index-footer: 10;--vp-z-index-local-nav: 20;--vp-z-index-nav: 30;--vp-z-index-layout-top: 40;--vp-z-index-backdrop: 50;--vp-z-index-sidebar: 60}@media (min-width: 960px){:root{--vp-z-index-sidebar: 25}}:root{--vp-layout-max-width: 1440px}:root{--vp-header-anchor-symbol: "#"}:root{--vp-code-line-height: 1.7;--vp-code-font-size: .875em;--vp-code-color: var(--vp-c-brand-1);--vp-code-link-color: var(--vp-c-brand-1);--vp-code-link-hover-color: var(--vp-c-brand-2);--vp-code-bg: var(--vp-c-default-soft);--vp-code-block-color: var(--vp-c-text-2);--vp-code-block-bg: var(--vp-c-bg-alt);--vp-code-block-divider-color: var(--vp-c-gutter);--vp-code-lang-color: var(--vp-c-text-3);--vp-code-line-highlight-color: var(--vp-c-default-soft);--vp-code-line-number-color: var(--vp-c-text-3);--vp-code-line-diff-add-color: var(--vp-c-success-soft);--vp-code-line-diff-add-symbol-color: var(--vp-c-success-1);--vp-code-line-diff-remove-color: var(--vp-c-danger-soft);--vp-code-line-diff-remove-symbol-color: var(--vp-c-danger-1);--vp-code-line-warning-color: var(--vp-c-warning-soft);--vp-code-line-error-color: var(--vp-c-danger-soft);--vp-code-copy-code-border-color: var(--vp-c-divider);--vp-code-copy-code-bg: var(--vp-c-bg-soft);--vp-code-copy-code-hover-border-color: var(--vp-c-divider);--vp-code-copy-code-hover-bg: var(--vp-c-bg);--vp-code-copy-code-active-text: var(--vp-c-text-2);--vp-code-copy-copied-text-content: "Copied";--vp-code-tab-divider: var(--vp-code-block-divider-color);--vp-code-tab-text-color: var(--vp-c-text-2);--vp-code-tab-bg: var(--vp-code-block-bg);--vp-code-tab-hover-text-color: var(--vp-c-text-1);--vp-code-tab-active-text-color: var(--vp-c-text-1);--vp-code-tab-active-bar-color: var(--vp-c-brand-1)}:root{--vp-button-brand-border: transparent;--vp-button-brand-text: var(--vp-c-white);--vp-button-brand-bg: var(--vp-c-brand-3);--vp-button-brand-hover-border: transparent;--vp-button-brand-hover-text: var(--vp-c-white);--vp-button-brand-hover-bg: var(--vp-c-brand-2);--vp-button-brand-active-border: transparent;--vp-button-brand-active-text: var(--vp-c-white);--vp-button-brand-active-bg: var(--vp-c-brand-1);--vp-button-alt-border: transparent;--vp-button-alt-text: var(--vp-c-text-1);--vp-button-alt-bg: var(--vp-c-default-3);--vp-button-alt-hover-border: transparent;--vp-button-alt-hover-text: var(--vp-c-text-1);--vp-button-alt-hover-bg: var(--vp-c-default-2);--vp-button-alt-active-border: transparent;--vp-button-alt-active-text: var(--vp-c-text-1);--vp-button-alt-active-bg: var(--vp-c-default-1);--vp-button-sponsor-border: var(--vp-c-text-2);--vp-button-sponsor-text: var(--vp-c-text-2);--vp-button-sponsor-bg: transparent;--vp-button-sponsor-hover-border: var(--vp-c-sponsor);--vp-button-sponsor-hover-text: var(--vp-c-sponsor);--vp-button-sponsor-hover-bg: transparent;--vp-button-sponsor-active-border: var(--vp-c-sponsor);--vp-button-sponsor-active-text: var(--vp-c-sponsor);--vp-button-sponsor-active-bg: transparent}:root{--vp-custom-block-font-size: 14px;--vp-custom-block-code-font-size: 13px;--vp-custom-block-info-border: transparent;--vp-custom-block-info-text: var(--vp-c-text-1);--vp-custom-block-info-bg: var(--vp-c-default-soft);--vp-custom-block-info-code-bg: var(--vp-c-default-soft);--vp-custom-block-note-border: transparent;--vp-custom-block-note-text: var(--vp-c-text-1);--vp-custom-block-note-bg: var(--vp-c-default-soft);--vp-custom-block-note-code-bg: var(--vp-c-default-soft);--vp-custom-block-tip-border: transparent;--vp-custom-block-tip-text: var(--vp-c-text-1);--vp-custom-block-tip-bg: var(--vp-c-tip-soft);--vp-custom-block-tip-code-bg: var(--vp-c-tip-soft);--vp-custom-block-important-border: transparent;--vp-custom-block-important-text: var(--vp-c-text-1);--vp-custom-block-important-bg: var(--vp-c-important-soft);--vp-custom-block-important-code-bg: var(--vp-c-important-soft);--vp-custom-block-warning-border: transparent;--vp-custom-block-warning-text: var(--vp-c-text-1);--vp-custom-block-warning-bg: var(--vp-c-warning-soft);--vp-custom-block-warning-code-bg: var(--vp-c-warning-soft);--vp-custom-block-danger-border: transparent;--vp-custom-block-danger-text: var(--vp-c-text-1);--vp-custom-block-danger-bg: var(--vp-c-danger-soft);--vp-custom-block-danger-code-bg: var(--vp-c-danger-soft);--vp-custom-block-caution-border: transparent;--vp-custom-block-caution-text: var(--vp-c-text-1);--vp-custom-block-caution-bg: var(--vp-c-caution-soft);--vp-custom-block-caution-code-bg: var(--vp-c-caution-soft);--vp-custom-block-details-border: var(--vp-custom-block-info-border);--vp-custom-block-details-text: var(--vp-custom-block-info-text);--vp-custom-block-details-bg: var(--vp-custom-block-info-bg);--vp-custom-block-details-code-bg: var(--vp-custom-block-info-code-bg)}:root{--vp-input-border-color: var(--vp-c-border);--vp-input-bg-color: var(--vp-c-bg-alt);--vp-input-switch-bg-color: var(--vp-c-default-soft)}:root{--vp-nav-height: 64px;--vp-nav-bg-color: var(--vp-c-bg);--vp-nav-screen-bg-color: var(--vp-c-bg);--vp-nav-logo-height: 24px}.hide-nav{--vp-nav-height: 0px}.hide-nav .VPSidebar{--vp-nav-height: 22px}:root{--vp-local-nav-bg-color: var(--vp-c-bg)}:root{--vp-sidebar-width: 272px;--vp-sidebar-bg-color: var(--vp-c-bg-alt)}:root{--vp-backdrop-bg-color: rgba(0, 0, 0, .6)}:root{--vp-home-hero-name-color: var(--vp-c-brand-1);--vp-home-hero-name-background: transparent;--vp-home-hero-image-background-image: none;--vp-home-hero-image-filter: none}:root{--vp-badge-info-border: transparent;--vp-badge-info-text: var(--vp-c-text-2);--vp-badge-info-bg: var(--vp-c-default-soft);--vp-badge-tip-border: transparent;--vp-badge-tip-text: var(--vp-c-tip-1);--vp-badge-tip-bg: var(--vp-c-tip-soft);--vp-badge-warning-border: transparent;--vp-badge-warning-text: var(--vp-c-warning-1);--vp-badge-warning-bg: var(--vp-c-warning-soft);--vp-badge-danger-border: transparent;--vp-badge-danger-text: var(--vp-c-danger-1);--vp-badge-danger-bg: var(--vp-c-danger-soft)}:root{--vp-carbon-ads-text-color: var(--vp-c-text-1);--vp-carbon-ads-poweredby-color: var(--vp-c-text-2);--vp-carbon-ads-bg-color: var(--vp-c-bg-soft);--vp-carbon-ads-hover-text-color: var(--vp-c-brand-1);--vp-carbon-ads-hover-poweredby-color: var(--vp-c-text-1)}:root{--vp-local-search-bg: var(--vp-c-bg);--vp-local-search-result-bg: var(--vp-c-bg);--vp-local-search-result-border: var(--vp-c-divider);--vp-local-search-result-selected-bg: var(--vp-c-bg);--vp-local-search-result-selected-border: var(--vp-c-brand-1);--vp-local-search-highlight-bg: var(--vp-c-brand-1);--vp-local-search-highlight-text: var(--vp-c-neutral-inverse)}@media (prefers-reduced-motion: reduce){*,:before,:after{animation-delay:-1ms!important;animation-duration:1ms!important;animation-iteration-count:1!important;background-attachment:initial!important;scroll-behavior:auto!important;transition-duration:0s!important;transition-delay:0s!important}}*,:before,:after{box-sizing:border-box}html{line-height:1.4;font-size:16px;-webkit-text-size-adjust:100%}html.dark{color-scheme:dark}body{margin:0;width:100%;min-width:320px;min-height:100vh;line-height:24px;font-family:var(--vp-font-family-base);font-size:16px;font-weight:400;color:var(--vp-c-text-1);background-color:var(--vp-c-bg);font-synthesis:style;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}main{display:block}h1,h2,h3,h4,h5,h6{margin:0;line-height:24px;font-size:16px;font-weight:400}p{margin:0}strong,b{font-weight:600}a,area,button,[role=button],input,label,select,summary,textarea{touch-action:manipulation}a{color:inherit;text-decoration:inherit}ol,ul{list-style:none;margin:0;padding:0}blockquote{margin:0}pre,code,kbd,samp{font-family:var(--vp-font-family-mono)}img,svg,video,canvas,audio,iframe,embed,object{display:block}figure{margin:0}img,video{max-width:100%;height:auto}button,input,optgroup,select,textarea{border:0;padding:0;line-height:inherit;color:inherit}button{padding:0;font-family:inherit;background-color:transparent;background-image:none}button:enabled,[role=button]:enabled{cursor:pointer}button:focus,button:focus-visible{outline:1px dotted;outline:4px auto -webkit-focus-ring-color}button:focus:not(:focus-visible){outline:none!important}input:focus,textarea:focus,select:focus{outline:none}table{border-collapse:collapse}input{background-color:transparent}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:var(--vp-c-text-3)}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:var(--vp-c-text-3)}input::placeholder,textarea::placeholder{color:var(--vp-c-text-3)}input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}input[type=number]{-moz-appearance:textfield}textarea{resize:vertical}select{-webkit-appearance:none}fieldset{margin:0;padding:0}h1,h2,h3,h4,h5,h6,li,p{overflow-wrap:break-word}vite-error-overlay{z-index:9999}mjx-container{overflow-x:auto}mjx-container>svg{display:inline-block;margin:auto}[class^=vpi-],[class*=" vpi-"],.vp-icon{width:1em;height:1em}[class^=vpi-].bg,[class*=" vpi-"].bg,.vp-icon.bg{background-size:100% 100%;background-color:transparent}[class^=vpi-]:not(.bg),[class*=" vpi-"]:not(.bg),.vp-icon:not(.bg){-webkit-mask:var(--icon) no-repeat;mask:var(--icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit}.vpi-align-left{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M21 6H3M15 12H3M17 18H3'/%3E%3C/svg%3E")}.vpi-arrow-right,.vpi-arrow-down,.vpi-arrow-left,.vpi-arrow-up{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h14M12 5l7 7-7 7'/%3E%3C/svg%3E")}.vpi-chevron-right,.vpi-chevron-down,.vpi-chevron-left,.vpi-chevron-up{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E")}.vpi-chevron-down,.vpi-arrow-down{transform:rotate(90deg)}.vpi-chevron-left,.vpi-arrow-left{transform:rotate(180deg)}.vpi-chevron-up,.vpi-arrow-up{transform:rotate(-90deg)}.vpi-square-pen{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7'/%3E%3Cpath d='M18.375 2.625a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4Z'/%3E%3C/svg%3E")}.vpi-plus{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h14M12 5v14'/%3E%3C/svg%3E")}.vpi-sun{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Cpath d='M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41'/%3E%3C/svg%3E")}.vpi-moon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z'/%3E%3C/svg%3E")}.vpi-more-horizontal{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='1'/%3E%3Ccircle cx='19' cy='12' r='1'/%3E%3Ccircle cx='5' cy='12' r='1'/%3E%3C/svg%3E")}.vpi-languages{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m5 8 6 6M4 14l6-6 2-3M2 5h12M7 2h1M22 22l-5-10-5 10M14 18h6'/%3E%3C/svg%3E")}.vpi-heart{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z'/%3E%3C/svg%3E")}.vpi-search{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E")}.vpi-layout-list{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='7' height='7' x='3' y='3' rx='1'/%3E%3Crect width='7' height='7' x='3' y='14' rx='1'/%3E%3Cpath d='M14 4h7M14 9h7M14 15h7M14 20h7'/%3E%3C/svg%3E")}.vpi-delete{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M20 5H9l-7 7 7 7h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2ZM18 9l-6 6M12 9l6 6'/%3E%3C/svg%3E")}.vpi-corner-down-left{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m9 10-5 5 5 5'/%3E%3Cpath d='M20 4v7a4 4 0 0 1-4 4H4'/%3E%3C/svg%3E")}:root{--vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3C/svg%3E");--vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14 2 2 4-4'/%3E%3C/svg%3E")}.vpi-social-discord{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418Z'/%3E%3C/svg%3E")}.vpi-social-facebook{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z'/%3E%3C/svg%3E")}.vpi-social-github{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")}.vpi-social-instagram{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7.03.084c-1.277.06-2.149.264-2.91.563a5.874 5.874 0 0 0-2.124 1.388 5.878 5.878 0 0 0-1.38 2.127C.321 4.926.12 5.8.064 7.076.008 8.354-.005 8.764.001 12.023c.007 3.259.021 3.667.083 4.947.061 1.277.264 2.149.563 2.911.308.789.72 1.457 1.388 2.123a5.872 5.872 0 0 0 2.129 1.38c.763.295 1.636.496 2.913.552 1.278.056 1.689.069 4.947.063 3.257-.007 3.668-.021 4.947-.082 1.28-.06 2.147-.265 2.91-.563a5.881 5.881 0 0 0 2.123-1.388 5.881 5.881 0 0 0 1.38-2.129c.295-.763.496-1.636.551-2.912.056-1.28.07-1.69.063-4.948-.006-3.258-.02-3.667-.081-4.947-.06-1.28-.264-2.148-.564-2.911a5.892 5.892 0 0 0-1.387-2.123 5.857 5.857 0 0 0-2.128-1.38C19.074.322 18.202.12 16.924.066 15.647.009 15.236-.006 11.977 0 8.718.008 8.31.021 7.03.084m.14 21.693c-1.17-.05-1.805-.245-2.228-.408a3.736 3.736 0 0 1-1.382-.895 3.695 3.695 0 0 1-.9-1.378c-.165-.423-.363-1.058-.417-2.228-.06-1.264-.072-1.644-.08-4.848-.006-3.204.006-3.583.061-4.848.05-1.169.246-1.805.408-2.228.216-.561.477-.96.895-1.382a3.705 3.705 0 0 1 1.379-.9c.423-.165 1.057-.361 2.227-.417 1.265-.06 1.644-.072 4.848-.08 3.203-.006 3.583.006 4.85.062 1.168.05 1.804.244 2.227.408.56.216.96.475 1.382.895.421.42.681.817.9 1.378.165.422.362 1.056.417 2.227.06 1.265.074 1.645.08 4.848.005 3.203-.006 3.583-.061 4.848-.051 1.17-.245 1.805-.408 2.23-.216.56-.477.96-.896 1.38a3.705 3.705 0 0 1-1.378.9c-.422.165-1.058.362-2.226.418-1.266.06-1.645.072-4.85.079-3.204.007-3.582-.006-4.848-.06m9.783-16.192a1.44 1.44 0 1 0 1.437-1.442 1.44 1.44 0 0 0-1.437 1.442M5.839 12.012a6.161 6.161 0 1 0 12.323-.024 6.162 6.162 0 0 0-12.323.024M8 12.008A4 4 0 1 1 12.008 16 4 4 0 0 1 8 12.008'/%3E%3C/svg%3E")}.vpi-social-linkedin{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z'/%3E%3C/svg%3E")}.vpi-social-mastodon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z'/%3E%3C/svg%3E")}.vpi-social-npm{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z'/%3E%3C/svg%3E")}.vpi-social-slack{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zm1.271 0a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zm0 1.271a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zm10.122 2.521a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zm-1.268 0a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zm-2.523 10.122a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zm0-1.268a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z'/%3E%3C/svg%3E")}.vpi-social-twitter,.vpi-social-x{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z'/%3E%3C/svg%3E")}.vpi-social-youtube{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z'/%3E%3C/svg%3E")}.visually-hidden{position:absolute;width:1px;height:1px;white-space:nowrap;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden}.custom-block{border:1px solid transparent;border-radius:8px;padding:16px 16px 8px;line-height:24px;font-size:var(--vp-custom-block-font-size);color:var(--vp-c-text-2)}.custom-block.info{border-color:var(--vp-custom-block-info-border);color:var(--vp-custom-block-info-text);background-color:var(--vp-custom-block-info-bg)}.custom-block.info a,.custom-block.info code{color:var(--vp-c-brand-1)}.custom-block.info a:hover,.custom-block.info a:hover>code{color:var(--vp-c-brand-2)}.custom-block.info code{background-color:var(--vp-custom-block-info-code-bg)}.custom-block.note{border-color:var(--vp-custom-block-note-border);color:var(--vp-custom-block-note-text);background-color:var(--vp-custom-block-note-bg)}.custom-block.note a,.custom-block.note code{color:var(--vp-c-brand-1)}.custom-block.note a:hover,.custom-block.note a:hover>code{color:var(--vp-c-brand-2)}.custom-block.note code{background-color:var(--vp-custom-block-note-code-bg)}.custom-block.tip{border-color:var(--vp-custom-block-tip-border);color:var(--vp-custom-block-tip-text);background-color:var(--vp-custom-block-tip-bg)}.custom-block.tip a,.custom-block.tip code{color:var(--vp-c-tip-1)}.custom-block.tip a:hover,.custom-block.tip a:hover>code{color:var(--vp-c-tip-2)}.custom-block.tip code{background-color:var(--vp-custom-block-tip-code-bg)}.custom-block.important{border-color:var(--vp-custom-block-important-border);color:var(--vp-custom-block-important-text);background-color:var(--vp-custom-block-important-bg)}.custom-block.important a,.custom-block.important code{color:var(--vp-c-important-1)}.custom-block.important a:hover,.custom-block.important a:hover>code{color:var(--vp-c-important-2)}.custom-block.important code{background-color:var(--vp-custom-block-important-code-bg)}.custom-block.warning{border-color:var(--vp-custom-block-warning-border);color:var(--vp-custom-block-warning-text);background-color:var(--vp-custom-block-warning-bg)}.custom-block.warning a,.custom-block.warning code{color:var(--vp-c-warning-1)}.custom-block.warning a:hover,.custom-block.warning a:hover>code{color:var(--vp-c-warning-2)}.custom-block.warning code{background-color:var(--vp-custom-block-warning-code-bg)}.custom-block.danger{border-color:var(--vp-custom-block-danger-border);color:var(--vp-custom-block-danger-text);background-color:var(--vp-custom-block-danger-bg)}.custom-block.danger a,.custom-block.danger code{color:var(--vp-c-danger-1)}.custom-block.danger a:hover,.custom-block.danger a:hover>code{color:var(--vp-c-danger-2)}.custom-block.danger code{background-color:var(--vp-custom-block-danger-code-bg)}.custom-block.caution{border-color:var(--vp-custom-block-caution-border);color:var(--vp-custom-block-caution-text);background-color:var(--vp-custom-block-caution-bg)}.custom-block.caution a,.custom-block.caution code{color:var(--vp-c-caution-1)}.custom-block.caution a:hover,.custom-block.caution a:hover>code{color:var(--vp-c-caution-2)}.custom-block.caution code{background-color:var(--vp-custom-block-caution-code-bg)}.custom-block.details{border-color:var(--vp-custom-block-details-border);color:var(--vp-custom-block-details-text);background-color:var(--vp-custom-block-details-bg)}.custom-block.details a{color:var(--vp-c-brand-1)}.custom-block.details a:hover,.custom-block.details a:hover>code{color:var(--vp-c-brand-2)}.custom-block.details code{background-color:var(--vp-custom-block-details-code-bg)}.custom-block-title{font-weight:600}.custom-block p+p{margin:8px 0}.custom-block.details summary{margin:0 0 8px;font-weight:700;cursor:pointer;-webkit-user-select:none;user-select:none}.custom-block.details summary+p{margin:8px 0}.custom-block a{color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px;transition:opacity .25s}.custom-block a:hover{opacity:.75}.custom-block code{font-size:var(--vp-custom-block-code-font-size)}.custom-block.custom-block th,.custom-block.custom-block blockquote>p{font-size:var(--vp-custom-block-font-size);color:inherit}.dark .vp-code span{color:var(--shiki-dark, inherit)}html:not(.dark) .vp-code span{color:var(--shiki-light, inherit)}.vp-code-group{margin-top:16px}.vp-code-group .tabs{position:relative;display:flex;margin-right:-24px;margin-left:-24px;padding:0 12px;background-color:var(--vp-code-tab-bg);overflow-x:auto;overflow-y:hidden;box-shadow:inset 0 -1px var(--vp-code-tab-divider)}@media (min-width: 640px){.vp-code-group .tabs{margin-right:0;margin-left:0;border-radius:8px 8px 0 0}}.vp-code-group .tabs input{position:fixed;opacity:0;pointer-events:none}.vp-code-group .tabs label{position:relative;display:inline-block;border-bottom:1px solid transparent;padding:0 12px;line-height:48px;font-size:14px;font-weight:500;color:var(--vp-code-tab-text-color);white-space:nowrap;cursor:pointer;transition:color .25s}.vp-code-group .tabs label:after{position:absolute;right:8px;bottom:-1px;left:8px;z-index:1;height:2px;border-radius:2px;content:"";background-color:transparent;transition:background-color .25s}.vp-code-group label:hover{color:var(--vp-code-tab-hover-text-color)}.vp-code-group input:checked+label{color:var(--vp-code-tab-active-text-color)}.vp-code-group input:checked+label:after{background-color:var(--vp-code-tab-active-bar-color)}.vp-code-group div[class*=language-],.vp-block{display:none;margin-top:0!important;border-top-left-radius:0!important;border-top-right-radius:0!important}.vp-code-group div[class*=language-].active,.vp-block.active{display:block}.vp-block{padding:20px 24px}.vp-doc h1,.vp-doc h2,.vp-doc h3,.vp-doc h4,.vp-doc h5,.vp-doc h6{position:relative;font-weight:600;outline:none}.vp-doc h1{letter-spacing:-.02em;line-height:40px;font-size:28px}.vp-doc h2{margin:48px 0 16px;border-top:1px solid var(--vp-c-divider);padding-top:24px;letter-spacing:-.02em;line-height:32px;font-size:24px}.vp-doc h3{margin:32px 0 0;letter-spacing:-.01em;line-height:28px;font-size:20px}.vp-doc h4{margin:24px 0 0;letter-spacing:-.01em;line-height:24px;font-size:18px}.vp-doc .header-anchor{position:absolute;top:0;left:0;margin-left:-.87em;font-weight:500;-webkit-user-select:none;user-select:none;opacity:0;text-decoration:none;transition:color .25s,opacity .25s}.vp-doc .header-anchor:before{content:var(--vp-header-anchor-symbol)}.vp-doc h1:hover .header-anchor,.vp-doc h1 .header-anchor:focus,.vp-doc h2:hover .header-anchor,.vp-doc h2 .header-anchor:focus,.vp-doc h3:hover .header-anchor,.vp-doc h3 .header-anchor:focus,.vp-doc h4:hover .header-anchor,.vp-doc h4 .header-anchor:focus,.vp-doc h5:hover .header-anchor,.vp-doc h5 .header-anchor:focus,.vp-doc h6:hover .header-anchor,.vp-doc h6 .header-anchor:focus{opacity:1}@media (min-width: 768px){.vp-doc h1{letter-spacing:-.02em;line-height:40px;font-size:32px}}.vp-doc h2 .header-anchor{top:24px}.vp-doc p,.vp-doc summary{margin:16px 0}.vp-doc p{line-height:28px}.vp-doc blockquote{margin:16px 0;border-left:2px solid var(--vp-c-divider);padding-left:16px;transition:border-color .5s;color:var(--vp-c-text-2)}.vp-doc blockquote>p{margin:0;font-size:16px;transition:color .5s}.vp-doc a{font-weight:500;color:var(--vp-c-brand-1);text-decoration:underline;text-underline-offset:2px;transition:color .25s,opacity .25s}.vp-doc a:hover{color:var(--vp-c-brand-2)}.vp-doc strong{font-weight:600}.vp-doc ul,.vp-doc ol{padding-left:1.25rem;margin:16px 0}.vp-doc ul{list-style:disc}.vp-doc ol{list-style:decimal}.vp-doc li+li{margin-top:8px}.vp-doc li>ol,.vp-doc li>ul{margin:8px 0 0}.vp-doc table{display:block;border-collapse:collapse;margin:20px 0;overflow-x:auto}.vp-doc tr{background-color:var(--vp-c-bg);border-top:1px solid var(--vp-c-divider);transition:background-color .5s}.vp-doc tr:nth-child(2n){background-color:var(--vp-c-bg-soft)}.vp-doc th,.vp-doc td{border:1px solid var(--vp-c-divider);padding:8px 16px}.vp-doc th{text-align:left;font-size:14px;font-weight:600;color:var(--vp-c-text-2);background-color:var(--vp-c-bg-soft)}.vp-doc td{font-size:14px}.vp-doc hr{margin:16px 0;border:none;border-top:1px solid var(--vp-c-divider)}.vp-doc .custom-block{margin:16px 0}.vp-doc .custom-block p{margin:8px 0;line-height:24px}.vp-doc .custom-block p:first-child{margin:0}.vp-doc .custom-block div[class*=language-]{margin:8px 0;border-radius:8px}.vp-doc .custom-block div[class*=language-] code{font-weight:400;background-color:transparent}.vp-doc .custom-block .vp-code-group .tabs{margin:0;border-radius:8px 8px 0 0}.vp-doc :not(pre,h1,h2,h3,h4,h5,h6)>code{font-size:var(--vp-code-font-size);color:var(--vp-code-color)}.vp-doc :not(pre)>code{border-radius:4px;padding:3px 6px;background-color:var(--vp-code-bg);transition:color .25s,background-color .5s}.vp-doc a>code{color:var(--vp-code-link-color)}.vp-doc a:hover>code{color:var(--vp-code-link-hover-color)}.vp-doc h1>code,.vp-doc h2>code,.vp-doc h3>code,.vp-doc h4>code{font-size:.9em}.vp-doc div[class*=language-],.vp-block{position:relative;margin:16px -24px;background-color:var(--vp-code-block-bg);overflow-x:auto;transition:background-color .5s}@media (min-width: 640px){.vp-doc div[class*=language-],.vp-block{border-radius:8px;margin:16px 0}}@media (max-width: 639px){.vp-doc li div[class*=language-]{border-radius:8px 0 0 8px}}.vp-doc div[class*=language-]+div[class*=language-],.vp-doc div[class$=-api]+div[class*=language-],.vp-doc div[class*=language-]+div[class$=-api]>div[class*=language-]{margin-top:-8px}.vp-doc [class*=language-] pre,.vp-doc [class*=language-] code{direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}.vp-doc [class*=language-] pre{position:relative;z-index:1;margin:0;padding:20px 0;background:transparent;overflow-x:auto}.vp-doc [class*=language-] code{display:block;padding:0 24px;width:fit-content;min-width:100%;line-height:var(--vp-code-line-height);font-size:var(--vp-code-font-size);color:var(--vp-code-block-color);transition:color .5s}.vp-doc [class*=language-] code .highlighted{background-color:var(--vp-code-line-highlight-color);transition:background-color .5s;margin:0 -24px;padding:0 24px;width:calc(100% + 48px);display:inline-block}.vp-doc [class*=language-] code .highlighted.error{background-color:var(--vp-code-line-error-color)}.vp-doc [class*=language-] code .highlighted.warning{background-color:var(--vp-code-line-warning-color)}.vp-doc [class*=language-] code .diff{transition:background-color .5s;margin:0 -24px;padding:0 24px;width:calc(100% + 48px);display:inline-block}.vp-doc [class*=language-] code .diff:before{position:absolute;left:10px}.vp-doc [class*=language-] .has-focused-lines .line:not(.has-focus){filter:blur(.095rem);opacity:.4;transition:filter .35s,opacity .35s}.vp-doc [class*=language-] .has-focused-lines .line:not(.has-focus){opacity:.7;transition:filter .35s,opacity .35s}.vp-doc [class*=language-]:hover .has-focused-lines .line:not(.has-focus){filter:blur(0);opacity:1}.vp-doc [class*=language-] code .diff.remove{background-color:var(--vp-code-line-diff-remove-color);opacity:.7}.vp-doc [class*=language-] code .diff.remove:before{content:"-";color:var(--vp-code-line-diff-remove-symbol-color)}.vp-doc [class*=language-] code .diff.add{background-color:var(--vp-code-line-diff-add-color)}.vp-doc [class*=language-] code .diff.add:before{content:"+";color:var(--vp-code-line-diff-add-symbol-color)}.vp-doc div[class*=language-].line-numbers-mode{padding-left:32px}.vp-doc .line-numbers-wrapper{position:absolute;top:0;bottom:0;left:0;z-index:3;border-right:1px solid var(--vp-code-block-divider-color);padding-top:20px;width:32px;text-align:center;font-family:var(--vp-font-family-mono);line-height:var(--vp-code-line-height);font-size:var(--vp-code-font-size);color:var(--vp-code-line-number-color);transition:border-color .5s,color .5s}.vp-doc [class*=language-]>button.copy{direction:ltr;position:absolute;top:12px;right:12px;z-index:3;border:1px solid var(--vp-code-copy-code-border-color);border-radius:4px;width:40px;height:40px;background-color:var(--vp-code-copy-code-bg);opacity:0;cursor:pointer;background-image:var(--vp-icon-copy);background-position:50%;background-size:20px;background-repeat:no-repeat;transition:border-color .25s,background-color .25s,opacity .25s}.vp-doc [class*=language-]:hover>button.copy,.vp-doc [class*=language-]>button.copy:focus{opacity:1}.vp-doc [class*=language-]>button.copy:hover,.vp-doc [class*=language-]>button.copy.copied{border-color:var(--vp-code-copy-code-hover-border-color);background-color:var(--vp-code-copy-code-hover-bg)}.vp-doc [class*=language-]>button.copy.copied,.vp-doc [class*=language-]>button.copy:hover.copied{border-radius:0 4px 4px 0;background-color:var(--vp-code-copy-code-hover-bg);background-image:var(--vp-icon-copied)}.vp-doc [class*=language-]>button.copy.copied:before,.vp-doc [class*=language-]>button.copy:hover.copied:before{position:relative;top:-1px;transform:translate(calc(-100% - 1px));display:flex;justify-content:center;align-items:center;border:1px solid var(--vp-code-copy-code-hover-border-color);border-right:0;border-radius:4px 0 0 4px;padding:0 10px;width:fit-content;height:40px;text-align:center;font-size:12px;font-weight:500;color:var(--vp-code-copy-code-active-text);background-color:var(--vp-code-copy-code-hover-bg);white-space:nowrap;content:var(--vp-code-copy-copied-text-content)}.vp-doc [class*=language-]>span.lang{position:absolute;top:2px;right:8px;z-index:2;font-size:12px;font-weight:500;-webkit-user-select:none;user-select:none;color:var(--vp-code-lang-color);transition:color .4s,opacity .4s}.vp-doc [class*=language-]:hover>button.copy+span.lang,.vp-doc [class*=language-]>button.copy:focus+span.lang{opacity:0}.vp-doc .VPTeamMembers{margin-top:24px}.vp-doc .VPTeamMembers.small.count-1 .container{margin:0!important;max-width:calc((100% - 24px)/2)!important}.vp-doc .VPTeamMembers.small.count-2 .container,.vp-doc .VPTeamMembers.small.count-3 .container{max-width:100%!important}.vp-doc .VPTeamMembers.medium.count-1 .container{margin:0!important;max-width:calc((100% - 24px)/2)!important}:is(.vp-external-link-icon,.vp-doc a[href*="://"],.vp-doc a[target=_blank]):not(.no-icon):after{display:inline-block;margin-top:-1px;margin-left:4px;width:11px;height:11px;background:currentColor;color:var(--vp-c-text-3);flex-shrink:0;--icon: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='M0 0h24v24H0V0z' fill='none' /%3E%3Cpath d='M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z' /%3E%3C/svg%3E");-webkit-mask-image:var(--icon);mask-image:var(--icon)}.vp-external-link-icon:after{content:""}.external-link-icon-enabled :is(.vp-doc a[href*="://"],.vp-doc a[target=_blank]):after{content:"";color:currentColor}.vp-sponsor{border-radius:16px;overflow:hidden}.vp-sponsor.aside{border-radius:12px}.vp-sponsor-section+.vp-sponsor-section{margin-top:4px}.vp-sponsor-tier{margin:0 0 4px!important;text-align:center;letter-spacing:1px!important;line-height:24px;width:100%;font-weight:600;color:var(--vp-c-text-2);background-color:var(--vp-c-bg-soft)}.vp-sponsor.normal .vp-sponsor-tier{padding:13px 0 11px;font-size:14px}.vp-sponsor.aside .vp-sponsor-tier{padding:9px 0 7px;font-size:12px}.vp-sponsor-grid+.vp-sponsor-tier{margin-top:4px}.vp-sponsor-grid{display:flex;flex-wrap:wrap;gap:4px}.vp-sponsor-grid.xmini .vp-sponsor-grid-link{height:64px}.vp-sponsor-grid.xmini .vp-sponsor-grid-image{max-width:64px;max-height:22px}.vp-sponsor-grid.mini .vp-sponsor-grid-link{height:72px}.vp-sponsor-grid.mini .vp-sponsor-grid-image{max-width:96px;max-height:24px}.vp-sponsor-grid.small .vp-sponsor-grid-link{height:96px}.vp-sponsor-grid.small .vp-sponsor-grid-image{max-width:96px;max-height:24px}.vp-sponsor-grid.medium .vp-sponsor-grid-link{height:112px}.vp-sponsor-grid.medium .vp-sponsor-grid-image{max-width:120px;max-height:36px}.vp-sponsor-grid.big .vp-sponsor-grid-link{height:184px}.vp-sponsor-grid.big .vp-sponsor-grid-image{max-width:192px;max-height:56px}.vp-sponsor-grid[data-vp-grid="2"] .vp-sponsor-grid-item{width:calc((100% - 4px)/2)}.vp-sponsor-grid[data-vp-grid="3"] .vp-sponsor-grid-item{width:calc((100% - 4px * 2) / 3)}.vp-sponsor-grid[data-vp-grid="4"] .vp-sponsor-grid-item{width:calc((100% - 12px)/4)}.vp-sponsor-grid[data-vp-grid="5"] .vp-sponsor-grid-item{width:calc((100% - 16px)/5)}.vp-sponsor-grid[data-vp-grid="6"] .vp-sponsor-grid-item{width:calc((100% - 4px * 5) / 6)}.vp-sponsor-grid-item{flex-shrink:0;width:100%;background-color:var(--vp-c-bg-soft);transition:background-color .25s}.vp-sponsor-grid-item:hover{background-color:var(--vp-c-default-soft)}.vp-sponsor-grid-item:hover .vp-sponsor-grid-image{filter:grayscale(0) invert(0)}.vp-sponsor-grid-item.empty:hover{background-color:var(--vp-c-bg-soft)}.dark .vp-sponsor-grid-item:hover{background-color:var(--vp-c-white)}.dark .vp-sponsor-grid-item.empty:hover{background-color:var(--vp-c-bg-soft)}.vp-sponsor-grid-link{display:flex}.vp-sponsor-grid-box{display:flex;justify-content:center;align-items:center;width:100%}.vp-sponsor-grid-image{max-width:100%;filter:grayscale(1);transition:filter .25s}.dark .vp-sponsor-grid-image{filter:grayscale(1) invert(1)}.VPBadge{display:inline-block;margin-left:2px;border:1px solid transparent;border-radius:12px;padding:0 10px;line-height:22px;font-size:12px;font-weight:500;transform:translateY(-2px)}.VPBadge.small{padding:0 6px;line-height:18px;font-size:10px;transform:translateY(-8px)}.VPDocFooter .VPBadge{display:none}.vp-doc h1>.VPBadge{margin-top:4px;vertical-align:top}.vp-doc h2>.VPBadge{margin-top:3px;padding:0 8px;vertical-align:top}.vp-doc h3>.VPBadge{vertical-align:middle}.vp-doc h4>.VPBadge,.vp-doc h5>.VPBadge,.vp-doc h6>.VPBadge{vertical-align:middle;line-height:18px}.VPBadge.info{border-color:var(--vp-badge-info-border);color:var(--vp-badge-info-text);background-color:var(--vp-badge-info-bg)}.VPBadge.tip{border-color:var(--vp-badge-tip-border);color:var(--vp-badge-tip-text);background-color:var(--vp-badge-tip-bg)}.VPBadge.warning{border-color:var(--vp-badge-warning-border);color:var(--vp-badge-warning-text);background-color:var(--vp-badge-warning-bg)}.VPBadge.danger{border-color:var(--vp-badge-danger-border);color:var(--vp-badge-danger-text);background-color:var(--vp-badge-danger-bg)}.VPBackdrop[data-v-b06cdb19]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:var(--vp-z-index-backdrop);background:var(--vp-backdrop-bg-color);transition:opacity .5s}.VPBackdrop.fade-enter-from[data-v-b06cdb19],.VPBackdrop.fade-leave-to[data-v-b06cdb19]{opacity:0}.VPBackdrop.fade-leave-active[data-v-b06cdb19]{transition-duration:.25s}@media (min-width: 1280px){.VPBackdrop[data-v-b06cdb19]{display:none}}.NotFound[data-v-951cab6c]{padding:64px 24px 96px;text-align:center}@media (min-width: 768px){.NotFound[data-v-951cab6c]{padding:96px 32px 168px}}.code[data-v-951cab6c]{line-height:64px;font-size:64px;font-weight:600}.title[data-v-951cab6c]{padding-top:12px;letter-spacing:2px;line-height:20px;font-size:20px;font-weight:700}.divider[data-v-951cab6c]{margin:24px auto 18px;width:64px;height:1px;background-color:var(--vp-c-divider)}.quote[data-v-951cab6c]{margin:0 auto;max-width:256px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.action[data-v-951cab6c]{padding-top:20px}.link[data-v-951cab6c]{display:inline-block;border:1px solid var(--vp-c-brand-1);border-radius:16px;padding:3px 16px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:border-color .25s,color .25s}.link[data-v-951cab6c]:hover{border-color:var(--vp-c-brand-2);color:var(--vp-c-brand-2)}.root[data-v-3f927ebe]{position:relative;z-index:1}.nested[data-v-3f927ebe]{padding-right:16px;padding-left:16px}.outline-link[data-v-3f927ebe]{display:block;line-height:32px;font-size:14px;font-weight:400;color:var(--vp-c-text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:color .5s}.outline-link[data-v-3f927ebe]:hover,.outline-link.active[data-v-3f927ebe]{color:var(--vp-c-text-1);transition:color .25s}.outline-link.nested[data-v-3f927ebe]{padding-left:13px}.VPDocAsideOutline[data-v-b38bf2ff]{display:none}.VPDocAsideOutline.has-outline[data-v-b38bf2ff]{display:block}.content[data-v-b38bf2ff]{position:relative;border-left:1px solid var(--vp-c-divider);padding-left:16px;font-size:13px;font-weight:500}.outline-marker[data-v-b38bf2ff]{position:absolute;top:32px;left:-1px;z-index:0;opacity:0;width:2px;border-radius:2px;height:18px;background-color:var(--vp-c-brand-1);transition:top .25s cubic-bezier(0,1,.5,1),background-color .5s,opacity .25s}.outline-title[data-v-b38bf2ff]{line-height:32px;font-size:14px;font-weight:600}.VPDocAside[data-v-6d7b3c46]{display:flex;flex-direction:column;flex-grow:1}.spacer[data-v-6d7b3c46]{flex-grow:1}.VPDocAside[data-v-6d7b3c46] .spacer+.VPDocAsideSponsors,.VPDocAside[data-v-6d7b3c46] .spacer+.VPDocAsideCarbonAds{margin-top:24px}.VPDocAside[data-v-6d7b3c46] .VPDocAsideSponsors+.VPDocAsideCarbonAds{margin-top:16px}.VPLastUpdated[data-v-475f71b8]{line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}@media (min-width: 640px){.VPLastUpdated[data-v-475f71b8]{line-height:32px;font-size:14px;font-weight:500}}.VPDocFooter[data-v-4f9813fa]{margin-top:64px}.edit-info[data-v-4f9813fa]{padding-bottom:18px}@media (min-width: 640px){.edit-info[data-v-4f9813fa]{display:flex;justify-content:space-between;align-items:center;padding-bottom:14px}}.edit-link-button[data-v-4f9813fa]{display:flex;align-items:center;border:0;line-height:32px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:color .25s}.edit-link-button[data-v-4f9813fa]:hover{color:var(--vp-c-brand-2)}.edit-link-icon[data-v-4f9813fa]{margin-right:8px}.prev-next[data-v-4f9813fa]{border-top:1px solid var(--vp-c-divider);padding-top:24px;display:grid;grid-row-gap:8px}@media (min-width: 640px){.prev-next[data-v-4f9813fa]{grid-template-columns:repeat(2,1fr);grid-column-gap:16px}}.pager-link[data-v-4f9813fa]{display:block;border:1px solid var(--vp-c-divider);border-radius:8px;padding:11px 16px 13px;width:100%;height:100%;transition:border-color .25s}.pager-link[data-v-4f9813fa]:hover{border-color:var(--vp-c-brand-1)}.pager-link.next[data-v-4f9813fa]{margin-left:auto;text-align:right}.desc[data-v-4f9813fa]{display:block;line-height:20px;font-size:12px;font-weight:500;color:var(--vp-c-text-2)}.title[data-v-4f9813fa]{display:block;line-height:20px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:color .25s}.VPDoc[data-v-83890dd9]{padding:32px 24px 96px;width:100%}@media (min-width: 768px){.VPDoc[data-v-83890dd9]{padding:48px 32px 128px}}@media (min-width: 960px){.VPDoc[data-v-83890dd9]{padding:48px 32px 0}.VPDoc:not(.has-sidebar) .container[data-v-83890dd9]{display:flex;justify-content:center;max-width:992px}.VPDoc:not(.has-sidebar) .content[data-v-83890dd9]{max-width:752px}}@media (min-width: 1280px){.VPDoc .container[data-v-83890dd9]{display:flex;justify-content:center}.VPDoc .aside[data-v-83890dd9]{display:block}}@media (min-width: 1440px){.VPDoc:not(.has-sidebar) .content[data-v-83890dd9]{max-width:784px}.VPDoc:not(.has-sidebar) .container[data-v-83890dd9]{max-width:1104px}}.container[data-v-83890dd9]{margin:0 auto;width:100%}.aside[data-v-83890dd9]{position:relative;display:none;order:2;flex-grow:1;padding-left:32px;width:100%;max-width:256px}.left-aside[data-v-83890dd9]{order:1;padding-left:unset;padding-right:32px}.aside-container[data-v-83890dd9]{position:fixed;top:0;padding-top:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + var(--vp-doc-top-height, 0px) + 48px);width:224px;height:100vh;overflow-x:hidden;overflow-y:auto;scrollbar-width:none}.aside-container[data-v-83890dd9]::-webkit-scrollbar{display:none}.aside-curtain[data-v-83890dd9]{position:fixed;bottom:0;z-index:10;width:224px;height:32px;background:linear-gradient(transparent,var(--vp-c-bg) 70%)}.aside-content[data-v-83890dd9]{display:flex;flex-direction:column;min-height:calc(100vh - (var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px));padding-bottom:32px}.content[data-v-83890dd9]{position:relative;margin:0 auto;width:100%}@media (min-width: 960px){.content[data-v-83890dd9]{padding:0 32px 128px}}@media (min-width: 1280px){.content[data-v-83890dd9]{order:1;margin:0;min-width:640px}}.content-container[data-v-83890dd9]{margin:0 auto}.VPDoc.has-aside .content-container[data-v-83890dd9]{max-width:688px}.VPButton[data-v-906d7fb4]{display:inline-block;border:1px solid transparent;text-align:center;font-weight:600;white-space:nowrap;transition:color .25s,border-color .25s,background-color .25s}.VPButton[data-v-906d7fb4]:active{transition:color .1s,border-color .1s,background-color .1s}.VPButton.medium[data-v-906d7fb4]{border-radius:20px;padding:0 20px;line-height:38px;font-size:14px}.VPButton.big[data-v-906d7fb4]{border-radius:24px;padding:0 24px;line-height:46px;font-size:16px}.VPButton.brand[data-v-906d7fb4]{border-color:var(--vp-button-brand-border);color:var(--vp-button-brand-text);background-color:var(--vp-button-brand-bg)}.VPButton.brand[data-v-906d7fb4]:hover{border-color:var(--vp-button-brand-hover-border);color:var(--vp-button-brand-hover-text);background-color:var(--vp-button-brand-hover-bg)}.VPButton.brand[data-v-906d7fb4]:active{border-color:var(--vp-button-brand-active-border);color:var(--vp-button-brand-active-text);background-color:var(--vp-button-brand-active-bg)}.VPButton.alt[data-v-906d7fb4]{border-color:var(--vp-button-alt-border);color:var(--vp-button-alt-text);background-color:var(--vp-button-alt-bg)}.VPButton.alt[data-v-906d7fb4]:hover{border-color:var(--vp-button-alt-hover-border);color:var(--vp-button-alt-hover-text);background-color:var(--vp-button-alt-hover-bg)}.VPButton.alt[data-v-906d7fb4]:active{border-color:var(--vp-button-alt-active-border);color:var(--vp-button-alt-active-text);background-color:var(--vp-button-alt-active-bg)}.VPButton.sponsor[data-v-906d7fb4]{border-color:var(--vp-button-sponsor-border);color:var(--vp-button-sponsor-text);background-color:var(--vp-button-sponsor-bg)}.VPButton.sponsor[data-v-906d7fb4]:hover{border-color:var(--vp-button-sponsor-hover-border);color:var(--vp-button-sponsor-hover-text);background-color:var(--vp-button-sponsor-hover-bg)}.VPButton.sponsor[data-v-906d7fb4]:active{border-color:var(--vp-button-sponsor-active-border);color:var(--vp-button-sponsor-active-text);background-color:var(--vp-button-sponsor-active-bg)}html:not(.dark) .VPImage.dark[data-v-35a7d0b8]{display:none}.dark .VPImage.light[data-v-35a7d0b8]{display:none}.VPHero[data-v-955009fc]{margin-top:calc((var(--vp-nav-height) + var(--vp-layout-top-height, 0px)) * -1);padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px) 24px 48px}@media (min-width: 640px){.VPHero[data-v-955009fc]{padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 48px 64px}}@media (min-width: 960px){.VPHero[data-v-955009fc]{padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 64px 64px}}.container[data-v-955009fc]{display:flex;flex-direction:column;margin:0 auto;max-width:1152px}@media (min-width: 960px){.container[data-v-955009fc]{flex-direction:row}}.main[data-v-955009fc]{position:relative;z-index:10;order:2;flex-grow:1;flex-shrink:0}.VPHero.has-image .container[data-v-955009fc]{text-align:center}@media (min-width: 960px){.VPHero.has-image .container[data-v-955009fc]{text-align:left}}@media (min-width: 960px){.main[data-v-955009fc]{order:1;width:calc((100% / 3) * 2)}.VPHero.has-image .main[data-v-955009fc]{max-width:592px}}.name[data-v-955009fc],.text[data-v-955009fc]{max-width:392px;letter-spacing:-.4px;line-height:40px;font-size:32px;font-weight:700;white-space:pre-wrap}.VPHero.has-image .name[data-v-955009fc],.VPHero.has-image .text[data-v-955009fc]{margin:0 auto}.name[data-v-955009fc]{color:var(--vp-home-hero-name-color)}.clip[data-v-955009fc]{background:var(--vp-home-hero-name-background);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:var(--vp-home-hero-name-color)}@media (min-width: 640px){.name[data-v-955009fc],.text[data-v-955009fc]{max-width:576px;line-height:56px;font-size:48px}}@media (min-width: 960px){.name[data-v-955009fc],.text[data-v-955009fc]{line-height:64px;font-size:56px}.VPHero.has-image .name[data-v-955009fc],.VPHero.has-image .text[data-v-955009fc]{margin:0}}.tagline[data-v-955009fc]{padding-top:8px;max-width:392px;line-height:28px;font-size:18px;font-weight:500;white-space:pre-wrap;color:var(--vp-c-text-2)}.VPHero.has-image .tagline[data-v-955009fc]{margin:0 auto}@media (min-width: 640px){.tagline[data-v-955009fc]{padding-top:12px;max-width:576px;line-height:32px;font-size:20px}}@media (min-width: 960px){.tagline[data-v-955009fc]{line-height:36px;font-size:24px}.VPHero.has-image .tagline[data-v-955009fc]{margin:0}}.actions[data-v-955009fc]{display:flex;flex-wrap:wrap;margin:-6px;padding-top:24px}.VPHero.has-image .actions[data-v-955009fc]{justify-content:center}@media (min-width: 640px){.actions[data-v-955009fc]{padding-top:32px}}@media (min-width: 960px){.VPHero.has-image .actions[data-v-955009fc]{justify-content:flex-start}}.action[data-v-955009fc]{flex-shrink:0;padding:6px}.image[data-v-955009fc]{order:1;margin:-76px -24px -48px}@media (min-width: 640px){.image[data-v-955009fc]{margin:-108px -24px -48px}}@media (min-width: 960px){.image[data-v-955009fc]{flex-grow:1;order:2;margin:0;min-height:100%}}.image-container[data-v-955009fc]{position:relative;margin:0 auto;width:320px;height:320px}@media (min-width: 640px){.image-container[data-v-955009fc]{width:392px;height:392px}}@media (min-width: 960px){.image-container[data-v-955009fc]{display:flex;justify-content:center;align-items:center;width:100%;height:100%;transform:translate(-32px,-32px)}}.image-bg[data-v-955009fc]{position:absolute;top:50%;left:50%;border-radius:50%;width:192px;height:192px;background-image:var(--vp-home-hero-image-background-image);filter:var(--vp-home-hero-image-filter);transform:translate(-50%,-50%)}@media (min-width: 640px){.image-bg[data-v-955009fc]{width:256px;height:256px}}@media (min-width: 960px){.image-bg[data-v-955009fc]{width:320px;height:320px}}[data-v-955009fc] .image-src{position:absolute;top:50%;left:50%;max-width:192px;max-height:192px;transform:translate(-50%,-50%)}@media (min-width: 640px){[data-v-955009fc] .image-src{max-width:256px;max-height:256px}}@media (min-width: 960px){[data-v-955009fc] .image-src{max-width:320px;max-height:320px}}.VPFeature[data-v-f5e9645b]{display:block;border:1px solid var(--vp-c-bg-soft);border-radius:12px;height:100%;background-color:var(--vp-c-bg-soft);transition:border-color .25s,background-color .25s}.VPFeature.link[data-v-f5e9645b]:hover{border-color:var(--vp-c-brand-1)}.box[data-v-f5e9645b]{display:flex;flex-direction:column;padding:24px;height:100%}.box[data-v-f5e9645b]>.VPImage{margin-bottom:20px}.icon[data-v-f5e9645b]{display:flex;justify-content:center;align-items:center;margin-bottom:20px;border-radius:6px;background-color:var(--vp-c-default-soft);width:48px;height:48px;font-size:24px;transition:background-color .25s}.title[data-v-f5e9645b]{line-height:24px;font-size:16px;font-weight:600}.details[data-v-f5e9645b]{flex-grow:1;padding-top:8px;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.link-text[data-v-f5e9645b]{padding-top:8px}.link-text-value[data-v-f5e9645b]{display:flex;align-items:center;font-size:14px;font-weight:500;color:var(--vp-c-brand-1)}.link-text-icon[data-v-f5e9645b]{margin-left:6px}.VPFeatures[data-v-d0a190d7]{position:relative;padding:0 24px}@media (min-width: 640px){.VPFeatures[data-v-d0a190d7]{padding:0 48px}}@media (min-width: 960px){.VPFeatures[data-v-d0a190d7]{padding:0 64px}}.container[data-v-d0a190d7]{margin:0 auto;max-width:1152px}.items[data-v-d0a190d7]{display:flex;flex-wrap:wrap;margin:-8px}.item[data-v-d0a190d7]{padding:8px;width:100%}@media (min-width: 640px){.item.grid-2[data-v-d0a190d7],.item.grid-4[data-v-d0a190d7],.item.grid-6[data-v-d0a190d7]{width:50%}}@media (min-width: 768px){.item.grid-2[data-v-d0a190d7],.item.grid-4[data-v-d0a190d7]{width:50%}.item.grid-3[data-v-d0a190d7],.item.grid-6[data-v-d0a190d7]{width:calc(100% / 3)}}@media (min-width: 960px){.item.grid-4[data-v-d0a190d7]{width:25%}}.container[data-v-7a48a447]{margin:auto;width:100%;max-width:1280px;padding:0 24px}@media (min-width: 640px){.container[data-v-7a48a447]{padding:0 48px}}@media (min-width: 960px){.container[data-v-7a48a447]{width:100%;padding:0 64px}}.vp-doc[data-v-7a48a447] .VPHomeSponsors,.vp-doc[data-v-7a48a447] .VPTeamPage{margin-left:var(--vp-offset, calc(50% - 50vw) );margin-right:var(--vp-offset, calc(50% - 50vw) )}.vp-doc[data-v-7a48a447] .VPHomeSponsors h2{border-top:none;letter-spacing:normal}.vp-doc[data-v-7a48a447] .VPHomeSponsors a,.vp-doc[data-v-7a48a447] .VPTeamPage a{text-decoration:none}.VPHome[data-v-cbb6ec48]{margin-bottom:96px}@media (min-width: 768px){.VPHome[data-v-cbb6ec48]{margin-bottom:128px}}.VPContent[data-v-91765379]{flex-grow:1;flex-shrink:0;margin:var(--vp-layout-top-height, 0px) auto 0;width:100%}.VPContent.is-home[data-v-91765379]{width:100%;max-width:100%}.VPContent.has-sidebar[data-v-91765379]{margin:0}@media (min-width: 960px){.VPContent[data-v-91765379]{padding-top:var(--vp-nav-height)}.VPContent.has-sidebar[data-v-91765379]{margin:var(--vp-layout-top-height, 0px) 0 0;padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPContent.has-sidebar[data-v-91765379]{padding-right:calc((100vw - var(--vp-layout-max-width)) / 2);padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.VPFooter[data-v-c970a860]{position:relative;z-index:var(--vp-z-index-footer);border-top:1px solid var(--vp-c-gutter);padding:32px 24px;background-color:var(--vp-c-bg)}.VPFooter.has-sidebar[data-v-c970a860]{display:none}.VPFooter[data-v-c970a860] a{text-decoration-line:underline;text-underline-offset:2px;transition:color .25s}.VPFooter[data-v-c970a860] a:hover{color:var(--vp-c-text-1)}@media (min-width: 768px){.VPFooter[data-v-c970a860]{padding:32px}}.container[data-v-c970a860]{margin:0 auto;max-width:var(--vp-layout-max-width);text-align:center}.message[data-v-c970a860],.copyright[data-v-c970a860]{line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.VPLocalNavOutlineDropdown[data-v-bc9dc845]{padding:12px 20px 11px}@media (min-width: 960px){.VPLocalNavOutlineDropdown[data-v-bc9dc845]{padding:12px 36px 11px}}.VPLocalNavOutlineDropdown button[data-v-bc9dc845]{display:block;font-size:12px;font-weight:500;line-height:24px;color:var(--vp-c-text-2);transition:color .5s;position:relative}.VPLocalNavOutlineDropdown button[data-v-bc9dc845]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPLocalNavOutlineDropdown button.open[data-v-bc9dc845]{color:var(--vp-c-text-1)}.icon[data-v-bc9dc845]{display:inline-block;vertical-align:middle;margin-left:2px;font-size:14px;transform:rotate(0);transition:transform .25s}@media (min-width: 960px){.VPLocalNavOutlineDropdown button[data-v-bc9dc845]{font-size:14px}.icon[data-v-bc9dc845]{font-size:16px}}.open>.icon[data-v-bc9dc845]{transform:rotate(90deg)}.items[data-v-bc9dc845]{position:absolute;top:40px;right:16px;left:16px;display:grid;gap:1px;border:1px solid var(--vp-c-border);border-radius:8px;background-color:var(--vp-c-gutter);max-height:calc(var(--vp-vh, 100vh) - 86px);overflow:hidden auto;box-shadow:var(--vp-shadow-3)}@media (min-width: 960px){.items[data-v-bc9dc845]{right:auto;left:calc(var(--vp-sidebar-width) + 32px);width:320px}}.header[data-v-bc9dc845]{background-color:var(--vp-c-bg-soft)}.top-link[data-v-bc9dc845]{display:block;padding:0 16px;line-height:48px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1)}.outline[data-v-bc9dc845]{padding:8px 0;background-color:var(--vp-c-bg-soft)}.flyout-enter-active[data-v-bc9dc845]{transition:all .2s ease-out}.flyout-leave-active[data-v-bc9dc845]{transition:all .15s ease-in}.flyout-enter-from[data-v-bc9dc845],.flyout-leave-to[data-v-bc9dc845]{opacity:0;transform:translateY(-16px)}.VPLocalNav[data-v-070ab83d]{position:sticky;top:0;left:0;z-index:var(--vp-z-index-local-nav);border-bottom:1px solid var(--vp-c-gutter);padding-top:var(--vp-layout-top-height, 0px);width:100%;background-color:var(--vp-local-nav-bg-color)}.VPLocalNav.fixed[data-v-070ab83d]{position:fixed}@media (min-width: 960px){.VPLocalNav[data-v-070ab83d]{top:var(--vp-nav-height)}.VPLocalNav.has-sidebar[data-v-070ab83d]{padding-left:var(--vp-sidebar-width)}.VPLocalNav.empty[data-v-070ab83d]{display:none}}@media (min-width: 1280px){.VPLocalNav[data-v-070ab83d]{display:none}}@media (min-width: 1440px){.VPLocalNav.has-sidebar[data-v-070ab83d]{padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.container[data-v-070ab83d]{display:flex;justify-content:space-between;align-items:center}.menu[data-v-070ab83d]{display:flex;align-items:center;padding:12px 24px 11px;line-height:24px;font-size:12px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.menu[data-v-070ab83d]:hover{color:var(--vp-c-text-1);transition:color .25s}@media (min-width: 768px){.menu[data-v-070ab83d]{padding:0 32px}}@media (min-width: 960px){.menu[data-v-070ab83d]{display:none}}.menu-icon[data-v-070ab83d]{margin-right:8px;font-size:14px}.VPOutlineDropdown[data-v-070ab83d]{padding:12px 24px 11px}@media (min-width: 768px){.VPOutlineDropdown[data-v-070ab83d]{padding:12px 32px 11px}}.VPSwitch[data-v-4a1c76db]{position:relative;border-radius:11px;display:block;width:40px;height:22px;flex-shrink:0;border:1px solid var(--vp-input-border-color);background-color:var(--vp-input-switch-bg-color);transition:border-color .25s!important}.VPSwitch[data-v-4a1c76db]:hover{border-color:var(--vp-c-brand-1)}.check[data-v-4a1c76db]{position:absolute;top:1px;left:1px;width:18px;height:18px;border-radius:50%;background-color:var(--vp-c-neutral-inverse);box-shadow:var(--vp-shadow-1);transition:transform .25s!important}.icon[data-v-4a1c76db]{position:relative;display:block;width:18px;height:18px;border-radius:50%;overflow:hidden}.icon[data-v-4a1c76db] [class^=vpi-]{position:absolute;top:3px;left:3px;width:12px;height:12px;color:var(--vp-c-text-2)}.dark .icon[data-v-4a1c76db] [class^=vpi-]{color:var(--vp-c-text-1);transition:opacity .25s!important}.sun[data-v-e40a8bb6]{opacity:1}.moon[data-v-e40a8bb6],.dark .sun[data-v-e40a8bb6]{opacity:0}.dark .moon[data-v-e40a8bb6]{opacity:1}.dark .VPSwitchAppearance[data-v-e40a8bb6] .check{transform:translate(18px)}.VPNavBarAppearance[data-v-af096f4a]{display:none}@media (min-width: 1280px){.VPNavBarAppearance[data-v-af096f4a]{display:flex;align-items:center}}.VPMenuGroup+.VPMenuLink[data-v-acbfed09]{margin:12px -12px 0;border-top:1px solid var(--vp-c-divider);padding:12px 12px 0}.link[data-v-acbfed09]{display:block;border-radius:6px;padding:0 12px;line-height:32px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);white-space:nowrap;transition:background-color .25s,color .25s}.link[data-v-acbfed09]:hover{color:var(--vp-c-brand-1);background-color:var(--vp-c-default-soft)}.link.active[data-v-acbfed09]{color:var(--vp-c-brand-1)}.VPMenuGroup[data-v-48c802d0]{margin:12px -12px 0;border-top:1px solid var(--vp-c-divider);padding:12px 12px 0}.VPMenuGroup[data-v-48c802d0]:first-child{margin-top:0;border-top:0;padding-top:0}.VPMenuGroup+.VPMenuGroup[data-v-48c802d0]{margin-top:12px;border-top:1px solid var(--vp-c-divider)}.title[data-v-48c802d0]{padding:0 12px;line-height:32px;font-size:14px;font-weight:600;color:var(--vp-c-text-2);white-space:nowrap;transition:color .25s}.VPMenu[data-v-7dd3104a]{border-radius:12px;padding:12px;min-width:128px;border:1px solid var(--vp-c-divider);background-color:var(--vp-c-bg-elv);box-shadow:var(--vp-shadow-3);transition:background-color .5s;max-height:calc(100vh - var(--vp-nav-height));overflow-y:auto}.VPMenu[data-v-7dd3104a] .group{margin:0 -12px;padding:0 12px 12px}.VPMenu[data-v-7dd3104a] .group+.group{border-top:1px solid var(--vp-c-divider);padding:11px 12px 12px}.VPMenu[data-v-7dd3104a] .group:last-child{padding-bottom:0}.VPMenu[data-v-7dd3104a] .group+.item{border-top:1px solid var(--vp-c-divider);padding:11px 16px 0}.VPMenu[data-v-7dd3104a] .item{padding:0 16px;white-space:nowrap}.VPMenu[data-v-7dd3104a] .label{flex-grow:1;line-height:28px;font-size:12px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.VPMenu[data-v-7dd3104a] .action{padding-left:24px}.VPFlyout[data-v-04f5c5e9]{position:relative}.VPFlyout[data-v-04f5c5e9]:hover{color:var(--vp-c-brand-1);transition:color .25s}.VPFlyout:hover .text[data-v-04f5c5e9]{color:var(--vp-c-text-2)}.VPFlyout:hover .icon[data-v-04f5c5e9]{fill:var(--vp-c-text-2)}.VPFlyout.active .text[data-v-04f5c5e9]{color:var(--vp-c-brand-1)}.VPFlyout.active:hover .text[data-v-04f5c5e9]{color:var(--vp-c-brand-2)}.button[aria-expanded=false]+.menu[data-v-04f5c5e9]{opacity:0;visibility:hidden;transform:translateY(0)}.VPFlyout:hover .menu[data-v-04f5c5e9],.button[aria-expanded=true]+.menu[data-v-04f5c5e9]{opacity:1;visibility:visible;transform:translateY(0)}.button[data-v-04f5c5e9]{display:flex;align-items:center;padding:0 12px;height:var(--vp-nav-height);color:var(--vp-c-text-1);transition:color .5s}.text[data-v-04f5c5e9]{display:flex;align-items:center;line-height:var(--vp-nav-height);font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.option-icon[data-v-04f5c5e9]{margin-right:0;font-size:16px}.text-icon[data-v-04f5c5e9]{margin-left:4px;font-size:14px}.icon[data-v-04f5c5e9]{font-size:20px;transition:fill .25s}.menu[data-v-04f5c5e9]{position:absolute;top:calc(var(--vp-nav-height) / 2 + 20px);right:0;opacity:0;visibility:hidden;transition:opacity .25s,visibility .25s,transform .25s}.VPSocialLink[data-v-717b8b75]{display:flex;justify-content:center;align-items:center;width:36px;height:36px;color:var(--vp-c-text-2);transition:color .5s}.VPSocialLink[data-v-717b8b75]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPSocialLink[data-v-717b8b75]>svg,.VPSocialLink[data-v-717b8b75]>[class^=vpi-social-]{width:20px;height:20px;fill:currentColor}.VPSocialLinks[data-v-ee7a9424]{display:flex;justify-content:center}.VPNavBarExtra[data-v-925effce]{display:none;margin-right:-12px}@media (min-width: 768px){.VPNavBarExtra[data-v-925effce]{display:block}}@media (min-width: 1280px){.VPNavBarExtra[data-v-925effce]{display:none}}.trans-title[data-v-925effce]{padding:0 24px 0 12px;line-height:32px;font-size:14px;font-weight:700;color:var(--vp-c-text-1)}.item.appearance[data-v-925effce],.item.social-links[data-v-925effce]{display:flex;align-items:center;padding:0 12px}.item.appearance[data-v-925effce]{min-width:176px}.appearance-action[data-v-925effce]{margin-right:-2px}.social-links-list[data-v-925effce]{margin:-4px -8px}.VPNavBarHamburger[data-v-5dea55bf]{display:flex;justify-content:center;align-items:center;width:48px;height:var(--vp-nav-height)}@media (min-width: 768px){.VPNavBarHamburger[data-v-5dea55bf]{display:none}}.container[data-v-5dea55bf]{position:relative;width:16px;height:14px;overflow:hidden}.VPNavBarHamburger:hover .top[data-v-5dea55bf]{top:0;left:0;transform:translate(4px)}.VPNavBarHamburger:hover .middle[data-v-5dea55bf]{top:6px;left:0;transform:translate(0)}.VPNavBarHamburger:hover .bottom[data-v-5dea55bf]{top:12px;left:0;transform:translate(8px)}.VPNavBarHamburger.active .top[data-v-5dea55bf]{top:6px;transform:translate(0) rotate(225deg)}.VPNavBarHamburger.active .middle[data-v-5dea55bf]{top:6px;transform:translate(16px)}.VPNavBarHamburger.active .bottom[data-v-5dea55bf]{top:6px;transform:translate(0) rotate(135deg)}.VPNavBarHamburger.active:hover .top[data-v-5dea55bf],.VPNavBarHamburger.active:hover .middle[data-v-5dea55bf],.VPNavBarHamburger.active:hover .bottom[data-v-5dea55bf]{background-color:var(--vp-c-text-2);transition:top .25s,background-color .25s,transform .25s}.top[data-v-5dea55bf],.middle[data-v-5dea55bf],.bottom[data-v-5dea55bf]{position:absolute;width:16px;height:2px;background-color:var(--vp-c-text-1);transition:top .25s,background-color .5s,transform .25s}.top[data-v-5dea55bf]{top:0;left:0;transform:translate(0)}.middle[data-v-5dea55bf]{top:6px;left:0;transform:translate(8px)}.bottom[data-v-5dea55bf]{top:12px;left:0;transform:translate(4px)}.VPNavBarMenuLink[data-v-956ec74c]{display:flex;align-items:center;padding:0 12px;line-height:var(--vp-nav-height);font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.VPNavBarMenuLink.active[data-v-956ec74c],.VPNavBarMenuLink[data-v-956ec74c]:hover{color:var(--vp-c-brand-1)}.VPNavBarMenu[data-v-e6d46098]{display:none}@media (min-width: 768px){.VPNavBarMenu[data-v-e6d46098]{display:flex}}/*! @docsearch/css 3.6.3 | MIT License | © Algolia, Inc. and contributors | https://docsearch.algolia.com */:root{--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:rgba(101,108,133,.8);--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 hsla(0,0%,100%,.5),0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px rgba(30,35,90,.4);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 rgba(30,35,90,.4);--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 rgba(69,98,155,.12)}html[data-theme=dark]{--docsearch-text-color:#f5f6f7;--docsearch-container-background:rgba(9,10,17,.8);--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 rgba(3,4,9,.3);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 rgba(3,4,9,.30196078431372547);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 rgba(73,76,106,.5),0 -4px 8px 0 rgba(0,0,0,.2);--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;display:flex;font-weight:500;height:36px;justify-content:space-between;margin:0 0 0 16px;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:none}.DocSearch-Button-Container{align-items:center;display:flex}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;position:relative;padding:0 0 2px;border:0;top:-1px;width:20px}.DocSearch-Button-Key--pressed{transform:translate3d(0,1px,0);box-shadow:var(--docsearch-key-pressed-shadow)}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder{display:none}}.DocSearch--active{overflow:hidden!important}.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a{text-decoration:none}.DocSearch-Link{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:none;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator{display:none}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}}.DocSearch-Reset{animation:fade-in .1s ease-in forwards;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;padding:2px;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Cancel{display:none}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:transparent}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{color:var(--docsearch-muted-color);display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--deleting{transition:none}}.DocSearch-Hit--deleting{opacity:0;transition:all .25s linear}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--favoriting{transition:none}}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:all .25s linear;transition-delay:.25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;stroke-width:var(--docsearch-icon-stroke-width);width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit[aria-selected=true] mark{text-decoration:underline}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color);stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{transition:none}}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:none;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li{align-items:center;display:flex}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:2px;box-shadow:var(--docsearch-key-shadow);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;color:var(--docsearch-muted-color);border:0;width:20px}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@media (max-width:768px){:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Dropdown{max-height:calc(var(--docsearch-vh, 1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Cancel{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:none;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}[class*=DocSearch]{--docsearch-primary-color: var(--vp-c-brand-1);--docsearch-highlight-color: var(--docsearch-primary-color);--docsearch-text-color: var(--vp-c-text-1);--docsearch-muted-color: var(--vp-c-text-2);--docsearch-searchbox-shadow: none;--docsearch-searchbox-background: transparent;--docsearch-searchbox-focus-background: transparent;--docsearch-key-gradient: transparent;--docsearch-key-shadow: none;--docsearch-modal-background: var(--vp-c-bg-soft);--docsearch-footer-background: var(--vp-c-bg)}.dark [class*=DocSearch]{--docsearch-modal-shadow: none;--docsearch-footer-shadow: none;--docsearch-logo-color: var(--vp-c-text-2);--docsearch-hit-background: var(--vp-c-default-soft);--docsearch-hit-color: var(--vp-c-text-2);--docsearch-hit-shadow: none}.DocSearch-Button{display:flex;justify-content:center;align-items:center;margin:0;padding:0;width:48px;height:55px;background:transparent;transition:border-color .25s}.DocSearch-Button:hover{background:transparent}.DocSearch-Button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}.DocSearch-Button-Key--pressed{transform:none;box-shadow:none}.DocSearch-Button:focus:not(:focus-visible){outline:none!important}@media (min-width: 768px){.DocSearch-Button{justify-content:flex-start;border:1px solid transparent;border-radius:8px;padding:0 10px 0 12px;width:100%;height:40px;background-color:var(--vp-c-bg-alt)}.DocSearch-Button:hover{border-color:var(--vp-c-brand-1);background:var(--vp-c-bg-alt)}}.DocSearch-Button .DocSearch-Button-Container{display:flex;align-items:center}.DocSearch-Button .DocSearch-Search-Icon{position:relative;width:16px;height:16px;color:var(--vp-c-text-1);fill:currentColor;transition:color .5s}.DocSearch-Button:hover .DocSearch-Search-Icon{color:var(--vp-c-text-1)}@media (min-width: 768px){.DocSearch-Button .DocSearch-Search-Icon{top:1px;margin-right:8px;width:14px;height:14px;color:var(--vp-c-text-2)}}.DocSearch-Button .DocSearch-Button-Placeholder{display:none;margin-top:2px;padding:0 16px 0 0;font-size:13px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.DocSearch-Button:hover .DocSearch-Button-Placeholder{color:var(--vp-c-text-1)}@media (min-width: 768px){.DocSearch-Button .DocSearch-Button-Placeholder{display:inline-block}}.DocSearch-Button .DocSearch-Button-Keys{direction:ltr;display:none;min-width:auto}@media (min-width: 768px){.DocSearch-Button .DocSearch-Button-Keys{display:flex;align-items:center}}.DocSearch-Button .DocSearch-Button-Key{display:block;margin:2px 0 0;border:1px solid var(--vp-c-divider);border-right:none;border-radius:4px 0 0 4px;padding-left:6px;min-width:0;width:auto;height:22px;line-height:22px;font-family:var(--vp-font-family-base);font-size:12px;font-weight:500;transition:color .5s,border-color .5s}.DocSearch-Button .DocSearch-Button-Key+.DocSearch-Button-Key{border-right:1px solid var(--vp-c-divider);border-left:none;border-radius:0 4px 4px 0;padding-left:2px;padding-right:6px}.DocSearch-Button .DocSearch-Button-Key:first-child{font-size:0!important}.DocSearch-Button .DocSearch-Button-Key:first-child:after{content:"Ctrl";font-size:12px;letter-spacing:normal;color:var(--docsearch-muted-color)}.mac .DocSearch-Button .DocSearch-Button-Key:first-child:after{content:"⌘"}.DocSearch-Button .DocSearch-Button-Key:first-child>*{display:none}.DocSearch-Search-Icon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' stroke-width='1.6' viewBox='0 0 20 20'%3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' d='m14.386 14.386 4.088 4.088-4.088-4.088A7.533 7.533 0 1 1 3.733 3.733a7.533 7.533 0 0 1 10.653 10.653z'/%3E%3C/svg%3E")}.VPNavBarSearch{display:flex;align-items:center}@media (min-width: 768px){.VPNavBarSearch{flex-grow:1;padding-left:24px}}@media (min-width: 960px){.VPNavBarSearch{padding-left:32px}}.dark .DocSearch-Footer{border-top:1px solid var(--vp-c-divider)}.DocSearch-Form{border:1px solid var(--vp-c-brand-1);background-color:var(--vp-c-white)}.dark .DocSearch-Form{background-color:var(--vp-c-default-soft)}.DocSearch-Screen-Icon>svg{margin:auto}.VPNavBarSocialLinks[data-v-164c457f]{display:none}@media (min-width: 1280px){.VPNavBarSocialLinks[data-v-164c457f]{display:flex;align-items:center}}.title[data-v-0f4f798b]{display:flex;align-items:center;border-bottom:1px solid transparent;width:100%;height:var(--vp-nav-height);font-size:16px;font-weight:600;color:var(--vp-c-text-1);transition:opacity .25s}@media (min-width: 960px){.title[data-v-0f4f798b]{flex-shrink:0}.VPNavBarTitle.has-sidebar .title[data-v-0f4f798b]{border-bottom-color:var(--vp-c-divider)}}[data-v-0f4f798b] .logo{margin-right:8px;height:var(--vp-nav-logo-height)}.VPNavBarTranslations[data-v-c80d9ad0]{display:none}@media (min-width: 1280px){.VPNavBarTranslations[data-v-c80d9ad0]{display:flex;align-items:center}}.title[data-v-c80d9ad0]{padding:0 24px 0 12px;line-height:32px;font-size:14px;font-weight:700;color:var(--vp-c-text-1)}.VPNavBar[data-v-822684d1]{position:relative;height:var(--vp-nav-height);pointer-events:none;white-space:nowrap;transition:background-color .25s}.VPNavBar.screen-open[data-v-822684d1]{transition:none;background-color:var(--vp-nav-bg-color);border-bottom:1px solid var(--vp-c-divider)}.VPNavBar[data-v-822684d1]:not(.home){background-color:var(--vp-nav-bg-color)}@media (min-width: 960px){.VPNavBar[data-v-822684d1]:not(.home){background-color:transparent}.VPNavBar[data-v-822684d1]:not(.has-sidebar):not(.home.top){background-color:var(--vp-nav-bg-color)}}.wrapper[data-v-822684d1]{padding:0 8px 0 24px}@media (min-width: 768px){.wrapper[data-v-822684d1]{padding:0 32px}}@media (min-width: 960px){.VPNavBar.has-sidebar .wrapper[data-v-822684d1]{padding:0}}.container[data-v-822684d1]{display:flex;justify-content:space-between;margin:0 auto;max-width:calc(var(--vp-layout-max-width) - 64px);height:var(--vp-nav-height);pointer-events:none}.container>.title[data-v-822684d1],.container>.content[data-v-822684d1]{pointer-events:none}.container[data-v-822684d1] *{pointer-events:auto}@media (min-width: 960px){.VPNavBar.has-sidebar .container[data-v-822684d1]{max-width:100%}}.title[data-v-822684d1]{flex-shrink:0;height:calc(var(--vp-nav-height) - 1px);transition:background-color .5s}@media (min-width: 960px){.VPNavBar.has-sidebar .title[data-v-822684d1]{position:absolute;top:0;left:0;z-index:2;padding:0 32px;width:var(--vp-sidebar-width);height:var(--vp-nav-height);background-color:transparent}}@media (min-width: 1440px){.VPNavBar.has-sidebar .title[data-v-822684d1]{padding-left:max(32px,calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));width:calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px)}}.content[data-v-822684d1]{flex-grow:1}@media (min-width: 960px){.VPNavBar.has-sidebar .content[data-v-822684d1]{position:relative;z-index:1;padding-right:32px;padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPNavBar.has-sidebar .content[data-v-822684d1]{padding-right:calc((100vw - var(--vp-layout-max-width)) / 2 + 32px);padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.content-body[data-v-822684d1]{display:flex;justify-content:flex-end;align-items:center;height:var(--vp-nav-height);transition:background-color .5s}@media (min-width: 960px){.VPNavBar:not(.home.top) .content-body[data-v-822684d1]{position:relative;background-color:var(--vp-nav-bg-color)}.VPNavBar:not(.has-sidebar):not(.home.top) .content-body[data-v-822684d1]{background-color:transparent}}@media (max-width: 767px){.content-body[data-v-822684d1]{column-gap:.5rem}}.menu+.translations[data-v-822684d1]:before,.menu+.appearance[data-v-822684d1]:before,.menu+.social-links[data-v-822684d1]:before,.translations+.appearance[data-v-822684d1]:before,.appearance+.social-links[data-v-822684d1]:before{margin-right:8px;margin-left:8px;width:1px;height:24px;background-color:var(--vp-c-divider);content:""}.menu+.appearance[data-v-822684d1]:before,.translations+.appearance[data-v-822684d1]:before{margin-right:16px}.appearance+.social-links[data-v-822684d1]:before{margin-left:16px}.social-links[data-v-822684d1]{margin-right:-8px}.divider[data-v-822684d1]{width:100%;height:1px}@media (min-width: 960px){.VPNavBar.has-sidebar .divider[data-v-822684d1]{padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPNavBar.has-sidebar .divider[data-v-822684d1]{padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.divider-line[data-v-822684d1]{width:100%;height:1px;transition:background-color .5s}.VPNavBar:not(.home) .divider-line[data-v-822684d1]{background-color:var(--vp-c-gutter)}@media (min-width: 960px){.VPNavBar:not(.home.top) .divider-line[data-v-822684d1]{background-color:var(--vp-c-gutter)}.VPNavBar:not(.has-sidebar):not(.home.top) .divider[data-v-822684d1]{background-color:var(--vp-c-gutter)}}.VPNavScreenAppearance[data-v-ffb44008]{display:flex;justify-content:space-between;align-items:center;border-radius:8px;padding:12px 14px 12px 16px;background-color:var(--vp-c-bg-soft)}.text[data-v-ffb44008]{line-height:24px;font-size:12px;font-weight:500;color:var(--vp-c-text-2)}.VPNavScreenMenuLink[data-v-735512b8]{display:block;border-bottom:1px solid var(--vp-c-divider);padding:12px 0 11px;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:border-color .25s,color .25s}.VPNavScreenMenuLink[data-v-735512b8]:hover{color:var(--vp-c-brand-1)}.VPNavScreenMenuGroupLink[data-v-372ae7c0]{display:block;margin-left:12px;line-height:32px;font-size:14px;font-weight:400;color:var(--vp-c-text-1);transition:color .25s}.VPNavScreenMenuGroupLink[data-v-372ae7c0]:hover{color:var(--vp-c-brand-1)}.VPNavScreenMenuGroupSection[data-v-4b8941ac]{display:block}.title[data-v-4b8941ac]{line-height:32px;font-size:13px;font-weight:700;color:var(--vp-c-text-2);transition:color .25s}.VPNavScreenMenuGroup[data-v-875057a5]{border-bottom:1px solid var(--vp-c-divider);height:48px;overflow:hidden;transition:border-color .5s}.VPNavScreenMenuGroup .items[data-v-875057a5]{visibility:hidden}.VPNavScreenMenuGroup.open .items[data-v-875057a5]{visibility:visible}.VPNavScreenMenuGroup.open[data-v-875057a5]{padding-bottom:10px;height:auto}.VPNavScreenMenuGroup.open .button[data-v-875057a5]{padding-bottom:6px;color:var(--vp-c-brand-1)}.VPNavScreenMenuGroup.open .button-icon[data-v-875057a5]{transform:rotate(45deg)}.button[data-v-875057a5]{display:flex;justify-content:space-between;align-items:center;padding:12px 4px 11px 0;width:100%;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.button[data-v-875057a5]:hover{color:var(--vp-c-brand-1)}.button-icon[data-v-875057a5]{transition:transform .25s}.group[data-v-875057a5]:first-child{padding-top:0}.group+.group[data-v-875057a5],.group+.item[data-v-875057a5]{padding-top:4px}.VPNavScreenTranslations[data-v-362991c2]{height:24px;overflow:hidden}.VPNavScreenTranslations.open[data-v-362991c2]{height:auto}.title[data-v-362991c2]{display:flex;align-items:center;font-size:14px;font-weight:500;color:var(--vp-c-text-1)}.icon[data-v-362991c2]{font-size:16px}.icon.lang[data-v-362991c2]{margin-right:8px}.icon.chevron[data-v-362991c2]{margin-left:4px}.list[data-v-362991c2]{padding:4px 0 0 24px}.link[data-v-362991c2]{line-height:32px;font-size:13px;color:var(--vp-c-text-1)}.VPNavScreen[data-v-833aabba]{position:fixed;top:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px));right:0;bottom:0;left:0;padding:0 32px;width:100%;background-color:var(--vp-nav-screen-bg-color);overflow-y:auto;transition:background-color .25s;pointer-events:auto}.VPNavScreen.fade-enter-active[data-v-833aabba],.VPNavScreen.fade-leave-active[data-v-833aabba]{transition:opacity .25s}.VPNavScreen.fade-enter-active .container[data-v-833aabba],.VPNavScreen.fade-leave-active .container[data-v-833aabba]{transition:transform .25s ease}.VPNavScreen.fade-enter-from[data-v-833aabba],.VPNavScreen.fade-leave-to[data-v-833aabba]{opacity:0}.VPNavScreen.fade-enter-from .container[data-v-833aabba],.VPNavScreen.fade-leave-to .container[data-v-833aabba]{transform:translateY(-8px)}@media (min-width: 768px){.VPNavScreen[data-v-833aabba]{display:none}}.container[data-v-833aabba]{margin:0 auto;padding:24px 0 96px;max-width:288px}.menu+.translations[data-v-833aabba],.menu+.appearance[data-v-833aabba],.translations+.appearance[data-v-833aabba]{margin-top:24px}.menu+.social-links[data-v-833aabba]{margin-top:16px}.appearance+.social-links[data-v-833aabba]{margin-top:16px}.VPNav[data-v-f1e365da]{position:relative;top:var(--vp-layout-top-height, 0px);left:0;z-index:var(--vp-z-index-nav);width:100%;pointer-events:none;transition:background-color .5s}@media (min-width: 960px){.VPNav[data-v-f1e365da]{position:fixed}}.VPSidebarItem.level-0[data-v-196b2e5f]{padding-bottom:24px}.VPSidebarItem.collapsed.level-0[data-v-196b2e5f]{padding-bottom:10px}.item[data-v-196b2e5f]{position:relative;display:flex;width:100%}.VPSidebarItem.collapsible>.item[data-v-196b2e5f]{cursor:pointer}.indicator[data-v-196b2e5f]{position:absolute;top:6px;bottom:6px;left:-17px;width:2px;border-radius:2px;transition:background-color .25s}.VPSidebarItem.level-2.is-active>.item>.indicator[data-v-196b2e5f],.VPSidebarItem.level-3.is-active>.item>.indicator[data-v-196b2e5f],.VPSidebarItem.level-4.is-active>.item>.indicator[data-v-196b2e5f],.VPSidebarItem.level-5.is-active>.item>.indicator[data-v-196b2e5f]{background-color:var(--vp-c-brand-1)}.link[data-v-196b2e5f]{display:flex;align-items:center;flex-grow:1}.text[data-v-196b2e5f]{flex-grow:1;padding:4px 0;line-height:24px;font-size:14px;transition:color .25s}.VPSidebarItem.level-0 .text[data-v-196b2e5f]{font-weight:700;color:var(--vp-c-text-1)}.VPSidebarItem.level-1 .text[data-v-196b2e5f],.VPSidebarItem.level-2 .text[data-v-196b2e5f],.VPSidebarItem.level-3 .text[data-v-196b2e5f],.VPSidebarItem.level-4 .text[data-v-196b2e5f],.VPSidebarItem.level-5 .text[data-v-196b2e5f]{font-weight:500;color:var(--vp-c-text-2)}.VPSidebarItem.level-0.is-link>.item>.link:hover .text[data-v-196b2e5f],.VPSidebarItem.level-1.is-link>.item>.link:hover .text[data-v-196b2e5f],.VPSidebarItem.level-2.is-link>.item>.link:hover .text[data-v-196b2e5f],.VPSidebarItem.level-3.is-link>.item>.link:hover .text[data-v-196b2e5f],.VPSidebarItem.level-4.is-link>.item>.link:hover .text[data-v-196b2e5f],.VPSidebarItem.level-5.is-link>.item>.link:hover .text[data-v-196b2e5f]{color:var(--vp-c-brand-1)}.VPSidebarItem.level-0.has-active>.item>.text[data-v-196b2e5f],.VPSidebarItem.level-1.has-active>.item>.text[data-v-196b2e5f],.VPSidebarItem.level-2.has-active>.item>.text[data-v-196b2e5f],.VPSidebarItem.level-3.has-active>.item>.text[data-v-196b2e5f],.VPSidebarItem.level-4.has-active>.item>.text[data-v-196b2e5f],.VPSidebarItem.level-5.has-active>.item>.text[data-v-196b2e5f],.VPSidebarItem.level-0.has-active>.item>.link>.text[data-v-196b2e5f],.VPSidebarItem.level-1.has-active>.item>.link>.text[data-v-196b2e5f],.VPSidebarItem.level-2.has-active>.item>.link>.text[data-v-196b2e5f],.VPSidebarItem.level-3.has-active>.item>.link>.text[data-v-196b2e5f],.VPSidebarItem.level-4.has-active>.item>.link>.text[data-v-196b2e5f],.VPSidebarItem.level-5.has-active>.item>.link>.text[data-v-196b2e5f]{color:var(--vp-c-text-1)}.VPSidebarItem.level-0.is-active>.item .link>.text[data-v-196b2e5f],.VPSidebarItem.level-1.is-active>.item .link>.text[data-v-196b2e5f],.VPSidebarItem.level-2.is-active>.item .link>.text[data-v-196b2e5f],.VPSidebarItem.level-3.is-active>.item .link>.text[data-v-196b2e5f],.VPSidebarItem.level-4.is-active>.item .link>.text[data-v-196b2e5f],.VPSidebarItem.level-5.is-active>.item .link>.text[data-v-196b2e5f]{color:var(--vp-c-brand-1)}.caret[data-v-196b2e5f]{display:flex;justify-content:center;align-items:center;margin-right:-7px;width:32px;height:32px;color:var(--vp-c-text-3);cursor:pointer;transition:color .25s;flex-shrink:0}.item:hover .caret[data-v-196b2e5f]{color:var(--vp-c-text-2)}.item:hover .caret[data-v-196b2e5f]:hover{color:var(--vp-c-text-1)}.caret-icon[data-v-196b2e5f]{font-size:18px;transform:rotate(90deg);transition:transform .25s}.VPSidebarItem.collapsed .caret-icon[data-v-196b2e5f]{transform:rotate(0)}.VPSidebarItem.level-1 .items[data-v-196b2e5f],.VPSidebarItem.level-2 .items[data-v-196b2e5f],.VPSidebarItem.level-3 .items[data-v-196b2e5f],.VPSidebarItem.level-4 .items[data-v-196b2e5f],.VPSidebarItem.level-5 .items[data-v-196b2e5f]{border-left:1px solid var(--vp-c-divider);padding-left:16px}.VPSidebarItem.collapsed .items[data-v-196b2e5f]{display:none}.no-transition[data-v-9e426adc] .caret-icon{transition:none}.group+.group[data-v-9e426adc]{border-top:1px solid var(--vp-c-divider);padding-top:10px}@media (min-width: 960px){.group[data-v-9e426adc]{padding-top:10px;width:calc(var(--vp-sidebar-width) - 64px)}}.VPSidebar[data-v-18756405]{position:fixed;top:var(--vp-layout-top-height, 0px);bottom:0;left:0;z-index:var(--vp-z-index-sidebar);padding:32px 32px 96px;width:calc(100vw - 64px);max-width:320px;background-color:var(--vp-sidebar-bg-color);opacity:0;box-shadow:var(--vp-c-shadow-3);overflow-x:hidden;overflow-y:auto;transform:translate(-100%);transition:opacity .5s,transform .25s ease;overscroll-behavior:contain}.VPSidebar.open[data-v-18756405]{opacity:1;visibility:visible;transform:translate(0);transition:opacity .25s,transform .5s cubic-bezier(.19,1,.22,1)}.dark .VPSidebar[data-v-18756405]{box-shadow:var(--vp-shadow-1)}@media (min-width: 960px){.VPSidebar[data-v-18756405]{padding-top:var(--vp-nav-height);width:var(--vp-sidebar-width);max-width:100%;background-color:var(--vp-sidebar-bg-color);opacity:1;visibility:visible;box-shadow:none;transform:translate(0)}}@media (min-width: 1440px){.VPSidebar[data-v-18756405]{padding-left:max(32px,calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));width:calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px)}}@media (min-width: 960px){.curtain[data-v-18756405]{position:sticky;top:-64px;left:0;z-index:1;margin-top:calc(var(--vp-nav-height) * -1);margin-right:-32px;margin-left:-32px;height:var(--vp-nav-height);background-color:var(--vp-sidebar-bg-color)}}.nav[data-v-18756405]{outline:0}.VPSkipLink[data-v-c3508ec8]{top:8px;left:8px;padding:8px 16px;z-index:999;border-radius:8px;font-size:12px;font-weight:700;text-decoration:none;color:var(--vp-c-brand-1);box-shadow:var(--vp-shadow-3);background-color:var(--vp-c-bg)}.VPSkipLink[data-v-c3508ec8]:focus{height:auto;width:auto;clip:auto;clip-path:none}@media (min-width: 1280px){.VPSkipLink[data-v-c3508ec8]{top:14px;left:16px}}.Layout[data-v-a9a9e638]{display:flex;flex-direction:column;min-height:100vh}.VPHomeSponsors[data-v-db81191c]{border-top:1px solid var(--vp-c-gutter);padding-top:88px!important}.VPHomeSponsors[data-v-db81191c]{margin:96px 0}@media (min-width: 768px){.VPHomeSponsors[data-v-db81191c]{margin:128px 0}}.VPHomeSponsors[data-v-db81191c]{padding:0 24px}@media (min-width: 768px){.VPHomeSponsors[data-v-db81191c]{padding:0 48px}}@media (min-width: 960px){.VPHomeSponsors[data-v-db81191c]{padding:0 64px}}.container[data-v-db81191c]{margin:0 auto;max-width:1152px}.love[data-v-db81191c]{margin:0 auto;width:fit-content;font-size:28px;color:var(--vp-c-text-3)}.icon[data-v-db81191c]{display:inline-block}.message[data-v-db81191c]{margin:0 auto;padding-top:10px;max-width:320px;text-align:center;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}.sponsors[data-v-db81191c]{padding-top:32px}.action[data-v-db81191c]{padding-top:40px;text-align:center}.VPTeamPage[data-v-c2f8e101]{margin:96px 0}@media (min-width: 768px){.VPTeamPage[data-v-c2f8e101]{margin:128px 0}}.VPHome .VPTeamPageTitle[data-v-c2f8e101-s]{border-top:1px solid var(--vp-c-gutter);padding-top:88px!important}.VPTeamPageSection+.VPTeamPageSection[data-v-c2f8e101-s],.VPTeamMembers+.VPTeamPageSection[data-v-c2f8e101-s]{margin-top:64px}.VPTeamMembers+.VPTeamMembers[data-v-c2f8e101-s]{margin-top:24px}@media (min-width: 768px){.VPTeamPageTitle+.VPTeamPageSection[data-v-c2f8e101-s]{margin-top:16px}.VPTeamPageSection+.VPTeamPageSection[data-v-c2f8e101-s],.VPTeamMembers+.VPTeamPageSection[data-v-c2f8e101-s]{margin-top:96px}}.VPTeamMembers[data-v-c2f8e101-s]{padding:0 24px}@media (min-width: 768px){.VPTeamMembers[data-v-c2f8e101-s]{padding:0 48px}}@media (min-width: 960px){.VPTeamMembers[data-v-c2f8e101-s]{padding:0 64px}}.VPTeamPageTitle[data-v-e277e15c]{padding:48px 32px;text-align:center}@media (min-width: 768px){.VPTeamPageTitle[data-v-e277e15c]{padding:64px 48px 48px}}@media (min-width: 960px){.VPTeamPageTitle[data-v-e277e15c]{padding:80px 64px 48px}}.title[data-v-e277e15c]{letter-spacing:0;line-height:44px;font-size:36px;font-weight:500}@media (min-width: 768px){.title[data-v-e277e15c]{letter-spacing:-.5px;line-height:56px;font-size:48px}}.lead[data-v-e277e15c]{margin:0 auto;max-width:512px;padding-top:12px;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}@media (min-width: 768px){.lead[data-v-e277e15c]{max-width:592px;letter-spacing:.15px;line-height:28px;font-size:20px}}.VPTeamPageSection[data-v-d43bc49d]{padding:0 32px}@media (min-width: 768px){.VPTeamPageSection[data-v-d43bc49d]{padding:0 48px}}@media (min-width: 960px){.VPTeamPageSection[data-v-d43bc49d]{padding:0 64px}}.title[data-v-d43bc49d]{position:relative;margin:0 auto;max-width:1152px;text-align:center;color:var(--vp-c-text-2)}.title-line[data-v-d43bc49d]{position:absolute;top:16px;left:0;width:100%;height:1px;background-color:var(--vp-c-divider)}.title-text[data-v-d43bc49d]{position:relative;display:inline-block;padding:0 24px;letter-spacing:0;line-height:32px;font-size:20px;font-weight:500;background-color:var(--vp-c-bg)}.lead[data-v-d43bc49d]{margin:0 auto;max-width:480px;padding-top:12px;text-align:center;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}.members[data-v-d43bc49d]{padding-top:40px}.VPTeamMembersItem[data-v-f9987cb6]{display:flex;flex-direction:column;gap:2px;border-radius:12px;width:100%;height:100%;overflow:hidden}.VPTeamMembersItem.small .profile[data-v-f9987cb6]{padding:32px}.VPTeamMembersItem.small .data[data-v-f9987cb6]{padding-top:20px}.VPTeamMembersItem.small .avatar[data-v-f9987cb6]{width:64px;height:64px}.VPTeamMembersItem.small .name[data-v-f9987cb6]{line-height:24px;font-size:16px}.VPTeamMembersItem.small .affiliation[data-v-f9987cb6]{padding-top:4px;line-height:20px;font-size:14px}.VPTeamMembersItem.small .desc[data-v-f9987cb6]{padding-top:12px;line-height:20px;font-size:14px}.VPTeamMembersItem.small .links[data-v-f9987cb6]{margin:0 -16px -20px;padding:10px 0 0}.VPTeamMembersItem.medium .profile[data-v-f9987cb6]{padding:48px 32px}.VPTeamMembersItem.medium .data[data-v-f9987cb6]{padding-top:24px;text-align:center}.VPTeamMembersItem.medium .avatar[data-v-f9987cb6]{width:96px;height:96px}.VPTeamMembersItem.medium .name[data-v-f9987cb6]{letter-spacing:.15px;line-height:28px;font-size:20px}.VPTeamMembersItem.medium .affiliation[data-v-f9987cb6]{padding-top:4px;font-size:16px}.VPTeamMembersItem.medium .desc[data-v-f9987cb6]{padding-top:16px;max-width:288px;font-size:16px}.VPTeamMembersItem.medium .links[data-v-f9987cb6]{margin:0 -16px -12px;padding:16px 12px 0}.profile[data-v-f9987cb6]{flex-grow:1;background-color:var(--vp-c-bg-soft)}.data[data-v-f9987cb6]{text-align:center}.avatar[data-v-f9987cb6]{position:relative;flex-shrink:0;margin:0 auto;border-radius:50%;box-shadow:var(--vp-shadow-3)}.avatar-img[data-v-f9987cb6]{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;object-fit:cover}.name[data-v-f9987cb6]{margin:0;font-weight:600}.affiliation[data-v-f9987cb6]{margin:0;font-weight:500;color:var(--vp-c-text-2)}.org.link[data-v-f9987cb6]{color:var(--vp-c-text-2);transition:color .25s}.org.link[data-v-f9987cb6]:hover{color:var(--vp-c-brand-1)}.desc[data-v-f9987cb6]{margin:0 auto}.desc[data-v-f9987cb6] a{font-weight:500;color:var(--vp-c-brand-1);text-decoration-style:dotted;transition:color .25s}.links[data-v-f9987cb6]{display:flex;justify-content:center;height:56px}.sp-link[data-v-f9987cb6]{display:flex;justify-content:center;align-items:center;text-align:center;padding:16px;font-size:14px;font-weight:500;color:var(--vp-c-sponsor);background-color:var(--vp-c-bg-soft);transition:color .25s,background-color .25s}.sp .sp-link.link[data-v-f9987cb6]:hover,.sp .sp-link.link[data-v-f9987cb6]:focus{outline:none;color:var(--vp-c-white);background-color:var(--vp-c-sponsor)}.sp-icon[data-v-f9987cb6]{margin-right:8px;font-size:16px}.VPTeamMembers.small .container[data-v-fba19bad]{grid-template-columns:repeat(auto-fit,minmax(224px,1fr))}.VPTeamMembers.small.count-1 .container[data-v-fba19bad]{max-width:276px}.VPTeamMembers.small.count-2 .container[data-v-fba19bad]{max-width:576px}.VPTeamMembers.small.count-3 .container[data-v-fba19bad]{max-width:876px}.VPTeamMembers.medium .container[data-v-fba19bad]{grid-template-columns:repeat(auto-fit,minmax(256px,1fr))}@media (min-width: 375px){.VPTeamMembers.medium .container[data-v-fba19bad]{grid-template-columns:repeat(auto-fit,minmax(288px,1fr))}}.VPTeamMembers.medium.count-1 .container[data-v-fba19bad]{max-width:368px}.VPTeamMembers.medium.count-2 .container[data-v-fba19bad]{max-width:760px}.container[data-v-fba19bad]{display:grid;gap:24px;margin:0 auto;max-width:1152px}.enjoyer{margin-top:.5rem;margin-bottom:0rem;border-radius:14px;padding-top:.2rem;padding-bottom:.2rem;position:relative;font-size:.9rem;font-weight:700;line-height:1.1rem;display:flex;align-items:center;justify-content:center;width:100%;gap:1rem;background-color:var(--vp-c-bg-alt);border:2px solid var(--vp-c-bg-alt);transition:border-color .5s}.enjoyer:hover{border:2px solid var(--vp-c-brand-light)}.enjoyer img{transition:transform .5s;transform:scale(1.25)}.enjoyer:hover img{transform:scale(1.75)}.enjoyer .heading{background-image:linear-gradient(120deg,#b047ff 16%,var(--vp-c-brand-lighter),var(--vp-c-brand-lighter));background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}.enjoyer .extra-info{color:var(--vp-c-text-1);opacity:0;font-size:.7rem;padding-left:.1rem;transition:opacity .5s}.enjoyer:hover .extra-info{opacity:.9}.VPVersionPicker[data-v-d483b3a6] button .text{color:var(--vp-c-text-1)!important}.VPVersionPicker[data-v-d483b3a6]:hover button .text{color:var(--vp-c-text-2)!important}:root{--vp-plugin-tabs-tab-text-color: var(--vp-c-text-2);--vp-plugin-tabs-tab-active-text-color: var(--vp-c-text-1);--vp-plugin-tabs-tab-hover-text-color: var(--vp-c-text-1);--vp-plugin-tabs-tab-bg: var(--vp-c-bg-soft);--vp-plugin-tabs-tab-divider: var(--vp-c-divider);--vp-plugin-tabs-tab-active-bar-color: var(--vp-c-brand-1)}.plugin-tabs{margin:16px 0;background-color:var(--vp-plugin-tabs-tab-bg);border-radius:8px}.plugin-tabs--tab-list{position:relative;padding:0 12px;overflow-x:auto;overflow-y:hidden}.plugin-tabs--tab-list:after{content:"";position:absolute;bottom:0;left:0;right:0;height:2px;background-color:var(--vp-plugin-tabs-tab-divider)}.plugin-tabs--tab{position:relative;padding:0 12px;line-height:48px;border-bottom:2px solid transparent;color:var(--vp-plugin-tabs-tab-text-color);font-size:14px;font-weight:500;white-space:nowrap;transition:color .25s}.plugin-tabs--tab[aria-selected=true]{color:var(--vp-plugin-tabs-tab-active-text-color)}.plugin-tabs--tab:hover{color:var(--vp-plugin-tabs-tab-hover-text-color)}.plugin-tabs--tab:after{content:"";position:absolute;bottom:-2px;left:8px;right:8px;height:2px;background-color:transparent;transition:background-color .25s;z-index:1}.plugin-tabs--tab[aria-selected=true]:after{background-color:var(--vp-plugin-tabs-tab-active-bar-color)}.plugin-tabs--content[data-v-9b0d03d2]{padding:16px}.plugin-tabs--content[data-v-9b0d03d2]>:first-child:first-child{margin-top:0}.plugin-tabs--content[data-v-9b0d03d2]>:last-child:last-child{margin-bottom:0}.plugin-tabs--content[data-v-9b0d03d2]>div[class*=language-]{border-radius:8px;margin:16px 0}:root:not(.dark) .plugin-tabs--content[data-v-9b0d03d2] div[class*=language-]{background-color:var(--vp-c-bg)}.VPHero .clip{white-space:pre;max-width:500px}@font-face{font-family:JuliaMono-Regular;src:url(https://cdn.jsdelivr.net/gh/cormullion/juliamono/webfonts/JuliaMono-Regular.woff2)}:root{--vp-font-family-base: "Barlow", "Inter var experimental", "Inter var", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;--vp-font-family-mono: JuliaMono-Regular, monospace;font-feature-settings:"calt" 0}.mono pre,.mono code{font-family:JuliaMono-Light}:root{--julia-blue: #4063d8;--julia-purple: #9558b2;--julia-red: #cb3c33;--julia-green: #389826;--vp-c-brand: #389826;--vp-c-brand-light: #3dd027;--vp-c-brand-lighter: #9499ff;--vp-c-brand-lightest: #bcc0ff;--vp-c-brand-dark: #535bf2;--vp-c-brand-darker: #454ce1;--vp-c-brand-dimm: #212425}:root{--vp-button-brand-border: var(--vp-c-brand-light);--vp-button-brand-text: var(--vp-c-white);--vp-button-brand-bg: var(--vp-c-brand);--vp-button-brand-hover-border: var(--vp-c-brand-light);--vp-button-brand-hover-text: var(--vp-c-white);--vp-button-brand-hover-bg: var(--vp-c-brand-light);--vp-button-brand-active-border: var(--vp-c-brand-light);--vp-button-brand-active-text: var(--vp-c-white);--vp-button-brand-active-bg: var(--vp-button-brand-bg)}:root{--vp-home-hero-name-color: transparent;--vp-home-hero-name-background: -webkit-linear-gradient( 120deg, #9558b2 30%, #cb3c33 );--vp-home-hero-image-background-image: linear-gradient( -45deg, #9558b2 30%, #389826 30%, #cb3c33 );--vp-home-hero-image-filter: blur(40px)}@media (min-width: 640px){:root{--vp-home-hero-image-filter: blur(56px)}}@media (min-width: 960px){:root{--vp-home-hero-image-filter: blur(72px)}}:root.dark{--vp-custom-block-tip-border: var(--vp-c-brand);--vp-custom-block-tip-text: var(--vp-c-brand-lightest);--vp-custom-block-tip-bg: var(--vp-c-brand-dimm);--vp-c-black: hsl(220 20% 9%);--vp-c-black-pure: hsl(220, 24%, 4%);--vp-c-black-soft: hsl(220 16% 13%);--vp-c-black-mute: hsl(220 14% 17%);--vp-c-gray: hsl(220 8% 56%);--vp-c-gray-dark-1: hsl(220 10% 39%);--vp-c-gray-dark-2: hsl(220 12% 28%);--vp-c-gray-dark-3: hsl(220 12% 23%);--vp-c-gray-dark-4: hsl(220 14% 17%);--vp-c-gray-dark-5: hsl(220 16% 13%);--vp-custom-block-info-bg: hsl(220 14% 17%)}.DocSearch{--docsearch-primary-color: var(--vp-c-brand) !important}mjx-container>svg{display:block;margin:auto}mjx-container{padding:.5rem 0}mjx-container{display:inline;margin:auto 2px -2px}mjx-container>svg{margin:auto;display:inline}:root{--vp-c-brand-1: #cb3c33;--vp-c-brand-2: #cb3c33;--vp-c-brand-3: #cb3c33;--vp-c-sponsor: #ca2971;--vitest-c-sponsor-hover: #c13071}.dark{--vp-c-brand-1: #91dd33;--vp-c-brand-2: #91dd33;--vp-c-brand-3: #91dd33;--vp-c-sponsor: #91dd33;--vitest-c-sponsor-hover: #e51370}:root:not(.dark) .dark-only{display:none}:root:is(.dark) .light-only{display:none}@media (min-width: 1440px){.VPSidebar{padding-left:20px!important;width:250px!important}.VPNavBar .title{padding-left:15px!important;width:230px!important}.VPContent.has-sidebar{padding-left:250px!important;padding-right:5vw!important}.VPNavBar .curtain{width:100%!important}.VPDoc{padding:32px 0 0!important}.VPNavBar.has-sidebar .content{padding-left:250px!important;padding-right:20px!important}.VPNavBar .divider{padding-left:250px!important}}@media (min-width: 960px){.VPDoc{padding:32px 32px 0 10!important}.VPContent.has-sidebar{padding-left:255px!important}}.VPNavBar{padding-right:0!important}.VPDoc.has-aside .content-container{max-width:100%!important}.aside{max-width:200px!important;padding-left:0!important}.VPDocOutlineItem li{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:200px}.VPNavBar .title{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.jldocstring.custom-block{border:1px solid var(--vp-c-gray-2);color:var(--vp-c-text-1)}.jldocstring.custom-block summary{font-weight:700;cursor:pointer;-webkit-user-select:none;user-select:none;margin:0 0 8px}.img-box[data-v-06a0366f]{box-sizing:content-box;border-radius:14px;margin:20px;height:350px;width:250px;overflow:hidden;display:inline-block;color:#fff;position:relative;background-color:transparent;border:2px solid var(--vp-c-bg-alt)}.img-box h2[data-v-06a0366f]{border-top:0}.img-box img[data-v-06a0366f]{height:100%;width:100%;object-fit:cover;opacity:.3;transition:transform .3s ease,opacity .3s ease}.caption[data-v-06a0366f]{position:absolute;bottom:30px;color:var(--vp-c-text-1);left:10px;opacity:1;transition:transform .3s ease,opacity .3s ease}.subcaption[data-v-06a0366f]{position:absolute;bottom:5px;color:var(--vp-c-text-1);left:10px;opacity:0;transition:transform .3s ease,opacity .3s ease}.transparent-box1[data-v-06a0366f]{height:250px;width:250px;background-color:transparent;position:absolute;top:0;left:0;transition:background-color .3s ease}.transparent-box2[data-v-06a0366f]{height:100px;width:250px;background-color:transparent;position:absolute;top:250px;left:0;transition:background-color .3s ease}.img-box:hover img[data-v-06a0366f]{transform:scale(1.1)}.img-box:hover .transparent-box1[data-v-06a0366f],.img-box:hover .transparent-box2[data-v-06a0366f]{background-color:var(--vp-c-bg-alt)}.img-box:hover .caption[data-v-06a0366f],.img-box:hover .subcaption[data-v-06a0366f]{transform:translateY(-20px);opacity:1}.img-box[data-v-06a0366f]:hover{border:2px solid var(--vp-c-brand-light);cursor:pointer}.caption>p[data-v-06a0366f]:nth-child(2){font-size:.8em}.subcaption>p[data-v-06a0366f]:nth-child(2){font-size:.8em}.opacity-low[data-v-06a0366f]{opacity:.85}.heading[data-v-578d61bc]{text-align:center;font-size:2em;letter-spacing:1px;padding:40px;color:#fff}.gallery-image[data-v-578d61bc]{padding:20px;display:flex;flex-wrap:wrap;justify-content:center}.gallery-image[data-v-578d61bc] img{height:350px;width:250px;transform:scale(1);transition:transform .4s ease}.VPLocalSearchBox[data-v-42e65fb9]{position:fixed;z-index:100;top:0;right:0;bottom:0;left:0;display:flex}.backdrop[data-v-42e65fb9]{position:absolute;top:0;right:0;bottom:0;left:0;background:var(--vp-backdrop-bg-color);transition:opacity .5s}.shell[data-v-42e65fb9]{position:relative;padding:12px;margin:64px auto;display:flex;flex-direction:column;gap:16px;background:var(--vp-local-search-bg);width:min(100vw - 60px,900px);height:min-content;max-height:min(100vh - 128px,900px);border-radius:6px}@media (max-width: 767px){.shell[data-v-42e65fb9]{margin:0;width:100vw;height:100vh;max-height:none;border-radius:0}}.search-bar[data-v-42e65fb9]{border:1px solid var(--vp-c-divider);border-radius:4px;display:flex;align-items:center;padding:0 12px;cursor:text}@media (max-width: 767px){.search-bar[data-v-42e65fb9]{padding:0 8px}}.search-bar[data-v-42e65fb9]:focus-within{border-color:var(--vp-c-brand-1)}.local-search-icon[data-v-42e65fb9]{display:block;font-size:18px}.navigate-icon[data-v-42e65fb9]{display:block;font-size:14px}.search-icon[data-v-42e65fb9]{margin:8px}@media (max-width: 767px){.search-icon[data-v-42e65fb9]{display:none}}.search-input[data-v-42e65fb9]{padding:6px 12px;font-size:inherit;width:100%}@media (max-width: 767px){.search-input[data-v-42e65fb9]{padding:6px 4px}}.search-actions[data-v-42e65fb9]{display:flex;gap:4px}@media (any-pointer: coarse){.search-actions[data-v-42e65fb9]{gap:8px}}@media (min-width: 769px){.search-actions.before[data-v-42e65fb9]{display:none}}.search-actions button[data-v-42e65fb9]{padding:8px}.search-actions button[data-v-42e65fb9]:not([disabled]):hover,.toggle-layout-button.detailed-list[data-v-42e65fb9]{color:var(--vp-c-brand-1)}.search-actions button.clear-button[data-v-42e65fb9]:disabled{opacity:.37}.search-keyboard-shortcuts[data-v-42e65fb9]{font-size:.8rem;opacity:75%;display:flex;flex-wrap:wrap;gap:16px;line-height:14px}.search-keyboard-shortcuts span[data-v-42e65fb9]{display:flex;align-items:center;gap:4px}@media (max-width: 767px){.search-keyboard-shortcuts[data-v-42e65fb9]{display:none}}.search-keyboard-shortcuts kbd[data-v-42e65fb9]{background:#8080801a;border-radius:4px;padding:3px 6px;min-width:24px;display:inline-block;text-align:center;vertical-align:middle;border:1px solid rgba(128,128,128,.15);box-shadow:0 2px 2px #0000001a}.results[data-v-42e65fb9]{display:flex;flex-direction:column;gap:6px;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain}.result[data-v-42e65fb9]{display:flex;align-items:center;gap:8px;border-radius:4px;transition:none;line-height:1rem;border:solid 2px var(--vp-local-search-result-border);outline:none}.result>div[data-v-42e65fb9]{margin:12px;width:100%;overflow:hidden}@media (max-width: 767px){.result>div[data-v-42e65fb9]{margin:8px}}.titles[data-v-42e65fb9]{display:flex;flex-wrap:wrap;gap:4px;position:relative;z-index:1001;padding:2px 0}.title[data-v-42e65fb9]{display:flex;align-items:center;gap:4px}.title.main[data-v-42e65fb9]{font-weight:500}.title-icon[data-v-42e65fb9]{opacity:.5;font-weight:500;color:var(--vp-c-brand-1)}.title svg[data-v-42e65fb9]{opacity:.5}.result.selected[data-v-42e65fb9]{--vp-local-search-result-bg: var(--vp-local-search-result-selected-bg);border-color:var(--vp-local-search-result-selected-border)}.excerpt-wrapper[data-v-42e65fb9]{position:relative}.excerpt[data-v-42e65fb9]{opacity:50%;pointer-events:none;max-height:140px;overflow:hidden;position:relative;margin-top:4px}.result.selected .excerpt[data-v-42e65fb9]{opacity:1}.excerpt[data-v-42e65fb9] *{font-size:.8rem!important;line-height:130%!important}.titles[data-v-42e65fb9] mark,.excerpt[data-v-42e65fb9] mark{background-color:var(--vp-local-search-highlight-bg);color:var(--vp-local-search-highlight-text);border-radius:2px;padding:0 2px}.excerpt[data-v-42e65fb9] .vp-code-group .tabs{display:none}.excerpt[data-v-42e65fb9] .vp-code-group div[class*=language-]{border-radius:8px!important}.excerpt-gradient-bottom[data-v-42e65fb9]{position:absolute;bottom:-1px;left:0;width:100%;height:8px;background:linear-gradient(transparent,var(--vp-local-search-result-bg));z-index:1000}.excerpt-gradient-top[data-v-42e65fb9]{position:absolute;top:-1px;left:0;width:100%;height:8px;background:linear-gradient(var(--vp-local-search-result-bg),transparent);z-index:1000}.result.selected .titles[data-v-42e65fb9],.result.selected .title-icon[data-v-42e65fb9]{color:var(--vp-c-brand-1)!important}.no-results[data-v-42e65fb9]{font-size:.9rem;text-align:center;padding:12px}svg[data-v-42e65fb9]{flex:none} diff --git a/previews/PR1023/assets/tutorials_advanced_1_GravitationalWaveForm.md.CE8fiIvN.js b/previews/PR1023/assets/tutorials_advanced_1_GravitationalWaveForm.md.CE8fiIvN.js new file mode 100644 index 0000000000..b8c3e2c177 --- /dev/null +++ b/previews/PR1023/assets/tutorials_advanced_1_GravitationalWaveForm.md.CE8fiIvN.js @@ -0,0 +1,286 @@ +import{_ as t,c as i,a2 as n,j as A,a as h,o as a}from"./chunks/framework.DFwXuivk.js";const j=JSON.parse('{"title":"Training a Neural ODE to Model Gravitational Waveforms","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/advanced/1_GravitationalWaveForm.md","filePath":"tutorials/advanced/1_GravitationalWaveForm.md","lastUpdated":null}'),e={name:"tutorials/advanced/1_GravitationalWaveForm.md"},l={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},p={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.339ex"},xmlns:"http://www.w3.org/2000/svg",width:"10.819ex",height:"1.658ex",role:"img",focusable:"false",viewBox:"0 -583 4782.1 733","aria-hidden":"true"},k={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},E={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.339ex"},xmlns:"http://www.w3.org/2000/svg",width:"2.008ex",height:"1.339ex",role:"img",focusable:"false",viewBox:"0 -442 887.6 592","aria-hidden":"true"},r={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},d={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.339ex"},xmlns:"http://www.w3.org/2000/svg",width:"2.008ex",height:"1.339ex",role:"img",focusable:"false",viewBox:"0 -442 887.6 592","aria-hidden":"true"},Q={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},C={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"24.527ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 10840.9 1000","aria-hidden":"true"},o={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},g={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.117ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3587.6 1000","aria-hidden":"true"},f={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},v={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.049ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3557.6 1000","aria-hidden":"true"},y={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},I={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.138ex",height:"1.439ex",role:"img",focusable:"false",viewBox:"0 -442 503 636","aria-hidden":"true"},F={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},u={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"0"},xmlns:"http://www.w3.org/2000/svg",width:"2.378ex",height:"1.545ex",role:"img",focusable:"false",viewBox:"0 -683 1051 683","aria-hidden":"true"},c={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},m={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.054ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 466 453","aria-hidden":"true"},B={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},T={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.117ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3587.6 1000","aria-hidden":"true"},q={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},z={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.049ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3557.6 1000","aria-hidden":"true"},V={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},D={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.138ex",height:"1.439ex",role:"img",focusable:"false",viewBox:"0 -442 503 636","aria-hidden":"true"},U={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},b={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"0"},xmlns:"http://www.w3.org/2000/svg",width:"2.378ex",height:"1.545ex",role:"img",focusable:"false",viewBox:"0 -683 1051 683","aria-hidden":"true"},P={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},R={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.054ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 466 453","aria-hidden":"true"};function X(K,s,O,w,N,x){return a(),i("div",null,[s[41]||(s[41]=n(`

    Training a Neural ODE to Model Gravitational Waveforms

    This code is adapted from Astroinformatics/ScientificMachineLearning

    The code has been minimally adapted from Keith et. al. 2021 which originally used Flux.jl

    Package Imports

    julia
    using Lux, ComponentArrays, LineSearches, OrdinaryDiffEqLowOrderRK, Optimization,
    +      OptimizationOptimJL, Printf, Random, SciMLSensitivity
    +using CairoMakie

    Define some Utility Functions

    Tip

    This section can be skipped. It defines functions to simulate the model, however, from a scientific machine learning perspective, isn't super relevant.

    `,7)),A("p",null,[s[6]||(s[6]=h("We need a very crude 2-body path. Assume the 1-body motion is a newtonian 2-body position vector ")),A("mjx-container",l,[(a(),i("svg",p,s[0]||(s[0]=[n('',1)]))),s[1]||(s[1]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"r"),A("mo",null,"="),A("msub",null,[A("mi",null,"r"),A("mn",null,"1")]),A("mo",null,"−"),A("msub",null,[A("mi",null,"r"),A("mn",null,"2")])])],-1))]),s[7]||(s[7]=h(" and use Newtonian formulas to get ")),A("mjx-container",k,[(a(),i("svg",E,s[2]||(s[2]=[n('',1)]))),s[3]||(s[3]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("msub",null,[A("mi",null,"r"),A("mn",null,"1")])])],-1))]),s[8]||(s[8]=h(", ")),A("mjx-container",r,[(a(),i("svg",d,s[4]||(s[4]=[n('',1)]))),s[5]||(s[5]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("msub",null,[A("mi",null,"r"),A("mn",null,"2")])])],-1))]),s[9]||(s[9]=h(" (e.g. Theoretical Mechanics of Particles and Continua 4.3)"))]),s[42]||(s[42]=n(`
    julia
    function one2two(path, m₁, m₂)
    +    M = m₁ + m₂
    +    r₁ = m₂ / M .* path
    +    r₂ = -m₁ / M .* path
    +    return r₁, r₂
    +end
    one2two (generic function with 1 method)
    `,2)),A("p",null,[s[12]||(s[12]=h("Next we define a function to perform the change of variables: ")),A("mjx-container",Q,[(a(),i("svg",C,s[10]||(s[10]=[n('',1)]))),s[11]||(s[11]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mo",{stretchy:"false"},"("),A("mi",null,"χ"),A("mo",{stretchy:"false"},"("),A("mi",null,"t"),A("mo",{stretchy:"false"},")"),A("mo",null,","),A("mi",null,"ϕ"),A("mo",{stretchy:"false"},"("),A("mi",null,"t"),A("mo",{stretchy:"false"},")"),A("mo",{stretchy:"false"},")"),A("mo",{stretchy:"false"},"↦"),A("mo",{stretchy:"false"},"("),A("mi",null,"x"),A("mo",{stretchy:"false"},"("),A("mi",null,"t"),A("mo",{stretchy:"false"},")"),A("mo",null,","),A("mi",null,"y"),A("mo",{stretchy:"false"},"("),A("mi",null,"t"),A("mo",{stretchy:"false"},")"),A("mo",{stretchy:"false"},")")])],-1))])]),s[43]||(s[43]=n(`
    julia
    @views function soln2orbit(soln, model_params=nothing)
    +    @assert size(soln, 1)  [2, 4] "size(soln,1) must be either 2 or 4"
    +
    +    if size(soln, 1) == 2
    +        χ = soln[1, :]
    +        ϕ = soln[2, :]
    +
    +        @assert length(model_params)==3 "model_params must have length 3 when size(soln,2) = 2"
    +        p, M, e = model_params
    +    else
    +        χ = soln[1, :]
    +        ϕ = soln[2, :]
    +        p = soln[3, :]
    +        e = soln[4, :]
    +    end
    +
    +    r = p ./ (1 .+ e .* cos.(χ))
    +    x = r .* cos.(ϕ)
    +    y = r .* sin.(ϕ)
    +
    +    orbit = vcat(x', y')
    +    return orbit
    +end
    soln2orbit (generic function with 2 methods)

    This function uses second-order one-sided difference stencils at the endpoints; see https://doi.org/10.1090/S0025-5718-1988-0935077-0

    julia
    function d_dt(v::AbstractVector, dt)
    +    a = -3 / 2 * v[1] + 2 * v[2] - 1 / 2 * v[3]
    +    b = (v[3:end] .- v[1:(end - 2)]) / 2
    +    c = 3 / 2 * v[end] - 2 * v[end - 1] + 1 / 2 * v[end - 2]
    +    return [a; b; c] / dt
    +end
    d_dt (generic function with 1 method)

    This function uses second-order one-sided difference stencils at the endpoints; see https://doi.org/10.1090/S0025-5718-1988-0935077-0

    julia
    function d2_dt2(v::AbstractVector, dt)
    +    a = 2 * v[1] - 5 * v[2] + 4 * v[3] - v[4]
    +    b = v[1:(end - 2)] .- 2 * v[2:(end - 1)] .+ v[3:end]
    +    c = 2 * v[end] - 5 * v[end - 1] + 4 * v[end - 2] - v[end - 3]
    +    return [a; b; c] / (dt^2)
    +end
    d2_dt2 (generic function with 1 method)

    Now we define a function to compute the trace-free moment tensor from the orbit

    julia
    function orbit2tensor(orbit, component, mass=1)
    +    x = orbit[1, :]
    +    y = orbit[2, :]
    +
    +    Ixx = x .^ 2
    +    Iyy = y .^ 2
    +    Ixy = x .* y
    +    trace = Ixx .+ Iyy
    +
    +    if component[1] == 1 && component[2] == 1
    +        tmp = Ixx .- trace ./ 3
    +    elseif component[1] == 2 && component[2] == 2
    +        tmp = Iyy .- trace ./ 3
    +    else
    +        tmp = Ixy
    +    end
    +
    +    return mass .* tmp
    +end
    +
    +function h_22_quadrupole_components(dt, orbit, component, mass=1)
    +    mtensor = orbit2tensor(orbit, component, mass)
    +    mtensor_ddot = d2_dt2(mtensor, dt)
    +    return 2 * mtensor_ddot
    +end
    +
    +function h_22_quadrupole(dt, orbit, mass=1)
    +    h11 = h_22_quadrupole_components(dt, orbit, (1, 1), mass)
    +    h22 = h_22_quadrupole_components(dt, orbit, (2, 2), mass)
    +    h12 = h_22_quadrupole_components(dt, orbit, (1, 2), mass)
    +    return h11, h12, h22
    +end
    +
    +function h_22_strain_one_body(dt::T, orbit) where {T}
    +    h11, h12, h22 = h_22_quadrupole(dt, orbit)
    +
    +    h₊ = h11 - h22
    +    hₓ = T(2) * h12
    +
    +    scaling_const =(T(π) / 5)
    +    return scaling_const * h₊, -scaling_const * hₓ
    +end
    +
    +function h_22_quadrupole_two_body(dt, orbit1, mass1, orbit2, mass2)
    +    h11_1, h12_1, h22_1 = h_22_quadrupole(dt, orbit1, mass1)
    +    h11_2, h12_2, h22_2 = h_22_quadrupole(dt, orbit2, mass2)
    +    h11 = h11_1 + h11_2
    +    h12 = h12_1 + h12_2
    +    h22 = h22_1 + h22_2
    +    return h11, h12, h22
    +end
    +
    +function h_22_strain_two_body(dt::T, orbit1, mass1, orbit2, mass2) where {T}
    +    # compute (2,2) mode strain from orbits of BH 1 of mass1 and BH2 of mass 2
    +
    +    @assert abs(mass1 + mass2 - 1.0)<1e-12 "Masses do not sum to unity"
    +
    +    h11, h12, h22 = h_22_quadrupole_two_body(dt, orbit1, mass1, orbit2, mass2)
    +
    +    h₊ = h11 - h22
    +    hₓ = T(2) * h12
    +
    +    scaling_const =(T(π) / 5)
    +    return scaling_const * h₊, -scaling_const * hₓ
    +end
    +
    +function compute_waveform(dt::T, soln, mass_ratio, model_params=nothing) where {T}
    +    @assert mass_ratio1 "mass_ratio must be <= 1"
    +    @assert mass_ratio0 "mass_ratio must be non-negative"
    +
    +    orbit = soln2orbit(soln, model_params)
    +    if mass_ratio > 0
    +        m₂ = inv(T(1) + mass_ratio)
    +        m₁ = mass_ratio * m₂
    +
    +        orbit₁, orbit₂ = one2two(orbit, m₁, m₂)
    +        waveform = h_22_strain_two_body(dt, orbit₁, m₁, orbit₂, m₂)
    +    else
    +        waveform = h_22_strain_one_body(dt, orbit)
    +    end
    +    return waveform
    +end
    compute_waveform (generic function with 2 methods)

    Simulating the True Model

    RelativisticOrbitModel defines system of odes which describes motion of point like particle in schwarzschild background, uses

    `,13)),A("mjx-container",o,[(a(),i("svg",g,s[13]||(s[13]=[n('',1)]))),s[14]||(s[14]=A("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[A("mi",null,"u"),A("mo",{stretchy:"false"},"["),A("mn",null,"1"),A("mo",{stretchy:"false"},"]"),A("mo",null,"="),A("mi",null,"χ")])],-1))]),A("mjx-container",f,[(a(),i("svg",v,s[15]||(s[15]=[n('',1)]))),s[16]||(s[16]=A("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[A("mi",null,"u"),A("mo",{stretchy:"false"},"["),A("mn",null,"2"),A("mo",{stretchy:"false"},"]"),A("mo",null,"="),A("mi",null,"ϕ")])],-1))]),A("p",null,[s[23]||(s[23]=h("where, ")),A("mjx-container",y,[(a(),i("svg",I,s[17]||(s[17]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D45D",d:"M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z",style:{"stroke-width":"3"}})])])],-1)]))),s[18]||(s[18]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"p")])],-1))]),s[24]||(s[24]=h(", ")),A("mjx-container",F,[(a(),i("svg",u,s[19]||(s[19]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D440",d:"M289 629Q289 635 232 637Q208 637 201 638T194 648Q194 649 196 659Q197 662 198 666T199 671T201 676T203 679T207 681T212 683T220 683T232 684Q238 684 262 684T307 683Q386 683 398 683T414 678Q415 674 451 396L487 117L510 154Q534 190 574 254T662 394Q837 673 839 675Q840 676 842 678T846 681L852 683H948Q965 683 988 683T1017 684Q1051 684 1051 673Q1051 668 1048 656T1045 643Q1041 637 1008 637Q968 636 957 634T939 623Q936 618 867 340T797 59Q797 55 798 54T805 50T822 48T855 46H886Q892 37 892 35Q892 19 885 5Q880 0 869 0Q864 0 828 1T736 2Q675 2 644 2T609 1Q592 1 592 11Q592 13 594 25Q598 41 602 43T625 46Q652 46 685 49Q699 52 704 61Q706 65 742 207T813 490T848 631L654 322Q458 10 453 5Q451 4 449 3Q444 0 433 0Q418 0 415 7Q413 11 374 317L335 624L267 354Q200 88 200 79Q206 46 272 46H282Q288 41 289 37T286 19Q282 3 278 1Q274 0 267 0Q265 0 255 0T221 1T157 2Q127 2 95 1T58 0Q43 0 39 2T35 11Q35 13 38 25T43 40Q45 46 65 46Q135 46 154 86Q158 92 223 354T289 629Z",style:{"stroke-width":"3"}})])])],-1)]))),s[20]||(s[20]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"M")])],-1))]),s[25]||(s[25]=h(", and ")),A("mjx-container",c,[(a(),i("svg",m,s[21]||(s[21]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D452",d:"M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z",style:{"stroke-width":"3"}})])])],-1)]))),s[22]||(s[22]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"e")])],-1))]),s[26]||(s[26]=h(" are constants"))]),s[44]||(s[44]=n(`
    julia
    function RelativisticOrbitModel(u, (p, M, e), t)
    +    χ, ϕ = u
    +
    +    numer = (p - 2 - 2 * e * cos(χ)) * (1 + e * cos(χ))^2
    +    denom = sqrt((p - 2)^2 - 4 * e^2)
    +
    +    χ̇ = numer * sqrt(p - 6 - 2 * e * cos(χ)) / (M * (p^2) * denom)
    +    ϕ̇ = numer / (M * (p^(3 / 2)) * denom)
    +
    +    return [χ̇, ϕ̇]
    +end
    +
    +mass_ratio = 0.0         # test particle
    +u0 = Float64[π, 0.0]     # initial conditions
    +datasize = 250
    +tspan = (0.0f0, 6.0f4)   # timespace for GW waveform
    +tsteps = range(tspan[1], tspan[2]; length=datasize)  # time at each timestep
    +dt_data = tsteps[2] - tsteps[1]
    +dt = 100.0
    +const ode_model_params = [100.0, 1.0, 0.5]; # p, M, e

    Let's simulate the true model and plot the results using OrdinaryDiffEq.jl

    julia
    prob = ODEProblem(RelativisticOrbitModel, u0, tspan, ode_model_params)
    +soln = Array(solve(prob, RK4(); saveat=tsteps, dt, adaptive=false))
    +waveform = first(compute_waveform(dt_data, soln, mass_ratio, ode_model_params))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Time", ylabel="Waveform")
    +
    +    l = lines!(ax, tsteps, waveform; linewidth=2, alpha=0.75)
    +    s = scatter!(ax, tsteps, waveform; marker=:circle, markersize=12, alpha=0.5)
    +
    +    axislegend(ax, [[l, s]], ["Waveform Data"])
    +
    +    fig
    +end

    Defiing a Neural Network Model

    Next, we define the neural network model that takes 1 input (time) and has two outputs. We'll make a function ODE_model that takes the initial conditions, neural network parameters and a time as inputs and returns the derivatives.

    It is typically never recommended to use globals but incase you do use them, make sure to mark them as const.

    We will deviate from the standard Neural Network initialization and use WeightInitializers.jl,

    julia
    const nn = Chain(Base.Fix1(fast_activation, cos),
    +    Dense(1 => 32, cos; init_weight=truncated_normal(; std=1e-4), init_bias=zeros32),
    +    Dense(32 => 32, cos; init_weight=truncated_normal(; std=1e-4), init_bias=zeros32),
    +    Dense(32 => 2; init_weight=truncated_normal(; std=1e-4), init_bias=zeros32))
    +ps, st = Lux.setup(Random.default_rng(), nn)
    ((layer_1 = NamedTuple(), layer_2 = (weight = Float32[0.00014798867; 0.0001283755; -0.0001917945; 3.3228196f-5; -2.6541045f-5; -7.975404f-5; -7.092557f-5; -9.0006855f-5; -0.00010432666; -0.0001582305; 0.00011267975; -3.444654f-5; -9.600945f-5; 2.8409087f-5; 5.7547153f-5; -4.970076f-5; 2.046465f-5; 8.749019f-6; 0.00013897507; -8.843735f-6; 5.8316316f-5; 1.33647545f-5; -2.3945151f-5; -0.00019256481; 2.0440255f-6; 7.665036f-5; 7.0418944f-5; -1.478229f-5; 9.342598f-5; -0.00015591538; -4.5475575f-5; -0.00012614082;;], bias = Float32[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.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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), layer_3 = (weight = Float32[6.289329f-5 -0.00012899227 -7.0849266f-5 3.424427f-5 -0.00014294294 9.092271f-5 1.9861705f-5 -0.00020486339 0.00014140282 -5.7926198f-5 0.00012580563 3.976018f-5 1.100778f-5 7.652588f-5 -0.00015733847 -1.979117f-5 -2.0289622f-6 -6.7930196f-6 -4.5295787f-5 2.2391352f-5 -3.927852f-5 0.00018191025 0.0001640962 0.00010366936 -4.4512766f-5 -7.5653224f-5 0.00010830701 8.7929953f-7 0.00012046669 2.4013454f-5 0.00014076312 -0.00013183871; -4.7972153f-5 0.00011150861 -3.7190406f-5 9.121937f-5 -0.00010013644 2.8713104f-5 4.641554f-5 -1.5365074f-5 -2.0453728f-5 -0.00013698272 -2.3076393f-5 -5.7660716f-5 3.585004f-6 8.321239f-5 -0.00013441942 2.9746785f-5 2.0607064f-5 8.571386f-5 9.492374f-5 3.4114895f-5 -5.762854f-5 -9.081341f-5 -6.314866f-5 7.2077423f-6 0.00023802661 5.7517093f-5 -4.9155748f-5 1.2719572f-5 7.161465f-5 -0.00016839153 -4.1478852f-5 -5.9046262f-5; -2.9938063f-5 5.5241326f-5 1.1746462f-5 -6.0956474f-5 -4.192573f-5 3.8743932f-5 -5.3232892f-5 7.759226f-5 2.684328f-5 0.00011954861 3.9134986f-5 0.00013964466 4.1704818f-5 0.000106225416 -4.9426613f-5 0.00010018988 -6.675354f-5 -0.00010403922 -0.00017239648 -0.00013530202 -2.4472069f-5 9.1792914f-5 0.00014092802 -0.00014417266 6.6564055f-5 2.9273719f-5 -7.643671f-6 -8.035956f-5 -1.8555611f-5 7.823969f-5 -0.00012648669 -5.176932f-5; -0.00018445784 -0.00016699555 -2.1285985f-5 9.4690876f-7 0.0001585242 -1.0795486f-5 -1.1848228f-5 4.74355f-5 8.790459f-6 -8.956207f-5 -0.00019490978 0.00021997328 -9.609839f-8 -0.00010916037 -3.892144f-5 6.3916494f-5 7.681881f-5 -0.00011807908 -0.00017212381 -0.00018349661 8.6814776f-5 6.0045826f-5 7.09515f-5 9.022243f-5 -7.049568f-5 -0.00013075661 -0.0001992019 3.3228356f-5 4.2630118f-6 -1.41205355f-5 -0.00018963483 0.00015777664; 0.00018126491 2.3202228f-5 -5.495445f-5 -4.946576f-7 -0.00020756968 0.00022925969 5.503714f-5 -6.6733686f-5 -3.9605053f-5 8.9995505f-5 0.00016215538 -0.00014901724 -0.000113528695 9.1734364f-5 0.00013460332 3.164675f-5 0.00011464552 1.3743814f-5 -9.705088f-6 -1.5063842f-5 -0.000105181956 -8.101596f-5 -1.4773998f-5 -4.7479796f-5 -7.020212f-5 -1.2936013f-5 -5.8906862f-5 -4.3236964f-6 -0.00013548507 0.000110176996 -5.2493553f-5 -8.339872f-6; 0.00014380175 -3.5924462f-5 -4.52999f-5 2.1514736f-5 -0.00020766298 -1.7351893f-5 7.9613244f-5 0.0001905701 3.0340694f-5 5.0138933f-5 -3.984415f-6 -0.00015125364 0.00015956702 -1.392205f-5 -3.635585f-5 0.00022001681 5.91466f-5 -0.00015853895 7.022997f-5 -1.8219034f-5 -3.6560552f-5 0.00013926311 -6.6375236f-5 6.2436798f-6 -3.8841477f-5 5.4191773f-5 -4.7340418f-5 8.6398664f-5 -6.0206105f-5 1.4901871f-5 -3.557371f-5 -3.2751283f-5; 0.00015866013 -0.00018365905 0.00019000433 3.928957f-5 0.000100898724 0.00019121302 0.00011651945 1.9493575f-5 0.00014185574 -6.381918f-5 9.468081f-5 -5.449231f-5 -3.1079664f-5 -7.316235f-5 -1.46296725f-5 -8.44827f-5 -2.324579f-5 9.611487f-5 -0.00018836417 -0.00014876756 4.4095086f-5 3.3882204f-6 -8.825502f-5 3.1465417f-5 0.00012619214 6.1826584f-5 0.00010061589 -9.284439f-5 6.107f-5 -0.00018807476 6.4877626f-5 -0.000121999954; -8.5641674f-5 -1.3133318f-5 3.1929572f-5 -5.934451f-5 7.0588656f-5 0.0002013159 -0.00016559058 -2.233838f-5 -1.4553927f-5 4.1629923f-5 0.00024530233 0.00012909896 0.00018083502 -0.000119821285 -0.0001745207 -0.00013740954 -5.5037024f-5 9.581295f-5 0.0001602952 0.00013878937 -8.0092905f-5 -0.00010669961 6.486757f-5 4.6803184f-6 -0.00010437932 5.5193468f-5 1.9592484f-5 3.52069f-5 -0.00012098054 2.8355807f-6 -4.223768f-5 5.9603328f-5; 6.647512f-5 -7.651593f-5 -7.045441f-5 -6.9189075f-5 2.1325188f-5 3.5744788f-6 -1.3802712f-5 2.5542184f-5 -2.9736013f-5 6.44827f-5 -0.00010273267 -9.560108f-5 -0.00014832508 6.260054f-5 -5.1025545f-5 -6.963479f-5 -4.299914f-5 -4.3417534f-5 0.0001540578 3.5573554f-5 3.2626234f-5 -9.97229f-5 -3.444653f-5 -5.6763725f-5 -7.5928234f-5 -3.071837f-5 -0.00021853072 2.5228403f-5 -3.6620877f-5 0.00012246045 -1.4872443f-5 1.841769f-5; -0.0001188636 -6.524213f-5 -2.2877752f-5 4.632825f-5 -1.1418591f-5 9.142981f-5 0.0001675149 -1.9919431f-5 -0.00011349276 -0.00013851613 -1.757684f-5 -0.00014613128 0.0001068853 7.522353f-5 -9.3130104f-5 6.484308f-5 -8.492532f-5 -4.397045f-5 -9.0616435f-5 5.6238932f-5 0.00011258058 6.7984714f-5 4.3041862f-5 5.8434587f-5 6.9005415f-5 0.00011230302 -4.809528f-5 1.3548491f-5 -4.926104f-5 -1.7329085f-5 -0.00028108715 -0.00012603487; -4.171165f-5 0.00010611511 3.4812806f-6 -0.00012482349 -5.3257183f-5 0.00016939598 2.9564746f-5 4.8874685f-6 -0.00011994621 -0.00026434002 3.6563153f-5 -0.000108040615 -7.026481f-5 2.7034612f-5 3.3245436f-5 5.518623f-5 0.00015428747 -2.83204f-5 5.0359064f-5 -0.00024188824 7.56617f-5 -7.7807505f-5 3.4013906f-6 8.007004f-6 3.9183702f-5 7.3195915f-5 3.231583f-5 7.934296f-6 0.00022212125 8.448415f-5 4.1704367f-5 -5.398324f-5; -8.224716f-5 5.6144036f-5 0.00010965635 3.7896003f-5 4.7579024f-6 3.596343f-5 0.0001756822 8.707022f-5 2.3367626f-5 8.813453f-6 0.00012343613 -3.068682f-6 -6.350598f-6 3.4608598f-5 4.112685f-5 -0.000109935296 3.6222606f-5 -2.7707993f-5 5.5938457f-5 -9.080702f-5 0.00010973305 -0.00040191333 -0.000121186655 -1.7417953f-5 -2.886204f-5 7.5300995f-5 6.176085f-5 5.0990384f-6 -2.4672994f-5 0.00010083148 -0.00017672713 -0.00010527357; -7.6542325f-5 -4.887439f-5 4.4795204f-5 -5.118064f-5 2.2101027f-5 -8.722431f-5 -1.5876874f-5 3.2201962f-5 7.430702f-5 9.7987635f-5 5.678952f-5 4.103541f-5 6.1897146f-5 5.9394017f-5 0.00017383661 -4.654219f-5 5.272721f-5 -0.00016875502 -1.3612849f-5 -3.7497615f-5 -4.8632966f-5 -9.375605f-5 3.0336598f-5 0.00016506345 6.448615f-5 -2.2019703f-5 -0.0001863126 -0.00012096228 -0.00014580866 -6.976547f-5 -0.00015476714 -7.5878204f-5; 5.084713f-5 -0.00021186467 2.1613598f-5 -4.6291356f-5 3.004238f-5 0.00016760328 -4.9907212f-5 9.497809f-5 -1.6691067f-5 -0.00013202691 0.00014834417 0.00012773061 3.0298817f-5 -1.1706837f-5 -1.42734325f-5 2.5085385f-5 8.448661f-5 6.0359416f-5 -2.4104298f-5 8.7597575f-5 0.000121300895 -8.5296175f-5 -1.31261595f-5 -0.0002458211 0.00011386037 8.230593f-5 9.957604f-5 -0.000109471024 -0.000101480946 0.00014499597 -9.220983f-6 2.2058508f-5; 4.8723276f-5 -1.6514532f-5 -0.0002468032 -4.9717022f-5 -7.79167f-5 -6.1969775f-5 0.0001073215 0.00018630148 -0.00021227564 1.0337452f-5 -0.000110470944 -5.334019f-5 0.000112096546 -0.00013046447 6.6720764f-5 -5.432939f-5 1.0038856f-5 -4.29304f-6 6.0018825f-5 -5.820133f-5 -2.3095005f-5 -5.657121f-5 -0.00012440086 -8.591388f-5 -0.00012554288 0.00010523489 -0.000111681264 0.00021312517 2.1284488f-7 0.00010232037 0.00013876813 0.0001451994; -7.494194f-5 -0.00019951252 0.00015804444 -7.931216f-5 3.0945268f-6 -0.00021899202 -0.00019707732 3.6243835f-6 -0.00015080615 -5.8808688f-5 8.493303f-6 0.00010061238 9.35891f-5 -8.0895166f-5 -7.4010213f-6 9.68475f-5 -6.619761f-5 0.00019664227 5.1728017f-5 -3.5319747f-5 -1.8978888f-5 4.020748f-5 -0.00015314738 -6.8800975f-5 -9.088428f-5 6.2876315f-6 -1.0762799f-5 0.0001739711 -0.00012083959 -7.6869735f-5 -1.8775695f-6 0.0002110241; 0.00020664533 -3.8356404f-5 -3.639981f-5 6.6069056f-6 0.0002150255 -1.105098f-5 9.458304f-5 3.5168116f-5 4.1931882f-5 -3.794645f-5 5.109525f-5 8.714127f-5 7.221925f-5 5.057045f-6 0.00011038904 -0.00018290084 2.3290859f-5 -3.6203204f-5 -3.981772f-5 -0.00013440159 8.675202f-5 -5.4943102f-6 7.266125f-5 -3.9068636f-5 -2.5095518f-5 4.3375676f-5 9.906182f-6 -8.512961f-6 -0.00012463176 -2.8709976f-5 -0.0001875602 -9.898851f-5; 0.0002062297 -1.7319557f-5 -0.00016271313 -1.2332152f-5 4.4490756f-5 -7.7858436f-5 -2.1417101f-5 8.3703315f-5 0.0001557044 -0.00011835118 5.8567413f-5 3.918367f-5 -2.3871171f-5 -9.139766f-5 0.00027838128 -0.0001281093 0.000112045745 6.355378f-5 0.00013682224 -6.740831f-5 8.912105f-5 4.103716f-5 4.492756f-5 -6.26335f-5 0.00025819617 6.9468864f-5 -3.5967318f-5 -3.032951f-5 8.049461f-5 -1.25148f-5 -2.2473672f-5 2.1698948f-5; -7.269528f-5 -0.00012516121 6.7834335f-5 3.5365916f-5 9.4599854f-5 5.065827f-5 -0.00011152873 0.0001427831 -0.00021785761 -4.7557187f-6 6.365417f-5 7.37164f-5 7.1094975f-5 -1.8372193f-5 0.00011231499 8.884766f-5 -3.1563144f-5 4.6293702f-5 -5.124871f-5 0.0002186435 3.342431f-5 3.2399035f-5 -8.354723f-5 3.765436f-5 -5.6786386f-5 3.4903765f-5 -0.00012040491 -0.00015075131 -1.5091981f-5 4.4941695f-5 6.308678f-5 4.3056505f-5; 3.351414f-5 -0.00014271175 0.00017131938 -0.00010088954 2.9894476f-5 -0.000113792055 2.7023705f-5 1.28059455f-5 -4.983779f-7 -0.000112544185 2.0941325f-6 -5.2774485f-5 -0.000106039486 -3.205883f-5 2.7262116f-5 -5.2474334f-5 -0.00012837445 1.6826858f-5 -7.145139f-5 0.00013343793 -9.974608f-5 0.00017567938 8.4046085f-5 -0.00014363631 0.00012854532 -0.00013070022 -3.172005f-5 1.76047f-5 -9.0335736f-5 -1.754041f-5 8.696777f-5 0.00012956029; -0.00018782426 0.00017699254 3.149139f-5 -4.99698f-5 7.8038574f-5 2.818771f-5 0.00022553114 9.590483f-6 7.341247f-5 -0.00014300141 0.0002734399 -0.00013367516 -1.2282188f-5 -3.070524f-5 -4.0326096f-5 7.698534f-5 -0.00012843356 -5.6019122f-5 1.1880202f-6 -6.780416f-5 -4.288794f-5 -5.121403f-5 -0.00019581003 -9.3209295f-5 6.6032386f-5 -8.8718843f-7 5.1536685f-5 -0.00014158712 7.121518f-5 -8.5905245f-5 0.00015030308 -5.6274668f-5; -5.91273f-5 2.667418f-5 0.00012173791 1.00059415f-5 -8.0069556f-5 -9.820306f-5 -0.00012170542 8.378669f-5 0.00016907272 7.989081f-5 -9.078782f-6 0.00026348335 9.293973f-5 4.040083f-5 -0.00018577027 -0.00019673149 -5.740228f-5 -7.330596f-5 0.00016787944 6.829441f-5 4.410893f-5 2.1007763f-5 -0.00015965947 4.5795405f-5 -0.00018885931 -0.00017394606 -0.00010925013 -5.149483f-5 -0.00020355567 -6.1030503f-5 -5.1728937f-5 2.9340394f-5; 0.00013693758 -0.00014005817 0.00010481041 -5.797798f-5 -4.048482f-5 -7.644748f-5 -3.0935473f-5 5.6017776f-5 -0.00014096715 6.812392f-5 -1.9517864f-5 1.2078835f-5 5.2177766f-5 4.231554f-5 0.000116617644 -0.00012488794 -4.1700772f-5 0.00011917023 -0.00015670038 -0.000103008395 5.9587246f-6 -8.658024f-5 4.2958178f-5 5.402395f-5 -0.00013350612 -0.00012053447 0.000101511156 8.700682f-5 -1.5777901f-5 -3.3261258f-5 -5.280248f-5 5.8354533f-5; -0.00020004802 4.2591022f-5 -3.7916545f-6 5.848705f-6 -3.4376142f-5 -2.5124384f-5 -1.1709151f-5 4.7170077f-5 -9.483936f-6 2.1743093f-5 -7.2951654f-5 1.35000455f-5 7.552683f-5 9.084621f-5 -8.024526f-6 -2.131134f-5 -7.918156f-5 -4.9303988f-5 0.00015841947 -7.639694f-5 -6.701421f-5 0.00020400074 8.10917f-6 -0.00013003442 -6.820468f-5 -1.9383338f-5 6.901344f-5 -0.00010831981 -2.5970878f-5 3.8305636f-5 6.564423f-5 3.1417763f-5; -0.00016382785 -8.254858f-5 0.00012010008 -0.00014978845 9.3223725f-6 -7.65836f-5 -0.0001389151 2.3776574f-6 0.00010048893 -1.0069865f-5 0.00011513229 7.9882484f-5 5.657715f-5 2.2221302f-5 3.65756f-5 -0.00020418508 0.00016715754 -0.0002513969 2.255126f-5 0.00014347043 -0.00012792795 -3.7204714f-5 -0.00012602791 0.0001213054 9.629434f-6 8.668678f-5 -7.264592f-5 0.0001709462 0.00014189305 -2.8030583f-5 9.5291936f-5 1.6033402f-5; 9.873253f-5 -0.00016460502 5.3794003f-5 3.08519f-5 -7.868859f-5 -1.7641012f-5 8.791397f-5 -0.000101237405 1.5865027f-5 0.00017055974 0.00033521306 -8.547244f-5 -4.3114323f-5 7.744298f-5 -8.7189655f-5 5.8678976f-5 0.00011043076 4.333132f-5 -0.00014446281 5.1741783f-5 -3.813609f-5 -6.0597315f-5 -9.771785f-5 0.00016370777 -8.8192515f-5 -0.00011716584 8.827072f-6 -4.4404693f-5 3.727705f-7 -2.924044f-5 0.00015301318 7.6967f-5; -2.7693168f-5 0.0001663314 0.00018915265 -6.367479f-5 0.00011415843 -9.113931f-5 -5.885339f-5 2.3013947f-5 -8.5922205f-5 -9.334885f-5 -3.864745f-5 -0.00012202202 -0.0001209435 -3.7900256f-5 -3.813278f-5 -0.00014817737 0.00013423587 4.8620004f-5 -0.00021318468 -0.00021753427 -4.258982f-5 -9.925543f-5 -1.3697903f-5 -8.00122f-5 2.6809148f-5 0.00015645399 0.00012051571 -1.0606383f-7 -1.7874921f-5 3.831381f-5 -1.197501f-5 5.2063097f-5; 2.8714978f-6 6.90757f-5 -0.00015171764 0.00020949625 4.6531713f-6 0.00015994276 -8.393382f-5 -9.581163f-6 -9.736687f-5 0.00017050117 -0.00015886013 -0.00027448655 6.217103f-5 0.00017041352 -1.0683171f-5 -0.00013700667 -1.4040064f-5 1.1740796f-6 -1.6264146f-5 -9.725939f-6 6.1090526f-5 -5.4130665f-5 9.185083f-5 -8.574102f-5 -8.912103f-5 3.5294725f-5 5.8031135f-5 2.407458f-6 0.00017823472 0.00012349125 9.97671f-5 9.889217f-5; 5.0403345f-5 6.829975f-5 -0.00011087512 -0.0002034794 -0.00016650361 9.249765f-5 3.2089847f-5 0.00015634432 6.094444f-5 4.1363404f-5 7.436349f-6 0.00013688966 -0.00013218693 7.99489f-5 -3.936639f-5 -2.6110276f-5 0.0003528559 7.467061f-5 5.594828f-5 -0.00019002314 -2.7961547f-5 -0.00028334607 -4.4637447f-5 5.3465246f-5 0.00014880052 -3.1073043f-5 -3.7360107f-5 5.2465195f-5 -2.292667f-6 3.222533f-5 -3.659026f-5 1.6538628f-5; -0.00013727378 -0.00022803275 8.518639f-5 0.0001404138 0.00016037932 -0.0001381259 3.6358913f-5 2.7000491f-5 0.00011553917 2.4459045f-5 1.7618628f-5 0.00017882141 0.0001968822 0.00013338713 2.3761932f-5 3.2353735f-5 0.00022275365 -1.5661397f-5 -0.00014963915 8.59156f-5 -3.295399f-5 -7.559035f-5 -6.74688f-5 1.868308f-5 -3.1442137f-6 -2.7208916f-5 -0.00014883529 0.00013670279 4.0551837f-5 -0.00018453944 -9.6279626f-5 1.5015081f-5; -0.00021324691 1.9568513f-5 2.8413555f-5 -6.08873f-5 6.632513f-5 -0.00014127647 3.4786794f-5 -7.8905505f-5 1.604637f-5 -6.833524f-5 8.2607505f-5 -0.00018783257 0.00013860513 8.130636f-5 -5.675258f-5 0.0002921465 -0.00011495117 0.00010721372 -0.00010607168 9.358432f-5 -3.543438f-5 -8.053401f-5 5.4574848f-5 -0.0001098857 -0.00013411244 -0.0001522711 0.00016539948 -5.7681238f-5 2.9871584f-5 -0.00014114701 6.3481284f-6 0.00013794337; 8.3092156f-5 2.7902099f-5 -9.75656f-5 -1.8865496f-5 7.323678f-5 0.000262229 -7.489286f-5 -1.1426142f-5 0.00022319547 -5.055722f-5 -9.105156f-6 3.4471059f-6 -0.00015784599 0.00014489138 -5.668865f-5 -0.00012680284 6.851014f-5 0.00023398332 3.717287f-6 5.8330512f-5 -0.000120279605 -2.2869315f-5 -0.0001467045 8.990784f-5 -6.7251385f-6 0.0001507413 7.4212396f-5 0.000113473805 -9.460157f-5 5.04164f-5 -9.531469f-5 8.755353f-5], bias = Float32[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.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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), layer_4 = (weight = Float32[-4.5658362f-5 -6.7949f-5 3.798372f-5 -8.829764f-5 -1.3014227f-5 1.2838754f-5 -1.4072927f-5 -4.885181f-5 3.5925146f-5 2.4817182f-5 7.282435f-5 7.9797835f-5 7.235881f-5 2.2705874f-5 -7.128685f-5 -7.052428f-5 6.427351f-5 8.168424f-5 -5.3329717f-5 6.197203f-5 -7.5120886f-5 9.8776116f-5 -2.0051406f-5 -7.375525f-5 0.000106042826 -8.089046f-5 -6.8328445f-5 -6.412571f-5 5.7237332f-5 1.3227511f-5 -0.00020962827 0.00015985763; -0.00011662117 1.582265f-5 6.975102f-5 5.797877f-5 -0.00010437497 -5.1038278f-5 -4.0289066f-5 -7.176196f-5 -5.352049f-5 2.6909376f-5 0.00011169085 0.00011102239 -0.000107661435 5.041146f-5 -6.310288f-5 3.518474f-5 1.0684749f-5 -0.00013644567 -6.9206294f-6 6.371999f-5 -2.6431774f-6 -0.0001470346 6.3890766f-5 9.16673f-6 3.4269528f-5 -5.0108138f-5 -3.493495f-6 -0.00015794244 3.472015f-5 -6.379643f-5 -4.7585076f-5 -0.000110352164], bias = Float32[0.0, 0.0])), (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple(), layer_4 = NamedTuple()))

    Similar to most DL frameworks, Lux defaults to using Float32, however, in this case we need Float64

    julia
    const params = ComponentArray(ps |> f64)
    +
    +const nn_model = StatefulLuxLayer{true}(nn, nothing, st)
    StatefulLuxLayer{true}(
    +    Chain(
    +        layer_1 = WrappedFunction(Base.Fix1{typeof(LuxLib.API.fast_activation), typeof(cos)}(LuxLib.API.fast_activation, cos)),
    +        layer_2 = Dense(1 => 32, cos),  # 64 parameters
    +        layer_3 = Dense(32 => 32, cos),  # 1_056 parameters
    +        layer_4 = Dense(32 => 2),       # 66 parameters
    +    ),
    +)         # Total: 1_186 parameters,
    +          #        plus 0 states.

    Now we define a system of odes which describes motion of point like particle with Newtonian physics, uses

    `,14)),A("mjx-container",B,[(a(),i("svg",T,s[27]||(s[27]=[n('',1)]))),s[28]||(s[28]=A("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[A("mi",null,"u"),A("mo",{stretchy:"false"},"["),A("mn",null,"1"),A("mo",{stretchy:"false"},"]"),A("mo",null,"="),A("mi",null,"χ")])],-1))]),A("mjx-container",q,[(a(),i("svg",z,s[29]||(s[29]=[n('',1)]))),s[30]||(s[30]=A("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[A("mi",null,"u"),A("mo",{stretchy:"false"},"["),A("mn",null,"2"),A("mo",{stretchy:"false"},"]"),A("mo",null,"="),A("mi",null,"ϕ")])],-1))]),A("p",null,[s[37]||(s[37]=h("where, ")),A("mjx-container",V,[(a(),i("svg",D,s[31]||(s[31]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D45D",d:"M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z",style:{"stroke-width":"3"}})])])],-1)]))),s[32]||(s[32]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"p")])],-1))]),s[38]||(s[38]=h(", ")),A("mjx-container",U,[(a(),i("svg",b,s[33]||(s[33]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D440",d:"M289 629Q289 635 232 637Q208 637 201 638T194 648Q194 649 196 659Q197 662 198 666T199 671T201 676T203 679T207 681T212 683T220 683T232 684Q238 684 262 684T307 683Q386 683 398 683T414 678Q415 674 451 396L487 117L510 154Q534 190 574 254T662 394Q837 673 839 675Q840 676 842 678T846 681L852 683H948Q965 683 988 683T1017 684Q1051 684 1051 673Q1051 668 1048 656T1045 643Q1041 637 1008 637Q968 636 957 634T939 623Q936 618 867 340T797 59Q797 55 798 54T805 50T822 48T855 46H886Q892 37 892 35Q892 19 885 5Q880 0 869 0Q864 0 828 1T736 2Q675 2 644 2T609 1Q592 1 592 11Q592 13 594 25Q598 41 602 43T625 46Q652 46 685 49Q699 52 704 61Q706 65 742 207T813 490T848 631L654 322Q458 10 453 5Q451 4 449 3Q444 0 433 0Q418 0 415 7Q413 11 374 317L335 624L267 354Q200 88 200 79Q206 46 272 46H282Q288 41 289 37T286 19Q282 3 278 1Q274 0 267 0Q265 0 255 0T221 1T157 2Q127 2 95 1T58 0Q43 0 39 2T35 11Q35 13 38 25T43 40Q45 46 65 46Q135 46 154 86Q158 92 223 354T289 629Z",style:{"stroke-width":"3"}})])])],-1)]))),s[34]||(s[34]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"M")])],-1))]),s[39]||(s[39]=h(", and ")),A("mjx-container",P,[(a(),i("svg",R,s[35]||(s[35]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D452",d:"M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z",style:{"stroke-width":"3"}})])])],-1)]))),s[36]||(s[36]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"e")])],-1))]),s[40]||(s[40]=h(" are constants"))]),s[45]||(s[45]=n(`
    julia
    function ODE_model(u, nn_params, t)
    +    χ, ϕ = u
    +    p, M, e = ode_model_params
    +
    +    # In this example we know that \`st\` is am empty NamedTuple hence we can safely ignore
    +    # it, however, in general, we should use \`st\` to store the state of the neural network.
    +    y = 1 .+ nn_model([first(u)], nn_params)
    +
    +    numer = (1 + e * cos(χ))^2
    +    denom = M * (p^(3 / 2))
    +
    +    χ̇ = (numer / denom) * y[1]
    +    ϕ̇ = (numer / denom) * y[2]
    +
    +    return [χ̇, ϕ̇]
    +end
    ODE_model (generic function with 1 method)

    Let us now simulate the neural network model and plot the results. We'll use the untrained neural network parameters to simulate the model.

    julia
    prob_nn = ODEProblem(ODE_model, u0, tspan, params)
    +soln_nn = Array(solve(prob_nn, RK4(); u0, p=params, saveat=tsteps, dt, adaptive=false))
    +waveform_nn = first(compute_waveform(dt_data, soln_nn, mass_ratio, ode_model_params))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Time", ylabel="Waveform")
    +
    +    l1 = lines!(ax, tsteps, waveform; linewidth=2, alpha=0.75)
    +    s1 = scatter!(
    +        ax, tsteps, waveform; marker=:circle, markersize=12, alpha=0.5, strokewidth=2)
    +
    +    l2 = lines!(ax, tsteps, waveform_nn; linewidth=2, alpha=0.75)
    +    s2 = scatter!(
    +        ax, tsteps, waveform_nn; marker=:circle, markersize=12, alpha=0.5, strokewidth=2)
    +
    +    axislegend(ax, [[l1, s1], [l2, s2]],
    +        ["Waveform Data", "Waveform Neural Net (Untrained)"]; position=:lb)
    +
    +    fig
    +end

    Setting Up for Training the Neural Network

    Next, we define the objective (loss) function to be minimized when training the neural differential equations.

    julia
    const mseloss = MSELoss()
    +
    +function loss(θ)
    +    pred = Array(solve(prob_nn, RK4(); u0, p=θ, saveat=tsteps, dt, adaptive=false))
    +    pred_waveform = first(compute_waveform(dt_data, pred, mass_ratio, ode_model_params))
    +    return mseloss(pred_waveform, waveform)
    +end
    loss (generic function with 1 method)

    Warmup the loss function

    julia
    loss(params)
    0.0007031695500064645

    Now let us define a callback function to store the loss over time

    julia
    const losses = Float64[]
    +
    +function callback(θ, l)
    +    push!(losses, l)
    +    @printf "Training \\t Iteration: %5d \\t Loss: %.10f\\n" θ.iter l
    +    return false
    +end
    callback (generic function with 1 method)

    Training the Neural Network

    Training uses the BFGS optimizers. This seems to give good results because the Newtonian model seems to give a very good initial guess

    julia
    adtype = Optimization.AutoZygote()
    +optf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)
    +optprob = Optimization.OptimizationProblem(optf, params)
    +res = Optimization.solve(
    +    optprob, BFGS(; initial_stepnorm=0.01, linesearch=LineSearches.BackTracking());
    +    callback, maxiters=1000)
    retcode: Success
    +u: ComponentVector{Float64}(layer_1 = Float64[], layer_2 = (weight = [0.0001479886705053106; 0.00012837549729740222; -0.00019179450464456877; 3.322819611637084e-5; -2.6541045372146618e-5; -7.975404150768842e-5; -7.092556916177105e-5; -9.000685531646908e-5; -0.00010432666022084597; -0.00015823049761818606; 0.0001126797506002084; -3.444654066698e-5; -9.600944758858865e-5; 2.8409087462921232e-5; 5.754715311919196e-5; -4.9700760428110564e-5; 2.0464649423930583e-5; 8.749018888913114e-6; 0.0001389750686939419; -8.843734576651803e-6; 5.831631642649848e-5; 1.3364754522626191e-5; -2.3945151042422434e-5; -0.00019256481027693886; 2.0440254502292897e-6; 7.66503580961444e-5; 7.041894423301891e-5; -1.4782290236328528e-5; 9.342598059437742e-5; -0.00015591537521681518; -4.547557546171363e-5; -0.00012614081788351716;;], bias = [3.1618821547760237e-16, -2.239715669473555e-17, 2.538697890277846e-16, 3.0756254592508004e-17, 5.928300473541879e-18, -1.755045016605607e-16, -1.9693294904156052e-18, 1.0816634619367045e-17, -1.5099870307573793e-16, -2.3770075837870637e-17, 1.7961534013830336e-16, 3.740195902526728e-18, 3.8268793412463466e-18, 1.3398236140253248e-17, 4.480848124758183e-17, 1.813701563686835e-17, 3.0287440289475135e-17, 8.56756171288473e-18, 4.4199278980586825e-17, -7.040194979405464e-18, 4.937424637028749e-19, 7.950769350341129e-19, -4.37353035495063e-18, -2.860529948821097e-17, 2.9720407135201326e-18, 9.958207788192736e-17, 9.01360056680392e-17, 2.970758097357983e-18, 1.1322895285109382e-16, -5.67468551327775e-17, -4.3152995329292506e-17, 1.0725677217871096e-16]), layer_3 = (weight = [6.289465276899174e-5 -0.00012899090320893898 -7.084790373079785e-5 3.424563150879349e-5 -0.00014294157695580832 9.092407166867638e-5 1.986306783187381e-5 -0.00020486202807255978 0.00014140418538267642 -5.792483530564015e-5 0.00012580699153153993 3.976154225206352e-5 1.1009142367080704e-5 7.65272434768583e-5 -0.00015733710275121706 -1.9789807952793187e-5 -2.0275997081162693e-6 -6.791657102029507e-6 -4.5294424085621645e-5 2.2392714567514397e-5 -3.9277156206981564e-5 0.00018191160965620935 0.00016409756248726888 0.00010367071994954402 -4.451140371706867e-5 -7.565186202150628e-5 0.00010830837167709316 8.806619980087237e-7 0.00012046805390532141 2.4014816558009666e-5 0.0001407644831892413 -0.00013183734513909863; -4.797249286049889e-5 0.00011150827257231838 -3.7190746037156566e-5 9.121903193452253e-5 -0.00010013678339739477 2.8712764366426587e-5 4.641519834556517e-5 -1.536541432280625e-5 -2.0454068102045332e-5 -0.00013698306221478497 -2.3076732498812634e-5 -5.7661056156141256e-5 3.584664033477361e-6 8.321205158288444e-5 -0.00013441975689922577 2.9746445112757968e-5 2.0606723670860167e-5 8.5713518534683e-5 9.492339657888808e-5 3.411455535249629e-5 -5.762887823359229e-5 -9.081374966037613e-5 -6.314900175632126e-5 7.207402437854578e-6 0.00023802626882250268 5.7516752609879734e-5 -4.9156087437515224e-5 1.2719231823646323e-5 7.16143133890716e-5 -0.00016839187238794638 -4.147919181698136e-5 -5.904660221269333e-5; -2.9938078753612105e-5 5.524130965307436e-5 1.1746446304759924e-5 -6.095649014502691e-5 -4.192574642990644e-5 3.874391613601782e-5 -5.323290834246129e-5 7.759224381255062e-5 2.6843263455821043e-5 0.00011954859500940973 3.9134969753949765e-5 0.00013964464442063195 4.170480160349125e-5 0.00010622539984718038 -4.9426629359795904e-5 0.00010018986203897818 -6.675355844242426e-5 -0.00010403923961609531 -0.0001723964976034678 -0.0001353020358718552 -2.447208471755424e-5 9.17928976351775e-5 0.00014092800692845208 -0.00014417267966825424 6.656403847694467e-5 2.927370250939e-5 -7.643686970250403e-6 -8.035957735307443e-5 -1.855562705065513e-5 7.823967307297597e-5 -0.00012648670390523896 -5.1769334916453e-5; -0.00018446107866088244 -0.0001669987949387632 -2.1289227206331026e-5 9.436665347784126e-7 0.00015852095670218798 -1.0798727871371625e-5 -1.1851469807664616e-5 4.743225794321932e-5 8.787216884450972e-6 -8.956531097259353e-5 -0.0001949130208774972 0.0002199700421808594 -9.934061075320488e-8 -0.00010916361212345545 -3.892468235768816e-5 6.391325145180741e-5 7.681556884584203e-5 -0.00011808232089585478 -0.00017212704993630417 -0.00018349985190049597 8.681153407472689e-5 6.0042583882232845e-5 7.094825845363752e-5 9.021918516761999e-5 -7.04989187031691e-5 -0.00013075985485535278 -0.00019920513737794275 3.322511396639211e-5 4.259769539422367e-6 -1.412377774589985e-5 -0.0001896380680225474 0.00015777339571309255; 0.00018126487184791354 2.320218691612119e-5 -5.495449085710086e-5 -4.946991870318129e-7 -0.00020756972453081547 0.00022925964940814742 5.503709899504179e-5 -6.673372781360077e-5 -3.9605094294431785e-5 8.999546326240993e-5 0.00016215534042576774 -0.00014901728508984237 -0.00011352873634304405 9.173432254475044e-5 0.0001346032825532413 3.164670697888798e-5 0.00011464547633668842 1.3743772164259254e-5 -9.705129465048722e-6 -1.50638831618315e-5 -0.00010518199787465417 -8.10160033287437e-5 -1.4774039933302285e-5 -4.74798377544105e-5 -7.020216225636689e-5 -1.2936054823415126e-5 -5.890690381046875e-5 -4.323737990391989e-6 -0.00013548510987301847 0.00011017695424389561 -5.2493594644959365e-5 -8.339913343563779e-6; 0.00014380303581491364 -3.59231762668163e-5 -4.52986150885597e-5 2.1516021650309755e-5 -0.00020766168928458141 -1.7350606878614316e-5 7.961453046663694e-5 0.00019057139251162198 3.0341980153017373e-5 5.014021916211703e-5 -3.9831288741057685e-6 -0.00015125235405503577 0.00015956830428694228 -1.39207641150316e-5 -3.63545641557769e-5 0.00022001809519496887 5.914788743029572e-5 -0.00015853766855071058 7.023125907652439e-5 -1.8217748231112443e-5 -3.655926594729437e-5 0.00013926439531860177 -6.6373950186975e-5 6.244965778004472e-6 -3.8840191347848076e-5 5.419305852046229e-5 -4.733913193559242e-5 8.639995029443175e-5 -6.02048185210222e-5 1.4903156614295779e-5 -3.557242417810331e-5 -3.2749996546054805e-5; 0.00015866126997585836 -0.0001836579110966653 0.00019000546964540016 3.9290712462545305e-5 0.00010089986537074956 0.00019121416627619492 0.0001165205896688079 1.9494716267371664e-5 0.00014185687834121196 -6.381803612733881e-5 9.468194840898577e-5 -5.449116796064852e-5 -3.107852242813476e-5 -7.316120971502455e-5 -1.4628530865437775e-5 -8.448155930075574e-5 -2.3244648022071265e-5 9.611601055091557e-5 -0.00018836302550319988 -0.00014876642015572325 4.4096227808196114e-5 3.389362033133095e-6 -8.825388138923504e-5 3.146655873584421e-5 0.0001261932841008933 6.182772560002377e-5 0.00010061703434636945 -9.284324986204202e-5 6.107114242346946e-5 -0.00018807361701314002 6.487876745829595e-5 -0.0001219988123774184; -8.564073420716439e-5 -1.3132378691852178e-5 3.1930511729973555e-5 -5.934357165828628e-5 7.058959538695134e-5 0.00020131683498034742 -0.0001655896404118224 -2.2337440052111937e-5 -1.455298758814693e-5 4.1630862076952195e-5 0.00024530327293901074 0.00012909989975738056 0.00018083596017091005 -0.0001198203454551221 -0.00017451975788575945 -0.0001374086051073796 -5.5036084697388845e-5 9.581389251976027e-5 0.00016029613555288032 0.00013879031114625496 -8.009196523930294e-5 -0.0001066986724909327 6.486850991491895e-5 4.6812578402239385e-6 -0.00010437838415968476 5.5194407585035466e-5 1.959342346522558e-5 3.520783950803548e-5 -0.00012097960195391954 2.836520186927469e-6 -4.2236740293487285e-5 5.960426726956115e-5; 6.647209725259526e-5 -7.651895079845446e-5 -7.045743054559194e-5 -6.9192097860775e-5 2.132216454980387e-5 3.571455501395316e-6 -1.3805734986938413e-5 2.553916042586079e-5 -2.97390362430873e-5 6.447967812336081e-5 -0.00010273569582579912 -9.560410048665009e-5 -0.00014832810497694322 6.259751885578468e-5 -5.1028568257729236e-5 -6.96378157482609e-5 -4.300216473724298e-5 -4.342055776591052e-5 0.00015405477083903202 3.557053046448518e-5 3.262321101998668e-5 -9.972592319912836e-5 -3.444955304815956e-5 -5.676674859214285e-5 -7.59312571500579e-5 -3.072139238441361e-5 -0.00021853374723662707 2.522537929677314e-5 -3.662390022157407e-5 0.00012245742605217693 -1.4875466284262025e-5 1.8414666421339533e-5; -0.00011886521815564398 -6.524374612150913e-5 -2.2879368316582974e-5 4.6326631945454614e-5 -1.1420208011508104e-5 9.142819044402994e-5 0.00016751327939321407 -1.9921047624183742e-5 -0.00011349437545529134 -0.00013851774701857685 -1.757845666385657e-5 -0.00014613289522483094 0.00010688368502063092 7.52219116290928e-5 -9.313172040517409e-5 6.484146297200571e-5 -8.492693586983839e-5 -4.397206566888977e-5 -9.061805167244798e-5 5.623731567513991e-5 0.00011257896267100275 6.798309777852946e-5 4.304024560017399e-5 5.843297049045521e-5 6.900379821647747e-5 0.0001123014067158958 -4.8096896989837945e-5 1.3546874015197246e-5 -4.926265819473804e-5 -1.7330701212140458e-5 -0.0002810887685884818 -0.0001260364820157201; -4.171135321317918e-5 0.00010611540904559503 3.4815772158581993e-6 -0.00012482319459028085 -5.325688641110906e-5 0.00016939627506129852 2.9565042615867675e-5 4.887765164166148e-6 -0.00011994591647468147 -0.0002643397254979961 3.6563449731910304e-5 -0.00010804031796229549 -7.026451373181859e-5 2.7034908391069555e-5 3.324573311314421e-5 5.5186525179887896e-5 0.00015428776362736243 -2.8320104200392956e-5 5.03593602223536e-5 -0.00024188793929002712 7.566199759079577e-5 -7.780720795213713e-5 3.4016872012579864e-6 8.00730061367726e-6 3.9183998644002725e-5 7.319621193513683e-5 3.2316127664525524e-5 7.934592878737014e-6 0.00022212154556822418 8.448444544395662e-5 4.17046632099662e-5 -5.398294330749349e-5; -8.224721432633562e-5 5.61439842349583e-5 0.00010965629871498955 3.789595166018335e-5 4.7578509984385065e-6 3.596337728232256e-5 0.00017568215070787923 8.707016922563427e-5 2.3367574154698542e-5 8.813401560482127e-6 0.0001234360747694236 -3.068733352839627e-6 -6.350649531660612e-6 3.4608546680837024e-5 4.112679698301585e-5 -0.00010993534715816276 3.622255416849729e-5 -2.7708043948215367e-5 5.59384056905484e-5 -9.0807072869203e-5 0.00010973300186015771 -0.0004019133853071172 -0.00012118670611379568 -1.7418004521451195e-5 -2.8862090861358614e-5 7.530094398681183e-5 6.176080159640047e-5 5.098986999663594e-6 -2.467304557648373e-5 0.00010083142796794092 -0.0001767271828648438 -0.00010527361928688237; -7.654431041909667e-5 -4.8876375645610345e-5 4.4793218561715685e-5 -5.118262501665159e-5 2.2099041101766958e-5 -8.722629658759928e-5 -1.5878860127399476e-5 3.219997657115324e-5 7.430503378973277e-5 9.798564920321022e-5 5.678753282527489e-5 4.10334256722243e-5 6.189516048298042e-5 5.939203097486151e-5 0.00017383462605184317 -4.6544176571757114e-5 5.2725223808094874e-5 -0.00016875701052950528 -1.3614834957383448e-5 -3.7499601008592375e-5 -4.863495209602258e-5 -9.375803287721997e-5 3.033461203275912e-5 0.0001650614655355806 6.448416448082938e-5 -2.202168920657988e-5 -0.00018631458019254248 -0.00012096426448434415 -0.0001458106483786667 -6.976745439341422e-5 -0.00015476912753538866 -7.588019011190834e-5; 5.084889967158913e-5 -0.0002118628977327435 2.1615366175426974e-5 -4.628958736380742e-5 3.0044148341895383e-5 0.000167605052819033 -4.9905443621775474e-5 9.497985633837404e-5 -1.6689298310180207e-5 -0.00013202513905659954 0.00014834594226025125 0.00012773238308776916 3.0300585830023534e-5 -1.170506816511903e-5 -1.427166403251309e-5 2.5087153015683612e-5 8.448837656809808e-5 6.036118470414422e-5 -2.4102529597685917e-5 8.759934321327946e-5 0.0001213026629998597 -8.529440633670552e-5 -1.3124391035907058e-5 -0.00024581934080877734 0.00011386213777636062 8.230769931154801e-5 9.95778104411677e-5 -0.00010946925572303252 -0.00010147917742093715 0.00014499773574109525 -9.219214508866447e-6 2.206027643163116e-5; 4.872209719202946e-5 -1.6515710383585896e-5 -0.00024680436727769566 -4.971820054173809e-5 -7.791788048756661e-5 -6.197095318178782e-5 0.00010732032423426213 0.00018630029843940332 -0.0002122768197366312 1.0336273946695764e-5 -0.00011047212284005137 -5.33413691371061e-5 0.00011209536786942717 -0.00013046564673253685 6.671958580433138e-5 -5.4330568316563104e-5 1.0037677741147184e-5 -4.294218440682454e-6 6.00176466762311e-5 -5.820250917871861e-5 -2.3096182856296826e-5 -5.657238908292169e-5 -0.00012440203827985923 -8.59150601242843e-5 -0.00012554405803506647 0.00010523371055775168 -0.0001116824420093857 0.00021312398929900116 2.1166653290328563e-7 0.00010231919476816056 0.00013876694755914318 0.0001451982247019862; -7.494417764139279e-5 -0.00019951475656018904 0.00015804220060926176 -7.931439427087599e-5 3.0922906254648934e-6 -0.00021899425587510813 -0.00019707955175439121 3.622147232060664e-6 -0.00015080839034529197 -5.881092397505103e-5 8.491066409234073e-6 0.0001006101422255249 9.358686406737273e-5 -8.089740254112125e-5 -7.4032575419883154e-6 9.684526344168517e-5 -6.619984446919158e-5 0.00019664003525500526 5.1725780621542454e-5 -3.5321982751010306e-5 -1.8981124186062922e-5 4.020524397597996e-5 -0.00015314961888256108 -6.880321120734988e-5 -9.088651381793096e-5 6.285395328782717e-6 -1.0765035541076204e-5 0.00017396886437305597 -0.00012084182776637331 -7.687197171509937e-5 -1.8798057233994109e-6 0.00021102186769819464; 0.00020664584287765776 -3.8355891705979897e-5 -3.6399299392038005e-5 6.607417686210196e-6 0.00021502601437128844 -1.1050467878194525e-5 9.458355186830901e-5 3.5168627687707705e-5 4.193239426564024e-5 -3.794593878814658e-5 5.109576075079418e-5 8.714178245605662e-5 7.221976109172776e-5 5.0575573146133675e-6 0.0001103895511510568 -0.00018290032760381962 2.3291370849220616e-5 -3.6202692103360195e-5 -3.9817209585128185e-5 -0.00013440107879836335 8.675253327561265e-5 -5.49379812986347e-6 7.266176096487563e-5 -3.906812428289934e-5 -2.509500602576635e-5 4.337618800087514e-5 9.90669384515076e-6 -8.512449243825297e-6 -0.00012463124305617427 -2.870946348088488e-5 -0.0001875596907888751 -9.898799628394211e-5; 0.00020623337629364102 -1.7315879385597635e-5 -0.00016270945045985903 -1.2328475104014735e-5 4.449443374177408e-5 -7.785475893762671e-5 -2.1413424046492117e-5 8.370699221848523e-5 0.000155708078882868 -0.0001183475003287118 5.857109069472575e-5 3.91873466200093e-5 -2.3867493591407574e-5 -9.139398455737204e-5 0.0002783849588653411 -0.00012810562177911647 0.00011204942281473427 6.355745724285063e-5 0.0001368259211361555 -6.740463571041781e-5 8.912472846567275e-5 4.104083861456283e-5 4.493123858118412e-5 -6.262982490594223e-5 0.0002581998517329251 6.94725415727431e-5 -3.596364033875597e-5 -3.0325831839591016e-5 8.049828763467198e-5 -1.251112255853661e-5 -2.246999495547461e-5 2.170262566357397e-5; -7.269410690885596e-5 -0.0001251600404585374 6.783550650917726e-5 3.5367087714739696e-5 9.460102608766662e-5 5.065944076971189e-5 -0.00011152755889004006 0.00014278427277797807 -0.00021785643895516307 -4.754547096199631e-6 6.365534516855869e-5 7.371757254343718e-5 7.109614687845041e-5 -1.8371021557932062e-5 0.00011231616388879872 8.884882862087531e-5 -3.156197255254455e-5 4.629487392133382e-5 -5.124753790103359e-5 0.0002186446728800824 3.3425480235499926e-5 3.2400206858192544e-5 -8.354605944720767e-5 3.7655532817475244e-5 -5.6785214671499055e-5 3.490493707697897e-5 -0.00012040373969018368 -0.00015075013636039298 -1.5090809772185105e-5 4.494286639139337e-5 6.308795144189355e-5 4.305767668749807e-5; 3.351272907782971e-5 -0.00014271316531487365 0.00017131796566862998 -0.00010089095367259683 2.9893063856043093e-5 -0.00011379346751748679 2.7022292942612736e-5 1.2804533343636294e-5 -4.997900877469654e-7 -0.00011254559713089998 2.0927202964011898e-6 -5.2775897257042654e-5 -0.00010604089829978496 -3.2060241847311866e-5 2.7260704245755892e-5 -5.247574581556296e-5 -0.00012837586173230223 1.6825445799958772e-5 -7.14528002394406e-5 0.00013343652180953494 -9.974749327778115e-5 0.00017567796685359055 8.404467307588655e-5 -0.00014363772124889842 0.00012854390597528387 -0.00013070163613558867 -3.1721462346857146e-5 1.7603287505671327e-5 -9.033714804938979e-5 -1.7541821489811035e-5 8.696635568373544e-5 0.00012955887295863943; -0.0001878250669456718 0.00017699173886778834 3.1490583665283875e-5 -4.9970604863645144e-5 7.803776944039973e-5 2.8186904187735986e-5 0.0002255303360520187 9.589678398173646e-6 7.341166465760129e-5 -0.0001430022140035097 0.00027343908268942475 -0.00013367596429323178 -1.2282993424901562e-5 -3.0706044612614154e-5 -4.0326901484674764e-5 7.69845381959591e-5 -0.00012843436442797423 -5.60199269735477e-5 1.1872151894090286e-6 -6.780496650624453e-5 -4.288874433275588e-5 -5.121483363343764e-5 -0.00019581083788087008 -9.321010028958637e-5 6.603158081399841e-5 -8.879934235450455e-7 5.153587963416006e-5 -0.00014158792791438645 7.121437638982065e-5 -8.590605020305797e-5 0.00015030227487425012 -5.627547315686887e-5; -5.912982921471255e-5 2.6671649930003353e-5 0.0001217353794618502 1.0003410561690304e-5 -8.007208704839708e-5 -9.820559241234105e-5 -0.00012170795414022059 8.378415916922863e-5 0.00016907019128666848 7.98882767685585e-5 -9.081312573465576e-6 0.00026348081994910527 9.293719743255049e-5 4.0398300579904996e-5 -0.0001857728045888528 -0.00019673402018270558 -5.740481244175033e-5 -7.330848781748973e-5 0.00016787690513411888 6.829187735092528e-5 4.4106397790526715e-5 2.10052323654917e-5 -0.0001596619975043766 4.579287381605193e-5 -0.00018886184149778757 -0.00017394858766238031 -0.00010925266430604168 -5.149736059138837e-5 -0.00020355819903670398 -6.10330341896618e-5 -5.1731468165602006e-5 2.933786275208068e-5; 0.00013693632350120444 -0.00014005942652650644 0.00010480915075684338 -5.797923954154539e-5 -4.048608029328477e-5 -7.644874135215723e-5 -3.093673153265391e-5 5.601651715047773e-5 -0.0001409684119112487 6.81226592446107e-5 -1.951912240250197e-5 1.2077576643115068e-5 5.2176506828313445e-5 4.231428097633459e-5 0.0001166163855982284 -0.00012488920042009213 -4.170203105380961e-5 0.00011916897342822298 -0.0001567016370659357 -0.00010300965372656689 5.957465832090611e-6 -8.658150186014573e-5 4.295691901867082e-5 5.402269012345384e-5 -0.00013350738303919544 -0.00012053572576909303 0.00010150989688050917 8.700555913897953e-5 -1.5779160135512695e-5 -3.326251684987132e-5 -5.28037381132333e-5 5.8353274611788524e-5; -0.00020004856283175256 4.259047550168292e-5 -3.792201099155815e-6 5.848158295162834e-6 -3.4376688703008655e-5 -2.5124930246777475e-5 -1.1709697858707859e-5 4.716953030457042e-5 -9.484482646614072e-6 2.1742546820506443e-5 -7.295220071081669e-5 1.3499498933566629e-5 7.55262799853952e-5 9.08456632229046e-5 -8.025072887351924e-6 -2.1311886442520993e-5 -7.918210845072637e-5 -4.9304534471406444e-5 0.000158418922225437 -7.639748305645662e-5 -6.701475736317054e-5 0.00020400019188546685 8.10862370290679e-6 -0.00013003496219733888 -6.820522772013102e-5 -1.938388500402002e-5 6.901289366088074e-5 -0.0001083203541869752 -2.5971424250558162e-5 3.8305089262040196e-5 6.564368145209885e-5 3.141721667508057e-5; -0.00016382765105970868 -8.254837966103736e-5 0.00012010027486086995 -0.00014978825428568356 9.322569629714677e-6 -7.658340408977685e-5 -0.00013891490315598058 2.3778545333899853e-6 0.00010048912436888892 -1.0069668216036951e-5 0.00011513248383255072 7.988268108294746e-5 5.657734864928179e-5 2.2221499155987366e-5 3.6575795737574026e-5 -0.0002041848850161636 0.00016715774173337443 -0.0002513967113294505 2.2551456557831785e-5 0.00014347062888975663 -0.00012792775604919142 -3.72045172219962e-5 -0.00012602771247782337 0.00012130559544732033 9.629631411937894e-6 8.668697474479114e-5 -7.264572131259922e-5 0.00017094639107074062 0.00014189324493474678 -2.8030385957553316e-5 9.529213339976429e-5 1.6033599157364382e-5; 9.873387646805597e-5 -0.00016460367875694885 5.379534671375904e-5 3.085324463612487e-5 -7.868724311989627e-5 -1.763966862924076e-5 8.791531329919498e-5 -0.0001012360614986088 1.586637084258842e-5 0.00017056108229737688 0.0003352144023956782 -8.547109861680222e-5 -4.3112979954427944e-5 7.744432262555797e-5 -8.718831192524184e-5 5.868031915455153e-5 0.00011043210291248863 4.3332665183731736e-5 -0.00014446147067062346 5.174312648890671e-5 -3.8134747926928233e-5 -6.059597105191893e-5 -9.77165061776422e-5 0.00016370910928528192 -8.81911717151185e-5 -0.00011716449332012918 8.828415258935756e-6 -4.4403349209426575e-5 3.741140353969072e-7 -2.9239096664218282e-5 0.00015301452843417457 7.696834403034666e-5; -2.7695354106393765e-5 0.00016632921699478355 0.00018915046177849762 -6.367697994880486e-5 0.00011415624260246616 -9.11414934993136e-5 -5.885557754969983e-5 2.30117603902139e-5 -8.592439178333956e-5 -9.335103447970256e-5 -3.864963571264616e-5 -0.00012202420828122748 -0.0001209456858081137 -3.790244215940256e-5 -3.813496721283482e-5 -0.0001481795515022614 0.00013423368739006882 4.861781792408604e-5 -0.00021318687129256048 -0.00021753645330624839 -4.259200784451272e-5 -9.925761321516884e-5 -1.3700089653294145e-5 -8.001438607183606e-5 2.6806961727405877e-5 0.00015645179894330214 0.00012051352325637061 -1.0825014163252523e-7 -1.7877107780226786e-5 3.8311624052447006e-5 -1.1977196550441838e-5 5.2060910206493225e-5; 2.8731227105327503e-6 6.907732547757515e-5 -0.00015171601755514588 0.00020949787956694324 4.6547962285971415e-6 0.0001599443881589351 -8.393219233924548e-5 -9.579538001829758e-6 -9.736524718549436e-5 0.0001705027921873409 -0.00015885850500284198 -0.00027448492384949514 6.217265270448975e-5 0.0001704151460019333 -1.0681546356619121e-5 -0.0001370050498933148 -1.4038439459663462e-5 1.175704440602927e-6 -1.626252144136782e-5 -9.724314096937818e-6 6.109215117091378e-5 -5.412904049237955e-5 9.185245524192443e-5 -8.573939469147337e-5 -8.911940442133451e-5 3.529634939538247e-5 5.8032760151279896e-5 2.4090828249161067e-6 0.00017823634932780417 0.00012349287369784785 9.976872622998566e-5 9.889379232687275e-5; 5.0404076179055e-5 6.830047991223153e-5 -0.00011087438556735437 -0.00020347867044057805 -0.00016650287957765261 9.249837953228266e-5 3.2090578175650714e-5 0.00015634505311589412 6.094517070430916e-5 4.136413540088819e-5 7.437079917672853e-6 0.00013689039392027894 -0.00013218620384015446 7.994963002255082e-5 -3.9365659316733255e-5 -2.610954484572779e-5 0.00035285661928918116 7.467133750304492e-5 5.594901071724866e-5 -0.0001900224125655004 -2.7960815854218598e-5 -0.0002833453437722856 -4.463671589639137e-5 5.346597740406128e-5 0.0001488012529500193 -3.1072311825316805e-5 -3.73593758502623e-5 5.246592613383105e-5 -2.291935883311706e-6 3.2226060144401e-5 -3.65895286029777e-5 1.6539359281687062e-5; -0.00013727221734980522 -0.00022803118840484076 8.518794570890029e-5 0.0001404153598317011 0.00016038087856332518 -0.00013812434840174004 3.6360471179527155e-5 2.700204900366091e-5 0.00011554073066990985 2.44606024837531e-5 1.7620185511350382e-5 0.00017882297184160633 0.00019688376128515473 0.00013338869107729496 2.376348934677044e-5 3.235529298154295e-5 0.00022275520391604623 -1.5659839070115587e-5 -0.00014963759089978677 8.591715673292766e-5 -3.2952432908764275e-5 -7.558879510424328e-5 -6.746724024805487e-5 1.868463810140957e-5 -3.1426558477441617e-6 -2.7207358604479152e-5 -0.0001488337285506493 0.00013670434496207865 4.055339454980837e-5 -0.00018453788574943842 -9.627806789166615e-5 1.501663869321251e-5; -0.00021324839605452688 1.9567026296011234e-5 2.8412067816565533e-5 -6.088878859968207e-5 6.632363959711673e-5 -0.00014127795572361934 3.4785306464488654e-5 -7.890699186331531e-5 1.6044882553123984e-5 -6.833672802398019e-5 8.260601765274357e-5 -0.00018783405818480347 0.0001386036428206891 8.130487270450853e-5 -5.675406561435374e-5 0.00029214500403527884 -0.0001149526606846353 0.00010721222946217883 -0.00010607316932376794 9.35828328997143e-5 -3.543586632671935e-5 -8.053549669652573e-5 5.457336095192161e-5 -0.0001098871899253261 -0.00013411393144137563 -0.000152272582514836 0.00016539799701918752 -5.768272518848395e-5 2.9870096962857977e-5 -0.00014114850188573898 6.3466413243580365e-6 0.0001379418799237672; 8.309488175216532e-5 2.7904824214768077e-5 -9.756287482090278e-5 -1.8862770325360788e-5 7.323950257632361e-5 0.000262231730353226 -7.489013233208069e-5 -1.1423416531041828e-5 0.00022319819681359897 -5.0554495196434365e-5 -9.102430617361763e-6 3.449831360919828e-6 -0.00015784326688372873 0.00014489410813912218 -5.668592285001469e-5 -0.00012680011723641984 6.851286588716759e-5 0.00023398604088942988 3.720012450849063e-6 5.8333237298210174e-5 -0.00012027687926529734 -2.2866589738261037e-5 -0.00014670176761210474 8.99105622876621e-5 -6.722413040553145e-6 0.00015074402171666687 7.421512118089048e-5 0.0001134765304370363 -9.459884613971525e-5 5.0419127269538136e-5 -9.531196274547547e-5 8.755625885458661e-5], bias = [1.362463491334985e-9, -3.398904685654539e-10, -1.610066669886397e-11, -3.242221072784985e-9, -4.156017242074563e-11, 1.2860145909590977e-9, 1.141612458391299e-9, 9.394425035937008e-10, -3.0232951195917684e-9, -1.616627081790752e-9, 2.966151805736721e-10, -5.1390080646152605e-11, -1.9857415354524423e-9, 1.7684656463219359e-9, -1.1783483755736966e-9, -2.236220861232494e-9, 5.121142395241432e-10, 3.6773329978313097e-9, 1.1715955501843653e-9, -1.4121728149894085e-9, -8.049888293545121e-10, -2.5309145760393373e-9, -1.2587820853669075e-9, -5.465639278681154e-10, 1.9709534420796504e-10, 1.3435347112437137e-9, -2.1863119136768887e-9, 1.6248834716321566e-9, 7.310938454045174e-10, 1.557831007680469e-9, -1.4870843604346265e-9, 2.725478406142474e-9]), layer_4 = (weight = [-0.0007374361934195449 -0.0007597268657267519 -0.0006537941531990138 -0.0007800752735170239 -0.0007047920986039328 -0.000678939082443919 -0.0007058507704826389 -0.0007406296612836417 -0.0006558525313057186 -0.0006669606334663165 -0.0006189535229626955 -0.0006119800360087953 -0.0006194189803236911 -0.0006690719304301911 -0.000763064690569369 -0.0007623020384361817 -0.0006275043556428826 -0.0006100933551841793 -0.0007451075583788393 -0.0006298057986045238 -0.0007668987434951661 -0.0005930016240738988 -0.0007118292427099427 -0.0007655331122073681 -0.000585735044956384 -0.0007726682904175011 -0.0007601062108833979 -0.0007559035208590189 -0.0006345405282430247 -0.0006785503088444641 -0.0009014060900150451 -0.000531920086844552; 0.00013594893440536723 0.00026839277162856644 0.0003223211408476348 0.000310548806501568 0.00014819514965658817 0.00020153183148601252 0.00021228104648558522 0.0001808081529319296 0.00019904956265658853 0.00027947947796219696 0.00036426097493794357 0.00036359251154835363 0.00014490865705834625 0.0003029815590890083 0.0001894672295971893 0.00028775482287253247 0.0002632548694413957 0.00011612435116104449 0.0002456494818520329 0.00031629009864845084 0.0002499269396489655 0.00010553547110531008 0.0003164608754771367 0.0002617368496312524 0.0002868396494856868 0.00020246197007451418 0.0002490765888576313 9.462765896848049e-5 0.00028729026752222437 0.000188773670293046 0.00020498502796661137 0.00014221790314839118], bias = [-0.0006917778715618791, 0.0002525701222495951]))

    Visualizing the Results

    Let us now plot the loss over time

    julia
    begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Iteration", ylabel="Loss")
    +
    +    lines!(ax, losses; linewidth=4, alpha=0.75)
    +    scatter!(ax, 1:length(losses), losses; marker=:circle, markersize=12, strokewidth=2)
    +
    +    fig
    +end

    Finally let us visualize the results

    julia
    prob_nn = ODEProblem(ODE_model, u0, tspan, res.u)
    +soln_nn = Array(solve(prob_nn, RK4(); u0, p=res.u, saveat=tsteps, dt, adaptive=false))
    +waveform_nn_trained = first(compute_waveform(
    +    dt_data, soln_nn, mass_ratio, ode_model_params))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Time", ylabel="Waveform")
    +
    +    l1 = lines!(ax, tsteps, waveform; linewidth=2, alpha=0.75)
    +    s1 = scatter!(
    +        ax, tsteps, waveform; marker=:circle, alpha=0.5, strokewidth=2, markersize=12)
    +
    +    l2 = lines!(ax, tsteps, waveform_nn; linewidth=2, alpha=0.75)
    +    s2 = scatter!(
    +        ax, tsteps, waveform_nn; marker=:circle, alpha=0.5, strokewidth=2, markersize=12)
    +
    +    l3 = lines!(ax, tsteps, waveform_nn_trained; linewidth=2, alpha=0.75)
    +    s3 = scatter!(ax, tsteps, waveform_nn_trained; marker=:circle,
    +        alpha=0.5, strokewidth=2, markersize=12)
    +
    +    axislegend(ax, [[l1, s1], [l2, s2], [l3, s3]],
    +        ["Waveform Data", "Waveform Neural Net (Untrained)", "Waveform Neural Net"];
    +        position=:lb)
    +
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 128 × AMD EPYC 7502 32-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 16 default, 0 interactive, 8 GC (on 16 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 16
    +  JULIA_DEPOT_PATH = /cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 16
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate

    This page was generated using Literate.jl.

    `,31))])}const Z=t(e,[["render",X]]);export{j as __pageData,Z as default}; diff --git a/previews/PR1023/assets/tutorials_advanced_1_GravitationalWaveForm.md.CE8fiIvN.lean.js b/previews/PR1023/assets/tutorials_advanced_1_GravitationalWaveForm.md.CE8fiIvN.lean.js new file mode 100644 index 0000000000..b8c3e2c177 --- /dev/null +++ b/previews/PR1023/assets/tutorials_advanced_1_GravitationalWaveForm.md.CE8fiIvN.lean.js @@ -0,0 +1,286 @@ +import{_ as t,c as i,a2 as n,j as A,a as h,o as a}from"./chunks/framework.DFwXuivk.js";const j=JSON.parse('{"title":"Training a Neural ODE to Model Gravitational Waveforms","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/advanced/1_GravitationalWaveForm.md","filePath":"tutorials/advanced/1_GravitationalWaveForm.md","lastUpdated":null}'),e={name:"tutorials/advanced/1_GravitationalWaveForm.md"},l={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},p={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.339ex"},xmlns:"http://www.w3.org/2000/svg",width:"10.819ex",height:"1.658ex",role:"img",focusable:"false",viewBox:"0 -583 4782.1 733","aria-hidden":"true"},k={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},E={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.339ex"},xmlns:"http://www.w3.org/2000/svg",width:"2.008ex",height:"1.339ex",role:"img",focusable:"false",viewBox:"0 -442 887.6 592","aria-hidden":"true"},r={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},d={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.339ex"},xmlns:"http://www.w3.org/2000/svg",width:"2.008ex",height:"1.339ex",role:"img",focusable:"false",viewBox:"0 -442 887.6 592","aria-hidden":"true"},Q={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},C={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"24.527ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 10840.9 1000","aria-hidden":"true"},o={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},g={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.117ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3587.6 1000","aria-hidden":"true"},f={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},v={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.049ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3557.6 1000","aria-hidden":"true"},y={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},I={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.138ex",height:"1.439ex",role:"img",focusable:"false",viewBox:"0 -442 503 636","aria-hidden":"true"},F={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},u={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"0"},xmlns:"http://www.w3.org/2000/svg",width:"2.378ex",height:"1.545ex",role:"img",focusable:"false",viewBox:"0 -683 1051 683","aria-hidden":"true"},c={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},m={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.054ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 466 453","aria-hidden":"true"},B={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},T={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.117ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3587.6 1000","aria-hidden":"true"},q={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},z={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.049ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3557.6 1000","aria-hidden":"true"},V={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},D={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.439ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.138ex",height:"1.439ex",role:"img",focusable:"false",viewBox:"0 -442 503 636","aria-hidden":"true"},U={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},b={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"0"},xmlns:"http://www.w3.org/2000/svg",width:"2.378ex",height:"1.545ex",role:"img",focusable:"false",viewBox:"0 -683 1051 683","aria-hidden":"true"},P={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},R={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"1.054ex",height:"1.025ex",role:"img",focusable:"false",viewBox:"0 -442 466 453","aria-hidden":"true"};function X(K,s,O,w,N,x){return a(),i("div",null,[s[41]||(s[41]=n(`

    Training a Neural ODE to Model Gravitational Waveforms

    This code is adapted from Astroinformatics/ScientificMachineLearning

    The code has been minimally adapted from Keith et. al. 2021 which originally used Flux.jl

    Package Imports

    julia
    using Lux, ComponentArrays, LineSearches, OrdinaryDiffEqLowOrderRK, Optimization,
    +      OptimizationOptimJL, Printf, Random, SciMLSensitivity
    +using CairoMakie

    Define some Utility Functions

    Tip

    This section can be skipped. It defines functions to simulate the model, however, from a scientific machine learning perspective, isn't super relevant.

    `,7)),A("p",null,[s[6]||(s[6]=h("We need a very crude 2-body path. Assume the 1-body motion is a newtonian 2-body position vector ")),A("mjx-container",l,[(a(),i("svg",p,s[0]||(s[0]=[n('',1)]))),s[1]||(s[1]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"r"),A("mo",null,"="),A("msub",null,[A("mi",null,"r"),A("mn",null,"1")]),A("mo",null,"−"),A("msub",null,[A("mi",null,"r"),A("mn",null,"2")])])],-1))]),s[7]||(s[7]=h(" and use Newtonian formulas to get ")),A("mjx-container",k,[(a(),i("svg",E,s[2]||(s[2]=[n('',1)]))),s[3]||(s[3]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("msub",null,[A("mi",null,"r"),A("mn",null,"1")])])],-1))]),s[8]||(s[8]=h(", ")),A("mjx-container",r,[(a(),i("svg",d,s[4]||(s[4]=[n('',1)]))),s[5]||(s[5]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("msub",null,[A("mi",null,"r"),A("mn",null,"2")])])],-1))]),s[9]||(s[9]=h(" (e.g. Theoretical Mechanics of Particles and Continua 4.3)"))]),s[42]||(s[42]=n(`
    julia
    function one2two(path, m₁, m₂)
    +    M = m₁ + m₂
    +    r₁ = m₂ / M .* path
    +    r₂ = -m₁ / M .* path
    +    return r₁, r₂
    +end
    one2two (generic function with 1 method)
    `,2)),A("p",null,[s[12]||(s[12]=h("Next we define a function to perform the change of variables: ")),A("mjx-container",Q,[(a(),i("svg",C,s[10]||(s[10]=[n('',1)]))),s[11]||(s[11]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mo",{stretchy:"false"},"("),A("mi",null,"χ"),A("mo",{stretchy:"false"},"("),A("mi",null,"t"),A("mo",{stretchy:"false"},")"),A("mo",null,","),A("mi",null,"ϕ"),A("mo",{stretchy:"false"},"("),A("mi",null,"t"),A("mo",{stretchy:"false"},")"),A("mo",{stretchy:"false"},")"),A("mo",{stretchy:"false"},"↦"),A("mo",{stretchy:"false"},"("),A("mi",null,"x"),A("mo",{stretchy:"false"},"("),A("mi",null,"t"),A("mo",{stretchy:"false"},")"),A("mo",null,","),A("mi",null,"y"),A("mo",{stretchy:"false"},"("),A("mi",null,"t"),A("mo",{stretchy:"false"},")"),A("mo",{stretchy:"false"},")")])],-1))])]),s[43]||(s[43]=n(`
    julia
    @views function soln2orbit(soln, model_params=nothing)
    +    @assert size(soln, 1)  [2, 4] "size(soln,1) must be either 2 or 4"
    +
    +    if size(soln, 1) == 2
    +        χ = soln[1, :]
    +        ϕ = soln[2, :]
    +
    +        @assert length(model_params)==3 "model_params must have length 3 when size(soln,2) = 2"
    +        p, M, e = model_params
    +    else
    +        χ = soln[1, :]
    +        ϕ = soln[2, :]
    +        p = soln[3, :]
    +        e = soln[4, :]
    +    end
    +
    +    r = p ./ (1 .+ e .* cos.(χ))
    +    x = r .* cos.(ϕ)
    +    y = r .* sin.(ϕ)
    +
    +    orbit = vcat(x', y')
    +    return orbit
    +end
    soln2orbit (generic function with 2 methods)

    This function uses second-order one-sided difference stencils at the endpoints; see https://doi.org/10.1090/S0025-5718-1988-0935077-0

    julia
    function d_dt(v::AbstractVector, dt)
    +    a = -3 / 2 * v[1] + 2 * v[2] - 1 / 2 * v[3]
    +    b = (v[3:end] .- v[1:(end - 2)]) / 2
    +    c = 3 / 2 * v[end] - 2 * v[end - 1] + 1 / 2 * v[end - 2]
    +    return [a; b; c] / dt
    +end
    d_dt (generic function with 1 method)

    This function uses second-order one-sided difference stencils at the endpoints; see https://doi.org/10.1090/S0025-5718-1988-0935077-0

    julia
    function d2_dt2(v::AbstractVector, dt)
    +    a = 2 * v[1] - 5 * v[2] + 4 * v[3] - v[4]
    +    b = v[1:(end - 2)] .- 2 * v[2:(end - 1)] .+ v[3:end]
    +    c = 2 * v[end] - 5 * v[end - 1] + 4 * v[end - 2] - v[end - 3]
    +    return [a; b; c] / (dt^2)
    +end
    d2_dt2 (generic function with 1 method)

    Now we define a function to compute the trace-free moment tensor from the orbit

    julia
    function orbit2tensor(orbit, component, mass=1)
    +    x = orbit[1, :]
    +    y = orbit[2, :]
    +
    +    Ixx = x .^ 2
    +    Iyy = y .^ 2
    +    Ixy = x .* y
    +    trace = Ixx .+ Iyy
    +
    +    if component[1] == 1 && component[2] == 1
    +        tmp = Ixx .- trace ./ 3
    +    elseif component[1] == 2 && component[2] == 2
    +        tmp = Iyy .- trace ./ 3
    +    else
    +        tmp = Ixy
    +    end
    +
    +    return mass .* tmp
    +end
    +
    +function h_22_quadrupole_components(dt, orbit, component, mass=1)
    +    mtensor = orbit2tensor(orbit, component, mass)
    +    mtensor_ddot = d2_dt2(mtensor, dt)
    +    return 2 * mtensor_ddot
    +end
    +
    +function h_22_quadrupole(dt, orbit, mass=1)
    +    h11 = h_22_quadrupole_components(dt, orbit, (1, 1), mass)
    +    h22 = h_22_quadrupole_components(dt, orbit, (2, 2), mass)
    +    h12 = h_22_quadrupole_components(dt, orbit, (1, 2), mass)
    +    return h11, h12, h22
    +end
    +
    +function h_22_strain_one_body(dt::T, orbit) where {T}
    +    h11, h12, h22 = h_22_quadrupole(dt, orbit)
    +
    +    h₊ = h11 - h22
    +    hₓ = T(2) * h12
    +
    +    scaling_const =(T(π) / 5)
    +    return scaling_const * h₊, -scaling_const * hₓ
    +end
    +
    +function h_22_quadrupole_two_body(dt, orbit1, mass1, orbit2, mass2)
    +    h11_1, h12_1, h22_1 = h_22_quadrupole(dt, orbit1, mass1)
    +    h11_2, h12_2, h22_2 = h_22_quadrupole(dt, orbit2, mass2)
    +    h11 = h11_1 + h11_2
    +    h12 = h12_1 + h12_2
    +    h22 = h22_1 + h22_2
    +    return h11, h12, h22
    +end
    +
    +function h_22_strain_two_body(dt::T, orbit1, mass1, orbit2, mass2) where {T}
    +    # compute (2,2) mode strain from orbits of BH 1 of mass1 and BH2 of mass 2
    +
    +    @assert abs(mass1 + mass2 - 1.0)<1e-12 "Masses do not sum to unity"
    +
    +    h11, h12, h22 = h_22_quadrupole_two_body(dt, orbit1, mass1, orbit2, mass2)
    +
    +    h₊ = h11 - h22
    +    hₓ = T(2) * h12
    +
    +    scaling_const =(T(π) / 5)
    +    return scaling_const * h₊, -scaling_const * hₓ
    +end
    +
    +function compute_waveform(dt::T, soln, mass_ratio, model_params=nothing) where {T}
    +    @assert mass_ratio1 "mass_ratio must be <= 1"
    +    @assert mass_ratio0 "mass_ratio must be non-negative"
    +
    +    orbit = soln2orbit(soln, model_params)
    +    if mass_ratio > 0
    +        m₂ = inv(T(1) + mass_ratio)
    +        m₁ = mass_ratio * m₂
    +
    +        orbit₁, orbit₂ = one2two(orbit, m₁, m₂)
    +        waveform = h_22_strain_two_body(dt, orbit₁, m₁, orbit₂, m₂)
    +    else
    +        waveform = h_22_strain_one_body(dt, orbit)
    +    end
    +    return waveform
    +end
    compute_waveform (generic function with 2 methods)

    Simulating the True Model

    RelativisticOrbitModel defines system of odes which describes motion of point like particle in schwarzschild background, uses

    `,13)),A("mjx-container",o,[(a(),i("svg",g,s[13]||(s[13]=[n('',1)]))),s[14]||(s[14]=A("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[A("mi",null,"u"),A("mo",{stretchy:"false"},"["),A("mn",null,"1"),A("mo",{stretchy:"false"},"]"),A("mo",null,"="),A("mi",null,"χ")])],-1))]),A("mjx-container",f,[(a(),i("svg",v,s[15]||(s[15]=[n('',1)]))),s[16]||(s[16]=A("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[A("mi",null,"u"),A("mo",{stretchy:"false"},"["),A("mn",null,"2"),A("mo",{stretchy:"false"},"]"),A("mo",null,"="),A("mi",null,"ϕ")])],-1))]),A("p",null,[s[23]||(s[23]=h("where, ")),A("mjx-container",y,[(a(),i("svg",I,s[17]||(s[17]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D45D",d:"M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z",style:{"stroke-width":"3"}})])])],-1)]))),s[18]||(s[18]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"p")])],-1))]),s[24]||(s[24]=h(", ")),A("mjx-container",F,[(a(),i("svg",u,s[19]||(s[19]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D440",d:"M289 629Q289 635 232 637Q208 637 201 638T194 648Q194 649 196 659Q197 662 198 666T199 671T201 676T203 679T207 681T212 683T220 683T232 684Q238 684 262 684T307 683Q386 683 398 683T414 678Q415 674 451 396L487 117L510 154Q534 190 574 254T662 394Q837 673 839 675Q840 676 842 678T846 681L852 683H948Q965 683 988 683T1017 684Q1051 684 1051 673Q1051 668 1048 656T1045 643Q1041 637 1008 637Q968 636 957 634T939 623Q936 618 867 340T797 59Q797 55 798 54T805 50T822 48T855 46H886Q892 37 892 35Q892 19 885 5Q880 0 869 0Q864 0 828 1T736 2Q675 2 644 2T609 1Q592 1 592 11Q592 13 594 25Q598 41 602 43T625 46Q652 46 685 49Q699 52 704 61Q706 65 742 207T813 490T848 631L654 322Q458 10 453 5Q451 4 449 3Q444 0 433 0Q418 0 415 7Q413 11 374 317L335 624L267 354Q200 88 200 79Q206 46 272 46H282Q288 41 289 37T286 19Q282 3 278 1Q274 0 267 0Q265 0 255 0T221 1T157 2Q127 2 95 1T58 0Q43 0 39 2T35 11Q35 13 38 25T43 40Q45 46 65 46Q135 46 154 86Q158 92 223 354T289 629Z",style:{"stroke-width":"3"}})])])],-1)]))),s[20]||(s[20]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"M")])],-1))]),s[25]||(s[25]=h(", and ")),A("mjx-container",c,[(a(),i("svg",m,s[21]||(s[21]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D452",d:"M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z",style:{"stroke-width":"3"}})])])],-1)]))),s[22]||(s[22]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"e")])],-1))]),s[26]||(s[26]=h(" are constants"))]),s[44]||(s[44]=n(`
    julia
    function RelativisticOrbitModel(u, (p, M, e), t)
    +    χ, ϕ = u
    +
    +    numer = (p - 2 - 2 * e * cos(χ)) * (1 + e * cos(χ))^2
    +    denom = sqrt((p - 2)^2 - 4 * e^2)
    +
    +    χ̇ = numer * sqrt(p - 6 - 2 * e * cos(χ)) / (M * (p^2) * denom)
    +    ϕ̇ = numer / (M * (p^(3 / 2)) * denom)
    +
    +    return [χ̇, ϕ̇]
    +end
    +
    +mass_ratio = 0.0         # test particle
    +u0 = Float64[π, 0.0]     # initial conditions
    +datasize = 250
    +tspan = (0.0f0, 6.0f4)   # timespace for GW waveform
    +tsteps = range(tspan[1], tspan[2]; length=datasize)  # time at each timestep
    +dt_data = tsteps[2] - tsteps[1]
    +dt = 100.0
    +const ode_model_params = [100.0, 1.0, 0.5]; # p, M, e

    Let's simulate the true model and plot the results using OrdinaryDiffEq.jl

    julia
    prob = ODEProblem(RelativisticOrbitModel, u0, tspan, ode_model_params)
    +soln = Array(solve(prob, RK4(); saveat=tsteps, dt, adaptive=false))
    +waveform = first(compute_waveform(dt_data, soln, mass_ratio, ode_model_params))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Time", ylabel="Waveform")
    +
    +    l = lines!(ax, tsteps, waveform; linewidth=2, alpha=0.75)
    +    s = scatter!(ax, tsteps, waveform; marker=:circle, markersize=12, alpha=0.5)
    +
    +    axislegend(ax, [[l, s]], ["Waveform Data"])
    +
    +    fig
    +end

    Defiing a Neural Network Model

    Next, we define the neural network model that takes 1 input (time) and has two outputs. We'll make a function ODE_model that takes the initial conditions, neural network parameters and a time as inputs and returns the derivatives.

    It is typically never recommended to use globals but incase you do use them, make sure to mark them as const.

    We will deviate from the standard Neural Network initialization and use WeightInitializers.jl,

    julia
    const nn = Chain(Base.Fix1(fast_activation, cos),
    +    Dense(1 => 32, cos; init_weight=truncated_normal(; std=1e-4), init_bias=zeros32),
    +    Dense(32 => 32, cos; init_weight=truncated_normal(; std=1e-4), init_bias=zeros32),
    +    Dense(32 => 2; init_weight=truncated_normal(; std=1e-4), init_bias=zeros32))
    +ps, st = Lux.setup(Random.default_rng(), nn)
    ((layer_1 = NamedTuple(), layer_2 = (weight = Float32[0.00014798867; 0.0001283755; -0.0001917945; 3.3228196f-5; -2.6541045f-5; -7.975404f-5; -7.092557f-5; -9.0006855f-5; -0.00010432666; -0.0001582305; 0.00011267975; -3.444654f-5; -9.600945f-5; 2.8409087f-5; 5.7547153f-5; -4.970076f-5; 2.046465f-5; 8.749019f-6; 0.00013897507; -8.843735f-6; 5.8316316f-5; 1.33647545f-5; -2.3945151f-5; -0.00019256481; 2.0440255f-6; 7.665036f-5; 7.0418944f-5; -1.478229f-5; 9.342598f-5; -0.00015591538; -4.5475575f-5; -0.00012614082;;], bias = Float32[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.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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), layer_3 = (weight = Float32[6.289329f-5 -0.00012899227 -7.0849266f-5 3.424427f-5 -0.00014294294 9.092271f-5 1.9861705f-5 -0.00020486339 0.00014140282 -5.7926198f-5 0.00012580563 3.976018f-5 1.100778f-5 7.652588f-5 -0.00015733847 -1.979117f-5 -2.0289622f-6 -6.7930196f-6 -4.5295787f-5 2.2391352f-5 -3.927852f-5 0.00018191025 0.0001640962 0.00010366936 -4.4512766f-5 -7.5653224f-5 0.00010830701 8.7929953f-7 0.00012046669 2.4013454f-5 0.00014076312 -0.00013183871; -4.7972153f-5 0.00011150861 -3.7190406f-5 9.121937f-5 -0.00010013644 2.8713104f-5 4.641554f-5 -1.5365074f-5 -2.0453728f-5 -0.00013698272 -2.3076393f-5 -5.7660716f-5 3.585004f-6 8.321239f-5 -0.00013441942 2.9746785f-5 2.0607064f-5 8.571386f-5 9.492374f-5 3.4114895f-5 -5.762854f-5 -9.081341f-5 -6.314866f-5 7.2077423f-6 0.00023802661 5.7517093f-5 -4.9155748f-5 1.2719572f-5 7.161465f-5 -0.00016839153 -4.1478852f-5 -5.9046262f-5; -2.9938063f-5 5.5241326f-5 1.1746462f-5 -6.0956474f-5 -4.192573f-5 3.8743932f-5 -5.3232892f-5 7.759226f-5 2.684328f-5 0.00011954861 3.9134986f-5 0.00013964466 4.1704818f-5 0.000106225416 -4.9426613f-5 0.00010018988 -6.675354f-5 -0.00010403922 -0.00017239648 -0.00013530202 -2.4472069f-5 9.1792914f-5 0.00014092802 -0.00014417266 6.6564055f-5 2.9273719f-5 -7.643671f-6 -8.035956f-5 -1.8555611f-5 7.823969f-5 -0.00012648669 -5.176932f-5; -0.00018445784 -0.00016699555 -2.1285985f-5 9.4690876f-7 0.0001585242 -1.0795486f-5 -1.1848228f-5 4.74355f-5 8.790459f-6 -8.956207f-5 -0.00019490978 0.00021997328 -9.609839f-8 -0.00010916037 -3.892144f-5 6.3916494f-5 7.681881f-5 -0.00011807908 -0.00017212381 -0.00018349661 8.6814776f-5 6.0045826f-5 7.09515f-5 9.022243f-5 -7.049568f-5 -0.00013075661 -0.0001992019 3.3228356f-5 4.2630118f-6 -1.41205355f-5 -0.00018963483 0.00015777664; 0.00018126491 2.3202228f-5 -5.495445f-5 -4.946576f-7 -0.00020756968 0.00022925969 5.503714f-5 -6.6733686f-5 -3.9605053f-5 8.9995505f-5 0.00016215538 -0.00014901724 -0.000113528695 9.1734364f-5 0.00013460332 3.164675f-5 0.00011464552 1.3743814f-5 -9.705088f-6 -1.5063842f-5 -0.000105181956 -8.101596f-5 -1.4773998f-5 -4.7479796f-5 -7.020212f-5 -1.2936013f-5 -5.8906862f-5 -4.3236964f-6 -0.00013548507 0.000110176996 -5.2493553f-5 -8.339872f-6; 0.00014380175 -3.5924462f-5 -4.52999f-5 2.1514736f-5 -0.00020766298 -1.7351893f-5 7.9613244f-5 0.0001905701 3.0340694f-5 5.0138933f-5 -3.984415f-6 -0.00015125364 0.00015956702 -1.392205f-5 -3.635585f-5 0.00022001681 5.91466f-5 -0.00015853895 7.022997f-5 -1.8219034f-5 -3.6560552f-5 0.00013926311 -6.6375236f-5 6.2436798f-6 -3.8841477f-5 5.4191773f-5 -4.7340418f-5 8.6398664f-5 -6.0206105f-5 1.4901871f-5 -3.557371f-5 -3.2751283f-5; 0.00015866013 -0.00018365905 0.00019000433 3.928957f-5 0.000100898724 0.00019121302 0.00011651945 1.9493575f-5 0.00014185574 -6.381918f-5 9.468081f-5 -5.449231f-5 -3.1079664f-5 -7.316235f-5 -1.46296725f-5 -8.44827f-5 -2.324579f-5 9.611487f-5 -0.00018836417 -0.00014876756 4.4095086f-5 3.3882204f-6 -8.825502f-5 3.1465417f-5 0.00012619214 6.1826584f-5 0.00010061589 -9.284439f-5 6.107f-5 -0.00018807476 6.4877626f-5 -0.000121999954; -8.5641674f-5 -1.3133318f-5 3.1929572f-5 -5.934451f-5 7.0588656f-5 0.0002013159 -0.00016559058 -2.233838f-5 -1.4553927f-5 4.1629923f-5 0.00024530233 0.00012909896 0.00018083502 -0.000119821285 -0.0001745207 -0.00013740954 -5.5037024f-5 9.581295f-5 0.0001602952 0.00013878937 -8.0092905f-5 -0.00010669961 6.486757f-5 4.6803184f-6 -0.00010437932 5.5193468f-5 1.9592484f-5 3.52069f-5 -0.00012098054 2.8355807f-6 -4.223768f-5 5.9603328f-5; 6.647512f-5 -7.651593f-5 -7.045441f-5 -6.9189075f-5 2.1325188f-5 3.5744788f-6 -1.3802712f-5 2.5542184f-5 -2.9736013f-5 6.44827f-5 -0.00010273267 -9.560108f-5 -0.00014832508 6.260054f-5 -5.1025545f-5 -6.963479f-5 -4.299914f-5 -4.3417534f-5 0.0001540578 3.5573554f-5 3.2626234f-5 -9.97229f-5 -3.444653f-5 -5.6763725f-5 -7.5928234f-5 -3.071837f-5 -0.00021853072 2.5228403f-5 -3.6620877f-5 0.00012246045 -1.4872443f-5 1.841769f-5; -0.0001188636 -6.524213f-5 -2.2877752f-5 4.632825f-5 -1.1418591f-5 9.142981f-5 0.0001675149 -1.9919431f-5 -0.00011349276 -0.00013851613 -1.757684f-5 -0.00014613128 0.0001068853 7.522353f-5 -9.3130104f-5 6.484308f-5 -8.492532f-5 -4.397045f-5 -9.0616435f-5 5.6238932f-5 0.00011258058 6.7984714f-5 4.3041862f-5 5.8434587f-5 6.9005415f-5 0.00011230302 -4.809528f-5 1.3548491f-5 -4.926104f-5 -1.7329085f-5 -0.00028108715 -0.00012603487; -4.171165f-5 0.00010611511 3.4812806f-6 -0.00012482349 -5.3257183f-5 0.00016939598 2.9564746f-5 4.8874685f-6 -0.00011994621 -0.00026434002 3.6563153f-5 -0.000108040615 -7.026481f-5 2.7034612f-5 3.3245436f-5 5.518623f-5 0.00015428747 -2.83204f-5 5.0359064f-5 -0.00024188824 7.56617f-5 -7.7807505f-5 3.4013906f-6 8.007004f-6 3.9183702f-5 7.3195915f-5 3.231583f-5 7.934296f-6 0.00022212125 8.448415f-5 4.1704367f-5 -5.398324f-5; -8.224716f-5 5.6144036f-5 0.00010965635 3.7896003f-5 4.7579024f-6 3.596343f-5 0.0001756822 8.707022f-5 2.3367626f-5 8.813453f-6 0.00012343613 -3.068682f-6 -6.350598f-6 3.4608598f-5 4.112685f-5 -0.000109935296 3.6222606f-5 -2.7707993f-5 5.5938457f-5 -9.080702f-5 0.00010973305 -0.00040191333 -0.000121186655 -1.7417953f-5 -2.886204f-5 7.5300995f-5 6.176085f-5 5.0990384f-6 -2.4672994f-5 0.00010083148 -0.00017672713 -0.00010527357; -7.6542325f-5 -4.887439f-5 4.4795204f-5 -5.118064f-5 2.2101027f-5 -8.722431f-5 -1.5876874f-5 3.2201962f-5 7.430702f-5 9.7987635f-5 5.678952f-5 4.103541f-5 6.1897146f-5 5.9394017f-5 0.00017383661 -4.654219f-5 5.272721f-5 -0.00016875502 -1.3612849f-5 -3.7497615f-5 -4.8632966f-5 -9.375605f-5 3.0336598f-5 0.00016506345 6.448615f-5 -2.2019703f-5 -0.0001863126 -0.00012096228 -0.00014580866 -6.976547f-5 -0.00015476714 -7.5878204f-5; 5.084713f-5 -0.00021186467 2.1613598f-5 -4.6291356f-5 3.004238f-5 0.00016760328 -4.9907212f-5 9.497809f-5 -1.6691067f-5 -0.00013202691 0.00014834417 0.00012773061 3.0298817f-5 -1.1706837f-5 -1.42734325f-5 2.5085385f-5 8.448661f-5 6.0359416f-5 -2.4104298f-5 8.7597575f-5 0.000121300895 -8.5296175f-5 -1.31261595f-5 -0.0002458211 0.00011386037 8.230593f-5 9.957604f-5 -0.000109471024 -0.000101480946 0.00014499597 -9.220983f-6 2.2058508f-5; 4.8723276f-5 -1.6514532f-5 -0.0002468032 -4.9717022f-5 -7.79167f-5 -6.1969775f-5 0.0001073215 0.00018630148 -0.00021227564 1.0337452f-5 -0.000110470944 -5.334019f-5 0.000112096546 -0.00013046447 6.6720764f-5 -5.432939f-5 1.0038856f-5 -4.29304f-6 6.0018825f-5 -5.820133f-5 -2.3095005f-5 -5.657121f-5 -0.00012440086 -8.591388f-5 -0.00012554288 0.00010523489 -0.000111681264 0.00021312517 2.1284488f-7 0.00010232037 0.00013876813 0.0001451994; -7.494194f-5 -0.00019951252 0.00015804444 -7.931216f-5 3.0945268f-6 -0.00021899202 -0.00019707732 3.6243835f-6 -0.00015080615 -5.8808688f-5 8.493303f-6 0.00010061238 9.35891f-5 -8.0895166f-5 -7.4010213f-6 9.68475f-5 -6.619761f-5 0.00019664227 5.1728017f-5 -3.5319747f-5 -1.8978888f-5 4.020748f-5 -0.00015314738 -6.8800975f-5 -9.088428f-5 6.2876315f-6 -1.0762799f-5 0.0001739711 -0.00012083959 -7.6869735f-5 -1.8775695f-6 0.0002110241; 0.00020664533 -3.8356404f-5 -3.639981f-5 6.6069056f-6 0.0002150255 -1.105098f-5 9.458304f-5 3.5168116f-5 4.1931882f-5 -3.794645f-5 5.109525f-5 8.714127f-5 7.221925f-5 5.057045f-6 0.00011038904 -0.00018290084 2.3290859f-5 -3.6203204f-5 -3.981772f-5 -0.00013440159 8.675202f-5 -5.4943102f-6 7.266125f-5 -3.9068636f-5 -2.5095518f-5 4.3375676f-5 9.906182f-6 -8.512961f-6 -0.00012463176 -2.8709976f-5 -0.0001875602 -9.898851f-5; 0.0002062297 -1.7319557f-5 -0.00016271313 -1.2332152f-5 4.4490756f-5 -7.7858436f-5 -2.1417101f-5 8.3703315f-5 0.0001557044 -0.00011835118 5.8567413f-5 3.918367f-5 -2.3871171f-5 -9.139766f-5 0.00027838128 -0.0001281093 0.000112045745 6.355378f-5 0.00013682224 -6.740831f-5 8.912105f-5 4.103716f-5 4.492756f-5 -6.26335f-5 0.00025819617 6.9468864f-5 -3.5967318f-5 -3.032951f-5 8.049461f-5 -1.25148f-5 -2.2473672f-5 2.1698948f-5; -7.269528f-5 -0.00012516121 6.7834335f-5 3.5365916f-5 9.4599854f-5 5.065827f-5 -0.00011152873 0.0001427831 -0.00021785761 -4.7557187f-6 6.365417f-5 7.37164f-5 7.1094975f-5 -1.8372193f-5 0.00011231499 8.884766f-5 -3.1563144f-5 4.6293702f-5 -5.124871f-5 0.0002186435 3.342431f-5 3.2399035f-5 -8.354723f-5 3.765436f-5 -5.6786386f-5 3.4903765f-5 -0.00012040491 -0.00015075131 -1.5091981f-5 4.4941695f-5 6.308678f-5 4.3056505f-5; 3.351414f-5 -0.00014271175 0.00017131938 -0.00010088954 2.9894476f-5 -0.000113792055 2.7023705f-5 1.28059455f-5 -4.983779f-7 -0.000112544185 2.0941325f-6 -5.2774485f-5 -0.000106039486 -3.205883f-5 2.7262116f-5 -5.2474334f-5 -0.00012837445 1.6826858f-5 -7.145139f-5 0.00013343793 -9.974608f-5 0.00017567938 8.4046085f-5 -0.00014363631 0.00012854532 -0.00013070022 -3.172005f-5 1.76047f-5 -9.0335736f-5 -1.754041f-5 8.696777f-5 0.00012956029; -0.00018782426 0.00017699254 3.149139f-5 -4.99698f-5 7.8038574f-5 2.818771f-5 0.00022553114 9.590483f-6 7.341247f-5 -0.00014300141 0.0002734399 -0.00013367516 -1.2282188f-5 -3.070524f-5 -4.0326096f-5 7.698534f-5 -0.00012843356 -5.6019122f-5 1.1880202f-6 -6.780416f-5 -4.288794f-5 -5.121403f-5 -0.00019581003 -9.3209295f-5 6.6032386f-5 -8.8718843f-7 5.1536685f-5 -0.00014158712 7.121518f-5 -8.5905245f-5 0.00015030308 -5.6274668f-5; -5.91273f-5 2.667418f-5 0.00012173791 1.00059415f-5 -8.0069556f-5 -9.820306f-5 -0.00012170542 8.378669f-5 0.00016907272 7.989081f-5 -9.078782f-6 0.00026348335 9.293973f-5 4.040083f-5 -0.00018577027 -0.00019673149 -5.740228f-5 -7.330596f-5 0.00016787944 6.829441f-5 4.410893f-5 2.1007763f-5 -0.00015965947 4.5795405f-5 -0.00018885931 -0.00017394606 -0.00010925013 -5.149483f-5 -0.00020355567 -6.1030503f-5 -5.1728937f-5 2.9340394f-5; 0.00013693758 -0.00014005817 0.00010481041 -5.797798f-5 -4.048482f-5 -7.644748f-5 -3.0935473f-5 5.6017776f-5 -0.00014096715 6.812392f-5 -1.9517864f-5 1.2078835f-5 5.2177766f-5 4.231554f-5 0.000116617644 -0.00012488794 -4.1700772f-5 0.00011917023 -0.00015670038 -0.000103008395 5.9587246f-6 -8.658024f-5 4.2958178f-5 5.402395f-5 -0.00013350612 -0.00012053447 0.000101511156 8.700682f-5 -1.5777901f-5 -3.3261258f-5 -5.280248f-5 5.8354533f-5; -0.00020004802 4.2591022f-5 -3.7916545f-6 5.848705f-6 -3.4376142f-5 -2.5124384f-5 -1.1709151f-5 4.7170077f-5 -9.483936f-6 2.1743093f-5 -7.2951654f-5 1.35000455f-5 7.552683f-5 9.084621f-5 -8.024526f-6 -2.131134f-5 -7.918156f-5 -4.9303988f-5 0.00015841947 -7.639694f-5 -6.701421f-5 0.00020400074 8.10917f-6 -0.00013003442 -6.820468f-5 -1.9383338f-5 6.901344f-5 -0.00010831981 -2.5970878f-5 3.8305636f-5 6.564423f-5 3.1417763f-5; -0.00016382785 -8.254858f-5 0.00012010008 -0.00014978845 9.3223725f-6 -7.65836f-5 -0.0001389151 2.3776574f-6 0.00010048893 -1.0069865f-5 0.00011513229 7.9882484f-5 5.657715f-5 2.2221302f-5 3.65756f-5 -0.00020418508 0.00016715754 -0.0002513969 2.255126f-5 0.00014347043 -0.00012792795 -3.7204714f-5 -0.00012602791 0.0001213054 9.629434f-6 8.668678f-5 -7.264592f-5 0.0001709462 0.00014189305 -2.8030583f-5 9.5291936f-5 1.6033402f-5; 9.873253f-5 -0.00016460502 5.3794003f-5 3.08519f-5 -7.868859f-5 -1.7641012f-5 8.791397f-5 -0.000101237405 1.5865027f-5 0.00017055974 0.00033521306 -8.547244f-5 -4.3114323f-5 7.744298f-5 -8.7189655f-5 5.8678976f-5 0.00011043076 4.333132f-5 -0.00014446281 5.1741783f-5 -3.813609f-5 -6.0597315f-5 -9.771785f-5 0.00016370777 -8.8192515f-5 -0.00011716584 8.827072f-6 -4.4404693f-5 3.727705f-7 -2.924044f-5 0.00015301318 7.6967f-5; -2.7693168f-5 0.0001663314 0.00018915265 -6.367479f-5 0.00011415843 -9.113931f-5 -5.885339f-5 2.3013947f-5 -8.5922205f-5 -9.334885f-5 -3.864745f-5 -0.00012202202 -0.0001209435 -3.7900256f-5 -3.813278f-5 -0.00014817737 0.00013423587 4.8620004f-5 -0.00021318468 -0.00021753427 -4.258982f-5 -9.925543f-5 -1.3697903f-5 -8.00122f-5 2.6809148f-5 0.00015645399 0.00012051571 -1.0606383f-7 -1.7874921f-5 3.831381f-5 -1.197501f-5 5.2063097f-5; 2.8714978f-6 6.90757f-5 -0.00015171764 0.00020949625 4.6531713f-6 0.00015994276 -8.393382f-5 -9.581163f-6 -9.736687f-5 0.00017050117 -0.00015886013 -0.00027448655 6.217103f-5 0.00017041352 -1.0683171f-5 -0.00013700667 -1.4040064f-5 1.1740796f-6 -1.6264146f-5 -9.725939f-6 6.1090526f-5 -5.4130665f-5 9.185083f-5 -8.574102f-5 -8.912103f-5 3.5294725f-5 5.8031135f-5 2.407458f-6 0.00017823472 0.00012349125 9.97671f-5 9.889217f-5; 5.0403345f-5 6.829975f-5 -0.00011087512 -0.0002034794 -0.00016650361 9.249765f-5 3.2089847f-5 0.00015634432 6.094444f-5 4.1363404f-5 7.436349f-6 0.00013688966 -0.00013218693 7.99489f-5 -3.936639f-5 -2.6110276f-5 0.0003528559 7.467061f-5 5.594828f-5 -0.00019002314 -2.7961547f-5 -0.00028334607 -4.4637447f-5 5.3465246f-5 0.00014880052 -3.1073043f-5 -3.7360107f-5 5.2465195f-5 -2.292667f-6 3.222533f-5 -3.659026f-5 1.6538628f-5; -0.00013727378 -0.00022803275 8.518639f-5 0.0001404138 0.00016037932 -0.0001381259 3.6358913f-5 2.7000491f-5 0.00011553917 2.4459045f-5 1.7618628f-5 0.00017882141 0.0001968822 0.00013338713 2.3761932f-5 3.2353735f-5 0.00022275365 -1.5661397f-5 -0.00014963915 8.59156f-5 -3.295399f-5 -7.559035f-5 -6.74688f-5 1.868308f-5 -3.1442137f-6 -2.7208916f-5 -0.00014883529 0.00013670279 4.0551837f-5 -0.00018453944 -9.6279626f-5 1.5015081f-5; -0.00021324691 1.9568513f-5 2.8413555f-5 -6.08873f-5 6.632513f-5 -0.00014127647 3.4786794f-5 -7.8905505f-5 1.604637f-5 -6.833524f-5 8.2607505f-5 -0.00018783257 0.00013860513 8.130636f-5 -5.675258f-5 0.0002921465 -0.00011495117 0.00010721372 -0.00010607168 9.358432f-5 -3.543438f-5 -8.053401f-5 5.4574848f-5 -0.0001098857 -0.00013411244 -0.0001522711 0.00016539948 -5.7681238f-5 2.9871584f-5 -0.00014114701 6.3481284f-6 0.00013794337; 8.3092156f-5 2.7902099f-5 -9.75656f-5 -1.8865496f-5 7.323678f-5 0.000262229 -7.489286f-5 -1.1426142f-5 0.00022319547 -5.055722f-5 -9.105156f-6 3.4471059f-6 -0.00015784599 0.00014489138 -5.668865f-5 -0.00012680284 6.851014f-5 0.00023398332 3.717287f-6 5.8330512f-5 -0.000120279605 -2.2869315f-5 -0.0001467045 8.990784f-5 -6.7251385f-6 0.0001507413 7.4212396f-5 0.000113473805 -9.460157f-5 5.04164f-5 -9.531469f-5 8.755353f-5], bias = Float32[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.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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), layer_4 = (weight = Float32[-4.5658362f-5 -6.7949f-5 3.798372f-5 -8.829764f-5 -1.3014227f-5 1.2838754f-5 -1.4072927f-5 -4.885181f-5 3.5925146f-5 2.4817182f-5 7.282435f-5 7.9797835f-5 7.235881f-5 2.2705874f-5 -7.128685f-5 -7.052428f-5 6.427351f-5 8.168424f-5 -5.3329717f-5 6.197203f-5 -7.5120886f-5 9.8776116f-5 -2.0051406f-5 -7.375525f-5 0.000106042826 -8.089046f-5 -6.8328445f-5 -6.412571f-5 5.7237332f-5 1.3227511f-5 -0.00020962827 0.00015985763; -0.00011662117 1.582265f-5 6.975102f-5 5.797877f-5 -0.00010437497 -5.1038278f-5 -4.0289066f-5 -7.176196f-5 -5.352049f-5 2.6909376f-5 0.00011169085 0.00011102239 -0.000107661435 5.041146f-5 -6.310288f-5 3.518474f-5 1.0684749f-5 -0.00013644567 -6.9206294f-6 6.371999f-5 -2.6431774f-6 -0.0001470346 6.3890766f-5 9.16673f-6 3.4269528f-5 -5.0108138f-5 -3.493495f-6 -0.00015794244 3.472015f-5 -6.379643f-5 -4.7585076f-5 -0.000110352164], bias = Float32[0.0, 0.0])), (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple(), layer_4 = NamedTuple()))

    Similar to most DL frameworks, Lux defaults to using Float32, however, in this case we need Float64

    julia
    const params = ComponentArray(ps |> f64)
    +
    +const nn_model = StatefulLuxLayer{true}(nn, nothing, st)
    StatefulLuxLayer{true}(
    +    Chain(
    +        layer_1 = WrappedFunction(Base.Fix1{typeof(LuxLib.API.fast_activation), typeof(cos)}(LuxLib.API.fast_activation, cos)),
    +        layer_2 = Dense(1 => 32, cos),  # 64 parameters
    +        layer_3 = Dense(32 => 32, cos),  # 1_056 parameters
    +        layer_4 = Dense(32 => 2),       # 66 parameters
    +    ),
    +)         # Total: 1_186 parameters,
    +          #        plus 0 states.

    Now we define a system of odes which describes motion of point like particle with Newtonian physics, uses

    `,14)),A("mjx-container",B,[(a(),i("svg",T,s[27]||(s[27]=[n('',1)]))),s[28]||(s[28]=A("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[A("mi",null,"u"),A("mo",{stretchy:"false"},"["),A("mn",null,"1"),A("mo",{stretchy:"false"},"]"),A("mo",null,"="),A("mi",null,"χ")])],-1))]),A("mjx-container",q,[(a(),i("svg",z,s[29]||(s[29]=[n('',1)]))),s[30]||(s[30]=A("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[A("mi",null,"u"),A("mo",{stretchy:"false"},"["),A("mn",null,"2"),A("mo",{stretchy:"false"},"]"),A("mo",null,"="),A("mi",null,"ϕ")])],-1))]),A("p",null,[s[37]||(s[37]=h("where, ")),A("mjx-container",V,[(a(),i("svg",D,s[31]||(s[31]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D45D",d:"M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z",style:{"stroke-width":"3"}})])])],-1)]))),s[32]||(s[32]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"p")])],-1))]),s[38]||(s[38]=h(", ")),A("mjx-container",U,[(a(),i("svg",b,s[33]||(s[33]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D440",d:"M289 629Q289 635 232 637Q208 637 201 638T194 648Q194 649 196 659Q197 662 198 666T199 671T201 676T203 679T207 681T212 683T220 683T232 684Q238 684 262 684T307 683Q386 683 398 683T414 678Q415 674 451 396L487 117L510 154Q534 190 574 254T662 394Q837 673 839 675Q840 676 842 678T846 681L852 683H948Q965 683 988 683T1017 684Q1051 684 1051 673Q1051 668 1048 656T1045 643Q1041 637 1008 637Q968 636 957 634T939 623Q936 618 867 340T797 59Q797 55 798 54T805 50T822 48T855 46H886Q892 37 892 35Q892 19 885 5Q880 0 869 0Q864 0 828 1T736 2Q675 2 644 2T609 1Q592 1 592 11Q592 13 594 25Q598 41 602 43T625 46Q652 46 685 49Q699 52 704 61Q706 65 742 207T813 490T848 631L654 322Q458 10 453 5Q451 4 449 3Q444 0 433 0Q418 0 415 7Q413 11 374 317L335 624L267 354Q200 88 200 79Q206 46 272 46H282Q288 41 289 37T286 19Q282 3 278 1Q274 0 267 0Q265 0 255 0T221 1T157 2Q127 2 95 1T58 0Q43 0 39 2T35 11Q35 13 38 25T43 40Q45 46 65 46Q135 46 154 86Q158 92 223 354T289 629Z",style:{"stroke-width":"3"}})])])],-1)]))),s[34]||(s[34]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"M")])],-1))]),s[39]||(s[39]=h(", and ")),A("mjx-container",P,[(a(),i("svg",R,s[35]||(s[35]=[A("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[A("g",{"data-mml-node":"math"},[A("g",{"data-mml-node":"mi"},[A("path",{"data-c":"1D452",d:"M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z",style:{"stroke-width":"3"}})])])],-1)]))),s[36]||(s[36]=A("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[A("mi",null,"e")])],-1))]),s[40]||(s[40]=h(" are constants"))]),s[45]||(s[45]=n(`
    julia
    function ODE_model(u, nn_params, t)
    +    χ, ϕ = u
    +    p, M, e = ode_model_params
    +
    +    # In this example we know that \`st\` is am empty NamedTuple hence we can safely ignore
    +    # it, however, in general, we should use \`st\` to store the state of the neural network.
    +    y = 1 .+ nn_model([first(u)], nn_params)
    +
    +    numer = (1 + e * cos(χ))^2
    +    denom = M * (p^(3 / 2))
    +
    +    χ̇ = (numer / denom) * y[1]
    +    ϕ̇ = (numer / denom) * y[2]
    +
    +    return [χ̇, ϕ̇]
    +end
    ODE_model (generic function with 1 method)

    Let us now simulate the neural network model and plot the results. We'll use the untrained neural network parameters to simulate the model.

    julia
    prob_nn = ODEProblem(ODE_model, u0, tspan, params)
    +soln_nn = Array(solve(prob_nn, RK4(); u0, p=params, saveat=tsteps, dt, adaptive=false))
    +waveform_nn = first(compute_waveform(dt_data, soln_nn, mass_ratio, ode_model_params))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Time", ylabel="Waveform")
    +
    +    l1 = lines!(ax, tsteps, waveform; linewidth=2, alpha=0.75)
    +    s1 = scatter!(
    +        ax, tsteps, waveform; marker=:circle, markersize=12, alpha=0.5, strokewidth=2)
    +
    +    l2 = lines!(ax, tsteps, waveform_nn; linewidth=2, alpha=0.75)
    +    s2 = scatter!(
    +        ax, tsteps, waveform_nn; marker=:circle, markersize=12, alpha=0.5, strokewidth=2)
    +
    +    axislegend(ax, [[l1, s1], [l2, s2]],
    +        ["Waveform Data", "Waveform Neural Net (Untrained)"]; position=:lb)
    +
    +    fig
    +end

    Setting Up for Training the Neural Network

    Next, we define the objective (loss) function to be minimized when training the neural differential equations.

    julia
    const mseloss = MSELoss()
    +
    +function loss(θ)
    +    pred = Array(solve(prob_nn, RK4(); u0, p=θ, saveat=tsteps, dt, adaptive=false))
    +    pred_waveform = first(compute_waveform(dt_data, pred, mass_ratio, ode_model_params))
    +    return mseloss(pred_waveform, waveform)
    +end
    loss (generic function with 1 method)

    Warmup the loss function

    julia
    loss(params)
    0.0007031695500064645

    Now let us define a callback function to store the loss over time

    julia
    const losses = Float64[]
    +
    +function callback(θ, l)
    +    push!(losses, l)
    +    @printf "Training \\t Iteration: %5d \\t Loss: %.10f\\n" θ.iter l
    +    return false
    +end
    callback (generic function with 1 method)

    Training the Neural Network

    Training uses the BFGS optimizers. This seems to give good results because the Newtonian model seems to give a very good initial guess

    julia
    adtype = Optimization.AutoZygote()
    +optf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)
    +optprob = Optimization.OptimizationProblem(optf, params)
    +res = Optimization.solve(
    +    optprob, BFGS(; initial_stepnorm=0.01, linesearch=LineSearches.BackTracking());
    +    callback, maxiters=1000)
    retcode: Success
    +u: ComponentVector{Float64}(layer_1 = Float64[], layer_2 = (weight = [0.0001479886705053106; 0.00012837549729740222; -0.00019179450464456877; 3.322819611637084e-5; -2.6541045372146618e-5; -7.975404150768842e-5; -7.092556916177105e-5; -9.000685531646908e-5; -0.00010432666022084597; -0.00015823049761818606; 0.0001126797506002084; -3.444654066698e-5; -9.600944758858865e-5; 2.8409087462921232e-5; 5.754715311919196e-5; -4.9700760428110564e-5; 2.0464649423930583e-5; 8.749018888913114e-6; 0.0001389750686939419; -8.843734576651803e-6; 5.831631642649848e-5; 1.3364754522626191e-5; -2.3945151042422434e-5; -0.00019256481027693886; 2.0440254502292897e-6; 7.66503580961444e-5; 7.041894423301891e-5; -1.4782290236328528e-5; 9.342598059437742e-5; -0.00015591537521681518; -4.547557546171363e-5; -0.00012614081788351716;;], bias = [3.1618821547760237e-16, -2.239715669473555e-17, 2.538697890277846e-16, 3.0756254592508004e-17, 5.928300473541879e-18, -1.755045016605607e-16, -1.9693294904156052e-18, 1.0816634619367045e-17, -1.5099870307573793e-16, -2.3770075837870637e-17, 1.7961534013830336e-16, 3.740195902526728e-18, 3.8268793412463466e-18, 1.3398236140253248e-17, 4.480848124758183e-17, 1.813701563686835e-17, 3.0287440289475135e-17, 8.56756171288473e-18, 4.4199278980586825e-17, -7.040194979405464e-18, 4.937424637028749e-19, 7.950769350341129e-19, -4.37353035495063e-18, -2.860529948821097e-17, 2.9720407135201326e-18, 9.958207788192736e-17, 9.01360056680392e-17, 2.970758097357983e-18, 1.1322895285109382e-16, -5.67468551327775e-17, -4.3152995329292506e-17, 1.0725677217871096e-16]), layer_3 = (weight = [6.289465276899174e-5 -0.00012899090320893898 -7.084790373079785e-5 3.424563150879349e-5 -0.00014294157695580832 9.092407166867638e-5 1.986306783187381e-5 -0.00020486202807255978 0.00014140418538267642 -5.792483530564015e-5 0.00012580699153153993 3.976154225206352e-5 1.1009142367080704e-5 7.65272434768583e-5 -0.00015733710275121706 -1.9789807952793187e-5 -2.0275997081162693e-6 -6.791657102029507e-6 -4.5294424085621645e-5 2.2392714567514397e-5 -3.9277156206981564e-5 0.00018191160965620935 0.00016409756248726888 0.00010367071994954402 -4.451140371706867e-5 -7.565186202150628e-5 0.00010830837167709316 8.806619980087237e-7 0.00012046805390532141 2.4014816558009666e-5 0.0001407644831892413 -0.00013183734513909863; -4.797249286049889e-5 0.00011150827257231838 -3.7190746037156566e-5 9.121903193452253e-5 -0.00010013678339739477 2.8712764366426587e-5 4.641519834556517e-5 -1.536541432280625e-5 -2.0454068102045332e-5 -0.00013698306221478497 -2.3076732498812634e-5 -5.7661056156141256e-5 3.584664033477361e-6 8.321205158288444e-5 -0.00013441975689922577 2.9746445112757968e-5 2.0606723670860167e-5 8.5713518534683e-5 9.492339657888808e-5 3.411455535249629e-5 -5.762887823359229e-5 -9.081374966037613e-5 -6.314900175632126e-5 7.207402437854578e-6 0.00023802626882250268 5.7516752609879734e-5 -4.9156087437515224e-5 1.2719231823646323e-5 7.16143133890716e-5 -0.00016839187238794638 -4.147919181698136e-5 -5.904660221269333e-5; -2.9938078753612105e-5 5.524130965307436e-5 1.1746446304759924e-5 -6.095649014502691e-5 -4.192574642990644e-5 3.874391613601782e-5 -5.323290834246129e-5 7.759224381255062e-5 2.6843263455821043e-5 0.00011954859500940973 3.9134969753949765e-5 0.00013964464442063195 4.170480160349125e-5 0.00010622539984718038 -4.9426629359795904e-5 0.00010018986203897818 -6.675355844242426e-5 -0.00010403923961609531 -0.0001723964976034678 -0.0001353020358718552 -2.447208471755424e-5 9.17928976351775e-5 0.00014092800692845208 -0.00014417267966825424 6.656403847694467e-5 2.927370250939e-5 -7.643686970250403e-6 -8.035957735307443e-5 -1.855562705065513e-5 7.823967307297597e-5 -0.00012648670390523896 -5.1769334916453e-5; -0.00018446107866088244 -0.0001669987949387632 -2.1289227206331026e-5 9.436665347784126e-7 0.00015852095670218798 -1.0798727871371625e-5 -1.1851469807664616e-5 4.743225794321932e-5 8.787216884450972e-6 -8.956531097259353e-5 -0.0001949130208774972 0.0002199700421808594 -9.934061075320488e-8 -0.00010916361212345545 -3.892468235768816e-5 6.391325145180741e-5 7.681556884584203e-5 -0.00011808232089585478 -0.00017212704993630417 -0.00018349985190049597 8.681153407472689e-5 6.0042583882232845e-5 7.094825845363752e-5 9.021918516761999e-5 -7.04989187031691e-5 -0.00013075985485535278 -0.00019920513737794275 3.322511396639211e-5 4.259769539422367e-6 -1.412377774589985e-5 -0.0001896380680225474 0.00015777339571309255; 0.00018126487184791354 2.320218691612119e-5 -5.495449085710086e-5 -4.946991870318129e-7 -0.00020756972453081547 0.00022925964940814742 5.503709899504179e-5 -6.673372781360077e-5 -3.9605094294431785e-5 8.999546326240993e-5 0.00016215534042576774 -0.00014901728508984237 -0.00011352873634304405 9.173432254475044e-5 0.0001346032825532413 3.164670697888798e-5 0.00011464547633668842 1.3743772164259254e-5 -9.705129465048722e-6 -1.50638831618315e-5 -0.00010518199787465417 -8.10160033287437e-5 -1.4774039933302285e-5 -4.74798377544105e-5 -7.020216225636689e-5 -1.2936054823415126e-5 -5.890690381046875e-5 -4.323737990391989e-6 -0.00013548510987301847 0.00011017695424389561 -5.2493594644959365e-5 -8.339913343563779e-6; 0.00014380303581491364 -3.59231762668163e-5 -4.52986150885597e-5 2.1516021650309755e-5 -0.00020766168928458141 -1.7350606878614316e-5 7.961453046663694e-5 0.00019057139251162198 3.0341980153017373e-5 5.014021916211703e-5 -3.9831288741057685e-6 -0.00015125235405503577 0.00015956830428694228 -1.39207641150316e-5 -3.63545641557769e-5 0.00022001809519496887 5.914788743029572e-5 -0.00015853766855071058 7.023125907652439e-5 -1.8217748231112443e-5 -3.655926594729437e-5 0.00013926439531860177 -6.6373950186975e-5 6.244965778004472e-6 -3.8840191347848076e-5 5.419305852046229e-5 -4.733913193559242e-5 8.639995029443175e-5 -6.02048185210222e-5 1.4903156614295779e-5 -3.557242417810331e-5 -3.2749996546054805e-5; 0.00015866126997585836 -0.0001836579110966653 0.00019000546964540016 3.9290712462545305e-5 0.00010089986537074956 0.00019121416627619492 0.0001165205896688079 1.9494716267371664e-5 0.00014185687834121196 -6.381803612733881e-5 9.468194840898577e-5 -5.449116796064852e-5 -3.107852242813476e-5 -7.316120971502455e-5 -1.4628530865437775e-5 -8.448155930075574e-5 -2.3244648022071265e-5 9.611601055091557e-5 -0.00018836302550319988 -0.00014876642015572325 4.4096227808196114e-5 3.389362033133095e-6 -8.825388138923504e-5 3.146655873584421e-5 0.0001261932841008933 6.182772560002377e-5 0.00010061703434636945 -9.284324986204202e-5 6.107114242346946e-5 -0.00018807361701314002 6.487876745829595e-5 -0.0001219988123774184; -8.564073420716439e-5 -1.3132378691852178e-5 3.1930511729973555e-5 -5.934357165828628e-5 7.058959538695134e-5 0.00020131683498034742 -0.0001655896404118224 -2.2337440052111937e-5 -1.455298758814693e-5 4.1630862076952195e-5 0.00024530327293901074 0.00012909989975738056 0.00018083596017091005 -0.0001198203454551221 -0.00017451975788575945 -0.0001374086051073796 -5.5036084697388845e-5 9.581389251976027e-5 0.00016029613555288032 0.00013879031114625496 -8.009196523930294e-5 -0.0001066986724909327 6.486850991491895e-5 4.6812578402239385e-6 -0.00010437838415968476 5.5194407585035466e-5 1.959342346522558e-5 3.520783950803548e-5 -0.00012097960195391954 2.836520186927469e-6 -4.2236740293487285e-5 5.960426726956115e-5; 6.647209725259526e-5 -7.651895079845446e-5 -7.045743054559194e-5 -6.9192097860775e-5 2.132216454980387e-5 3.571455501395316e-6 -1.3805734986938413e-5 2.553916042586079e-5 -2.97390362430873e-5 6.447967812336081e-5 -0.00010273569582579912 -9.560410048665009e-5 -0.00014832810497694322 6.259751885578468e-5 -5.1028568257729236e-5 -6.96378157482609e-5 -4.300216473724298e-5 -4.342055776591052e-5 0.00015405477083903202 3.557053046448518e-5 3.262321101998668e-5 -9.972592319912836e-5 -3.444955304815956e-5 -5.676674859214285e-5 -7.59312571500579e-5 -3.072139238441361e-5 -0.00021853374723662707 2.522537929677314e-5 -3.662390022157407e-5 0.00012245742605217693 -1.4875466284262025e-5 1.8414666421339533e-5; -0.00011886521815564398 -6.524374612150913e-5 -2.2879368316582974e-5 4.6326631945454614e-5 -1.1420208011508104e-5 9.142819044402994e-5 0.00016751327939321407 -1.9921047624183742e-5 -0.00011349437545529134 -0.00013851774701857685 -1.757845666385657e-5 -0.00014613289522483094 0.00010688368502063092 7.52219116290928e-5 -9.313172040517409e-5 6.484146297200571e-5 -8.492693586983839e-5 -4.397206566888977e-5 -9.061805167244798e-5 5.623731567513991e-5 0.00011257896267100275 6.798309777852946e-5 4.304024560017399e-5 5.843297049045521e-5 6.900379821647747e-5 0.0001123014067158958 -4.8096896989837945e-5 1.3546874015197246e-5 -4.926265819473804e-5 -1.7330701212140458e-5 -0.0002810887685884818 -0.0001260364820157201; -4.171135321317918e-5 0.00010611540904559503 3.4815772158581993e-6 -0.00012482319459028085 -5.325688641110906e-5 0.00016939627506129852 2.9565042615867675e-5 4.887765164166148e-6 -0.00011994591647468147 -0.0002643397254979961 3.6563449731910304e-5 -0.00010804031796229549 -7.026451373181859e-5 2.7034908391069555e-5 3.324573311314421e-5 5.5186525179887896e-5 0.00015428776362736243 -2.8320104200392956e-5 5.03593602223536e-5 -0.00024188793929002712 7.566199759079577e-5 -7.780720795213713e-5 3.4016872012579864e-6 8.00730061367726e-6 3.9183998644002725e-5 7.319621193513683e-5 3.2316127664525524e-5 7.934592878737014e-6 0.00022212154556822418 8.448444544395662e-5 4.17046632099662e-5 -5.398294330749349e-5; -8.224721432633562e-5 5.61439842349583e-5 0.00010965629871498955 3.789595166018335e-5 4.7578509984385065e-6 3.596337728232256e-5 0.00017568215070787923 8.707016922563427e-5 2.3367574154698542e-5 8.813401560482127e-6 0.0001234360747694236 -3.068733352839627e-6 -6.350649531660612e-6 3.4608546680837024e-5 4.112679698301585e-5 -0.00010993534715816276 3.622255416849729e-5 -2.7708043948215367e-5 5.59384056905484e-5 -9.0807072869203e-5 0.00010973300186015771 -0.0004019133853071172 -0.00012118670611379568 -1.7418004521451195e-5 -2.8862090861358614e-5 7.530094398681183e-5 6.176080159640047e-5 5.098986999663594e-6 -2.467304557648373e-5 0.00010083142796794092 -0.0001767271828648438 -0.00010527361928688237; -7.654431041909667e-5 -4.8876375645610345e-5 4.4793218561715685e-5 -5.118262501665159e-5 2.2099041101766958e-5 -8.722629658759928e-5 -1.5878860127399476e-5 3.219997657115324e-5 7.430503378973277e-5 9.798564920321022e-5 5.678753282527489e-5 4.10334256722243e-5 6.189516048298042e-5 5.939203097486151e-5 0.00017383462605184317 -4.6544176571757114e-5 5.2725223808094874e-5 -0.00016875701052950528 -1.3614834957383448e-5 -3.7499601008592375e-5 -4.863495209602258e-5 -9.375803287721997e-5 3.033461203275912e-5 0.0001650614655355806 6.448416448082938e-5 -2.202168920657988e-5 -0.00018631458019254248 -0.00012096426448434415 -0.0001458106483786667 -6.976745439341422e-5 -0.00015476912753538866 -7.588019011190834e-5; 5.084889967158913e-5 -0.0002118628977327435 2.1615366175426974e-5 -4.628958736380742e-5 3.0044148341895383e-5 0.000167605052819033 -4.9905443621775474e-5 9.497985633837404e-5 -1.6689298310180207e-5 -0.00013202513905659954 0.00014834594226025125 0.00012773238308776916 3.0300585830023534e-5 -1.170506816511903e-5 -1.427166403251309e-5 2.5087153015683612e-5 8.448837656809808e-5 6.036118470414422e-5 -2.4102529597685917e-5 8.759934321327946e-5 0.0001213026629998597 -8.529440633670552e-5 -1.3124391035907058e-5 -0.00024581934080877734 0.00011386213777636062 8.230769931154801e-5 9.95778104411677e-5 -0.00010946925572303252 -0.00010147917742093715 0.00014499773574109525 -9.219214508866447e-6 2.206027643163116e-5; 4.872209719202946e-5 -1.6515710383585896e-5 -0.00024680436727769566 -4.971820054173809e-5 -7.791788048756661e-5 -6.197095318178782e-5 0.00010732032423426213 0.00018630029843940332 -0.0002122768197366312 1.0336273946695764e-5 -0.00011047212284005137 -5.33413691371061e-5 0.00011209536786942717 -0.00013046564673253685 6.671958580433138e-5 -5.4330568316563104e-5 1.0037677741147184e-5 -4.294218440682454e-6 6.00176466762311e-5 -5.820250917871861e-5 -2.3096182856296826e-5 -5.657238908292169e-5 -0.00012440203827985923 -8.59150601242843e-5 -0.00012554405803506647 0.00010523371055775168 -0.0001116824420093857 0.00021312398929900116 2.1166653290328563e-7 0.00010231919476816056 0.00013876694755914318 0.0001451982247019862; -7.494417764139279e-5 -0.00019951475656018904 0.00015804220060926176 -7.931439427087599e-5 3.0922906254648934e-6 -0.00021899425587510813 -0.00019707955175439121 3.622147232060664e-6 -0.00015080839034529197 -5.881092397505103e-5 8.491066409234073e-6 0.0001006101422255249 9.358686406737273e-5 -8.089740254112125e-5 -7.4032575419883154e-6 9.684526344168517e-5 -6.619984446919158e-5 0.00019664003525500526 5.1725780621542454e-5 -3.5321982751010306e-5 -1.8981124186062922e-5 4.020524397597996e-5 -0.00015314961888256108 -6.880321120734988e-5 -9.088651381793096e-5 6.285395328782717e-6 -1.0765035541076204e-5 0.00017396886437305597 -0.00012084182776637331 -7.687197171509937e-5 -1.8798057233994109e-6 0.00021102186769819464; 0.00020664584287765776 -3.8355891705979897e-5 -3.6399299392038005e-5 6.607417686210196e-6 0.00021502601437128844 -1.1050467878194525e-5 9.458355186830901e-5 3.5168627687707705e-5 4.193239426564024e-5 -3.794593878814658e-5 5.109576075079418e-5 8.714178245605662e-5 7.221976109172776e-5 5.0575573146133675e-6 0.0001103895511510568 -0.00018290032760381962 2.3291370849220616e-5 -3.6202692103360195e-5 -3.9817209585128185e-5 -0.00013440107879836335 8.675253327561265e-5 -5.49379812986347e-6 7.266176096487563e-5 -3.906812428289934e-5 -2.509500602576635e-5 4.337618800087514e-5 9.90669384515076e-6 -8.512449243825297e-6 -0.00012463124305617427 -2.870946348088488e-5 -0.0001875596907888751 -9.898799628394211e-5; 0.00020623337629364102 -1.7315879385597635e-5 -0.00016270945045985903 -1.2328475104014735e-5 4.449443374177408e-5 -7.785475893762671e-5 -2.1413424046492117e-5 8.370699221848523e-5 0.000155708078882868 -0.0001183475003287118 5.857109069472575e-5 3.91873466200093e-5 -2.3867493591407574e-5 -9.139398455737204e-5 0.0002783849588653411 -0.00012810562177911647 0.00011204942281473427 6.355745724285063e-5 0.0001368259211361555 -6.740463571041781e-5 8.912472846567275e-5 4.104083861456283e-5 4.493123858118412e-5 -6.262982490594223e-5 0.0002581998517329251 6.94725415727431e-5 -3.596364033875597e-5 -3.0325831839591016e-5 8.049828763467198e-5 -1.251112255853661e-5 -2.246999495547461e-5 2.170262566357397e-5; -7.269410690885596e-5 -0.0001251600404585374 6.783550650917726e-5 3.5367087714739696e-5 9.460102608766662e-5 5.065944076971189e-5 -0.00011152755889004006 0.00014278427277797807 -0.00021785643895516307 -4.754547096199631e-6 6.365534516855869e-5 7.371757254343718e-5 7.109614687845041e-5 -1.8371021557932062e-5 0.00011231616388879872 8.884882862087531e-5 -3.156197255254455e-5 4.629487392133382e-5 -5.124753790103359e-5 0.0002186446728800824 3.3425480235499926e-5 3.2400206858192544e-5 -8.354605944720767e-5 3.7655532817475244e-5 -5.6785214671499055e-5 3.490493707697897e-5 -0.00012040373969018368 -0.00015075013636039298 -1.5090809772185105e-5 4.494286639139337e-5 6.308795144189355e-5 4.305767668749807e-5; 3.351272907782971e-5 -0.00014271316531487365 0.00017131796566862998 -0.00010089095367259683 2.9893063856043093e-5 -0.00011379346751748679 2.7022292942612736e-5 1.2804533343636294e-5 -4.997900877469654e-7 -0.00011254559713089998 2.0927202964011898e-6 -5.2775897257042654e-5 -0.00010604089829978496 -3.2060241847311866e-5 2.7260704245755892e-5 -5.247574581556296e-5 -0.00012837586173230223 1.6825445799958772e-5 -7.14528002394406e-5 0.00013343652180953494 -9.974749327778115e-5 0.00017567796685359055 8.404467307588655e-5 -0.00014363772124889842 0.00012854390597528387 -0.00013070163613558867 -3.1721462346857146e-5 1.7603287505671327e-5 -9.033714804938979e-5 -1.7541821489811035e-5 8.696635568373544e-5 0.00012955887295863943; -0.0001878250669456718 0.00017699173886778834 3.1490583665283875e-5 -4.9970604863645144e-5 7.803776944039973e-5 2.8186904187735986e-5 0.0002255303360520187 9.589678398173646e-6 7.341166465760129e-5 -0.0001430022140035097 0.00027343908268942475 -0.00013367596429323178 -1.2282993424901562e-5 -3.0706044612614154e-5 -4.0326901484674764e-5 7.69845381959591e-5 -0.00012843436442797423 -5.60199269735477e-5 1.1872151894090286e-6 -6.780496650624453e-5 -4.288874433275588e-5 -5.121483363343764e-5 -0.00019581083788087008 -9.321010028958637e-5 6.603158081399841e-5 -8.879934235450455e-7 5.153587963416006e-5 -0.00014158792791438645 7.121437638982065e-5 -8.590605020305797e-5 0.00015030227487425012 -5.627547315686887e-5; -5.912982921471255e-5 2.6671649930003353e-5 0.0001217353794618502 1.0003410561690304e-5 -8.007208704839708e-5 -9.820559241234105e-5 -0.00012170795414022059 8.378415916922863e-5 0.00016907019128666848 7.98882767685585e-5 -9.081312573465576e-6 0.00026348081994910527 9.293719743255049e-5 4.0398300579904996e-5 -0.0001857728045888528 -0.00019673402018270558 -5.740481244175033e-5 -7.330848781748973e-5 0.00016787690513411888 6.829187735092528e-5 4.4106397790526715e-5 2.10052323654917e-5 -0.0001596619975043766 4.579287381605193e-5 -0.00018886184149778757 -0.00017394858766238031 -0.00010925266430604168 -5.149736059138837e-5 -0.00020355819903670398 -6.10330341896618e-5 -5.1731468165602006e-5 2.933786275208068e-5; 0.00013693632350120444 -0.00014005942652650644 0.00010480915075684338 -5.797923954154539e-5 -4.048608029328477e-5 -7.644874135215723e-5 -3.093673153265391e-5 5.601651715047773e-5 -0.0001409684119112487 6.81226592446107e-5 -1.951912240250197e-5 1.2077576643115068e-5 5.2176506828313445e-5 4.231428097633459e-5 0.0001166163855982284 -0.00012488920042009213 -4.170203105380961e-5 0.00011916897342822298 -0.0001567016370659357 -0.00010300965372656689 5.957465832090611e-6 -8.658150186014573e-5 4.295691901867082e-5 5.402269012345384e-5 -0.00013350738303919544 -0.00012053572576909303 0.00010150989688050917 8.700555913897953e-5 -1.5779160135512695e-5 -3.326251684987132e-5 -5.28037381132333e-5 5.8353274611788524e-5; -0.00020004856283175256 4.259047550168292e-5 -3.792201099155815e-6 5.848158295162834e-6 -3.4376688703008655e-5 -2.5124930246777475e-5 -1.1709697858707859e-5 4.716953030457042e-5 -9.484482646614072e-6 2.1742546820506443e-5 -7.295220071081669e-5 1.3499498933566629e-5 7.55262799853952e-5 9.08456632229046e-5 -8.025072887351924e-6 -2.1311886442520993e-5 -7.918210845072637e-5 -4.9304534471406444e-5 0.000158418922225437 -7.639748305645662e-5 -6.701475736317054e-5 0.00020400019188546685 8.10862370290679e-6 -0.00013003496219733888 -6.820522772013102e-5 -1.938388500402002e-5 6.901289366088074e-5 -0.0001083203541869752 -2.5971424250558162e-5 3.8305089262040196e-5 6.564368145209885e-5 3.141721667508057e-5; -0.00016382765105970868 -8.254837966103736e-5 0.00012010027486086995 -0.00014978825428568356 9.322569629714677e-6 -7.658340408977685e-5 -0.00013891490315598058 2.3778545333899853e-6 0.00010048912436888892 -1.0069668216036951e-5 0.00011513248383255072 7.988268108294746e-5 5.657734864928179e-5 2.2221499155987366e-5 3.6575795737574026e-5 -0.0002041848850161636 0.00016715774173337443 -0.0002513967113294505 2.2551456557831785e-5 0.00014347062888975663 -0.00012792775604919142 -3.72045172219962e-5 -0.00012602771247782337 0.00012130559544732033 9.629631411937894e-6 8.668697474479114e-5 -7.264572131259922e-5 0.00017094639107074062 0.00014189324493474678 -2.8030385957553316e-5 9.529213339976429e-5 1.6033599157364382e-5; 9.873387646805597e-5 -0.00016460367875694885 5.379534671375904e-5 3.085324463612487e-5 -7.868724311989627e-5 -1.763966862924076e-5 8.791531329919498e-5 -0.0001012360614986088 1.586637084258842e-5 0.00017056108229737688 0.0003352144023956782 -8.547109861680222e-5 -4.3112979954427944e-5 7.744432262555797e-5 -8.718831192524184e-5 5.868031915455153e-5 0.00011043210291248863 4.3332665183731736e-5 -0.00014446147067062346 5.174312648890671e-5 -3.8134747926928233e-5 -6.059597105191893e-5 -9.77165061776422e-5 0.00016370910928528192 -8.81911717151185e-5 -0.00011716449332012918 8.828415258935756e-6 -4.4403349209426575e-5 3.741140353969072e-7 -2.9239096664218282e-5 0.00015301452843417457 7.696834403034666e-5; -2.7695354106393765e-5 0.00016632921699478355 0.00018915046177849762 -6.367697994880486e-5 0.00011415624260246616 -9.11414934993136e-5 -5.885557754969983e-5 2.30117603902139e-5 -8.592439178333956e-5 -9.335103447970256e-5 -3.864963571264616e-5 -0.00012202420828122748 -0.0001209456858081137 -3.790244215940256e-5 -3.813496721283482e-5 -0.0001481795515022614 0.00013423368739006882 4.861781792408604e-5 -0.00021318687129256048 -0.00021753645330624839 -4.259200784451272e-5 -9.925761321516884e-5 -1.3700089653294145e-5 -8.001438607183606e-5 2.6806961727405877e-5 0.00015645179894330214 0.00012051352325637061 -1.0825014163252523e-7 -1.7877107780226786e-5 3.8311624052447006e-5 -1.1977196550441838e-5 5.2060910206493225e-5; 2.8731227105327503e-6 6.907732547757515e-5 -0.00015171601755514588 0.00020949787956694324 4.6547962285971415e-6 0.0001599443881589351 -8.393219233924548e-5 -9.579538001829758e-6 -9.736524718549436e-5 0.0001705027921873409 -0.00015885850500284198 -0.00027448492384949514 6.217265270448975e-5 0.0001704151460019333 -1.0681546356619121e-5 -0.0001370050498933148 -1.4038439459663462e-5 1.175704440602927e-6 -1.626252144136782e-5 -9.724314096937818e-6 6.109215117091378e-5 -5.412904049237955e-5 9.185245524192443e-5 -8.573939469147337e-5 -8.911940442133451e-5 3.529634939538247e-5 5.8032760151279896e-5 2.4090828249161067e-6 0.00017823634932780417 0.00012349287369784785 9.976872622998566e-5 9.889379232687275e-5; 5.0404076179055e-5 6.830047991223153e-5 -0.00011087438556735437 -0.00020347867044057805 -0.00016650287957765261 9.249837953228266e-5 3.2090578175650714e-5 0.00015634505311589412 6.094517070430916e-5 4.136413540088819e-5 7.437079917672853e-6 0.00013689039392027894 -0.00013218620384015446 7.994963002255082e-5 -3.9365659316733255e-5 -2.610954484572779e-5 0.00035285661928918116 7.467133750304492e-5 5.594901071724866e-5 -0.0001900224125655004 -2.7960815854218598e-5 -0.0002833453437722856 -4.463671589639137e-5 5.346597740406128e-5 0.0001488012529500193 -3.1072311825316805e-5 -3.73593758502623e-5 5.246592613383105e-5 -2.291935883311706e-6 3.2226060144401e-5 -3.65895286029777e-5 1.6539359281687062e-5; -0.00013727221734980522 -0.00022803118840484076 8.518794570890029e-5 0.0001404153598317011 0.00016038087856332518 -0.00013812434840174004 3.6360471179527155e-5 2.700204900366091e-5 0.00011554073066990985 2.44606024837531e-5 1.7620185511350382e-5 0.00017882297184160633 0.00019688376128515473 0.00013338869107729496 2.376348934677044e-5 3.235529298154295e-5 0.00022275520391604623 -1.5659839070115587e-5 -0.00014963759089978677 8.591715673292766e-5 -3.2952432908764275e-5 -7.558879510424328e-5 -6.746724024805487e-5 1.868463810140957e-5 -3.1426558477441617e-6 -2.7207358604479152e-5 -0.0001488337285506493 0.00013670434496207865 4.055339454980837e-5 -0.00018453788574943842 -9.627806789166615e-5 1.501663869321251e-5; -0.00021324839605452688 1.9567026296011234e-5 2.8412067816565533e-5 -6.088878859968207e-5 6.632363959711673e-5 -0.00014127795572361934 3.4785306464488654e-5 -7.890699186331531e-5 1.6044882553123984e-5 -6.833672802398019e-5 8.260601765274357e-5 -0.00018783405818480347 0.0001386036428206891 8.130487270450853e-5 -5.675406561435374e-5 0.00029214500403527884 -0.0001149526606846353 0.00010721222946217883 -0.00010607316932376794 9.35828328997143e-5 -3.543586632671935e-5 -8.053549669652573e-5 5.457336095192161e-5 -0.0001098871899253261 -0.00013411393144137563 -0.000152272582514836 0.00016539799701918752 -5.768272518848395e-5 2.9870096962857977e-5 -0.00014114850188573898 6.3466413243580365e-6 0.0001379418799237672; 8.309488175216532e-5 2.7904824214768077e-5 -9.756287482090278e-5 -1.8862770325360788e-5 7.323950257632361e-5 0.000262231730353226 -7.489013233208069e-5 -1.1423416531041828e-5 0.00022319819681359897 -5.0554495196434365e-5 -9.102430617361763e-6 3.449831360919828e-6 -0.00015784326688372873 0.00014489410813912218 -5.668592285001469e-5 -0.00012680011723641984 6.851286588716759e-5 0.00023398604088942988 3.720012450849063e-6 5.8333237298210174e-5 -0.00012027687926529734 -2.2866589738261037e-5 -0.00014670176761210474 8.99105622876621e-5 -6.722413040553145e-6 0.00015074402171666687 7.421512118089048e-5 0.0001134765304370363 -9.459884613971525e-5 5.0419127269538136e-5 -9.531196274547547e-5 8.755625885458661e-5], bias = [1.362463491334985e-9, -3.398904685654539e-10, -1.610066669886397e-11, -3.242221072784985e-9, -4.156017242074563e-11, 1.2860145909590977e-9, 1.141612458391299e-9, 9.394425035937008e-10, -3.0232951195917684e-9, -1.616627081790752e-9, 2.966151805736721e-10, -5.1390080646152605e-11, -1.9857415354524423e-9, 1.7684656463219359e-9, -1.1783483755736966e-9, -2.236220861232494e-9, 5.121142395241432e-10, 3.6773329978313097e-9, 1.1715955501843653e-9, -1.4121728149894085e-9, -8.049888293545121e-10, -2.5309145760393373e-9, -1.2587820853669075e-9, -5.465639278681154e-10, 1.9709534420796504e-10, 1.3435347112437137e-9, -2.1863119136768887e-9, 1.6248834716321566e-9, 7.310938454045174e-10, 1.557831007680469e-9, -1.4870843604346265e-9, 2.725478406142474e-9]), layer_4 = (weight = [-0.0007374361934195449 -0.0007597268657267519 -0.0006537941531990138 -0.0007800752735170239 -0.0007047920986039328 -0.000678939082443919 -0.0007058507704826389 -0.0007406296612836417 -0.0006558525313057186 -0.0006669606334663165 -0.0006189535229626955 -0.0006119800360087953 -0.0006194189803236911 -0.0006690719304301911 -0.000763064690569369 -0.0007623020384361817 -0.0006275043556428826 -0.0006100933551841793 -0.0007451075583788393 -0.0006298057986045238 -0.0007668987434951661 -0.0005930016240738988 -0.0007118292427099427 -0.0007655331122073681 -0.000585735044956384 -0.0007726682904175011 -0.0007601062108833979 -0.0007559035208590189 -0.0006345405282430247 -0.0006785503088444641 -0.0009014060900150451 -0.000531920086844552; 0.00013594893440536723 0.00026839277162856644 0.0003223211408476348 0.000310548806501568 0.00014819514965658817 0.00020153183148601252 0.00021228104648558522 0.0001808081529319296 0.00019904956265658853 0.00027947947796219696 0.00036426097493794357 0.00036359251154835363 0.00014490865705834625 0.0003029815590890083 0.0001894672295971893 0.00028775482287253247 0.0002632548694413957 0.00011612435116104449 0.0002456494818520329 0.00031629009864845084 0.0002499269396489655 0.00010553547110531008 0.0003164608754771367 0.0002617368496312524 0.0002868396494856868 0.00020246197007451418 0.0002490765888576313 9.462765896848049e-5 0.00028729026752222437 0.000188773670293046 0.00020498502796661137 0.00014221790314839118], bias = [-0.0006917778715618791, 0.0002525701222495951]))

    Visualizing the Results

    Let us now plot the loss over time

    julia
    begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Iteration", ylabel="Loss")
    +
    +    lines!(ax, losses; linewidth=4, alpha=0.75)
    +    scatter!(ax, 1:length(losses), losses; marker=:circle, markersize=12, strokewidth=2)
    +
    +    fig
    +end

    Finally let us visualize the results

    julia
    prob_nn = ODEProblem(ODE_model, u0, tspan, res.u)
    +soln_nn = Array(solve(prob_nn, RK4(); u0, p=res.u, saveat=tsteps, dt, adaptive=false))
    +waveform_nn_trained = first(compute_waveform(
    +    dt_data, soln_nn, mass_ratio, ode_model_params))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Time", ylabel="Waveform")
    +
    +    l1 = lines!(ax, tsteps, waveform; linewidth=2, alpha=0.75)
    +    s1 = scatter!(
    +        ax, tsteps, waveform; marker=:circle, alpha=0.5, strokewidth=2, markersize=12)
    +
    +    l2 = lines!(ax, tsteps, waveform_nn; linewidth=2, alpha=0.75)
    +    s2 = scatter!(
    +        ax, tsteps, waveform_nn; marker=:circle, alpha=0.5, strokewidth=2, markersize=12)
    +
    +    l3 = lines!(ax, tsteps, waveform_nn_trained; linewidth=2, alpha=0.75)
    +    s3 = scatter!(ax, tsteps, waveform_nn_trained; marker=:circle,
    +        alpha=0.5, strokewidth=2, markersize=12)
    +
    +    axislegend(ax, [[l1, s1], [l2, s2], [l3, s3]],
    +        ["Waveform Data", "Waveform Neural Net (Untrained)", "Waveform Neural Net"];
    +        position=:lb)
    +
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 128 × AMD EPYC 7502 32-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 16 default, 0 interactive, 8 GC (on 16 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 16
    +  JULIA_DEPOT_PATH = /cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 16
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate

    This page was generated using Literate.jl.

    `,31))])}const Z=t(e,[["render",X]]);export{j as __pageData,Z as default}; diff --git a/previews/PR1023/assets/tutorials_beginner_1_Basics.md.C9naagCh.js b/previews/PR1023/assets/tutorials_beginner_1_Basics.md.C9naagCh.js new file mode 100644 index 0000000000..c4eeae9c29 --- /dev/null +++ b/previews/PR1023/assets/tutorials_beginner_1_Basics.md.C9naagCh.js @@ -0,0 +1,217 @@ +import{_ as l,c as i,a2 as n,j as s,a as e,o as t}from"./chunks/framework.DFwXuivk.js";const D=JSON.parse('{"title":"Julia & Lux for the Uninitiated","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/beginner/1_Basics.md","filePath":"tutorials/beginner/1_Basics.md","lastUpdated":null}'),p={name:"tutorials/beginner/1_Basics.md"},h={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},d={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.781ex"},xmlns:"http://www.w3.org/2000/svg",width:"13.013ex",height:"2.737ex",role:"img",focusable:"false",viewBox:"0 -864.9 5751.9 1209.9","aria-hidden":"true"},r={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},o={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"10.494ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 4638.6 1000","aria-hidden":"true"},k={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},Q={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"40.51ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 17905.2 1000","aria-hidden":"true"},T={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},c={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.05ex"},xmlns:"http://www.w3.org/2000/svg",width:"2.371ex",height:"1.595ex",role:"img",focusable:"false",viewBox:"0 -683 1048 705","aria-hidden":"true"},g={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},m={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"0.971ex",height:"1.595ex",role:"img",focusable:"false",viewBox:"0 -694 429 705","aria-hidden":"true"},u={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},E={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.65ex"},xmlns:"http://www.w3.org/2000/svg",width:"17.577ex",height:"2.347ex",role:"img",focusable:"false",viewBox:"0 -750 7769 1037.2","aria-hidden":"true"},y={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},b={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.819ex"},xmlns:"http://www.w3.org/2000/svg",width:"34.144ex",height:"6.757ex",role:"img",focusable:"false",viewBox:"0 -1740.7 15091.8 2986.6","aria-hidden":"true"};function F(C,a,v,f,x,w){return t(),i("div",null,[a[21]||(a[21]=n(`

    Julia & Lux for the Uninitiated

    This is a quick intro to Lux loosely based on:

    1. PyTorch's tutorial.

    2. Flux's tutorial (the link for which has now been lost to abyss).

    3. Jax's tutorial.

    It introduces basic Julia programming, as well Zygote, a source-to-source automatic differentiation (AD) framework in Julia. We'll use these tools to build a very simple neural network. Let's start with importing Lux.jl

    julia
    using Lux, Random

    Now let us control the randomness in our code using proper Pseudo Random Number Generator (PRNG)

    julia
    rng = Random.default_rng()
    +Random.seed!(rng, 0)
    Random.TaskLocalRNG()

    Arrays

    The starting point for all of our models is the Array (sometimes referred to as a Tensor in other frameworks). This is really just a list of numbers, which might be arranged into a shape like a square. Let's write down an array with three elements.

    julia
    x = [1, 2, 3]
    3-element Vector{Int64}:
    + 1
    + 2
    + 3

    Here's a matrix – a square array with four elements.

    julia
    x = [1 2; 3 4]
    2×2 Matrix{Int64}:
    + 1  2
    + 3  4

    We often work with arrays of thousands of elements, and don't usually write them down by hand. Here's how we can create an array of 5×3 = 15 elements, each a random number from zero to one.

    julia
    x = rand(rng, 5, 3)
    5×3 Matrix{Float64}:
    + 0.455238   0.746943   0.193291
    + 0.547642   0.746801   0.116989
    + 0.773354   0.97667    0.899766
    + 0.940585   0.0869468  0.422918
    + 0.0296477  0.351491   0.707534

    There's a few functions like this; try replacing rand with ones, zeros, or randn.

    By default, Julia works stores numbers is a high-precision format called Float64. In ML we often don't need all those digits, and can ask Julia to work with Float32 instead. We can even ask for more digits using BigFloat.

    julia
    x = rand(BigFloat, 5, 3)
    5×3 Matrix{BigFloat}:
    + 0.981339    0.793159  0.459019
    + 0.043883    0.624384  0.56055
    + 0.164786    0.524008  0.0355555
    + 0.414769    0.577181  0.621958
    + 0.00823197  0.30215   0.655881
    julia
    x = rand(Float32, 5, 3)
    5×3 Matrix{Float32}:
    + 0.567794   0.369178   0.342539
    + 0.0985227  0.201145   0.587206
    + 0.776598   0.148248   0.0851708
    + 0.723731   0.0770206  0.839303
    + 0.404728   0.230954   0.679087

    We can ask the array how many elements it has.

    julia
    length(x)
    15

    Or, more specifically, what size it has.

    julia
    size(x)
    (5, 3)

    We sometimes want to see some elements of the array on their own.

    julia
    x
    5×3 Matrix{Float32}:
    + 0.567794   0.369178   0.342539
    + 0.0985227  0.201145   0.587206
    + 0.776598   0.148248   0.0851708
    + 0.723731   0.0770206  0.839303
    + 0.404728   0.230954   0.679087
    julia
    x[2, 3]
    0.58720636f0

    This means get the second row and the third column. We can also get every row of the third column.

    julia
    x[:, 3]
    5-element Vector{Float32}:
    + 0.34253937
    + 0.58720636
    + 0.085170805
    + 0.8393034
    + 0.67908657

    We can add arrays, and subtract them, which adds or subtracts each element of the array.

    julia
    x + x
    5×3 Matrix{Float32}:
    + 1.13559   0.738356  0.685079
    + 0.197045  0.40229   1.17441
    + 1.5532    0.296496  0.170342
    + 1.44746   0.154041  1.67861
    + 0.809456  0.461908  1.35817
    julia
    x - x
    5×3 Matrix{Float32}:
    + 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.0  0.0  0.0

    Julia supports a feature called broadcasting, using the . syntax. This tiles small arrays (or single numbers) to fill bigger ones.

    julia
    x .+ 1
    5×3 Matrix{Float32}:
    + 1.56779  1.36918  1.34254
    + 1.09852  1.20114  1.58721
    + 1.7766   1.14825  1.08517
    + 1.72373  1.07702  1.8393
    + 1.40473  1.23095  1.67909

    We can see Julia tile the column vector 1:5 across all rows of the larger array.

    julia
    zeros(5, 5) .+ (1:5)
    5×5 Matrix{Float64}:
    + 1.0  1.0  1.0  1.0  1.0
    + 2.0  2.0  2.0  2.0  2.0
    + 3.0  3.0  3.0  3.0  3.0
    + 4.0  4.0  4.0  4.0  4.0
    + 5.0  5.0  5.0  5.0  5.0

    The x' syntax is used to transpose a column 1:5 into an equivalent row, and Julia will tile that across columns.

    julia
    zeros(5, 5) .+ (1:5)'
    5×5 Matrix{Float64}:
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0

    We can use this to make a times table.

    julia
    (1:5) .* (1:5)'
    5×5 Matrix{Int64}:
    + 1   2   3   4   5
    + 2   4   6   8  10
    + 3   6   9  12  15
    + 4   8  12  16  20
    + 5  10  15  20  25

    Finally, and importantly for machine learning, we can conveniently do things like matrix multiply.

    julia
    W = randn(5, 10)
    +x = rand(10)
    +W * x
    5-element Vector{Float64}:
    +  1.2197981041108443
    + -2.62625877100596
    + -2.8573820474674845
    + -2.4319346874291314
    +  1.0108668577150213

    Julia's arrays are very powerful, and you can learn more about what they can do here.

    CUDA Arrays

    CUDA functionality is provided separately by the CUDA.jl package. If you have a GPU and LuxCUDA is installed, Lux will provide CUDA capabilities. For additional details on backends see the manual section.

    You can manually add CUDA. Once CUDA is loaded you can move any array to the GPU with the cu function (or the gpu function exported by \`Lux\`\`), and it supports all of the above operations with the same syntax.

    julia
    using LuxCUDA
    +
    +if LuxCUDA.functional()
    +    x_cu = cu(rand(5, 3))
    +    @show x_cu
    +end
    5×3 CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}:
    + 0.857126  0.681728  0.73806
    + 0.191956  0.506485  0.622865
    + 0.857257  0.663036  0.239756
    + 0.54452   0.503186  0.27993
    + 0.833518  0.975649  0.967811

    (Im)mutability

    Lux as you might have read is Immutable by convention which means that the core library is built without any form of mutation and all functions are pure. However, we don't enforce it in any form. We do strongly recommend that users extending this framework for their respective applications don't mutate their arrays.

    julia
    x = reshape(1:8, 2, 4)
    2×4 reshape(::UnitRange{Int64}, 2, 4) with eltype Int64:
    + 1  3  5  7
    + 2  4  6  8

    To update this array, we should first copy the array.

    julia
    x_copy = copy(x)
    +view(x_copy, :, 1) .= 0
    +
    +println("Original Array ", x)
    +println("Mutated Array ", x_copy)
    Original Array [1 3 5 7; 2 4 6 8]
    +Mutated Array [0 3 5 7; 0 4 6 8]

    Note that our current default AD engine (Zygote) is unable to differentiate through this mutation, however, for these specialized cases it is quite trivial to write custom backward passes. (This problem will be fixed once we move towards Enzyme.jl)

    Managing Randomness

    We rely on the Julia StdLib Random for managing the randomness in our execution. First, we create an PRNG (pseudorandom number generator) and seed it.

    julia
    rng = Xoshiro(0)     # Creates a Xoshiro PRNG with seed 0
    Random.Xoshiro(0xdb2fa90498613fdf, 0x48d73dc42d195740, 0x8c49bc52dc8a77ea, 0x1911b814c02405e8, 0x22a21880af5dc689)

    If we call any function that relies on rng and uses it via randn, rand, etc. rng will be mutated. As we have already established we care a lot about immutability, hence we should use Lux.replicate on PRNGs before using them.

    First, let us run a random number generator 3 times with the replicated rng.

    julia
    random_vectors = Vector{Vector{Float64}}(undef, 3)
    +for i in 1:3
    +    random_vectors[i] = rand(Lux.replicate(rng), 10)
    +    println("Iteration $i ", random_vectors[i])
    +end
    +@assert random_vectors[1]  random_vectors[2]  random_vectors[3]
    Iteration 1 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]
    +Iteration 2 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]
    +Iteration 3 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]

    As expected we get the same output. We can remove the replicate call and we will get different outputs.

    julia
    for i in 1:3
    +    println("Iteration $i ", rand(rng, 10))
    +end
    Iteration 1 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]
    +Iteration 2 [0.018743665453639813, 0.8601828553599953, 0.6556360448565952, 0.7746656838366666, 0.7817315740767116, 0.5553797706980106, 0.1261990389976131, 0.4488101521328277, 0.624383955429775, 0.05657739601024536]
    +Iteration 3 [0.19597391412112541, 0.6830945313415872, 0.6776220912718907, 0.6456416023530093, 0.6340362477836592, 0.5595843665394066, 0.5675557670686644, 0.34351700231383653, 0.7237308297251812, 0.3691778381831775]

    Automatic Differentiation

    Julia has quite a few (maybe too many) AD tools. For the purpose of this tutorial, we will use:

    1. ForwardDiff.jl – For Jacobian-Vector Product (JVP)

    2. Zygote.jl – For Vector-Jacobian Product (VJP)

    Slight Detour: We have had several questions regarding if we will be considering any other AD system for the reverse-diff backend. For now we will stick to Zygote.jl, however once we have tested Lux extensively with Enzyme.jl, we will make the switch.

    Even though, theoretically, a VJP (Vector-Jacobian product - reverse autodiff) and a JVP (Jacobian-Vector product - forward-mode autodiff) are similar—they compute a product of a Jacobian and a vector—they differ by the computational complexity of the operation. In short, when you have a large number of parameters (hence a wide matrix), a JVP is less efficient computationally than a VJP, and, conversely, a JVP is more efficient when the Jacobian matrix is a tall matrix.

    julia
    using ComponentArrays, ForwardDiff, Zygote

    Gradients

    `,90)),s("p",null,[a[4]||(a[4]=e("For our first example, consider a simple function computing ")),s("mjx-container",h,[(t(),i("svg",d,a[0]||(a[0]=[n('',1)]))),a[1]||(a[1]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"f"),s("mo",{stretchy:"false"},"("),s("mi",null,"x"),s("mo",{stretchy:"false"},")"),s("mo",null,"="),s("mfrac",null,[s("mn",null,"1"),s("mn",null,"2")]),s("msup",null,[s("mi",null,"x"),s("mi",null,"T")]),s("mi",null,"x")])],-1))]),a[5]||(a[5]=e(", where ")),s("mjx-container",r,[(t(),i("svg",o,a[2]||(a[2]=[n('',1)]))),a[3]||(a[3]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",{mathvariant:"normal"},"∇"),s("mi",null,"f"),s("mo",{stretchy:"false"},"("),s("mi",null,"x"),s("mo",{stretchy:"false"},")"),s("mo",null,"="),s("mi",null,"x")])],-1))])]),a[22]||(a[22]=n(`
    julia
    f(x) = x' * x / 2
    +∇f(x) = x  # \`∇\` can be typed as \`\\nabla<TAB>\`
    +v = randn(rng, Float32, 4)
    4-element Vector{Float32}:
    + -0.4051151
    + -0.4593922
    +  0.92155594
    +  1.1871622

    Let's use ForwardDiff and Zygote to compute the gradients.

    julia
    println("Actual Gradient: ", ∇f(v))
    +println("Computed Gradient via Reverse Mode AD (Zygote): ", only(Zygote.gradient(f, v)))
    +println("Computed Gradient via Forward Mode AD (ForwardDiff): ", ForwardDiff.gradient(f, v))
    Actual Gradient: Float32[-0.4051151, -0.4593922, 0.92155594, 1.1871622]
    +Computed Gradient via Reverse Mode AD (Zygote): Float32[-0.4051151, -0.4593922, 0.92155594, 1.1871622]
    +Computed Gradient via Forward Mode AD (ForwardDiff): Float32[-0.4051151, -0.4593922, 0.92155594, 1.1871622]

    Note that AD.gradient will only work for scalar valued outputs.

    Jacobian-Vector Product

    I will defer the discussion on forward-mode AD to https://book.sciml.ai/notes/08-Forward-Mode_Automatic_Differentiation_(AD)_via_High_Dimensional_Algebras/. Here let us just look at a mini example on how to use it.

    julia
    f(x) = x .* x ./ 2
    +x = randn(rng, Float32, 5)
    +v = ones(Float32, 5)
    5-element Vector{Float32}:
    + 1.0
    + 1.0
    + 1.0
    + 1.0
    + 1.0

    Using DifferentiationInterface

    While DifferentiationInterface provides these functions for a wider range of backends, we currently don't recommend using them with Lux models, since the functions presented here come with additional goodies like fast second-order derivatives.

    Compute the jvp. AutoForwardDiff specifies that we want to use ForwardDiff.jl for the Jacobian-Vector Product

    julia
    jvp = jacobian_vector_product(f, AutoForwardDiff(), x, v)
    +println("JVP: ", jvp)
    JVP: Float32[-0.877497, 1.1953009, -0.057005208, 0.25055695, 0.09351656]

    Vector-Jacobian Product

    Using the same function and inputs, let us compute the VJP.

    julia
    vjp = vector_jacobian_product(f, AutoZygote(), x, v)
    +println("VJP: ", vjp)
    VJP: Float32[-0.877497, 1.1953009, -0.057005208, 0.25055695, 0.09351656]

    Linear Regression

    `,19)),s("p",null,[a[14]||(a[14]=e("Finally, now let us consider a linear regression problem. From a set of data-points ")),s("mjx-container",k,[(t(),i("svg",Q,a[6]||(a[6]=[n('',1)]))),a[7]||(a[7]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mo",{fence:"false",stretchy:"false"},"{"),s("mo",{stretchy:"false"},"("),s("msub",null,[s("mi",null,"x"),s("mi",null,"i")]),s("mo",null,","),s("msub",null,[s("mi",null,"y"),s("mi",null,"i")]),s("mo",{stretchy:"false"},")"),s("mo",null,","),s("mi",null,"i"),s("mo",null,"∈"),s("mo",{fence:"false",stretchy:"false"},"{"),s("mn",null,"1"),s("mo",null,","),s("mo",null,"…"),s("mo",null,","),s("mi",null,"k"),s("mo",{fence:"false",stretchy:"false"},"}"),s("mo",null,","),s("msub",null,[s("mi",null,"x"),s("mi",null,"i")]),s("mo",null,"∈"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"R")]),s("mi",null,"n")]),s("mo",null,","),s("msub",null,[s("mi",null,"y"),s("mi",null,"i")]),s("mo",null,"∈"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"R")]),s("mi",null,"m")]),s("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[15]||(a[15]=e(", we try to find a set of parameters ")),s("mjx-container",T,[(t(),i("svg",c,a[8]||(a[8]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D44A",d:"M436 683Q450 683 486 682T553 680Q604 680 638 681T677 682Q695 682 695 674Q695 670 692 659Q687 641 683 639T661 637Q636 636 621 632T600 624T597 615Q597 603 613 377T629 138L631 141Q633 144 637 151T649 170T666 200T690 241T720 295T759 362Q863 546 877 572T892 604Q892 619 873 628T831 637Q817 637 817 647Q817 650 819 660Q823 676 825 679T839 682Q842 682 856 682T895 682T949 681Q1015 681 1034 683Q1048 683 1048 672Q1048 666 1045 655T1038 640T1028 637Q1006 637 988 631T958 617T939 600T927 584L923 578L754 282Q586 -14 585 -15Q579 -22 561 -22Q546 -22 542 -17Q539 -14 523 229T506 480L494 462Q472 425 366 239Q222 -13 220 -15T215 -19Q210 -22 197 -22Q178 -22 176 -15Q176 -12 154 304T131 622Q129 631 121 633T82 637H58Q51 644 51 648Q52 671 64 683H76Q118 680 176 680Q301 680 313 683H323Q329 677 329 674T327 656Q322 641 318 637H297Q236 634 232 620Q262 160 266 136L501 550L499 587Q496 629 489 632Q483 636 447 637Q428 637 422 639T416 648Q416 650 418 660Q419 664 420 669T421 676T424 680T428 682T436 683Z",style:{"stroke-width":"3"}})])])],-1)]))),a[9]||(a[9]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"W")])],-1))]),a[16]||(a[16]=e(" and ")),s("mjx-container",g,[(t(),i("svg",m,a[10]||(a[10]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D44F",d:"M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z",style:{"stroke-width":"3"}})])])],-1)]))),a[11]||(a[11]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"b")])],-1))]),a[17]||(a[17]=e(", s.t. ")),s("mjx-container",u,[(t(),i("svg",E,a[12]||(a[12]=[n('',1)]))),a[13]||(a[13]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("msub",null,[s("mi",null,"f"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"W"),s("mo",null,","),s("mi",null,"b")])]),s("mo",{stretchy:"false"},"("),s("mi",null,"x"),s("mo",{stretchy:"false"},")"),s("mo",null,"="),s("mi",null,"W"),s("mi",null,"x"),s("mo",null,"+"),s("mi",null,"b")])],-1))]),a[18]||(a[18]=e(", which minimizes the mean squared error:"))]),s("mjx-container",y,[(t(),i("svg",b,a[19]||(a[19]=[n('',1)]))),a[20]||(a[20]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mi",null,"L"),s("mo",{stretchy:"false"},"("),s("mi",null,"W"),s("mo",null,","),s("mi",null,"b"),s("mo",{stretchy:"false"},")"),s("mo",{stretchy:"false"},"⟶"),s("munderover",null,[s("mo",{"data-mjx-texclass":"OP"},"∑"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"i"),s("mo",null,"="),s("mn",null,"1")]),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"k")])]),s("mfrac",null,[s("mn",null,"1"),s("mn",null,"2")]),s("mo",{"data-mjx-texclass":"ORD"},"∥"),s("msub",null,[s("mi",null,"y"),s("mi",null,"i")]),s("mo",null,"−"),s("msub",null,[s("mi",null,"f"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"W"),s("mo",null,","),s("mi",null,"b")])]),s("mo",{stretchy:"false"},"("),s("msub",null,[s("mi",null,"x"),s("mi",null,"i")]),s("mo",{stretchy:"false"},")"),s("msubsup",null,[s("mo",{"data-mjx-texclass":"ORD"},"∥"),s("mn",null,"2"),s("mn",null,"2")])])],-1))]),a[23]||(a[23]=n(`

    We can write f from scratch, but to demonstrate Lux, let us use the Dense layer.

    julia
    model = Dense(10 => 5)
    +
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    Random.TaskLocalRNG()

    Let us initialize the parameters and states (in this case it is empty) for the model.

    julia
    ps, st = Lux.setup(rng, model)
    +ps = ps |> ComponentArray
    ComponentVector{Float32}(weight = Float32[-0.48351598 0.29944375 0.44048917 0.5221656 0.20001543 0.1437841 4.8317274f-6 0.5310851 -0.30674052 0.034259234; -0.04903387 -0.4242767 0.27051234 0.40789893 -0.43846482 -0.17706361 -0.03258145 0.46514034 0.1958431 0.23992883; 0.45016125 0.48263642 -0.2990853 -0.18695377 -0.11023762 -0.4418456 0.40354207 0.25278285 0.18056087 -0.3523193; 0.05218964 -0.09701932 0.27035674 0.12589 -0.29561827 0.34717593 -0.42189494 -0.13073668 0.36829436 -0.3097294; 0.20277858 -0.51524514 -0.22635892 0.18841726 0.29828635 0.21690917 -0.04265762 -0.41919118 0.071482725 -0.45247704], bias = Float32[-0.04199602, -0.093925126, -0.0007736237, -0.19397983, 0.0066712513])

    Set problem dimensions.

    julia
    n_samples = 20
    +x_dim = 10
    +y_dim = 5
    5

    Generate random ground truth W and b.

    julia
    W = randn(rng, Float32, y_dim, x_dim)
    +b = randn(rng, Float32, y_dim)
    5-element Vector{Float32}:
    + -0.9436797
    +  1.5164032
    +  0.011937321
    +  1.4339262
    + -0.2771789

    Generate samples with additional noise.

    julia
    x_samples = randn(rng, Float32, x_dim, n_samples)
    +y_samples = W * x_samples .+ b .+ 0.01f0 .* randn(rng, Float32, y_dim, n_samples)
    +println("x shape: ", size(x_samples), "; y shape: ", size(y_samples))
    x shape: (10, 20); y shape: (5, 20)

    For updating our parameters let's use Optimisers.jl. We will use Stochastic Gradient Descent (SGD) with a learning rate of 0.01.

    julia
    using Optimisers, Printf

    Define the loss function

    julia
    lossfn = MSELoss()
    +
    +println("Loss Value with ground true parameters: ", lossfn(W * x_samples .+ b, y_samples))
    Loss Value with ground true parameters: 9.3742405e-5

    We will train the model using our training API.

    julia
    function train_model!(model, ps, st, opt, nepochs::Int)
    +    tstate = Training.TrainState(model, ps, st, opt)
    +    for i in 1:nepochs
    +        grads, loss, _, tstate = Training.single_train_step!(
    +            AutoZygote(), lossfn, (x_samples, y_samples), tstate)
    +        if i % 1000 == 1 || i == nepochs
    +            @printf "Loss Value after %6d iterations: %.8f\\n" i loss
    +        end
    +    end
    +    return tstate.model, tstate.parameters, tstate.states
    +end
    +
    +model, ps, st = train_model!(model, ps, st, Descent(0.01f0), 10000)
    +
    +println("Loss Value after training: ", lossfn(first(model(x_samples, ps, st)), y_samples))
    Loss Value after      1 iterations: 7.80465555
    +Loss Value after   1001 iterations: 0.12477568
    +Loss Value after   2001 iterations: 0.02535537
    +Loss Value after   3001 iterations: 0.00914141
    +Loss Value after   4001 iterations: 0.00407581
    +Loss Value after   5001 iterations: 0.00198415
    +Loss Value after   6001 iterations: 0.00101147
    +Loss Value after   7001 iterations: 0.00053332
    +Loss Value after   8001 iterations: 0.00029203
    +Loss Value after   9001 iterations: 0.00016878
    +Loss Value after  10000 iterations: 0.00010551
    +Loss Value after training: 0.00010546855

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.627 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,28))])}const H=l(p,[["render",F]]);export{D as __pageData,H as default}; diff --git a/previews/PR1023/assets/tutorials_beginner_1_Basics.md.C9naagCh.lean.js b/previews/PR1023/assets/tutorials_beginner_1_Basics.md.C9naagCh.lean.js new file mode 100644 index 0000000000..c4eeae9c29 --- /dev/null +++ b/previews/PR1023/assets/tutorials_beginner_1_Basics.md.C9naagCh.lean.js @@ -0,0 +1,217 @@ +import{_ as l,c as i,a2 as n,j as s,a as e,o as t}from"./chunks/framework.DFwXuivk.js";const D=JSON.parse('{"title":"Julia & Lux for the Uninitiated","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/beginner/1_Basics.md","filePath":"tutorials/beginner/1_Basics.md","lastUpdated":null}'),p={name:"tutorials/beginner/1_Basics.md"},h={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},d={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.781ex"},xmlns:"http://www.w3.org/2000/svg",width:"13.013ex",height:"2.737ex",role:"img",focusable:"false",viewBox:"0 -864.9 5751.9 1209.9","aria-hidden":"true"},r={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},o={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"10.494ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 4638.6 1000","aria-hidden":"true"},k={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},Q={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"40.51ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 17905.2 1000","aria-hidden":"true"},T={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},c={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.05ex"},xmlns:"http://www.w3.org/2000/svg",width:"2.371ex",height:"1.595ex",role:"img",focusable:"false",viewBox:"0 -683 1048 705","aria-hidden":"true"},g={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},m={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.025ex"},xmlns:"http://www.w3.org/2000/svg",width:"0.971ex",height:"1.595ex",role:"img",focusable:"false",viewBox:"0 -694 429 705","aria-hidden":"true"},u={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},E={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.65ex"},xmlns:"http://www.w3.org/2000/svg",width:"17.577ex",height:"2.347ex",role:"img",focusable:"false",viewBox:"0 -750 7769 1037.2","aria-hidden":"true"},y={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},b={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-2.819ex"},xmlns:"http://www.w3.org/2000/svg",width:"34.144ex",height:"6.757ex",role:"img",focusable:"false",viewBox:"0 -1740.7 15091.8 2986.6","aria-hidden":"true"};function F(C,a,v,f,x,w){return t(),i("div",null,[a[21]||(a[21]=n(`

    Julia & Lux for the Uninitiated

    This is a quick intro to Lux loosely based on:

    1. PyTorch's tutorial.

    2. Flux's tutorial (the link for which has now been lost to abyss).

    3. Jax's tutorial.

    It introduces basic Julia programming, as well Zygote, a source-to-source automatic differentiation (AD) framework in Julia. We'll use these tools to build a very simple neural network. Let's start with importing Lux.jl

    julia
    using Lux, Random

    Now let us control the randomness in our code using proper Pseudo Random Number Generator (PRNG)

    julia
    rng = Random.default_rng()
    +Random.seed!(rng, 0)
    Random.TaskLocalRNG()

    Arrays

    The starting point for all of our models is the Array (sometimes referred to as a Tensor in other frameworks). This is really just a list of numbers, which might be arranged into a shape like a square. Let's write down an array with three elements.

    julia
    x = [1, 2, 3]
    3-element Vector{Int64}:
    + 1
    + 2
    + 3

    Here's a matrix – a square array with four elements.

    julia
    x = [1 2; 3 4]
    2×2 Matrix{Int64}:
    + 1  2
    + 3  4

    We often work with arrays of thousands of elements, and don't usually write them down by hand. Here's how we can create an array of 5×3 = 15 elements, each a random number from zero to one.

    julia
    x = rand(rng, 5, 3)
    5×3 Matrix{Float64}:
    + 0.455238   0.746943   0.193291
    + 0.547642   0.746801   0.116989
    + 0.773354   0.97667    0.899766
    + 0.940585   0.0869468  0.422918
    + 0.0296477  0.351491   0.707534

    There's a few functions like this; try replacing rand with ones, zeros, or randn.

    By default, Julia works stores numbers is a high-precision format called Float64. In ML we often don't need all those digits, and can ask Julia to work with Float32 instead. We can even ask for more digits using BigFloat.

    julia
    x = rand(BigFloat, 5, 3)
    5×3 Matrix{BigFloat}:
    + 0.981339    0.793159  0.459019
    + 0.043883    0.624384  0.56055
    + 0.164786    0.524008  0.0355555
    + 0.414769    0.577181  0.621958
    + 0.00823197  0.30215   0.655881
    julia
    x = rand(Float32, 5, 3)
    5×3 Matrix{Float32}:
    + 0.567794   0.369178   0.342539
    + 0.0985227  0.201145   0.587206
    + 0.776598   0.148248   0.0851708
    + 0.723731   0.0770206  0.839303
    + 0.404728   0.230954   0.679087

    We can ask the array how many elements it has.

    julia
    length(x)
    15

    Or, more specifically, what size it has.

    julia
    size(x)
    (5, 3)

    We sometimes want to see some elements of the array on their own.

    julia
    x
    5×3 Matrix{Float32}:
    + 0.567794   0.369178   0.342539
    + 0.0985227  0.201145   0.587206
    + 0.776598   0.148248   0.0851708
    + 0.723731   0.0770206  0.839303
    + 0.404728   0.230954   0.679087
    julia
    x[2, 3]
    0.58720636f0

    This means get the second row and the third column. We can also get every row of the third column.

    julia
    x[:, 3]
    5-element Vector{Float32}:
    + 0.34253937
    + 0.58720636
    + 0.085170805
    + 0.8393034
    + 0.67908657

    We can add arrays, and subtract them, which adds or subtracts each element of the array.

    julia
    x + x
    5×3 Matrix{Float32}:
    + 1.13559   0.738356  0.685079
    + 0.197045  0.40229   1.17441
    + 1.5532    0.296496  0.170342
    + 1.44746   0.154041  1.67861
    + 0.809456  0.461908  1.35817
    julia
    x - x
    5×3 Matrix{Float32}:
    + 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.0  0.0  0.0

    Julia supports a feature called broadcasting, using the . syntax. This tiles small arrays (or single numbers) to fill bigger ones.

    julia
    x .+ 1
    5×3 Matrix{Float32}:
    + 1.56779  1.36918  1.34254
    + 1.09852  1.20114  1.58721
    + 1.7766   1.14825  1.08517
    + 1.72373  1.07702  1.8393
    + 1.40473  1.23095  1.67909

    We can see Julia tile the column vector 1:5 across all rows of the larger array.

    julia
    zeros(5, 5) .+ (1:5)
    5×5 Matrix{Float64}:
    + 1.0  1.0  1.0  1.0  1.0
    + 2.0  2.0  2.0  2.0  2.0
    + 3.0  3.0  3.0  3.0  3.0
    + 4.0  4.0  4.0  4.0  4.0
    + 5.0  5.0  5.0  5.0  5.0

    The x' syntax is used to transpose a column 1:5 into an equivalent row, and Julia will tile that across columns.

    julia
    zeros(5, 5) .+ (1:5)'
    5×5 Matrix{Float64}:
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0

    We can use this to make a times table.

    julia
    (1:5) .* (1:5)'
    5×5 Matrix{Int64}:
    + 1   2   3   4   5
    + 2   4   6   8  10
    + 3   6   9  12  15
    + 4   8  12  16  20
    + 5  10  15  20  25

    Finally, and importantly for machine learning, we can conveniently do things like matrix multiply.

    julia
    W = randn(5, 10)
    +x = rand(10)
    +W * x
    5-element Vector{Float64}:
    +  1.2197981041108443
    + -2.62625877100596
    + -2.8573820474674845
    + -2.4319346874291314
    +  1.0108668577150213

    Julia's arrays are very powerful, and you can learn more about what they can do here.

    CUDA Arrays

    CUDA functionality is provided separately by the CUDA.jl package. If you have a GPU and LuxCUDA is installed, Lux will provide CUDA capabilities. For additional details on backends see the manual section.

    You can manually add CUDA. Once CUDA is loaded you can move any array to the GPU with the cu function (or the gpu function exported by \`Lux\`\`), and it supports all of the above operations with the same syntax.

    julia
    using LuxCUDA
    +
    +if LuxCUDA.functional()
    +    x_cu = cu(rand(5, 3))
    +    @show x_cu
    +end
    5×3 CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}:
    + 0.857126  0.681728  0.73806
    + 0.191956  0.506485  0.622865
    + 0.857257  0.663036  0.239756
    + 0.54452   0.503186  0.27993
    + 0.833518  0.975649  0.967811

    (Im)mutability

    Lux as you might have read is Immutable by convention which means that the core library is built without any form of mutation and all functions are pure. However, we don't enforce it in any form. We do strongly recommend that users extending this framework for their respective applications don't mutate their arrays.

    julia
    x = reshape(1:8, 2, 4)
    2×4 reshape(::UnitRange{Int64}, 2, 4) with eltype Int64:
    + 1  3  5  7
    + 2  4  6  8

    To update this array, we should first copy the array.

    julia
    x_copy = copy(x)
    +view(x_copy, :, 1) .= 0
    +
    +println("Original Array ", x)
    +println("Mutated Array ", x_copy)
    Original Array [1 3 5 7; 2 4 6 8]
    +Mutated Array [0 3 5 7; 0 4 6 8]

    Note that our current default AD engine (Zygote) is unable to differentiate through this mutation, however, for these specialized cases it is quite trivial to write custom backward passes. (This problem will be fixed once we move towards Enzyme.jl)

    Managing Randomness

    We rely on the Julia StdLib Random for managing the randomness in our execution. First, we create an PRNG (pseudorandom number generator) and seed it.

    julia
    rng = Xoshiro(0)     # Creates a Xoshiro PRNG with seed 0
    Random.Xoshiro(0xdb2fa90498613fdf, 0x48d73dc42d195740, 0x8c49bc52dc8a77ea, 0x1911b814c02405e8, 0x22a21880af5dc689)

    If we call any function that relies on rng and uses it via randn, rand, etc. rng will be mutated. As we have already established we care a lot about immutability, hence we should use Lux.replicate on PRNGs before using them.

    First, let us run a random number generator 3 times with the replicated rng.

    julia
    random_vectors = Vector{Vector{Float64}}(undef, 3)
    +for i in 1:3
    +    random_vectors[i] = rand(Lux.replicate(rng), 10)
    +    println("Iteration $i ", random_vectors[i])
    +end
    +@assert random_vectors[1]  random_vectors[2]  random_vectors[3]
    Iteration 1 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]
    +Iteration 2 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]
    +Iteration 3 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]

    As expected we get the same output. We can remove the replicate call and we will get different outputs.

    julia
    for i in 1:3
    +    println("Iteration $i ", rand(rng, 10))
    +end
    Iteration 1 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]
    +Iteration 2 [0.018743665453639813, 0.8601828553599953, 0.6556360448565952, 0.7746656838366666, 0.7817315740767116, 0.5553797706980106, 0.1261990389976131, 0.4488101521328277, 0.624383955429775, 0.05657739601024536]
    +Iteration 3 [0.19597391412112541, 0.6830945313415872, 0.6776220912718907, 0.6456416023530093, 0.6340362477836592, 0.5595843665394066, 0.5675557670686644, 0.34351700231383653, 0.7237308297251812, 0.3691778381831775]

    Automatic Differentiation

    Julia has quite a few (maybe too many) AD tools. For the purpose of this tutorial, we will use:

    1. ForwardDiff.jl – For Jacobian-Vector Product (JVP)

    2. Zygote.jl – For Vector-Jacobian Product (VJP)

    Slight Detour: We have had several questions regarding if we will be considering any other AD system for the reverse-diff backend. For now we will stick to Zygote.jl, however once we have tested Lux extensively with Enzyme.jl, we will make the switch.

    Even though, theoretically, a VJP (Vector-Jacobian product - reverse autodiff) and a JVP (Jacobian-Vector product - forward-mode autodiff) are similar—they compute a product of a Jacobian and a vector—they differ by the computational complexity of the operation. In short, when you have a large number of parameters (hence a wide matrix), a JVP is less efficient computationally than a VJP, and, conversely, a JVP is more efficient when the Jacobian matrix is a tall matrix.

    julia
    using ComponentArrays, ForwardDiff, Zygote

    Gradients

    `,90)),s("p",null,[a[4]||(a[4]=e("For our first example, consider a simple function computing ")),s("mjx-container",h,[(t(),i("svg",d,a[0]||(a[0]=[n('',1)]))),a[1]||(a[1]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"f"),s("mo",{stretchy:"false"},"("),s("mi",null,"x"),s("mo",{stretchy:"false"},")"),s("mo",null,"="),s("mfrac",null,[s("mn",null,"1"),s("mn",null,"2")]),s("msup",null,[s("mi",null,"x"),s("mi",null,"T")]),s("mi",null,"x")])],-1))]),a[5]||(a[5]=e(", where ")),s("mjx-container",r,[(t(),i("svg",o,a[2]||(a[2]=[n('',1)]))),a[3]||(a[3]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",{mathvariant:"normal"},"∇"),s("mi",null,"f"),s("mo",{stretchy:"false"},"("),s("mi",null,"x"),s("mo",{stretchy:"false"},")"),s("mo",null,"="),s("mi",null,"x")])],-1))])]),a[22]||(a[22]=n(`
    julia
    f(x) = x' * x / 2
    +∇f(x) = x  # \`∇\` can be typed as \`\\nabla<TAB>\`
    +v = randn(rng, Float32, 4)
    4-element Vector{Float32}:
    + -0.4051151
    + -0.4593922
    +  0.92155594
    +  1.1871622

    Let's use ForwardDiff and Zygote to compute the gradients.

    julia
    println("Actual Gradient: ", ∇f(v))
    +println("Computed Gradient via Reverse Mode AD (Zygote): ", only(Zygote.gradient(f, v)))
    +println("Computed Gradient via Forward Mode AD (ForwardDiff): ", ForwardDiff.gradient(f, v))
    Actual Gradient: Float32[-0.4051151, -0.4593922, 0.92155594, 1.1871622]
    +Computed Gradient via Reverse Mode AD (Zygote): Float32[-0.4051151, -0.4593922, 0.92155594, 1.1871622]
    +Computed Gradient via Forward Mode AD (ForwardDiff): Float32[-0.4051151, -0.4593922, 0.92155594, 1.1871622]

    Note that AD.gradient will only work for scalar valued outputs.

    Jacobian-Vector Product

    I will defer the discussion on forward-mode AD to https://book.sciml.ai/notes/08-Forward-Mode_Automatic_Differentiation_(AD)_via_High_Dimensional_Algebras/. Here let us just look at a mini example on how to use it.

    julia
    f(x) = x .* x ./ 2
    +x = randn(rng, Float32, 5)
    +v = ones(Float32, 5)
    5-element Vector{Float32}:
    + 1.0
    + 1.0
    + 1.0
    + 1.0
    + 1.0

    Using DifferentiationInterface

    While DifferentiationInterface provides these functions for a wider range of backends, we currently don't recommend using them with Lux models, since the functions presented here come with additional goodies like fast second-order derivatives.

    Compute the jvp. AutoForwardDiff specifies that we want to use ForwardDiff.jl for the Jacobian-Vector Product

    julia
    jvp = jacobian_vector_product(f, AutoForwardDiff(), x, v)
    +println("JVP: ", jvp)
    JVP: Float32[-0.877497, 1.1953009, -0.057005208, 0.25055695, 0.09351656]

    Vector-Jacobian Product

    Using the same function and inputs, let us compute the VJP.

    julia
    vjp = vector_jacobian_product(f, AutoZygote(), x, v)
    +println("VJP: ", vjp)
    VJP: Float32[-0.877497, 1.1953009, -0.057005208, 0.25055695, 0.09351656]

    Linear Regression

    `,19)),s("p",null,[a[14]||(a[14]=e("Finally, now let us consider a linear regression problem. From a set of data-points ")),s("mjx-container",k,[(t(),i("svg",Q,a[6]||(a[6]=[n('',1)]))),a[7]||(a[7]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mo",{fence:"false",stretchy:"false"},"{"),s("mo",{stretchy:"false"},"("),s("msub",null,[s("mi",null,"x"),s("mi",null,"i")]),s("mo",null,","),s("msub",null,[s("mi",null,"y"),s("mi",null,"i")]),s("mo",{stretchy:"false"},")"),s("mo",null,","),s("mi",null,"i"),s("mo",null,"∈"),s("mo",{fence:"false",stretchy:"false"},"{"),s("mn",null,"1"),s("mo",null,","),s("mo",null,"…"),s("mo",null,","),s("mi",null,"k"),s("mo",{fence:"false",stretchy:"false"},"}"),s("mo",null,","),s("msub",null,[s("mi",null,"x"),s("mi",null,"i")]),s("mo",null,"∈"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"R")]),s("mi",null,"n")]),s("mo",null,","),s("msub",null,[s("mi",null,"y"),s("mi",null,"i")]),s("mo",null,"∈"),s("msup",null,[s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",{mathvariant:"double-struck"},"R")]),s("mi",null,"m")]),s("mo",{fence:"false",stretchy:"false"},"}")])],-1))]),a[15]||(a[15]=e(", we try to find a set of parameters ")),s("mjx-container",T,[(t(),i("svg",c,a[8]||(a[8]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D44A",d:"M436 683Q450 683 486 682T553 680Q604 680 638 681T677 682Q695 682 695 674Q695 670 692 659Q687 641 683 639T661 637Q636 636 621 632T600 624T597 615Q597 603 613 377T629 138L631 141Q633 144 637 151T649 170T666 200T690 241T720 295T759 362Q863 546 877 572T892 604Q892 619 873 628T831 637Q817 637 817 647Q817 650 819 660Q823 676 825 679T839 682Q842 682 856 682T895 682T949 681Q1015 681 1034 683Q1048 683 1048 672Q1048 666 1045 655T1038 640T1028 637Q1006 637 988 631T958 617T939 600T927 584L923 578L754 282Q586 -14 585 -15Q579 -22 561 -22Q546 -22 542 -17Q539 -14 523 229T506 480L494 462Q472 425 366 239Q222 -13 220 -15T215 -19Q210 -22 197 -22Q178 -22 176 -15Q176 -12 154 304T131 622Q129 631 121 633T82 637H58Q51 644 51 648Q52 671 64 683H76Q118 680 176 680Q301 680 313 683H323Q329 677 329 674T327 656Q322 641 318 637H297Q236 634 232 620Q262 160 266 136L501 550L499 587Q496 629 489 632Q483 636 447 637Q428 637 422 639T416 648Q416 650 418 660Q419 664 420 669T421 676T424 680T428 682T436 683Z",style:{"stroke-width":"3"}})])])],-1)]))),a[9]||(a[9]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"W")])],-1))]),a[16]||(a[16]=e(" and ")),s("mjx-container",g,[(t(),i("svg",m,a[10]||(a[10]=[s("g",{stroke:"currentColor",fill:"currentColor","stroke-width":"0",transform:"scale(1,-1)"},[s("g",{"data-mml-node":"math"},[s("g",{"data-mml-node":"mi"},[s("path",{"data-c":"1D44F",d:"M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z",style:{"stroke-width":"3"}})])])],-1)]))),a[11]||(a[11]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"b")])],-1))]),a[17]||(a[17]=e(", s.t. ")),s("mjx-container",u,[(t(),i("svg",E,a[12]||(a[12]=[n('',1)]))),a[13]||(a[13]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("msub",null,[s("mi",null,"f"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"W"),s("mo",null,","),s("mi",null,"b")])]),s("mo",{stretchy:"false"},"("),s("mi",null,"x"),s("mo",{stretchy:"false"},")"),s("mo",null,"="),s("mi",null,"W"),s("mi",null,"x"),s("mo",null,"+"),s("mi",null,"b")])],-1))]),a[18]||(a[18]=e(", which minimizes the mean squared error:"))]),s("mjx-container",y,[(t(),i("svg",b,a[19]||(a[19]=[n('',1)]))),a[20]||(a[20]=s("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[s("mi",null,"L"),s("mo",{stretchy:"false"},"("),s("mi",null,"W"),s("mo",null,","),s("mi",null,"b"),s("mo",{stretchy:"false"},")"),s("mo",{stretchy:"false"},"⟶"),s("munderover",null,[s("mo",{"data-mjx-texclass":"OP"},"∑"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"i"),s("mo",null,"="),s("mn",null,"1")]),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"k")])]),s("mfrac",null,[s("mn",null,"1"),s("mn",null,"2")]),s("mo",{"data-mjx-texclass":"ORD"},"∥"),s("msub",null,[s("mi",null,"y"),s("mi",null,"i")]),s("mo",null,"−"),s("msub",null,[s("mi",null,"f"),s("mrow",{"data-mjx-texclass":"ORD"},[s("mi",null,"W"),s("mo",null,","),s("mi",null,"b")])]),s("mo",{stretchy:"false"},"("),s("msub",null,[s("mi",null,"x"),s("mi",null,"i")]),s("mo",{stretchy:"false"},")"),s("msubsup",null,[s("mo",{"data-mjx-texclass":"ORD"},"∥"),s("mn",null,"2"),s("mn",null,"2")])])],-1))]),a[23]||(a[23]=n(`

    We can write f from scratch, but to demonstrate Lux, let us use the Dense layer.

    julia
    model = Dense(10 => 5)
    +
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    Random.TaskLocalRNG()

    Let us initialize the parameters and states (in this case it is empty) for the model.

    julia
    ps, st = Lux.setup(rng, model)
    +ps = ps |> ComponentArray
    ComponentVector{Float32}(weight = Float32[-0.48351598 0.29944375 0.44048917 0.5221656 0.20001543 0.1437841 4.8317274f-6 0.5310851 -0.30674052 0.034259234; -0.04903387 -0.4242767 0.27051234 0.40789893 -0.43846482 -0.17706361 -0.03258145 0.46514034 0.1958431 0.23992883; 0.45016125 0.48263642 -0.2990853 -0.18695377 -0.11023762 -0.4418456 0.40354207 0.25278285 0.18056087 -0.3523193; 0.05218964 -0.09701932 0.27035674 0.12589 -0.29561827 0.34717593 -0.42189494 -0.13073668 0.36829436 -0.3097294; 0.20277858 -0.51524514 -0.22635892 0.18841726 0.29828635 0.21690917 -0.04265762 -0.41919118 0.071482725 -0.45247704], bias = Float32[-0.04199602, -0.093925126, -0.0007736237, -0.19397983, 0.0066712513])

    Set problem dimensions.

    julia
    n_samples = 20
    +x_dim = 10
    +y_dim = 5
    5

    Generate random ground truth W and b.

    julia
    W = randn(rng, Float32, y_dim, x_dim)
    +b = randn(rng, Float32, y_dim)
    5-element Vector{Float32}:
    + -0.9436797
    +  1.5164032
    +  0.011937321
    +  1.4339262
    + -0.2771789

    Generate samples with additional noise.

    julia
    x_samples = randn(rng, Float32, x_dim, n_samples)
    +y_samples = W * x_samples .+ b .+ 0.01f0 .* randn(rng, Float32, y_dim, n_samples)
    +println("x shape: ", size(x_samples), "; y shape: ", size(y_samples))
    x shape: (10, 20); y shape: (5, 20)

    For updating our parameters let's use Optimisers.jl. We will use Stochastic Gradient Descent (SGD) with a learning rate of 0.01.

    julia
    using Optimisers, Printf

    Define the loss function

    julia
    lossfn = MSELoss()
    +
    +println("Loss Value with ground true parameters: ", lossfn(W * x_samples .+ b, y_samples))
    Loss Value with ground true parameters: 9.3742405e-5

    We will train the model using our training API.

    julia
    function train_model!(model, ps, st, opt, nepochs::Int)
    +    tstate = Training.TrainState(model, ps, st, opt)
    +    for i in 1:nepochs
    +        grads, loss, _, tstate = Training.single_train_step!(
    +            AutoZygote(), lossfn, (x_samples, y_samples), tstate)
    +        if i % 1000 == 1 || i == nepochs
    +            @printf "Loss Value after %6d iterations: %.8f\\n" i loss
    +        end
    +    end
    +    return tstate.model, tstate.parameters, tstate.states
    +end
    +
    +model, ps, st = train_model!(model, ps, st, Descent(0.01f0), 10000)
    +
    +println("Loss Value after training: ", lossfn(first(model(x_samples, ps, st)), y_samples))
    Loss Value after      1 iterations: 7.80465555
    +Loss Value after   1001 iterations: 0.12477568
    +Loss Value after   2001 iterations: 0.02535537
    +Loss Value after   3001 iterations: 0.00914141
    +Loss Value after   4001 iterations: 0.00407581
    +Loss Value after   5001 iterations: 0.00198415
    +Loss Value after   6001 iterations: 0.00101147
    +Loss Value after   7001 iterations: 0.00053332
    +Loss Value after   8001 iterations: 0.00029203
    +Loss Value after   9001 iterations: 0.00016878
    +Loss Value after  10000 iterations: 0.00010551
    +Loss Value after training: 0.00010546855

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.627 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,28))])}const H=l(p,[["render",F]]);export{D as __pageData,H as default}; diff --git a/previews/PR1023/assets/tutorials_beginner_2_PolynomialFitting.md.sRzotb_h.js b/previews/PR1023/assets/tutorials_beginner_2_PolynomialFitting.md.sRzotb_h.js new file mode 100644 index 0000000000..b98dd44765 --- /dev/null +++ b/previews/PR1023/assets/tutorials_beginner_2_PolynomialFitting.md.sRzotb_h.js @@ -0,0 +1,124 @@ +import{_ as l,c as a,a2 as s,j as i,a as n,o as t}from"./chunks/framework.DFwXuivk.js";const I=JSON.parse('{"title":"Fitting a Polynomial using MLP","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/beginner/2_PolynomialFitting.md","filePath":"tutorials/beginner/2_PolynomialFitting.md","lastUpdated":null}'),p={name:"tutorials/beginner/2_PolynomialFitting.md"},e={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},h={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"11.599ex",height:"2.351ex",role:"img",focusable:"false",viewBox:"0 -833.9 5126.6 1038.9","aria-hidden":"true"};function E(d,A,k,r,v,g){return t(),a("div",null,[A[4]||(A[4]=s(`

    Fitting a Polynomial using MLP

    In this tutorial we will fit a MultiLayer Perceptron (MLP) on data generated from a polynomial.

    Package Imports

    julia
    using Lux, ADTypes, LuxCUDA, Optimisers, Printf, Random, Statistics, Zygote
    +using CairoMakie

    Dataset

    `,5)),i("p",null,[A[2]||(A[2]=n("Generate 128 datapoints from the polynomial ")),i("mjx-container",e,[(t(),a("svg",h,A[0]||(A[0]=[s('',1)]))),A[1]||(A[1]=i("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[i("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[i("mi",null,"y"),i("mo",null,"="),i("msup",null,[i("mi",null,"x"),i("mn",null,"2")]),i("mo",null,"−"),i("mn",null,"2"),i("mi",null,"x")])],-1))]),A[3]||(A[3]=n("."))]),A[5]||(A[5]=s(`
    julia
    function generate_data(rng::AbstractRNG)
    +    x = reshape(collect(range(-2.0f0, 2.0f0, 128)), (1, 128))
    +    y = evalpoly.(x, ((0, -2, 1),)) .+ randn(rng, Float32, (1, 128)) .* 0.1f0
    +    return (x, y)
    +end
    generate_data (generic function with 1 method)

    Initialize the random number generator and fetch the dataset.

    julia
    rng = MersenneTwister()
    +Random.seed!(rng, 12345)
    +
    +(x, y) = generate_data(rng)
    (Float32[-2.0 -1.968504 -1.9370079 -1.9055119 -1.8740157 -1.8425196 -1.8110236 -1.7795275 -1.7480315 -1.7165354 -1.6850394 -1.6535434 -1.6220472 -1.5905511 -1.5590551 -1.527559 -1.496063 -1.464567 -1.4330709 -1.4015749 -1.3700787 -1.3385826 -1.3070866 -1.2755905 -1.2440945 -1.2125984 -1.1811024 -1.1496063 -1.1181102 -1.0866141 -1.0551181 -1.023622 -0.992126 -0.96062994 -0.92913383 -0.8976378 -0.86614174 -0.8346457 -0.8031496 -0.77165353 -0.7401575 -0.70866144 -0.6771653 -0.6456693 -0.61417323 -0.5826772 -0.5511811 -0.51968503 -0.48818898 -0.4566929 -0.42519686 -0.39370078 -0.36220473 -0.33070865 -0.2992126 -0.26771653 -0.23622048 -0.20472442 -0.17322835 -0.14173229 -0.11023622 -0.07874016 -0.047244094 -0.015748031 0.015748031 0.047244094 0.07874016 0.11023622 0.14173229 0.17322835 0.20472442 0.23622048 0.26771653 0.2992126 0.33070865 0.36220473 0.39370078 0.42519686 0.4566929 0.48818898 0.51968503 0.5511811 0.5826772 0.61417323 0.6456693 0.6771653 0.70866144 0.7401575 0.77165353 0.8031496 0.8346457 0.86614174 0.8976378 0.92913383 0.96062994 0.992126 1.023622 1.0551181 1.0866141 1.1181102 1.1496063 1.1811024 1.2125984 1.2440945 1.2755905 1.3070866 1.3385826 1.3700787 1.4015749 1.4330709 1.464567 1.496063 1.527559 1.5590551 1.5905511 1.6220472 1.6535434 1.6850394 1.7165354 1.7480315 1.7795275 1.8110236 1.8425196 1.8740157 1.9055119 1.9370079 1.968504 2.0], Float32[8.117236 7.8972864 7.667572 7.4936414 7.328542 7.108145 6.7541456 6.7384486 6.6983237 6.3637495 6.2701178 6.241937 5.816281 5.7183194 5.741348 5.2581186 5.2681656 5.195746 5.032705 4.73341 4.52024 4.3693867 4.107888 4.1828456 4.0022497 3.8969011 3.9108207 3.64644 3.3343754 3.398038 3.1887817 2.9930804 3.0189805 2.6904922 2.8576512 2.4778283 2.4524014 2.4018757 2.2896426 2.281252 1.9742292 1.7663455 1.8424188 1.6920981 1.6389992 1.7001468 1.4353992 1.3645461 1.2354317 0.9803549 0.9767632 0.9418648 1.0686756 0.6448233 0.6202136 0.57882756 0.44078717 0.48027995 0.35653025 0.39588368 0.21940619 0.17816184 -0.03322105 0.11007148 0.08922641 0.009766437 -0.06433817 -0.14132261 -0.22807482 -0.35395628 -0.6003383 -0.33544478 -0.49804282 -0.4382721 -0.52628386 -0.64495987 -0.46061087 -0.5594571 -0.82293516 -0.76425457 -0.8688824 -0.9489941 -0.90779305 -0.7559453 -0.8499767 -0.9161865 -0.9856883 -0.88951594 -1.0803379 -1.18564 -0.9934639 -0.9253495 -0.9679338 -0.9079035 -1.1395766 -1.1286439 -0.9248211 -1.0428307 -0.95401394 -1.0709 -1.0742047 -1.0277897 -0.8821303 -0.875082 -0.85050875 -0.97378695 -0.8013359 -0.78818554 -0.7897024 -0.7123551 -0.6859683 -0.76158035 -0.82030004 -0.8031547 -0.45583528 -0.61155146 -0.55658394 -0.4371308 -0.48983693 -0.37275374 -0.5424696 -0.2922556 -0.38200346 -0.30673835 -0.08820387 -0.3170582 0.0010350421 -0.13475561])

    Let's visualize the dataset

    julia
    begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +
    +    l = lines!(ax, x[1, :], x -> evalpoly(x, (0, -2, 1)); linewidth=3, color=:blue)
    +    s = scatter!(ax, x[1, :], y[1, :]; markersize=12, alpha=0.5,
    +        color=:orange, strokecolor=:black, strokewidth=2)
    +
    +    axislegend(ax, [l, s], ["True Quadratic Function", "Data Points"])
    +
    +    fig
    +end

    Neural Network

    For this problem, you should not be using a neural network. But let's still do that!

    julia
    model = Chain(Dense(1 => 16, relu), Dense(16 => 1))
    Chain(
    +    layer_1 = Dense(1 => 16, relu),     # 32 parameters
    +    layer_2 = Dense(16 => 1),           # 17 parameters
    +)         # Total: 49 parameters,
    +          #        plus 0 states.

    Optimizer

    We will use Adam from Optimisers.jl

    julia
    opt = Adam(0.03f0)
    Adam(0.03, (0.9, 0.999), 1.0e-8)

    Loss Function

    We will use the Training API so we need to ensure that our loss function takes 4 inputs – model, parameters, states and data. The function must return 3 values – loss, updated_state, and any computed statistics. This is already satisfied by the loss functions provided by Lux.

    julia
    const loss_function = MSELoss()
    +
    +const dev_cpu = cpu_device()
    +const dev_gpu = gpu_device()
    +
    +ps, st = Lux.setup(rng, model) |> dev_gpu
    ((layer_1 = (weight = Float32[2.9076505; -1.0578545; 0.7990667; -2.965008; -0.8048109; -0.20579764; -1.260598; 0.28946856; 3.2899156; -2.6431484; 0.51165134; 3.2938747; -3.0690823; -0.44096947; 0.8374606; -2.2932029;;], bias = Float32[0.30569053, -0.94259596, 0.9971247, -0.5167208, 0.6571946, -0.81446123, -0.66852736, 0.9849229, -0.40727592, 0.59543324, -0.17111921, 0.5009556, 0.58263564, -0.09693718, -0.2058456, -0.26793814]), layer_2 = (weight = Float32[-0.095568806 -0.3871873 0.07565363 0.18535946 -0.39300445 0.40623155 0.1490868 0.18481395 0.29315922 0.07375115 -0.23234403 0.015478307 -0.29206026 -0.3291591 0.27471745 0.3050475], bias = Float32[-0.12096125])), (layer_1 = NamedTuple(), layer_2 = NamedTuple()))

    Training

    First we will create a Training.TrainState which is essentially a convenience wrapper over parameters, states and optimizer states.

    julia
    tstate = Training.TrainState(model, ps, st, opt)
    TrainState
    +    model: Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(NNlib.relu), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}((layer_1 = Dense(1 => 16, relu), layer_2 = Dense(16 => 1)), nothing)
    +    # of parameters: 49
    +    # of states: 0
    +    optimizer: Adam(0.03, (0.9, 0.999), 1.0e-8)
    +    step: 0

    Now we will use Zygote for our AD requirements.

    julia
    vjp_rule = AutoZygote()
    ADTypes.AutoZygote()

    Finally the training loop.

    julia
    function main(tstate::Training.TrainState, vjp, data, epochs)
    +    data = data .|> gpu_device()
    +    for epoch in 1:epochs
    +        _, loss, _, tstate = Training.single_train_step!(vjp, loss_function, data, tstate)
    +        if epoch % 50 == 1 || epoch == epochs
    +            @printf "Epoch: %3d \\t Loss: %.5g\\n" epoch loss
    +        end
    +    end
    +    return tstate
    +end
    +
    +tstate = main(tstate, vjp_rule, (x, y), 250)
    +y_pred = dev_cpu(Lux.apply(tstate.model, dev_gpu(x), tstate.parameters, tstate.states)[1])
    Epoch:   1 	 Loss: 11.713
    +Epoch:  51 	 Loss: 0.082086
    +Epoch: 101 	 Loss: 0.062907
    +Epoch: 151 	 Loss: 0.04416
    +Epoch: 201 	 Loss: 0.030016
    +Epoch: 250 	 Loss: 0.022215

    Let's plot the results

    julia
    begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +
    +    l = lines!(ax, x[1, :], x -> evalpoly(x, (0, -2, 1)); linewidth=3)
    +    s1 = scatter!(ax, x[1, :], y[1, :]; markersize=12, alpha=0.5,
    +        color=:orange, strokecolor=:black, strokewidth=2)
    +    s2 = scatter!(ax, x[1, :], y_pred[1, :]; markersize=12, alpha=0.5,
    +        color=:green, strokecolor=:black, strokewidth=2)
    +
    +    axislegend(ax, [l, s1, s2], ["True Quadratic Function", "Actual Data", "Predictions"])
    +
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.609 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,38))])}const R=l(p,[["render",E]]);export{I as __pageData,R as default}; diff --git a/previews/PR1023/assets/tutorials_beginner_2_PolynomialFitting.md.sRzotb_h.lean.js b/previews/PR1023/assets/tutorials_beginner_2_PolynomialFitting.md.sRzotb_h.lean.js new file mode 100644 index 0000000000..b98dd44765 --- /dev/null +++ b/previews/PR1023/assets/tutorials_beginner_2_PolynomialFitting.md.sRzotb_h.lean.js @@ -0,0 +1,124 @@ +import{_ as l,c as a,a2 as s,j as i,a as n,o as t}from"./chunks/framework.DFwXuivk.js";const I=JSON.parse('{"title":"Fitting a Polynomial using MLP","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/beginner/2_PolynomialFitting.md","filePath":"tutorials/beginner/2_PolynomialFitting.md","lastUpdated":null}'),p={name:"tutorials/beginner/2_PolynomialFitting.md"},e={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},h={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.464ex"},xmlns:"http://www.w3.org/2000/svg",width:"11.599ex",height:"2.351ex",role:"img",focusable:"false",viewBox:"0 -833.9 5126.6 1038.9","aria-hidden":"true"};function E(d,A,k,r,v,g){return t(),a("div",null,[A[4]||(A[4]=s(`

    Fitting a Polynomial using MLP

    In this tutorial we will fit a MultiLayer Perceptron (MLP) on data generated from a polynomial.

    Package Imports

    julia
    using Lux, ADTypes, LuxCUDA, Optimisers, Printf, Random, Statistics, Zygote
    +using CairoMakie

    Dataset

    `,5)),i("p",null,[A[2]||(A[2]=n("Generate 128 datapoints from the polynomial ")),i("mjx-container",e,[(t(),a("svg",h,A[0]||(A[0]=[s('',1)]))),A[1]||(A[1]=i("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[i("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[i("mi",null,"y"),i("mo",null,"="),i("msup",null,[i("mi",null,"x"),i("mn",null,"2")]),i("mo",null,"−"),i("mn",null,"2"),i("mi",null,"x")])],-1))]),A[3]||(A[3]=n("."))]),A[5]||(A[5]=s(`
    julia
    function generate_data(rng::AbstractRNG)
    +    x = reshape(collect(range(-2.0f0, 2.0f0, 128)), (1, 128))
    +    y = evalpoly.(x, ((0, -2, 1),)) .+ randn(rng, Float32, (1, 128)) .* 0.1f0
    +    return (x, y)
    +end
    generate_data (generic function with 1 method)

    Initialize the random number generator and fetch the dataset.

    julia
    rng = MersenneTwister()
    +Random.seed!(rng, 12345)
    +
    +(x, y) = generate_data(rng)
    (Float32[-2.0 -1.968504 -1.9370079 -1.9055119 -1.8740157 -1.8425196 -1.8110236 -1.7795275 -1.7480315 -1.7165354 -1.6850394 -1.6535434 -1.6220472 -1.5905511 -1.5590551 -1.527559 -1.496063 -1.464567 -1.4330709 -1.4015749 -1.3700787 -1.3385826 -1.3070866 -1.2755905 -1.2440945 -1.2125984 -1.1811024 -1.1496063 -1.1181102 -1.0866141 -1.0551181 -1.023622 -0.992126 -0.96062994 -0.92913383 -0.8976378 -0.86614174 -0.8346457 -0.8031496 -0.77165353 -0.7401575 -0.70866144 -0.6771653 -0.6456693 -0.61417323 -0.5826772 -0.5511811 -0.51968503 -0.48818898 -0.4566929 -0.42519686 -0.39370078 -0.36220473 -0.33070865 -0.2992126 -0.26771653 -0.23622048 -0.20472442 -0.17322835 -0.14173229 -0.11023622 -0.07874016 -0.047244094 -0.015748031 0.015748031 0.047244094 0.07874016 0.11023622 0.14173229 0.17322835 0.20472442 0.23622048 0.26771653 0.2992126 0.33070865 0.36220473 0.39370078 0.42519686 0.4566929 0.48818898 0.51968503 0.5511811 0.5826772 0.61417323 0.6456693 0.6771653 0.70866144 0.7401575 0.77165353 0.8031496 0.8346457 0.86614174 0.8976378 0.92913383 0.96062994 0.992126 1.023622 1.0551181 1.0866141 1.1181102 1.1496063 1.1811024 1.2125984 1.2440945 1.2755905 1.3070866 1.3385826 1.3700787 1.4015749 1.4330709 1.464567 1.496063 1.527559 1.5590551 1.5905511 1.6220472 1.6535434 1.6850394 1.7165354 1.7480315 1.7795275 1.8110236 1.8425196 1.8740157 1.9055119 1.9370079 1.968504 2.0], Float32[8.117236 7.8972864 7.667572 7.4936414 7.328542 7.108145 6.7541456 6.7384486 6.6983237 6.3637495 6.2701178 6.241937 5.816281 5.7183194 5.741348 5.2581186 5.2681656 5.195746 5.032705 4.73341 4.52024 4.3693867 4.107888 4.1828456 4.0022497 3.8969011 3.9108207 3.64644 3.3343754 3.398038 3.1887817 2.9930804 3.0189805 2.6904922 2.8576512 2.4778283 2.4524014 2.4018757 2.2896426 2.281252 1.9742292 1.7663455 1.8424188 1.6920981 1.6389992 1.7001468 1.4353992 1.3645461 1.2354317 0.9803549 0.9767632 0.9418648 1.0686756 0.6448233 0.6202136 0.57882756 0.44078717 0.48027995 0.35653025 0.39588368 0.21940619 0.17816184 -0.03322105 0.11007148 0.08922641 0.009766437 -0.06433817 -0.14132261 -0.22807482 -0.35395628 -0.6003383 -0.33544478 -0.49804282 -0.4382721 -0.52628386 -0.64495987 -0.46061087 -0.5594571 -0.82293516 -0.76425457 -0.8688824 -0.9489941 -0.90779305 -0.7559453 -0.8499767 -0.9161865 -0.9856883 -0.88951594 -1.0803379 -1.18564 -0.9934639 -0.9253495 -0.9679338 -0.9079035 -1.1395766 -1.1286439 -0.9248211 -1.0428307 -0.95401394 -1.0709 -1.0742047 -1.0277897 -0.8821303 -0.875082 -0.85050875 -0.97378695 -0.8013359 -0.78818554 -0.7897024 -0.7123551 -0.6859683 -0.76158035 -0.82030004 -0.8031547 -0.45583528 -0.61155146 -0.55658394 -0.4371308 -0.48983693 -0.37275374 -0.5424696 -0.2922556 -0.38200346 -0.30673835 -0.08820387 -0.3170582 0.0010350421 -0.13475561])

    Let's visualize the dataset

    julia
    begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +
    +    l = lines!(ax, x[1, :], x -> evalpoly(x, (0, -2, 1)); linewidth=3, color=:blue)
    +    s = scatter!(ax, x[1, :], y[1, :]; markersize=12, alpha=0.5,
    +        color=:orange, strokecolor=:black, strokewidth=2)
    +
    +    axislegend(ax, [l, s], ["True Quadratic Function", "Data Points"])
    +
    +    fig
    +end

    Neural Network

    For this problem, you should not be using a neural network. But let's still do that!

    julia
    model = Chain(Dense(1 => 16, relu), Dense(16 => 1))
    Chain(
    +    layer_1 = Dense(1 => 16, relu),     # 32 parameters
    +    layer_2 = Dense(16 => 1),           # 17 parameters
    +)         # Total: 49 parameters,
    +          #        plus 0 states.

    Optimizer

    We will use Adam from Optimisers.jl

    julia
    opt = Adam(0.03f0)
    Adam(0.03, (0.9, 0.999), 1.0e-8)

    Loss Function

    We will use the Training API so we need to ensure that our loss function takes 4 inputs – model, parameters, states and data. The function must return 3 values – loss, updated_state, and any computed statistics. This is already satisfied by the loss functions provided by Lux.

    julia
    const loss_function = MSELoss()
    +
    +const dev_cpu = cpu_device()
    +const dev_gpu = gpu_device()
    +
    +ps, st = Lux.setup(rng, model) |> dev_gpu
    ((layer_1 = (weight = Float32[2.9076505; -1.0578545; 0.7990667; -2.965008; -0.8048109; -0.20579764; -1.260598; 0.28946856; 3.2899156; -2.6431484; 0.51165134; 3.2938747; -3.0690823; -0.44096947; 0.8374606; -2.2932029;;], bias = Float32[0.30569053, -0.94259596, 0.9971247, -0.5167208, 0.6571946, -0.81446123, -0.66852736, 0.9849229, -0.40727592, 0.59543324, -0.17111921, 0.5009556, 0.58263564, -0.09693718, -0.2058456, -0.26793814]), layer_2 = (weight = Float32[-0.095568806 -0.3871873 0.07565363 0.18535946 -0.39300445 0.40623155 0.1490868 0.18481395 0.29315922 0.07375115 -0.23234403 0.015478307 -0.29206026 -0.3291591 0.27471745 0.3050475], bias = Float32[-0.12096125])), (layer_1 = NamedTuple(), layer_2 = NamedTuple()))

    Training

    First we will create a Training.TrainState which is essentially a convenience wrapper over parameters, states and optimizer states.

    julia
    tstate = Training.TrainState(model, ps, st, opt)
    TrainState
    +    model: Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(NNlib.relu), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}((layer_1 = Dense(1 => 16, relu), layer_2 = Dense(16 => 1)), nothing)
    +    # of parameters: 49
    +    # of states: 0
    +    optimizer: Adam(0.03, (0.9, 0.999), 1.0e-8)
    +    step: 0

    Now we will use Zygote for our AD requirements.

    julia
    vjp_rule = AutoZygote()
    ADTypes.AutoZygote()

    Finally the training loop.

    julia
    function main(tstate::Training.TrainState, vjp, data, epochs)
    +    data = data .|> gpu_device()
    +    for epoch in 1:epochs
    +        _, loss, _, tstate = Training.single_train_step!(vjp, loss_function, data, tstate)
    +        if epoch % 50 == 1 || epoch == epochs
    +            @printf "Epoch: %3d \\t Loss: %.5g\\n" epoch loss
    +        end
    +    end
    +    return tstate
    +end
    +
    +tstate = main(tstate, vjp_rule, (x, y), 250)
    +y_pred = dev_cpu(Lux.apply(tstate.model, dev_gpu(x), tstate.parameters, tstate.states)[1])
    Epoch:   1 	 Loss: 11.713
    +Epoch:  51 	 Loss: 0.082086
    +Epoch: 101 	 Loss: 0.062907
    +Epoch: 151 	 Loss: 0.04416
    +Epoch: 201 	 Loss: 0.030016
    +Epoch: 250 	 Loss: 0.022215

    Let's plot the results

    julia
    begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +
    +    l = lines!(ax, x[1, :], x -> evalpoly(x, (0, -2, 1)); linewidth=3)
    +    s1 = scatter!(ax, x[1, :], y[1, :]; markersize=12, alpha=0.5,
    +        color=:orange, strokecolor=:black, strokewidth=2)
    +    s2 = scatter!(ax, x[1, :], y_pred[1, :]; markersize=12, alpha=0.5,
    +        color=:green, strokecolor=:black, strokewidth=2)
    +
    +    axislegend(ax, [l, s1, s2], ["True Quadratic Function", "Actual Data", "Predictions"])
    +
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.609 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,38))])}const R=l(p,[["render",E]]);export{I as __pageData,R as default}; diff --git a/previews/PR1023/assets/tutorials_beginner_3_SimpleRNN.md.CxWJLH3E.js b/previews/PR1023/assets/tutorials_beginner_3_SimpleRNN.md.CxWJLH3E.js new file mode 100644 index 0000000000..c94d2bb9ba --- /dev/null +++ b/previews/PR1023/assets/tutorials_beginner_3_SimpleRNN.md.CxWJLH3E.js @@ -0,0 +1,611 @@ +import{_ as a,c as n,a2 as i,o as p}from"./chunks/framework.DFwXuivk.js";const r=JSON.parse('{"title":"Training a Simple LSTM","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/beginner/3_SimpleRNN.md","filePath":"tutorials/beginner/3_SimpleRNN.md","lastUpdated":null}'),l={name:"tutorials/beginner/3_SimpleRNN.md"};function e(h,s,t,c,k,o){return p(),n("div",null,s[0]||(s[0]=[i(`

    Training a Simple LSTM

    In this tutorial we will go over using a recurrent neural network to classify clockwise and anticlockwise spirals. By the end of this tutorial you will be able to:

    1. Create custom Lux models.

    2. Become familiar with the Lux recurrent neural network API.

    3. Training using Optimisers.jl and Zygote.jl.

    Package Imports

    julia
    using ADTypes, Lux, LuxCUDA, JLD2, MLUtils, Optimisers, Zygote, Printf, Random, Statistics

    Dataset

    We will use MLUtils to generate 500 (noisy) clockwise and 500 (noisy) anticlockwise spirals. Using this data we will create a MLUtils.DataLoader. Our dataloader will give us sequences of size 2 × seq_len × batch_size and we need to predict a binary value whether the sequence is clockwise or anticlockwise.

    julia
    function get_dataloaders(; dataset_size=1000, sequence_length=50)
    +    # Create the spirals
    +    data = [MLUtils.Datasets.make_spiral(sequence_length) for _ in 1:dataset_size]
    +    # Get the labels
    +    labels = vcat(repeat([0.0f0], dataset_size ÷ 2), repeat([1.0f0], dataset_size ÷ 2))
    +    clockwise_spirals = [reshape(d[1][:, 1:sequence_length], :, sequence_length, 1)
    +                         for d in data[1:(dataset_size ÷ 2)]]
    +    anticlockwise_spirals = [reshape(
    +                                 d[1][:, (sequence_length + 1):end], :, sequence_length, 1)
    +                             for d in data[((dataset_size ÷ 2) + 1):end]]
    +    x_data = Float32.(cat(clockwise_spirals..., anticlockwise_spirals...; dims=3))
    +    # Split the dataset
    +    (x_train, y_train), (x_val, y_val) = splitobs((x_data, labels); at=0.8, shuffle=true)
    +    # Create DataLoaders
    +    return (
    +        # Use DataLoader to automatically minibatch and shuffle the data
    +        DataLoader(collect.((x_train, y_train)); batchsize=128, shuffle=true),
    +        # Don't shuffle the validation data
    +        DataLoader(collect.((x_val, y_val)); batchsize=128, shuffle=false))
    +end
    get_dataloaders (generic function with 1 method)

    Creating a Classifier

    We will be extending the Lux.AbstractLuxContainerLayer type for our custom model since it will contain a lstm block and a classifier head.

    We pass the fieldnames lstm_cell and classifier to the type to ensure that the parameters and states are automatically populated and we don't have to define Lux.initialparameters and Lux.initialstates.

    To understand more about container layers, please look at Container Layer.

    julia
    struct SpiralClassifier{L, C} <: Lux.AbstractLuxContainerLayer{(:lstm_cell, :classifier)}
    +    lstm_cell::L
    +    classifier::C
    +end

    We won't define the model from scratch but rather use the Lux.LSTMCell and Lux.Dense.

    julia
    function SpiralClassifier(in_dims, hidden_dims, out_dims)
    +    return SpiralClassifier(
    +        LSTMCell(in_dims => hidden_dims), Dense(hidden_dims => out_dims, sigmoid))
    +end
    Main.var"##225".SpiralClassifier

    We can use default Lux blocks – Recurrence(LSTMCell(in_dims => hidden_dims) – instead of defining the following. But let's still do it for the sake of it.

    Now we need to define the behavior of the Classifier when it is invoked.

    julia
    function (s::SpiralClassifier)(
    +        x::AbstractArray{T, 3}, ps::NamedTuple, st::NamedTuple) where {T}
    +    # First we will have to run the sequence through the LSTM Cell
    +    # The first call to LSTM Cell will create the initial hidden state
    +    # See that the parameters and states are automatically populated into a field called
    +    # \`lstm_cell\` We use \`eachslice\` to get the elements in the sequence without copying,
    +    # and \`Iterators.peel\` to split out the first element for LSTM initialization.
    +    x_init, x_rest = Iterators.peel(LuxOps.eachslice(x, Val(2)))
    +    (y, carry), st_lstm = s.lstm_cell(x_init, ps.lstm_cell, st.lstm_cell)
    +    # Now that we have the hidden state and memory in \`carry\` we will pass the input and
    +    # \`carry\` jointly
    +    for x in x_rest
    +        (y, carry), st_lstm = s.lstm_cell((x, carry), ps.lstm_cell, st_lstm)
    +    end
    +    # After running through the sequence we will pass the output through the classifier
    +    y, st_classifier = s.classifier(y, ps.classifier, st.classifier)
    +    # Finally remember to create the updated state
    +    st = merge(st, (classifier=st_classifier, lstm_cell=st_lstm))
    +    return vec(y), st
    +end

    Using the @compact API

    We can also define the model using the Lux.@compact API, which is a more concise way of defining models. This macro automatically handles the boilerplate code for you and as such we recommend this way of defining custom layers

    julia
    function SpiralClassifierCompact(in_dims, hidden_dims, out_dims)
    +    lstm_cell = LSTMCell(in_dims => hidden_dims)
    +    classifier = Dense(hidden_dims => out_dims, sigmoid)
    +    return @compact(; lstm_cell, classifier) do x::AbstractArray{T, 3} where {T}
    +        x_init, x_rest = Iterators.peel(LuxOps.eachslice(x, Val(2)))
    +        y, carry = lstm_cell(x_init)
    +        for x in x_rest
    +            y, carry = lstm_cell((x, carry))
    +        end
    +        @return vec(classifier(y))
    +    end
    +end
    SpiralClassifierCompact (generic function with 1 method)

    Defining Accuracy, Loss and Optimiser

    Now let's define the binarycrossentropy loss. Typically it is recommended to use logitbinarycrossentropy since it is more numerically stable, but for the sake of simplicity we will use binarycrossentropy.

    julia
    const lossfn = BinaryCrossEntropyLoss()
    +
    +function compute_loss(model, ps, st, (x, y))
    +    ŷ, st_ = model(x, ps, st)
    +    loss = lossfn(ŷ, y)
    +    return loss, st_, (; y_pred=ŷ)
    +end
    +
    +matches(y_pred, y_true) = sum((y_pred .> 0.5f0) .== y_true)
    +accuracy(y_pred, y_true) = matches(y_pred, y_true) / length(y_pred)
    accuracy (generic function with 1 method)

    Training the Model

    julia
    function main(model_type)
    +    dev = gpu_device()
    +
    +    # Get the dataloaders
    +    train_loader, val_loader = get_dataloaders() .|> dev
    +
    +    # Create the model
    +    model = model_type(2, 8, 1)
    +    rng = Xoshiro(0)
    +    ps, st = Lux.setup(rng, model) |> dev
    +
    +    train_state = Training.TrainState(model, ps, st, Adam(0.01f0))
    +
    +    for epoch in 1:25
    +        # Train the model
    +        for (x, y) in train_loader
    +            (_, loss, _, train_state) = Training.single_train_step!(
    +                AutoZygote(), lossfn, (x, y), train_state)
    +
    +            @printf "Epoch [%3d]: Loss %4.5f\\n" epoch loss
    +        end
    +
    +        # Validate the model
    +        st_ = Lux.testmode(train_state.states)
    +        for (x, y) in val_loader
    +            ŷ, st_ = model(x, train_state.parameters, st_)
    +            loss = lossfn(ŷ, y)
    +            acc = accuracy(ŷ, y)
    +            @printf "Validation: Loss %4.5f Accuracy %4.5f\\n" loss acc
    +        end
    +    end
    +
    +    return (train_state.parameters, train_state.states) |> cpu_device()
    +end
    +
    +ps_trained, st_trained = main(SpiralClassifier)
    Epoch [  1]: Loss 0.60926
    +Epoch [  1]: Loss 0.60205
    +Epoch [  1]: Loss 0.56447
    +Epoch [  1]: Loss 0.53935
    +Epoch [  1]: Loss 0.51961
    +Epoch [  1]: Loss 0.50630
    +Epoch [  1]: Loss 0.48399
    +Validation: Loss 0.46956 Accuracy 1.00000
    +Validation: Loss 0.47794 Accuracy 1.00000
    +Epoch [  2]: Loss 0.47301
    +Epoch [  2]: Loss 0.45405
    +Epoch [  2]: Loss 0.43968
    +Epoch [  2]: Loss 0.43054
    +Epoch [  2]: Loss 0.40202
    +Epoch [  2]: Loss 0.39666
    +Epoch [  2]: Loss 0.40138
    +Validation: Loss 0.37273 Accuracy 1.00000
    +Validation: Loss 0.38210 Accuracy 1.00000
    +Epoch [  3]: Loss 0.36731
    +Epoch [  3]: Loss 0.36875
    +Epoch [  3]: Loss 0.34892
    +Epoch [  3]: Loss 0.33812
    +Epoch [  3]: Loss 0.31629
    +Epoch [  3]: Loss 0.30792
    +Epoch [  3]: Loss 0.27809
    +Validation: Loss 0.28817 Accuracy 1.00000
    +Validation: Loss 0.29822 Accuracy 1.00000
    +Epoch [  4]: Loss 0.28662
    +Epoch [  4]: Loss 0.27989
    +Epoch [  4]: Loss 0.27278
    +Epoch [  4]: Loss 0.25235
    +Epoch [  4]: Loss 0.23497
    +Epoch [  4]: Loss 0.23847
    +Epoch [  4]: Loss 0.23192
    +Validation: Loss 0.21844 Accuracy 1.00000
    +Validation: Loss 0.22858 Accuracy 1.00000
    +Epoch [  5]: Loss 0.21529
    +Epoch [  5]: Loss 0.21660
    +Epoch [  5]: Loss 0.21147
    +Epoch [  5]: Loss 0.18347
    +Epoch [  5]: Loss 0.18387
    +Epoch [  5]: Loss 0.16418
    +Epoch [  5]: Loss 0.18488
    +Validation: Loss 0.16251 Accuracy 1.00000
    +Validation: Loss 0.17173 Accuracy 1.00000
    +Epoch [  6]: Loss 0.15106
    +Epoch [  6]: Loss 0.15557
    +Epoch [  6]: Loss 0.15604
    +Epoch [  6]: Loss 0.12610
    +Epoch [  6]: Loss 0.14466
    +Epoch [  6]: Loss 0.13525
    +Epoch [  6]: Loss 0.13401
    +Validation: Loss 0.11923 Accuracy 1.00000
    +Validation: Loss 0.12679 Accuracy 1.00000
    +Epoch [  7]: Loss 0.11300
    +Epoch [  7]: Loss 0.11270
    +Epoch [  7]: Loss 0.11182
    +Epoch [  7]: Loss 0.10579
    +Epoch [  7]: Loss 0.10077
    +Epoch [  7]: Loss 0.09092
    +Epoch [  7]: Loss 0.08957
    +Validation: Loss 0.08530 Accuracy 1.00000
    +Validation: Loss 0.09085 Accuracy 1.00000
    +Epoch [  8]: Loss 0.08321
    +Epoch [  8]: Loss 0.07613
    +Epoch [  8]: Loss 0.07561
    +Epoch [  8]: Loss 0.07250
    +Epoch [  8]: Loss 0.06895
    +Epoch [  8]: Loss 0.07155
    +Epoch [  8]: Loss 0.06246
    +Validation: Loss 0.05935 Accuracy 1.00000
    +Validation: Loss 0.06304 Accuracy 1.00000
    +Epoch [  9]: Loss 0.06135
    +Epoch [  9]: Loss 0.05983
    +Epoch [  9]: Loss 0.05429
    +Epoch [  9]: Loss 0.04415
    +Epoch [  9]: Loss 0.04965
    +Epoch [  9]: Loss 0.04801
    +Epoch [  9]: Loss 0.04264
    +Validation: Loss 0.04389 Accuracy 1.00000
    +Validation: Loss 0.04647 Accuracy 1.00000
    +Epoch [ 10]: Loss 0.04243
    +Epoch [ 10]: Loss 0.04109
    +Epoch [ 10]: Loss 0.04136
    +Epoch [ 10]: Loss 0.04201
    +Epoch [ 10]: Loss 0.03979
    +Epoch [ 10]: Loss 0.03471
    +Epoch [ 10]: Loss 0.03760
    +Validation: Loss 0.03546 Accuracy 1.00000
    +Validation: Loss 0.03756 Accuracy 1.00000
    +Epoch [ 11]: Loss 0.03545
    +Epoch [ 11]: Loss 0.03571
    +Epoch [ 11]: Loss 0.03202
    +Epoch [ 11]: Loss 0.03209
    +Epoch [ 11]: Loss 0.03134
    +Epoch [ 11]: Loss 0.03114
    +Epoch [ 11]: Loss 0.03593
    +Validation: Loss 0.03006 Accuracy 1.00000
    +Validation: Loss 0.03189 Accuracy 1.00000
    +Epoch [ 12]: Loss 0.03210
    +Epoch [ 12]: Loss 0.02768
    +Epoch [ 12]: Loss 0.02955
    +Epoch [ 12]: Loss 0.02631
    +Epoch [ 12]: Loss 0.02720
    +Epoch [ 12]: Loss 0.02667
    +Epoch [ 12]: Loss 0.03031
    +Validation: Loss 0.02612 Accuracy 1.00000
    +Validation: Loss 0.02773 Accuracy 1.00000
    +Epoch [ 13]: Loss 0.02589
    +Epoch [ 13]: Loss 0.02454
    +Epoch [ 13]: Loss 0.02716
    +Epoch [ 13]: Loss 0.02579
    +Epoch [ 13]: Loss 0.02323
    +Epoch [ 13]: Loss 0.02301
    +Epoch [ 13]: Loss 0.02099
    +Validation: Loss 0.02307 Accuracy 1.00000
    +Validation: Loss 0.02452 Accuracy 1.00000
    +Epoch [ 14]: Loss 0.02105
    +Epoch [ 14]: Loss 0.02170
    +Epoch [ 14]: Loss 0.02234
    +Epoch [ 14]: Loss 0.02238
    +Epoch [ 14]: Loss 0.02259
    +Epoch [ 14]: Loss 0.02282
    +Epoch [ 14]: Loss 0.01795
    +Validation: Loss 0.02066 Accuracy 1.00000
    +Validation: Loss 0.02199 Accuracy 1.00000
    +Epoch [ 15]: Loss 0.02140
    +Epoch [ 15]: Loss 0.02017
    +Epoch [ 15]: Loss 0.01932
    +Epoch [ 15]: Loss 0.02011
    +Epoch [ 15]: Loss 0.01752
    +Epoch [ 15]: Loss 0.02006
    +Epoch [ 15]: Loss 0.01963
    +Validation: Loss 0.01866 Accuracy 1.00000
    +Validation: Loss 0.01988 Accuracy 1.00000
    +Epoch [ 16]: Loss 0.01796
    +Epoch [ 16]: Loss 0.01636
    +Epoch [ 16]: Loss 0.01900
    +Epoch [ 16]: Loss 0.01740
    +Epoch [ 16]: Loss 0.01782
    +Epoch [ 16]: Loss 0.01824
    +Epoch [ 16]: Loss 0.01976
    +Validation: Loss 0.01696 Accuracy 1.00000
    +Validation: Loss 0.01810 Accuracy 1.00000
    +Epoch [ 17]: Loss 0.01745
    +Epoch [ 17]: Loss 0.01579
    +Epoch [ 17]: Loss 0.01777
    +Epoch [ 17]: Loss 0.01630
    +Epoch [ 17]: Loss 0.01578
    +Epoch [ 17]: Loss 0.01468
    +Epoch [ 17]: Loss 0.01627
    +Validation: Loss 0.01549 Accuracy 1.00000
    +Validation: Loss 0.01656 Accuracy 1.00000
    +Epoch [ 18]: Loss 0.01608
    +Epoch [ 18]: Loss 0.01398
    +Epoch [ 18]: Loss 0.01425
    +Epoch [ 18]: Loss 0.01537
    +Epoch [ 18]: Loss 0.01504
    +Epoch [ 18]: Loss 0.01471
    +Epoch [ 18]: Loss 0.01496
    +Validation: Loss 0.01423 Accuracy 1.00000
    +Validation: Loss 0.01523 Accuracy 1.00000
    +Epoch [ 19]: Loss 0.01355
    +Epoch [ 19]: Loss 0.01489
    +Epoch [ 19]: Loss 0.01364
    +Epoch [ 19]: Loss 0.01253
    +Epoch [ 19]: Loss 0.01360
    +Epoch [ 19]: Loss 0.01343
    +Epoch [ 19]: Loss 0.01639
    +Validation: Loss 0.01313 Accuracy 1.00000
    +Validation: Loss 0.01405 Accuracy 1.00000
    +Epoch [ 20]: Loss 0.01377
    +Epoch [ 20]: Loss 0.01183
    +Epoch [ 20]: Loss 0.01194
    +Epoch [ 20]: Loss 0.01194
    +Epoch [ 20]: Loss 0.01292
    +Epoch [ 20]: Loss 0.01361
    +Epoch [ 20]: Loss 0.01227
    +Validation: Loss 0.01211 Accuracy 1.00000
    +Validation: Loss 0.01297 Accuracy 1.00000
    +Epoch [ 21]: Loss 0.01212
    +Epoch [ 21]: Loss 0.01138
    +Epoch [ 21]: Loss 0.01102
    +Epoch [ 21]: Loss 0.01238
    +Epoch [ 21]: Loss 0.01200
    +Epoch [ 21]: Loss 0.01130
    +Epoch [ 21]: Loss 0.01082
    +Validation: Loss 0.01112 Accuracy 1.00000
    +Validation: Loss 0.01190 Accuracy 1.00000
    +Epoch [ 22]: Loss 0.01134
    +Epoch [ 22]: Loss 0.01031
    +Epoch [ 22]: Loss 0.01060
    +Epoch [ 22]: Loss 0.01130
    +Epoch [ 22]: Loss 0.01009
    +Epoch [ 22]: Loss 0.01053
    +Epoch [ 22]: Loss 0.00940
    +Validation: Loss 0.01002 Accuracy 1.00000
    +Validation: Loss 0.01071 Accuracy 1.00000
    +Epoch [ 23]: Loss 0.00886
    +Epoch [ 23]: Loss 0.01026
    +Epoch [ 23]: Loss 0.01005
    +Epoch [ 23]: Loss 0.00853
    +Epoch [ 23]: Loss 0.01033
    +Epoch [ 23]: Loss 0.00902
    +Epoch [ 23]: Loss 0.00969
    +Validation: Loss 0.00888 Accuracy 1.00000
    +Validation: Loss 0.00947 Accuracy 1.00000
    +Epoch [ 24]: Loss 0.00903
    +Epoch [ 24]: Loss 0.00856
    +Epoch [ 24]: Loss 0.00866
    +Epoch [ 24]: Loss 0.00883
    +Epoch [ 24]: Loss 0.00830
    +Epoch [ 24]: Loss 0.00781
    +Epoch [ 24]: Loss 0.00662
    +Validation: Loss 0.00795 Accuracy 1.00000
    +Validation: Loss 0.00846 Accuracy 1.00000
    +Epoch [ 25]: Loss 0.00830
    +Epoch [ 25]: Loss 0.00742
    +Epoch [ 25]: Loss 0.00822
    +Epoch [ 25]: Loss 0.00791
    +Epoch [ 25]: Loss 0.00721
    +Epoch [ 25]: Loss 0.00726
    +Epoch [ 25]: Loss 0.00582
    +Validation: Loss 0.00730 Accuracy 1.00000
    +Validation: Loss 0.00775 Accuracy 1.00000

    We can also train the compact model with the exact same code!

    julia
    ps_trained2, st_trained2 = main(SpiralClassifierCompact)
    Epoch [  1]: Loss 0.62249
    +Epoch [  1]: Loss 0.58988
    +Epoch [  1]: Loss 0.57122
    +Epoch [  1]: Loss 0.54145
    +Epoch [  1]: Loss 0.51676
    +Epoch [  1]: Loss 0.49941
    +Epoch [  1]: Loss 0.48712
    +Validation: Loss 0.46707 Accuracy 1.00000
    +Validation: Loss 0.46650 Accuracy 1.00000
    +Epoch [  2]: Loss 0.46435
    +Epoch [  2]: Loss 0.45555
    +Epoch [  2]: Loss 0.45454
    +Epoch [  2]: Loss 0.42345
    +Epoch [  2]: Loss 0.41436
    +Epoch [  2]: Loss 0.38527
    +Epoch [  2]: Loss 0.37442
    +Validation: Loss 0.36940 Accuracy 1.00000
    +Validation: Loss 0.36858 Accuracy 1.00000
    +Epoch [  3]: Loss 0.36752
    +Epoch [  3]: Loss 0.36360
    +Epoch [  3]: Loss 0.34430
    +Epoch [  3]: Loss 0.32734
    +Epoch [  3]: Loss 0.31783
    +Epoch [  3]: Loss 0.31825
    +Epoch [  3]: Loss 0.28565
    +Validation: Loss 0.28440 Accuracy 1.00000
    +Validation: Loss 0.28337 Accuracy 1.00000
    +Epoch [  4]: Loss 0.28307
    +Epoch [  4]: Loss 0.27199
    +Epoch [  4]: Loss 0.26836
    +Epoch [  4]: Loss 0.26051
    +Epoch [  4]: Loss 0.24528
    +Epoch [  4]: Loss 0.23063
    +Epoch [  4]: Loss 0.22536
    +Validation: Loss 0.21475 Accuracy 1.00000
    +Validation: Loss 0.21368 Accuracy 1.00000
    +Epoch [  5]: Loss 0.21305
    +Epoch [  5]: Loss 0.21531
    +Epoch [  5]: Loss 0.19616
    +Epoch [  5]: Loss 0.18414
    +Epoch [  5]: Loss 0.18294
    +Epoch [  5]: Loss 0.17875
    +Epoch [  5]: Loss 0.17815
    +Validation: Loss 0.15941 Accuracy 1.00000
    +Validation: Loss 0.15850 Accuracy 1.00000
    +Epoch [  6]: Loss 0.16464
    +Epoch [  6]: Loss 0.14669
    +Epoch [  6]: Loss 0.14234
    +Epoch [  6]: Loss 0.14785
    +Epoch [  6]: Loss 0.13936
    +Epoch [  6]: Loss 0.13121
    +Epoch [  6]: Loss 0.11054
    +Validation: Loss 0.11688 Accuracy 1.00000
    +Validation: Loss 0.11621 Accuracy 1.00000
    +Epoch [  7]: Loss 0.11895
    +Epoch [  7]: Loss 0.11755
    +Epoch [  7]: Loss 0.11153
    +Epoch [  7]: Loss 0.10806
    +Epoch [  7]: Loss 0.08931
    +Epoch [  7]: Loss 0.08989
    +Epoch [  7]: Loss 0.08885
    +Validation: Loss 0.08377 Accuracy 1.00000
    +Validation: Loss 0.08332 Accuracy 1.00000
    +Epoch [  8]: Loss 0.08392
    +Epoch [  8]: Loss 0.07975
    +Epoch [  8]: Loss 0.07711
    +Epoch [  8]: Loss 0.07462
    +Epoch [  8]: Loss 0.06929
    +Epoch [  8]: Loss 0.06475
    +Epoch [  8]: Loss 0.06222
    +Validation: Loss 0.05835 Accuracy 1.00000
    +Validation: Loss 0.05808 Accuracy 1.00000
    +Epoch [  9]: Loss 0.05835
    +Epoch [  9]: Loss 0.05645
    +Epoch [  9]: Loss 0.05303
    +Epoch [  9]: Loss 0.04974
    +Epoch [  9]: Loss 0.04989
    +Epoch [  9]: Loss 0.04836
    +Epoch [  9]: Loss 0.04374
    +Validation: Loss 0.04304 Accuracy 1.00000
    +Validation: Loss 0.04283 Accuracy 1.00000
    +Epoch [ 10]: Loss 0.04373
    +Epoch [ 10]: Loss 0.03963
    +Epoch [ 10]: Loss 0.04024
    +Epoch [ 10]: Loss 0.03893
    +Epoch [ 10]: Loss 0.04085
    +Epoch [ 10]: Loss 0.03933
    +Epoch [ 10]: Loss 0.02782
    +Validation: Loss 0.03470 Accuracy 1.00000
    +Validation: Loss 0.03451 Accuracy 1.00000
    +Epoch [ 11]: Loss 0.03413
    +Epoch [ 11]: Loss 0.03603
    +Epoch [ 11]: Loss 0.03246
    +Epoch [ 11]: Loss 0.03142
    +Epoch [ 11]: Loss 0.03040
    +Epoch [ 11]: Loss 0.03279
    +Epoch [ 11]: Loss 0.03336
    +Validation: Loss 0.02942 Accuracy 1.00000
    +Validation: Loss 0.02924 Accuracy 1.00000
    +Epoch [ 12]: Loss 0.03113
    +Epoch [ 12]: Loss 0.02712
    +Epoch [ 12]: Loss 0.02845
    +Epoch [ 12]: Loss 0.02904
    +Epoch [ 12]: Loss 0.02709
    +Epoch [ 12]: Loss 0.02722
    +Epoch [ 12]: Loss 0.02449
    +Validation: Loss 0.02555 Accuracy 1.00000
    +Validation: Loss 0.02540 Accuracy 1.00000
    +Epoch [ 13]: Loss 0.02730
    +Epoch [ 13]: Loss 0.02638
    +Epoch [ 13]: Loss 0.02358
    +Epoch [ 13]: Loss 0.02337
    +Epoch [ 13]: Loss 0.02417
    +Epoch [ 13]: Loss 0.02397
    +Epoch [ 13]: Loss 0.02159
    +Validation: Loss 0.02258 Accuracy 1.00000
    +Validation: Loss 0.02243 Accuracy 1.00000
    +Epoch [ 14]: Loss 0.02377
    +Epoch [ 14]: Loss 0.02260
    +Epoch [ 14]: Loss 0.02070
    +Epoch [ 14]: Loss 0.02170
    +Epoch [ 14]: Loss 0.02060
    +Epoch [ 14]: Loss 0.02212
    +Epoch [ 14]: Loss 0.02141
    +Validation: Loss 0.02019 Accuracy 1.00000
    +Validation: Loss 0.02006 Accuracy 1.00000
    +Epoch [ 15]: Loss 0.02146
    +Epoch [ 15]: Loss 0.01937
    +Epoch [ 15]: Loss 0.02047
    +Epoch [ 15]: Loss 0.01826
    +Epoch [ 15]: Loss 0.01953
    +Epoch [ 15]: Loss 0.01824
    +Epoch [ 15]: Loss 0.02201
    +Validation: Loss 0.01821 Accuracy 1.00000
    +Validation: Loss 0.01809 Accuracy 1.00000
    +Epoch [ 16]: Loss 0.01872
    +Epoch [ 16]: Loss 0.01647
    +Epoch [ 16]: Loss 0.01868
    +Epoch [ 16]: Loss 0.01763
    +Epoch [ 16]: Loss 0.01802
    +Epoch [ 16]: Loss 0.01730
    +Epoch [ 16]: Loss 0.01691
    +Validation: Loss 0.01653 Accuracy 1.00000
    +Validation: Loss 0.01642 Accuracy 1.00000
    +Epoch [ 17]: Loss 0.01638
    +Epoch [ 17]: Loss 0.01693
    +Epoch [ 17]: Loss 0.01747
    +Epoch [ 17]: Loss 0.01530
    +Epoch [ 17]: Loss 0.01570
    +Epoch [ 17]: Loss 0.01579
    +Epoch [ 17]: Loss 0.01431
    +Validation: Loss 0.01511 Accuracy 1.00000
    +Validation: Loss 0.01501 Accuracy 1.00000
    +Epoch [ 18]: Loss 0.01395
    +Epoch [ 18]: Loss 0.01493
    +Epoch [ 18]: Loss 0.01631
    +Epoch [ 18]: Loss 0.01388
    +Epoch [ 18]: Loss 0.01496
    +Epoch [ 18]: Loss 0.01520
    +Epoch [ 18]: Loss 0.01366
    +Validation: Loss 0.01390 Accuracy 1.00000
    +Validation: Loss 0.01381 Accuracy 1.00000
    +Epoch [ 19]: Loss 0.01337
    +Epoch [ 19]: Loss 0.01481
    +Epoch [ 19]: Loss 0.01359
    +Epoch [ 19]: Loss 0.01293
    +Epoch [ 19]: Loss 0.01317
    +Epoch [ 19]: Loss 0.01404
    +Epoch [ 19]: Loss 0.01416
    +Validation: Loss 0.01286 Accuracy 1.00000
    +Validation: Loss 0.01277 Accuracy 1.00000
    +Epoch [ 20]: Loss 0.01286
    +Epoch [ 20]: Loss 0.01335
    +Epoch [ 20]: Loss 0.01259
    +Epoch [ 20]: Loss 0.01343
    +Epoch [ 20]: Loss 0.01294
    +Epoch [ 20]: Loss 0.01124
    +Epoch [ 20]: Loss 0.01124
    +Validation: Loss 0.01194 Accuracy 1.00000
    +Validation: Loss 0.01186 Accuracy 1.00000
    +Epoch [ 21]: Loss 0.01159
    +Epoch [ 21]: Loss 0.01229
    +Epoch [ 21]: Loss 0.01273
    +Epoch [ 21]: Loss 0.01021
    +Epoch [ 21]: Loss 0.01159
    +Epoch [ 21]: Loss 0.01191
    +Epoch [ 21]: Loss 0.01311
    +Validation: Loss 0.01111 Accuracy 1.00000
    +Validation: Loss 0.01104 Accuracy 1.00000
    +Epoch [ 22]: Loss 0.01112
    +Epoch [ 22]: Loss 0.01155
    +Epoch [ 22]: Loss 0.01068
    +Epoch [ 22]: Loss 0.01120
    +Epoch [ 22]: Loss 0.00993
    +Epoch [ 22]: Loss 0.01129
    +Epoch [ 22]: Loss 0.01098
    +Validation: Loss 0.01033 Accuracy 1.00000
    +Validation: Loss 0.01026 Accuracy 1.00000
    +Epoch [ 23]: Loss 0.00950
    +Epoch [ 23]: Loss 0.01102
    +Epoch [ 23]: Loss 0.01060
    +Epoch [ 23]: Loss 0.01058
    +Epoch [ 23]: Loss 0.00987
    +Epoch [ 23]: Loss 0.01006
    +Epoch [ 23]: Loss 0.00747
    +Validation: Loss 0.00952 Accuracy 1.00000
    +Validation: Loss 0.00945 Accuracy 1.00000
    +Epoch [ 24]: Loss 0.00960
    +Epoch [ 24]: Loss 0.00995
    +Epoch [ 24]: Loss 0.00883
    +Epoch [ 24]: Loss 0.00888
    +Epoch [ 24]: Loss 0.00955
    +Epoch [ 24]: Loss 0.00915
    +Epoch [ 24]: Loss 0.00884
    +Validation: Loss 0.00861 Accuracy 1.00000
    +Validation: Loss 0.00856 Accuracy 1.00000
    +Epoch [ 25]: Loss 0.00958
    +Epoch [ 25]: Loss 0.00920
    +Epoch [ 25]: Loss 0.00803
    +Epoch [ 25]: Loss 0.00769
    +Epoch [ 25]: Loss 0.00804
    +Epoch [ 25]: Loss 0.00784
    +Epoch [ 25]: Loss 0.00760
    +Validation: Loss 0.00766 Accuracy 1.00000
    +Validation: Loss 0.00762 Accuracy 1.00000

    Saving the Model

    We can save the model using JLD2 (and any other serialization library of your choice) Note that we transfer the model to CPU before saving. Additionally, we recommend that you don't save the model struct and only save the parameters and states.

    julia
    @save "trained_model.jld2" ps_trained st_trained

    Let's try loading the model

    julia
    @load "trained_model.jld2" ps_trained st_trained
    2-element Vector{Symbol}:
    + :ps_trained
    + :st_trained

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +2 devices:
    +  0: Quadro RTX 5000 (sm_75, 15.227 GiB / 16.000 GiB available)
    +  1: Quadro RTX 5000 (sm_75, 15.549 GiB / 16.000 GiB available)

    This page was generated using Literate.jl.

    `,45)]))}const d=a(l,[["render",e]]);export{r as __pageData,d as default}; diff --git a/previews/PR1023/assets/tutorials_beginner_3_SimpleRNN.md.CxWJLH3E.lean.js b/previews/PR1023/assets/tutorials_beginner_3_SimpleRNN.md.CxWJLH3E.lean.js new file mode 100644 index 0000000000..c94d2bb9ba --- /dev/null +++ b/previews/PR1023/assets/tutorials_beginner_3_SimpleRNN.md.CxWJLH3E.lean.js @@ -0,0 +1,611 @@ +import{_ as a,c as n,a2 as i,o as p}from"./chunks/framework.DFwXuivk.js";const r=JSON.parse('{"title":"Training a Simple LSTM","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/beginner/3_SimpleRNN.md","filePath":"tutorials/beginner/3_SimpleRNN.md","lastUpdated":null}'),l={name:"tutorials/beginner/3_SimpleRNN.md"};function e(h,s,t,c,k,o){return p(),n("div",null,s[0]||(s[0]=[i(`

    Training a Simple LSTM

    In this tutorial we will go over using a recurrent neural network to classify clockwise and anticlockwise spirals. By the end of this tutorial you will be able to:

    1. Create custom Lux models.

    2. Become familiar with the Lux recurrent neural network API.

    3. Training using Optimisers.jl and Zygote.jl.

    Package Imports

    julia
    using ADTypes, Lux, LuxCUDA, JLD2, MLUtils, Optimisers, Zygote, Printf, Random, Statistics

    Dataset

    We will use MLUtils to generate 500 (noisy) clockwise and 500 (noisy) anticlockwise spirals. Using this data we will create a MLUtils.DataLoader. Our dataloader will give us sequences of size 2 × seq_len × batch_size and we need to predict a binary value whether the sequence is clockwise or anticlockwise.

    julia
    function get_dataloaders(; dataset_size=1000, sequence_length=50)
    +    # Create the spirals
    +    data = [MLUtils.Datasets.make_spiral(sequence_length) for _ in 1:dataset_size]
    +    # Get the labels
    +    labels = vcat(repeat([0.0f0], dataset_size ÷ 2), repeat([1.0f0], dataset_size ÷ 2))
    +    clockwise_spirals = [reshape(d[1][:, 1:sequence_length], :, sequence_length, 1)
    +                         for d in data[1:(dataset_size ÷ 2)]]
    +    anticlockwise_spirals = [reshape(
    +                                 d[1][:, (sequence_length + 1):end], :, sequence_length, 1)
    +                             for d in data[((dataset_size ÷ 2) + 1):end]]
    +    x_data = Float32.(cat(clockwise_spirals..., anticlockwise_spirals...; dims=3))
    +    # Split the dataset
    +    (x_train, y_train), (x_val, y_val) = splitobs((x_data, labels); at=0.8, shuffle=true)
    +    # Create DataLoaders
    +    return (
    +        # Use DataLoader to automatically minibatch and shuffle the data
    +        DataLoader(collect.((x_train, y_train)); batchsize=128, shuffle=true),
    +        # Don't shuffle the validation data
    +        DataLoader(collect.((x_val, y_val)); batchsize=128, shuffle=false))
    +end
    get_dataloaders (generic function with 1 method)

    Creating a Classifier

    We will be extending the Lux.AbstractLuxContainerLayer type for our custom model since it will contain a lstm block and a classifier head.

    We pass the fieldnames lstm_cell and classifier to the type to ensure that the parameters and states are automatically populated and we don't have to define Lux.initialparameters and Lux.initialstates.

    To understand more about container layers, please look at Container Layer.

    julia
    struct SpiralClassifier{L, C} <: Lux.AbstractLuxContainerLayer{(:lstm_cell, :classifier)}
    +    lstm_cell::L
    +    classifier::C
    +end

    We won't define the model from scratch but rather use the Lux.LSTMCell and Lux.Dense.

    julia
    function SpiralClassifier(in_dims, hidden_dims, out_dims)
    +    return SpiralClassifier(
    +        LSTMCell(in_dims => hidden_dims), Dense(hidden_dims => out_dims, sigmoid))
    +end
    Main.var"##225".SpiralClassifier

    We can use default Lux blocks – Recurrence(LSTMCell(in_dims => hidden_dims) – instead of defining the following. But let's still do it for the sake of it.

    Now we need to define the behavior of the Classifier when it is invoked.

    julia
    function (s::SpiralClassifier)(
    +        x::AbstractArray{T, 3}, ps::NamedTuple, st::NamedTuple) where {T}
    +    # First we will have to run the sequence through the LSTM Cell
    +    # The first call to LSTM Cell will create the initial hidden state
    +    # See that the parameters and states are automatically populated into a field called
    +    # \`lstm_cell\` We use \`eachslice\` to get the elements in the sequence without copying,
    +    # and \`Iterators.peel\` to split out the first element for LSTM initialization.
    +    x_init, x_rest = Iterators.peel(LuxOps.eachslice(x, Val(2)))
    +    (y, carry), st_lstm = s.lstm_cell(x_init, ps.lstm_cell, st.lstm_cell)
    +    # Now that we have the hidden state and memory in \`carry\` we will pass the input and
    +    # \`carry\` jointly
    +    for x in x_rest
    +        (y, carry), st_lstm = s.lstm_cell((x, carry), ps.lstm_cell, st_lstm)
    +    end
    +    # After running through the sequence we will pass the output through the classifier
    +    y, st_classifier = s.classifier(y, ps.classifier, st.classifier)
    +    # Finally remember to create the updated state
    +    st = merge(st, (classifier=st_classifier, lstm_cell=st_lstm))
    +    return vec(y), st
    +end

    Using the @compact API

    We can also define the model using the Lux.@compact API, which is a more concise way of defining models. This macro automatically handles the boilerplate code for you and as such we recommend this way of defining custom layers

    julia
    function SpiralClassifierCompact(in_dims, hidden_dims, out_dims)
    +    lstm_cell = LSTMCell(in_dims => hidden_dims)
    +    classifier = Dense(hidden_dims => out_dims, sigmoid)
    +    return @compact(; lstm_cell, classifier) do x::AbstractArray{T, 3} where {T}
    +        x_init, x_rest = Iterators.peel(LuxOps.eachslice(x, Val(2)))
    +        y, carry = lstm_cell(x_init)
    +        for x in x_rest
    +            y, carry = lstm_cell((x, carry))
    +        end
    +        @return vec(classifier(y))
    +    end
    +end
    SpiralClassifierCompact (generic function with 1 method)

    Defining Accuracy, Loss and Optimiser

    Now let's define the binarycrossentropy loss. Typically it is recommended to use logitbinarycrossentropy since it is more numerically stable, but for the sake of simplicity we will use binarycrossentropy.

    julia
    const lossfn = BinaryCrossEntropyLoss()
    +
    +function compute_loss(model, ps, st, (x, y))
    +    ŷ, st_ = model(x, ps, st)
    +    loss = lossfn(ŷ, y)
    +    return loss, st_, (; y_pred=ŷ)
    +end
    +
    +matches(y_pred, y_true) = sum((y_pred .> 0.5f0) .== y_true)
    +accuracy(y_pred, y_true) = matches(y_pred, y_true) / length(y_pred)
    accuracy (generic function with 1 method)

    Training the Model

    julia
    function main(model_type)
    +    dev = gpu_device()
    +
    +    # Get the dataloaders
    +    train_loader, val_loader = get_dataloaders() .|> dev
    +
    +    # Create the model
    +    model = model_type(2, 8, 1)
    +    rng = Xoshiro(0)
    +    ps, st = Lux.setup(rng, model) |> dev
    +
    +    train_state = Training.TrainState(model, ps, st, Adam(0.01f0))
    +
    +    for epoch in 1:25
    +        # Train the model
    +        for (x, y) in train_loader
    +            (_, loss, _, train_state) = Training.single_train_step!(
    +                AutoZygote(), lossfn, (x, y), train_state)
    +
    +            @printf "Epoch [%3d]: Loss %4.5f\\n" epoch loss
    +        end
    +
    +        # Validate the model
    +        st_ = Lux.testmode(train_state.states)
    +        for (x, y) in val_loader
    +            ŷ, st_ = model(x, train_state.parameters, st_)
    +            loss = lossfn(ŷ, y)
    +            acc = accuracy(ŷ, y)
    +            @printf "Validation: Loss %4.5f Accuracy %4.5f\\n" loss acc
    +        end
    +    end
    +
    +    return (train_state.parameters, train_state.states) |> cpu_device()
    +end
    +
    +ps_trained, st_trained = main(SpiralClassifier)
    Epoch [  1]: Loss 0.60926
    +Epoch [  1]: Loss 0.60205
    +Epoch [  1]: Loss 0.56447
    +Epoch [  1]: Loss 0.53935
    +Epoch [  1]: Loss 0.51961
    +Epoch [  1]: Loss 0.50630
    +Epoch [  1]: Loss 0.48399
    +Validation: Loss 0.46956 Accuracy 1.00000
    +Validation: Loss 0.47794 Accuracy 1.00000
    +Epoch [  2]: Loss 0.47301
    +Epoch [  2]: Loss 0.45405
    +Epoch [  2]: Loss 0.43968
    +Epoch [  2]: Loss 0.43054
    +Epoch [  2]: Loss 0.40202
    +Epoch [  2]: Loss 0.39666
    +Epoch [  2]: Loss 0.40138
    +Validation: Loss 0.37273 Accuracy 1.00000
    +Validation: Loss 0.38210 Accuracy 1.00000
    +Epoch [  3]: Loss 0.36731
    +Epoch [  3]: Loss 0.36875
    +Epoch [  3]: Loss 0.34892
    +Epoch [  3]: Loss 0.33812
    +Epoch [  3]: Loss 0.31629
    +Epoch [  3]: Loss 0.30792
    +Epoch [  3]: Loss 0.27809
    +Validation: Loss 0.28817 Accuracy 1.00000
    +Validation: Loss 0.29822 Accuracy 1.00000
    +Epoch [  4]: Loss 0.28662
    +Epoch [  4]: Loss 0.27989
    +Epoch [  4]: Loss 0.27278
    +Epoch [  4]: Loss 0.25235
    +Epoch [  4]: Loss 0.23497
    +Epoch [  4]: Loss 0.23847
    +Epoch [  4]: Loss 0.23192
    +Validation: Loss 0.21844 Accuracy 1.00000
    +Validation: Loss 0.22858 Accuracy 1.00000
    +Epoch [  5]: Loss 0.21529
    +Epoch [  5]: Loss 0.21660
    +Epoch [  5]: Loss 0.21147
    +Epoch [  5]: Loss 0.18347
    +Epoch [  5]: Loss 0.18387
    +Epoch [  5]: Loss 0.16418
    +Epoch [  5]: Loss 0.18488
    +Validation: Loss 0.16251 Accuracy 1.00000
    +Validation: Loss 0.17173 Accuracy 1.00000
    +Epoch [  6]: Loss 0.15106
    +Epoch [  6]: Loss 0.15557
    +Epoch [  6]: Loss 0.15604
    +Epoch [  6]: Loss 0.12610
    +Epoch [  6]: Loss 0.14466
    +Epoch [  6]: Loss 0.13525
    +Epoch [  6]: Loss 0.13401
    +Validation: Loss 0.11923 Accuracy 1.00000
    +Validation: Loss 0.12679 Accuracy 1.00000
    +Epoch [  7]: Loss 0.11300
    +Epoch [  7]: Loss 0.11270
    +Epoch [  7]: Loss 0.11182
    +Epoch [  7]: Loss 0.10579
    +Epoch [  7]: Loss 0.10077
    +Epoch [  7]: Loss 0.09092
    +Epoch [  7]: Loss 0.08957
    +Validation: Loss 0.08530 Accuracy 1.00000
    +Validation: Loss 0.09085 Accuracy 1.00000
    +Epoch [  8]: Loss 0.08321
    +Epoch [  8]: Loss 0.07613
    +Epoch [  8]: Loss 0.07561
    +Epoch [  8]: Loss 0.07250
    +Epoch [  8]: Loss 0.06895
    +Epoch [  8]: Loss 0.07155
    +Epoch [  8]: Loss 0.06246
    +Validation: Loss 0.05935 Accuracy 1.00000
    +Validation: Loss 0.06304 Accuracy 1.00000
    +Epoch [  9]: Loss 0.06135
    +Epoch [  9]: Loss 0.05983
    +Epoch [  9]: Loss 0.05429
    +Epoch [  9]: Loss 0.04415
    +Epoch [  9]: Loss 0.04965
    +Epoch [  9]: Loss 0.04801
    +Epoch [  9]: Loss 0.04264
    +Validation: Loss 0.04389 Accuracy 1.00000
    +Validation: Loss 0.04647 Accuracy 1.00000
    +Epoch [ 10]: Loss 0.04243
    +Epoch [ 10]: Loss 0.04109
    +Epoch [ 10]: Loss 0.04136
    +Epoch [ 10]: Loss 0.04201
    +Epoch [ 10]: Loss 0.03979
    +Epoch [ 10]: Loss 0.03471
    +Epoch [ 10]: Loss 0.03760
    +Validation: Loss 0.03546 Accuracy 1.00000
    +Validation: Loss 0.03756 Accuracy 1.00000
    +Epoch [ 11]: Loss 0.03545
    +Epoch [ 11]: Loss 0.03571
    +Epoch [ 11]: Loss 0.03202
    +Epoch [ 11]: Loss 0.03209
    +Epoch [ 11]: Loss 0.03134
    +Epoch [ 11]: Loss 0.03114
    +Epoch [ 11]: Loss 0.03593
    +Validation: Loss 0.03006 Accuracy 1.00000
    +Validation: Loss 0.03189 Accuracy 1.00000
    +Epoch [ 12]: Loss 0.03210
    +Epoch [ 12]: Loss 0.02768
    +Epoch [ 12]: Loss 0.02955
    +Epoch [ 12]: Loss 0.02631
    +Epoch [ 12]: Loss 0.02720
    +Epoch [ 12]: Loss 0.02667
    +Epoch [ 12]: Loss 0.03031
    +Validation: Loss 0.02612 Accuracy 1.00000
    +Validation: Loss 0.02773 Accuracy 1.00000
    +Epoch [ 13]: Loss 0.02589
    +Epoch [ 13]: Loss 0.02454
    +Epoch [ 13]: Loss 0.02716
    +Epoch [ 13]: Loss 0.02579
    +Epoch [ 13]: Loss 0.02323
    +Epoch [ 13]: Loss 0.02301
    +Epoch [ 13]: Loss 0.02099
    +Validation: Loss 0.02307 Accuracy 1.00000
    +Validation: Loss 0.02452 Accuracy 1.00000
    +Epoch [ 14]: Loss 0.02105
    +Epoch [ 14]: Loss 0.02170
    +Epoch [ 14]: Loss 0.02234
    +Epoch [ 14]: Loss 0.02238
    +Epoch [ 14]: Loss 0.02259
    +Epoch [ 14]: Loss 0.02282
    +Epoch [ 14]: Loss 0.01795
    +Validation: Loss 0.02066 Accuracy 1.00000
    +Validation: Loss 0.02199 Accuracy 1.00000
    +Epoch [ 15]: Loss 0.02140
    +Epoch [ 15]: Loss 0.02017
    +Epoch [ 15]: Loss 0.01932
    +Epoch [ 15]: Loss 0.02011
    +Epoch [ 15]: Loss 0.01752
    +Epoch [ 15]: Loss 0.02006
    +Epoch [ 15]: Loss 0.01963
    +Validation: Loss 0.01866 Accuracy 1.00000
    +Validation: Loss 0.01988 Accuracy 1.00000
    +Epoch [ 16]: Loss 0.01796
    +Epoch [ 16]: Loss 0.01636
    +Epoch [ 16]: Loss 0.01900
    +Epoch [ 16]: Loss 0.01740
    +Epoch [ 16]: Loss 0.01782
    +Epoch [ 16]: Loss 0.01824
    +Epoch [ 16]: Loss 0.01976
    +Validation: Loss 0.01696 Accuracy 1.00000
    +Validation: Loss 0.01810 Accuracy 1.00000
    +Epoch [ 17]: Loss 0.01745
    +Epoch [ 17]: Loss 0.01579
    +Epoch [ 17]: Loss 0.01777
    +Epoch [ 17]: Loss 0.01630
    +Epoch [ 17]: Loss 0.01578
    +Epoch [ 17]: Loss 0.01468
    +Epoch [ 17]: Loss 0.01627
    +Validation: Loss 0.01549 Accuracy 1.00000
    +Validation: Loss 0.01656 Accuracy 1.00000
    +Epoch [ 18]: Loss 0.01608
    +Epoch [ 18]: Loss 0.01398
    +Epoch [ 18]: Loss 0.01425
    +Epoch [ 18]: Loss 0.01537
    +Epoch [ 18]: Loss 0.01504
    +Epoch [ 18]: Loss 0.01471
    +Epoch [ 18]: Loss 0.01496
    +Validation: Loss 0.01423 Accuracy 1.00000
    +Validation: Loss 0.01523 Accuracy 1.00000
    +Epoch [ 19]: Loss 0.01355
    +Epoch [ 19]: Loss 0.01489
    +Epoch [ 19]: Loss 0.01364
    +Epoch [ 19]: Loss 0.01253
    +Epoch [ 19]: Loss 0.01360
    +Epoch [ 19]: Loss 0.01343
    +Epoch [ 19]: Loss 0.01639
    +Validation: Loss 0.01313 Accuracy 1.00000
    +Validation: Loss 0.01405 Accuracy 1.00000
    +Epoch [ 20]: Loss 0.01377
    +Epoch [ 20]: Loss 0.01183
    +Epoch [ 20]: Loss 0.01194
    +Epoch [ 20]: Loss 0.01194
    +Epoch [ 20]: Loss 0.01292
    +Epoch [ 20]: Loss 0.01361
    +Epoch [ 20]: Loss 0.01227
    +Validation: Loss 0.01211 Accuracy 1.00000
    +Validation: Loss 0.01297 Accuracy 1.00000
    +Epoch [ 21]: Loss 0.01212
    +Epoch [ 21]: Loss 0.01138
    +Epoch [ 21]: Loss 0.01102
    +Epoch [ 21]: Loss 0.01238
    +Epoch [ 21]: Loss 0.01200
    +Epoch [ 21]: Loss 0.01130
    +Epoch [ 21]: Loss 0.01082
    +Validation: Loss 0.01112 Accuracy 1.00000
    +Validation: Loss 0.01190 Accuracy 1.00000
    +Epoch [ 22]: Loss 0.01134
    +Epoch [ 22]: Loss 0.01031
    +Epoch [ 22]: Loss 0.01060
    +Epoch [ 22]: Loss 0.01130
    +Epoch [ 22]: Loss 0.01009
    +Epoch [ 22]: Loss 0.01053
    +Epoch [ 22]: Loss 0.00940
    +Validation: Loss 0.01002 Accuracy 1.00000
    +Validation: Loss 0.01071 Accuracy 1.00000
    +Epoch [ 23]: Loss 0.00886
    +Epoch [ 23]: Loss 0.01026
    +Epoch [ 23]: Loss 0.01005
    +Epoch [ 23]: Loss 0.00853
    +Epoch [ 23]: Loss 0.01033
    +Epoch [ 23]: Loss 0.00902
    +Epoch [ 23]: Loss 0.00969
    +Validation: Loss 0.00888 Accuracy 1.00000
    +Validation: Loss 0.00947 Accuracy 1.00000
    +Epoch [ 24]: Loss 0.00903
    +Epoch [ 24]: Loss 0.00856
    +Epoch [ 24]: Loss 0.00866
    +Epoch [ 24]: Loss 0.00883
    +Epoch [ 24]: Loss 0.00830
    +Epoch [ 24]: Loss 0.00781
    +Epoch [ 24]: Loss 0.00662
    +Validation: Loss 0.00795 Accuracy 1.00000
    +Validation: Loss 0.00846 Accuracy 1.00000
    +Epoch [ 25]: Loss 0.00830
    +Epoch [ 25]: Loss 0.00742
    +Epoch [ 25]: Loss 0.00822
    +Epoch [ 25]: Loss 0.00791
    +Epoch [ 25]: Loss 0.00721
    +Epoch [ 25]: Loss 0.00726
    +Epoch [ 25]: Loss 0.00582
    +Validation: Loss 0.00730 Accuracy 1.00000
    +Validation: Loss 0.00775 Accuracy 1.00000

    We can also train the compact model with the exact same code!

    julia
    ps_trained2, st_trained2 = main(SpiralClassifierCompact)
    Epoch [  1]: Loss 0.62249
    +Epoch [  1]: Loss 0.58988
    +Epoch [  1]: Loss 0.57122
    +Epoch [  1]: Loss 0.54145
    +Epoch [  1]: Loss 0.51676
    +Epoch [  1]: Loss 0.49941
    +Epoch [  1]: Loss 0.48712
    +Validation: Loss 0.46707 Accuracy 1.00000
    +Validation: Loss 0.46650 Accuracy 1.00000
    +Epoch [  2]: Loss 0.46435
    +Epoch [  2]: Loss 0.45555
    +Epoch [  2]: Loss 0.45454
    +Epoch [  2]: Loss 0.42345
    +Epoch [  2]: Loss 0.41436
    +Epoch [  2]: Loss 0.38527
    +Epoch [  2]: Loss 0.37442
    +Validation: Loss 0.36940 Accuracy 1.00000
    +Validation: Loss 0.36858 Accuracy 1.00000
    +Epoch [  3]: Loss 0.36752
    +Epoch [  3]: Loss 0.36360
    +Epoch [  3]: Loss 0.34430
    +Epoch [  3]: Loss 0.32734
    +Epoch [  3]: Loss 0.31783
    +Epoch [  3]: Loss 0.31825
    +Epoch [  3]: Loss 0.28565
    +Validation: Loss 0.28440 Accuracy 1.00000
    +Validation: Loss 0.28337 Accuracy 1.00000
    +Epoch [  4]: Loss 0.28307
    +Epoch [  4]: Loss 0.27199
    +Epoch [  4]: Loss 0.26836
    +Epoch [  4]: Loss 0.26051
    +Epoch [  4]: Loss 0.24528
    +Epoch [  4]: Loss 0.23063
    +Epoch [  4]: Loss 0.22536
    +Validation: Loss 0.21475 Accuracy 1.00000
    +Validation: Loss 0.21368 Accuracy 1.00000
    +Epoch [  5]: Loss 0.21305
    +Epoch [  5]: Loss 0.21531
    +Epoch [  5]: Loss 0.19616
    +Epoch [  5]: Loss 0.18414
    +Epoch [  5]: Loss 0.18294
    +Epoch [  5]: Loss 0.17875
    +Epoch [  5]: Loss 0.17815
    +Validation: Loss 0.15941 Accuracy 1.00000
    +Validation: Loss 0.15850 Accuracy 1.00000
    +Epoch [  6]: Loss 0.16464
    +Epoch [  6]: Loss 0.14669
    +Epoch [  6]: Loss 0.14234
    +Epoch [  6]: Loss 0.14785
    +Epoch [  6]: Loss 0.13936
    +Epoch [  6]: Loss 0.13121
    +Epoch [  6]: Loss 0.11054
    +Validation: Loss 0.11688 Accuracy 1.00000
    +Validation: Loss 0.11621 Accuracy 1.00000
    +Epoch [  7]: Loss 0.11895
    +Epoch [  7]: Loss 0.11755
    +Epoch [  7]: Loss 0.11153
    +Epoch [  7]: Loss 0.10806
    +Epoch [  7]: Loss 0.08931
    +Epoch [  7]: Loss 0.08989
    +Epoch [  7]: Loss 0.08885
    +Validation: Loss 0.08377 Accuracy 1.00000
    +Validation: Loss 0.08332 Accuracy 1.00000
    +Epoch [  8]: Loss 0.08392
    +Epoch [  8]: Loss 0.07975
    +Epoch [  8]: Loss 0.07711
    +Epoch [  8]: Loss 0.07462
    +Epoch [  8]: Loss 0.06929
    +Epoch [  8]: Loss 0.06475
    +Epoch [  8]: Loss 0.06222
    +Validation: Loss 0.05835 Accuracy 1.00000
    +Validation: Loss 0.05808 Accuracy 1.00000
    +Epoch [  9]: Loss 0.05835
    +Epoch [  9]: Loss 0.05645
    +Epoch [  9]: Loss 0.05303
    +Epoch [  9]: Loss 0.04974
    +Epoch [  9]: Loss 0.04989
    +Epoch [  9]: Loss 0.04836
    +Epoch [  9]: Loss 0.04374
    +Validation: Loss 0.04304 Accuracy 1.00000
    +Validation: Loss 0.04283 Accuracy 1.00000
    +Epoch [ 10]: Loss 0.04373
    +Epoch [ 10]: Loss 0.03963
    +Epoch [ 10]: Loss 0.04024
    +Epoch [ 10]: Loss 0.03893
    +Epoch [ 10]: Loss 0.04085
    +Epoch [ 10]: Loss 0.03933
    +Epoch [ 10]: Loss 0.02782
    +Validation: Loss 0.03470 Accuracy 1.00000
    +Validation: Loss 0.03451 Accuracy 1.00000
    +Epoch [ 11]: Loss 0.03413
    +Epoch [ 11]: Loss 0.03603
    +Epoch [ 11]: Loss 0.03246
    +Epoch [ 11]: Loss 0.03142
    +Epoch [ 11]: Loss 0.03040
    +Epoch [ 11]: Loss 0.03279
    +Epoch [ 11]: Loss 0.03336
    +Validation: Loss 0.02942 Accuracy 1.00000
    +Validation: Loss 0.02924 Accuracy 1.00000
    +Epoch [ 12]: Loss 0.03113
    +Epoch [ 12]: Loss 0.02712
    +Epoch [ 12]: Loss 0.02845
    +Epoch [ 12]: Loss 0.02904
    +Epoch [ 12]: Loss 0.02709
    +Epoch [ 12]: Loss 0.02722
    +Epoch [ 12]: Loss 0.02449
    +Validation: Loss 0.02555 Accuracy 1.00000
    +Validation: Loss 0.02540 Accuracy 1.00000
    +Epoch [ 13]: Loss 0.02730
    +Epoch [ 13]: Loss 0.02638
    +Epoch [ 13]: Loss 0.02358
    +Epoch [ 13]: Loss 0.02337
    +Epoch [ 13]: Loss 0.02417
    +Epoch [ 13]: Loss 0.02397
    +Epoch [ 13]: Loss 0.02159
    +Validation: Loss 0.02258 Accuracy 1.00000
    +Validation: Loss 0.02243 Accuracy 1.00000
    +Epoch [ 14]: Loss 0.02377
    +Epoch [ 14]: Loss 0.02260
    +Epoch [ 14]: Loss 0.02070
    +Epoch [ 14]: Loss 0.02170
    +Epoch [ 14]: Loss 0.02060
    +Epoch [ 14]: Loss 0.02212
    +Epoch [ 14]: Loss 0.02141
    +Validation: Loss 0.02019 Accuracy 1.00000
    +Validation: Loss 0.02006 Accuracy 1.00000
    +Epoch [ 15]: Loss 0.02146
    +Epoch [ 15]: Loss 0.01937
    +Epoch [ 15]: Loss 0.02047
    +Epoch [ 15]: Loss 0.01826
    +Epoch [ 15]: Loss 0.01953
    +Epoch [ 15]: Loss 0.01824
    +Epoch [ 15]: Loss 0.02201
    +Validation: Loss 0.01821 Accuracy 1.00000
    +Validation: Loss 0.01809 Accuracy 1.00000
    +Epoch [ 16]: Loss 0.01872
    +Epoch [ 16]: Loss 0.01647
    +Epoch [ 16]: Loss 0.01868
    +Epoch [ 16]: Loss 0.01763
    +Epoch [ 16]: Loss 0.01802
    +Epoch [ 16]: Loss 0.01730
    +Epoch [ 16]: Loss 0.01691
    +Validation: Loss 0.01653 Accuracy 1.00000
    +Validation: Loss 0.01642 Accuracy 1.00000
    +Epoch [ 17]: Loss 0.01638
    +Epoch [ 17]: Loss 0.01693
    +Epoch [ 17]: Loss 0.01747
    +Epoch [ 17]: Loss 0.01530
    +Epoch [ 17]: Loss 0.01570
    +Epoch [ 17]: Loss 0.01579
    +Epoch [ 17]: Loss 0.01431
    +Validation: Loss 0.01511 Accuracy 1.00000
    +Validation: Loss 0.01501 Accuracy 1.00000
    +Epoch [ 18]: Loss 0.01395
    +Epoch [ 18]: Loss 0.01493
    +Epoch [ 18]: Loss 0.01631
    +Epoch [ 18]: Loss 0.01388
    +Epoch [ 18]: Loss 0.01496
    +Epoch [ 18]: Loss 0.01520
    +Epoch [ 18]: Loss 0.01366
    +Validation: Loss 0.01390 Accuracy 1.00000
    +Validation: Loss 0.01381 Accuracy 1.00000
    +Epoch [ 19]: Loss 0.01337
    +Epoch [ 19]: Loss 0.01481
    +Epoch [ 19]: Loss 0.01359
    +Epoch [ 19]: Loss 0.01293
    +Epoch [ 19]: Loss 0.01317
    +Epoch [ 19]: Loss 0.01404
    +Epoch [ 19]: Loss 0.01416
    +Validation: Loss 0.01286 Accuracy 1.00000
    +Validation: Loss 0.01277 Accuracy 1.00000
    +Epoch [ 20]: Loss 0.01286
    +Epoch [ 20]: Loss 0.01335
    +Epoch [ 20]: Loss 0.01259
    +Epoch [ 20]: Loss 0.01343
    +Epoch [ 20]: Loss 0.01294
    +Epoch [ 20]: Loss 0.01124
    +Epoch [ 20]: Loss 0.01124
    +Validation: Loss 0.01194 Accuracy 1.00000
    +Validation: Loss 0.01186 Accuracy 1.00000
    +Epoch [ 21]: Loss 0.01159
    +Epoch [ 21]: Loss 0.01229
    +Epoch [ 21]: Loss 0.01273
    +Epoch [ 21]: Loss 0.01021
    +Epoch [ 21]: Loss 0.01159
    +Epoch [ 21]: Loss 0.01191
    +Epoch [ 21]: Loss 0.01311
    +Validation: Loss 0.01111 Accuracy 1.00000
    +Validation: Loss 0.01104 Accuracy 1.00000
    +Epoch [ 22]: Loss 0.01112
    +Epoch [ 22]: Loss 0.01155
    +Epoch [ 22]: Loss 0.01068
    +Epoch [ 22]: Loss 0.01120
    +Epoch [ 22]: Loss 0.00993
    +Epoch [ 22]: Loss 0.01129
    +Epoch [ 22]: Loss 0.01098
    +Validation: Loss 0.01033 Accuracy 1.00000
    +Validation: Loss 0.01026 Accuracy 1.00000
    +Epoch [ 23]: Loss 0.00950
    +Epoch [ 23]: Loss 0.01102
    +Epoch [ 23]: Loss 0.01060
    +Epoch [ 23]: Loss 0.01058
    +Epoch [ 23]: Loss 0.00987
    +Epoch [ 23]: Loss 0.01006
    +Epoch [ 23]: Loss 0.00747
    +Validation: Loss 0.00952 Accuracy 1.00000
    +Validation: Loss 0.00945 Accuracy 1.00000
    +Epoch [ 24]: Loss 0.00960
    +Epoch [ 24]: Loss 0.00995
    +Epoch [ 24]: Loss 0.00883
    +Epoch [ 24]: Loss 0.00888
    +Epoch [ 24]: Loss 0.00955
    +Epoch [ 24]: Loss 0.00915
    +Epoch [ 24]: Loss 0.00884
    +Validation: Loss 0.00861 Accuracy 1.00000
    +Validation: Loss 0.00856 Accuracy 1.00000
    +Epoch [ 25]: Loss 0.00958
    +Epoch [ 25]: Loss 0.00920
    +Epoch [ 25]: Loss 0.00803
    +Epoch [ 25]: Loss 0.00769
    +Epoch [ 25]: Loss 0.00804
    +Epoch [ 25]: Loss 0.00784
    +Epoch [ 25]: Loss 0.00760
    +Validation: Loss 0.00766 Accuracy 1.00000
    +Validation: Loss 0.00762 Accuracy 1.00000

    Saving the Model

    We can save the model using JLD2 (and any other serialization library of your choice) Note that we transfer the model to CPU before saving. Additionally, we recommend that you don't save the model struct and only save the parameters and states.

    julia
    @save "trained_model.jld2" ps_trained st_trained

    Let's try loading the model

    julia
    @load "trained_model.jld2" ps_trained st_trained
    2-element Vector{Symbol}:
    + :ps_trained
    + :st_trained

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +2 devices:
    +  0: Quadro RTX 5000 (sm_75, 15.227 GiB / 16.000 GiB available)
    +  1: Quadro RTX 5000 (sm_75, 15.549 GiB / 16.000 GiB available)

    This page was generated using Literate.jl.

    `,45)]))}const d=a(l,[["render",e]]);export{r as __pageData,d as default}; diff --git a/previews/PR1023/assets/tutorials_beginner_4_SimpleChains.md.BJAmU5gZ.js b/previews/PR1023/assets/tutorials_beginner_4_SimpleChains.md.BJAmU5gZ.js new file mode 100644 index 0000000000..ed2337fcda --- /dev/null +++ b/previews/PR1023/assets/tutorials_beginner_4_SimpleChains.md.BJAmU5gZ.js @@ -0,0 +1,143 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const g=JSON.parse('{"title":"MNIST Classification with SimpleChains","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/beginner/4_SimpleChains.md","filePath":"tutorials/beginner/4_SimpleChains.md","lastUpdated":null}'),p={name:"tutorials/beginner/4_SimpleChains.md"};function l(h,s,e,k,r,d){return t(),a("div",null,s[0]||(s[0]=[n(`

    MNIST Classification with SimpleChains

    SimpleChains.jl is an excellent framework for training small neural networks. In this tutorial we will demonstrate how to use the same API as Lux.jl to train a model using SimpleChains.jl. We will use the tutorial from SimpleChains.jl as a reference.

    Package Imports

    julia
    using Lux, ADTypes, MLUtils, Optimisers, Zygote, OneHotArrays, Random, Statistics, Printf
    +using MLDatasets: MNIST
    +using SimpleChains: SimpleChains

    Loading MNIST

    julia
    function loadmnist(batchsize, train_split)
    +    # Load MNIST
    +    N = 2000
    +    dataset = MNIST(; split=:train)
    +    imgs = dataset.features[:, :, 1:N]
    +    labels_raw = dataset.targets[1:N]
    +
    +    # Process images into (H, W, C, BS) batches
    +    x_data = Float32.(reshape(imgs, size(imgs, 1), size(imgs, 2), 1, size(imgs, 3)))
    +    y_data = onehotbatch(labels_raw, 0:9)
    +    (x_train, y_train), (x_test, y_test) = splitobs((x_data, y_data); at=train_split)
    +
    +    return (
    +        # Use DataLoader to automatically minibatch and shuffle the data
    +        DataLoader(collect.((x_train, y_train)); batchsize, shuffle=true),
    +        # Don't shuffle the test data
    +        DataLoader(collect.((x_test, y_test)); batchsize, shuffle=false))
    +end
    loadmnist (generic function with 1 method)

    Define the Model

    julia
    lux_model = Chain(Conv((5, 5), 1 => 6, relu), MaxPool((2, 2)),
    +    Conv((5, 5), 6 => 16, relu), MaxPool((2, 2)), FlattenLayer(3),
    +    Chain(Dense(256 => 128, relu), Dense(128 => 84, relu), Dense(84 => 10)))
    Chain(
    +    layer_1 = Conv((5, 5), 1 => 6, relu),  # 156 parameters
    +    layer_2 = MaxPool((2, 2)),
    +    layer_3 = Conv((5, 5), 6 => 16, relu),  # 2_416 parameters
    +    layer_4 = MaxPool((2, 2)),
    +    layer_5 = Lux.FlattenLayer{Static.StaticInt{3}}(static(3)),
    +    layer_6 = Chain(
    +        layer_1 = Dense(256 => 128, relu),  # 32_896 parameters
    +        layer_2 = Dense(128 => 84, relu),  # 10_836 parameters
    +        layer_3 = Dense(84 => 10),      # 850 parameters
    +    ),
    +)         # Total: 47_154 parameters,
    +          #        plus 0 states.

    We now need to convert the lux_model to SimpleChains.jl. We need to do this by defining the ToSimpleChainsAdaptor and providing the input dimensions.

    julia
    adaptor = ToSimpleChainsAdaptor((28, 28, 1))
    +simple_chains_model = adaptor(lux_model)
    SimpleChainsLayer(
    +    Chain(
    +        layer_1 = Conv((5, 5), 1 => 6, relu),  # 156 parameters
    +        layer_2 = MaxPool((2, 2)),
    +        layer_3 = Conv((5, 5), 6 => 16, relu),  # 2_416 parameters
    +        layer_4 = MaxPool((2, 2)),
    +        layer_5 = Lux.FlattenLayer{Static.StaticInt{3}}(static(3)),
    +        layer_6 = Chain(
    +            layer_1 = Dense(256 => 128, relu),  # 32_896 parameters
    +            layer_2 = Dense(128 => 84, relu),  # 10_836 parameters
    +            layer_3 = Dense(84 => 10),  # 850 parameters
    +        ),
    +    ),
    +)         # Total: 47_154 parameters,
    +          #        plus 0 states.

    Helper Functions

    julia
    const loss = CrossEntropyLoss(; logits=Val(true))
    +
    +function accuracy(model, ps, st, dataloader)
    +    total_correct, total = 0, 0
    +    st = Lux.testmode(st)
    +    for (x, y) in dataloader
    +        target_class = onecold(y)
    +        predicted_class = onecold(Array(first(model(x, ps, st))))
    +        total_correct += sum(target_class .== predicted_class)
    +        total += length(target_class)
    +    end
    +    return total_correct / total
    +end
    accuracy (generic function with 1 method)

    Define the Training Loop

    julia
    function train(model; rng=Xoshiro(0), kwargs...)
    +    train_dataloader, test_dataloader = loadmnist(128, 0.9)
    +    ps, st = Lux.setup(rng, model)
    +
    +    train_state = Training.TrainState(model, ps, st, Adam(3.0f-4))
    +
    +    ### Warmup the model
    +    x_proto = randn(rng, Float32, 28, 28, 1, 1)
    +    y_proto = onehotbatch([1], 0:9)
    +    Training.compute_gradients(AutoZygote(), loss, (x_proto, y_proto), train_state)
    +
    +    ### Lets train the model
    +    nepochs = 10
    +    tr_acc, te_acc = 0.0, 0.0
    +    for epoch in 1:nepochs
    +        stime = time()
    +        for (x, y) in train_dataloader
    +            gs, _, _, train_state = Training.single_train_step!(
    +                AutoZygote(), loss, (x, y), train_state)
    +        end
    +        ttime = time() - stime
    +
    +        tr_acc = accuracy(
    +            model, train_state.parameters, train_state.states, train_dataloader) * 100
    +        te_acc = accuracy(
    +            model, train_state.parameters, train_state.states, test_dataloader) * 100
    +
    +        @printf "[%2d/%2d] \\t Time %.2fs \\t Training Accuracy: %.2f%% \\t Test Accuracy: \\
    +                 %.2f%%\\n" epoch nepochs ttime tr_acc te_acc
    +    end
    +
    +    return tr_acc, te_acc
    +end
    train (generic function with 1 method)

    Finally Training the Model

    First we will train the Lux model

    julia
    tr_acc, te_acc = train(lux_model)
    [ 1/10] 	 Time 106.58s 	 Training Accuracy: 22.44% 	 Test Accuracy: 19.50%
    +[ 2/10] 	 Time 106.61s 	 Training Accuracy: 47.06% 	 Test Accuracy: 45.50%
    +[ 3/10] 	 Time 112.24s 	 Training Accuracy: 61.50% 	 Test Accuracy: 61.00%
    +[ 4/10] 	 Time 115.93s 	 Training Accuracy: 69.89% 	 Test Accuracy: 65.00%
    +[ 5/10] 	 Time 118.22s 	 Training Accuracy: 75.22% 	 Test Accuracy: 74.00%
    +[ 6/10] 	 Time 112.80s 	 Training Accuracy: 78.44% 	 Test Accuracy: 77.50%
    +[ 7/10] 	 Time 108.41s 	 Training Accuracy: 81.22% 	 Test Accuracy: 81.00%
    +[ 8/10] 	 Time 112.49s 	 Training Accuracy: 83.94% 	 Test Accuracy: 80.50%
    +[ 9/10] 	 Time 113.54s 	 Training Accuracy: 85.89% 	 Test Accuracy: 84.50%
    +[10/10] 	 Time 113.99s 	 Training Accuracy: 87.11% 	 Test Accuracy: 84.50%

    Now we will train the SimpleChains model

    julia
    train(simple_chains_model)
    [ 1/10] 	 Time 18.70s 	 Training Accuracy: 29.06% 	 Test Accuracy: 23.50%
    +[ 2/10] 	 Time 17.64s 	 Training Accuracy: 45.83% 	 Test Accuracy: 43.00%
    +[ 3/10] 	 Time 17.64s 	 Training Accuracy: 62.72% 	 Test Accuracy: 57.50%
    +[ 4/10] 	 Time 17.64s 	 Training Accuracy: 65.67% 	 Test Accuracy: 61.50%
    +[ 5/10] 	 Time 17.65s 	 Training Accuracy: 74.72% 	 Test Accuracy: 68.50%
    +[ 6/10] 	 Time 17.63s 	 Training Accuracy: 79.61% 	 Test Accuracy: 77.00%
    +[ 7/10] 	 Time 17.64s 	 Training Accuracy: 81.83% 	 Test Accuracy: 77.00%
    +[ 8/10] 	 Time 17.63s 	 Training Accuracy: 83.94% 	 Test Accuracy: 79.50%
    +[ 9/10] 	 Time 17.65s 	 Training Accuracy: 84.50% 	 Test Accuracy: 84.50%
    +[10/10] 	 Time 17.63s 	 Training Accuracy: 87.78% 	 Test Accuracy: 83.50%

    On my local machine we see a 3-4x speedup when using SimpleChains.jl. The conditions of the server this documentation is being built on is not ideal for CPU benchmarking hence, the speedup may not be as significant and even there might be regressions.

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate

    This page was generated using Literate.jl.

    `,32)]))}const c=i(p,[["render",l]]);export{g as __pageData,c as default}; diff --git a/previews/PR1023/assets/tutorials_beginner_4_SimpleChains.md.BJAmU5gZ.lean.js b/previews/PR1023/assets/tutorials_beginner_4_SimpleChains.md.BJAmU5gZ.lean.js new file mode 100644 index 0000000000..ed2337fcda --- /dev/null +++ b/previews/PR1023/assets/tutorials_beginner_4_SimpleChains.md.BJAmU5gZ.lean.js @@ -0,0 +1,143 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const g=JSON.parse('{"title":"MNIST Classification with SimpleChains","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/beginner/4_SimpleChains.md","filePath":"tutorials/beginner/4_SimpleChains.md","lastUpdated":null}'),p={name:"tutorials/beginner/4_SimpleChains.md"};function l(h,s,e,k,r,d){return t(),a("div",null,s[0]||(s[0]=[n(`

    MNIST Classification with SimpleChains

    SimpleChains.jl is an excellent framework for training small neural networks. In this tutorial we will demonstrate how to use the same API as Lux.jl to train a model using SimpleChains.jl. We will use the tutorial from SimpleChains.jl as a reference.

    Package Imports

    julia
    using Lux, ADTypes, MLUtils, Optimisers, Zygote, OneHotArrays, Random, Statistics, Printf
    +using MLDatasets: MNIST
    +using SimpleChains: SimpleChains

    Loading MNIST

    julia
    function loadmnist(batchsize, train_split)
    +    # Load MNIST
    +    N = 2000
    +    dataset = MNIST(; split=:train)
    +    imgs = dataset.features[:, :, 1:N]
    +    labels_raw = dataset.targets[1:N]
    +
    +    # Process images into (H, W, C, BS) batches
    +    x_data = Float32.(reshape(imgs, size(imgs, 1), size(imgs, 2), 1, size(imgs, 3)))
    +    y_data = onehotbatch(labels_raw, 0:9)
    +    (x_train, y_train), (x_test, y_test) = splitobs((x_data, y_data); at=train_split)
    +
    +    return (
    +        # Use DataLoader to automatically minibatch and shuffle the data
    +        DataLoader(collect.((x_train, y_train)); batchsize, shuffle=true),
    +        # Don't shuffle the test data
    +        DataLoader(collect.((x_test, y_test)); batchsize, shuffle=false))
    +end
    loadmnist (generic function with 1 method)

    Define the Model

    julia
    lux_model = Chain(Conv((5, 5), 1 => 6, relu), MaxPool((2, 2)),
    +    Conv((5, 5), 6 => 16, relu), MaxPool((2, 2)), FlattenLayer(3),
    +    Chain(Dense(256 => 128, relu), Dense(128 => 84, relu), Dense(84 => 10)))
    Chain(
    +    layer_1 = Conv((5, 5), 1 => 6, relu),  # 156 parameters
    +    layer_2 = MaxPool((2, 2)),
    +    layer_3 = Conv((5, 5), 6 => 16, relu),  # 2_416 parameters
    +    layer_4 = MaxPool((2, 2)),
    +    layer_5 = Lux.FlattenLayer{Static.StaticInt{3}}(static(3)),
    +    layer_6 = Chain(
    +        layer_1 = Dense(256 => 128, relu),  # 32_896 parameters
    +        layer_2 = Dense(128 => 84, relu),  # 10_836 parameters
    +        layer_3 = Dense(84 => 10),      # 850 parameters
    +    ),
    +)         # Total: 47_154 parameters,
    +          #        plus 0 states.

    We now need to convert the lux_model to SimpleChains.jl. We need to do this by defining the ToSimpleChainsAdaptor and providing the input dimensions.

    julia
    adaptor = ToSimpleChainsAdaptor((28, 28, 1))
    +simple_chains_model = adaptor(lux_model)
    SimpleChainsLayer(
    +    Chain(
    +        layer_1 = Conv((5, 5), 1 => 6, relu),  # 156 parameters
    +        layer_2 = MaxPool((2, 2)),
    +        layer_3 = Conv((5, 5), 6 => 16, relu),  # 2_416 parameters
    +        layer_4 = MaxPool((2, 2)),
    +        layer_5 = Lux.FlattenLayer{Static.StaticInt{3}}(static(3)),
    +        layer_6 = Chain(
    +            layer_1 = Dense(256 => 128, relu),  # 32_896 parameters
    +            layer_2 = Dense(128 => 84, relu),  # 10_836 parameters
    +            layer_3 = Dense(84 => 10),  # 850 parameters
    +        ),
    +    ),
    +)         # Total: 47_154 parameters,
    +          #        plus 0 states.

    Helper Functions

    julia
    const loss = CrossEntropyLoss(; logits=Val(true))
    +
    +function accuracy(model, ps, st, dataloader)
    +    total_correct, total = 0, 0
    +    st = Lux.testmode(st)
    +    for (x, y) in dataloader
    +        target_class = onecold(y)
    +        predicted_class = onecold(Array(first(model(x, ps, st))))
    +        total_correct += sum(target_class .== predicted_class)
    +        total += length(target_class)
    +    end
    +    return total_correct / total
    +end
    accuracy (generic function with 1 method)

    Define the Training Loop

    julia
    function train(model; rng=Xoshiro(0), kwargs...)
    +    train_dataloader, test_dataloader = loadmnist(128, 0.9)
    +    ps, st = Lux.setup(rng, model)
    +
    +    train_state = Training.TrainState(model, ps, st, Adam(3.0f-4))
    +
    +    ### Warmup the model
    +    x_proto = randn(rng, Float32, 28, 28, 1, 1)
    +    y_proto = onehotbatch([1], 0:9)
    +    Training.compute_gradients(AutoZygote(), loss, (x_proto, y_proto), train_state)
    +
    +    ### Lets train the model
    +    nepochs = 10
    +    tr_acc, te_acc = 0.0, 0.0
    +    for epoch in 1:nepochs
    +        stime = time()
    +        for (x, y) in train_dataloader
    +            gs, _, _, train_state = Training.single_train_step!(
    +                AutoZygote(), loss, (x, y), train_state)
    +        end
    +        ttime = time() - stime
    +
    +        tr_acc = accuracy(
    +            model, train_state.parameters, train_state.states, train_dataloader) * 100
    +        te_acc = accuracy(
    +            model, train_state.parameters, train_state.states, test_dataloader) * 100
    +
    +        @printf "[%2d/%2d] \\t Time %.2fs \\t Training Accuracy: %.2f%% \\t Test Accuracy: \\
    +                 %.2f%%\\n" epoch nepochs ttime tr_acc te_acc
    +    end
    +
    +    return tr_acc, te_acc
    +end
    train (generic function with 1 method)

    Finally Training the Model

    First we will train the Lux model

    julia
    tr_acc, te_acc = train(lux_model)
    [ 1/10] 	 Time 106.58s 	 Training Accuracy: 22.44% 	 Test Accuracy: 19.50%
    +[ 2/10] 	 Time 106.61s 	 Training Accuracy: 47.06% 	 Test Accuracy: 45.50%
    +[ 3/10] 	 Time 112.24s 	 Training Accuracy: 61.50% 	 Test Accuracy: 61.00%
    +[ 4/10] 	 Time 115.93s 	 Training Accuracy: 69.89% 	 Test Accuracy: 65.00%
    +[ 5/10] 	 Time 118.22s 	 Training Accuracy: 75.22% 	 Test Accuracy: 74.00%
    +[ 6/10] 	 Time 112.80s 	 Training Accuracy: 78.44% 	 Test Accuracy: 77.50%
    +[ 7/10] 	 Time 108.41s 	 Training Accuracy: 81.22% 	 Test Accuracy: 81.00%
    +[ 8/10] 	 Time 112.49s 	 Training Accuracy: 83.94% 	 Test Accuracy: 80.50%
    +[ 9/10] 	 Time 113.54s 	 Training Accuracy: 85.89% 	 Test Accuracy: 84.50%
    +[10/10] 	 Time 113.99s 	 Training Accuracy: 87.11% 	 Test Accuracy: 84.50%

    Now we will train the SimpleChains model

    julia
    train(simple_chains_model)
    [ 1/10] 	 Time 18.70s 	 Training Accuracy: 29.06% 	 Test Accuracy: 23.50%
    +[ 2/10] 	 Time 17.64s 	 Training Accuracy: 45.83% 	 Test Accuracy: 43.00%
    +[ 3/10] 	 Time 17.64s 	 Training Accuracy: 62.72% 	 Test Accuracy: 57.50%
    +[ 4/10] 	 Time 17.64s 	 Training Accuracy: 65.67% 	 Test Accuracy: 61.50%
    +[ 5/10] 	 Time 17.65s 	 Training Accuracy: 74.72% 	 Test Accuracy: 68.50%
    +[ 6/10] 	 Time 17.63s 	 Training Accuracy: 79.61% 	 Test Accuracy: 77.00%
    +[ 7/10] 	 Time 17.64s 	 Training Accuracy: 81.83% 	 Test Accuracy: 77.00%
    +[ 8/10] 	 Time 17.63s 	 Training Accuracy: 83.94% 	 Test Accuracy: 79.50%
    +[ 9/10] 	 Time 17.65s 	 Training Accuracy: 84.50% 	 Test Accuracy: 84.50%
    +[10/10] 	 Time 17.63s 	 Training Accuracy: 87.78% 	 Test Accuracy: 83.50%

    On my local machine we see a 3-4x speedup when using SimpleChains.jl. The conditions of the server this documentation is being built on is not ideal for CPU benchmarking hence, the speedup may not be as significant and even there might be regressions.

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate

    This page was generated using Literate.jl.

    `,32)]))}const c=i(p,[["render",l]]);export{g as __pageData,c as default}; diff --git a/previews/PR1023/assets/tutorials_beginner_5_OptimizationIntegration.md.B9JkcgjS.js b/previews/PR1023/assets/tutorials_beginner_5_OptimizationIntegration.md.B9JkcgjS.js new file mode 100644 index 0000000000..2590724477 --- /dev/null +++ b/previews/PR1023/assets/tutorials_beginner_5_OptimizationIntegration.md.B9JkcgjS.js @@ -0,0 +1,181 @@ +import{_ as s,c as i,a2 as a,o as n}from"./chunks/framework.DFwXuivk.js";const d=JSON.parse('{"title":"Training Lux Models using Optimization.jl","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/beginner/5_OptimizationIntegration.md","filePath":"tutorials/beginner/5_OptimizationIntegration.md","lastUpdated":null}'),t={name:"tutorials/beginner/5_OptimizationIntegration.md"};function p(l,A,h,e,k,E){return n(),i("div",null,A[0]||(A[0]=[a(`

    Training Lux Models using Optimization.jl

    Lux's native Training.TrainState is a great API for gradient-based learning of neural networks, however, it is geared towards using Optimisers.jl as the backend. However, often times we want to train the neural networks with other optimization methods like BFGS, LBFGS, etc. In this tutorial, we will show how to train Lux models with Optimization.jl that provides a simple unified interface to various optimization methods.

    We will base our tutorial on the minibatching tutorial from the official Optimization.jl docs.

    Neural ODE

    This tutorial uses a Neural ODE, however, we won't discuss that part in this tutorial. Please refer to the Neural ODE tutorial for more information.

    Imports packages

    julia
    using Lux, Optimization, OptimizationOptimisers, OptimizationOptimJL, OrdinaryDiffEqTsit5,
    +      SciMLSensitivity, Random, MLUtils, CairoMakie, ComponentArrays, Printf
    +using LuxCUDA
    +
    +const gdev = gpu_device()
    +const cdev = cpu_device()
    (::MLDataDevices.CPUDevice) (generic function with 5 methods)

    Generate some training data

    julia
    function lotka_volterra(du, u, p, t)
    +    x, y = u
    +    α, β, δ, γ = p
    +    du[1] = α * x - β * x * y
    +    du[2] = -δ * y + γ * x * y
    +    return nothing
    +end
    +
    +u0 = [1.0f0, 1.0f0]
    +
    +datasize = 32
    +tspan = (0.0f0, 2.0f0)
    +
    +const t = range(tspan[1], tspan[2]; length=datasize)
    +true_prob = ODEProblem(lotka_volterra, u0, (tspan[1], tspan[2]), [1.5, 1.0, 3.0, 1.0])
    +const ode_data = Array(solve(true_prob, Tsit5(); saveat=t))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1])
    +    lines!(ax, t, ode_data[1, :]; label=L"u_1(t)", color=:blue, linestyle=:dot, linewidth=4)
    +    lines!(ax, t, ode_data[2, :]; label=L"u_2(t)", color=:red, linestyle=:dot, linewidth=4)
    +    axislegend(ax; position=:lt)
    +    fig
    +end

    Define the DataLoader

    We will define the DataLoader to batch over the data, additionally we will pipe it through the gdev device to move the data to the GPU on each iteration.

    By default gdev will move all objects to the GPU. But we don't want to move the time vector to the GPU. So we will wrap it in a struct.

    julia
    struct TimeWrapper{T}
    +    t::T
    +end
    +
    +Base.length(t::TimeWrapper) = length(t.t)
    +
    +Base.getindex(t::TimeWrapper, i) = TimeWrapper(t.t[i])
    +
    +dataloader = DataLoader((ode_data, TimeWrapper(t)); batchsize=8) |> gdev
    MLDataDevices.DeviceIterator{MLDataDevices.CUDADevice{Nothing}, MLUtils.DataLoader{Tuple{Matrix{Float32}, Main.var"##225".TimeWrapper{StepRangeLen{Float32, Float64, Float64, Int64}}}, Random._GLOBAL_RNG, Val{nothing}}}(MLDataDevices.CUDADevice{Nothing}(nothing), DataLoader(::Tuple{Matrix{Float32}, Main.var"##225".TimeWrapper{StepRangeLen{Float32, Float64, Float64, Int64}}}, batchsize=8))

    Training the model

    Here we are using different optimization methods for demonstration purposes. This problem is trivial enough to not require this.

    Optimization.jl requires an abstract array as the parameters, hence we will construct a ComponentArray to store the parameters.

    Parameter Estimation vs State Estimation

    Optimization.jl performs state estimation, which effectively means for a function f(u, p), it is trying to compute the optimal u for a given p. This terminology might be confusing to ML practitioners, since in the ML world, we usually do parameter estimation. This effectively means that the u in Optimization.jl corresponds to our model parameters that is being optimized.

    julia
    function train_model(dataloader)
    +    model = Chain(Dense(2, 32, tanh), Dense(32, 32, tanh), Dense(32, 2))
    +    ps, st = Lux.setup(Random.default_rng(), model)
    +
    +    ps_ca = ComponentArray(ps) |> gdev
    +    st = st |> gdev
    +
    +    function callback(state, l)
    +        state.iter % 25 == 1 && @printf "Iteration: %5d, Loss: %.6e\\n" state.iter l
    +        return l < 1e-8 ## Terminate if loss is small
    +    end
    +
    +    smodel = StatefulLuxLayer{true}(model, nothing, st)
    +
    +    function loss_adjoint(θ, (u_batch, t_batch))
    +        t_batch = t_batch.t
    +        u0 = u_batch[:, 1]
    +        dudt(u, p, t) = smodel(u, p)
    +        prob = ODEProblem(dudt, u0, (t_batch[1], t_batch[end]), θ)
    +        pred = convert(AbstractArray, solve(prob, Tsit5(); saveat=t_batch))
    +        return MSELoss()(pred, u_batch)
    +    end
    +
    +    # Define the Optimization Function that takes in the optimization state (our parameters)
    +    # and optimization parameters (nothing in our case) and data from the dataloader and
    +    # returns the loss.
    +    opt_func = OptimizationFunction(loss_adjoint, Optimization.AutoZygote())
    +    opt_prob = OptimizationProblem(opt_func, ps_ca, dataloader)
    +
    +    epochs = 25
    +    res_adam = solve(opt_prob, Optimisers.Adam(0.001); callback, epochs)
    +
    +    # Let's finetune a bit with L-BFGS
    +    opt_prob = OptimizationProblem(opt_func, res_adam.u, (gdev(ode_data), TimeWrapper(t)))
    +    res_lbfgs = solve(opt_prob, LBFGS(); callback, maxiters=epochs)
    +
    +    # Now that we have a good fit, let's train it on the entire dataset without
    +    # Minibatching. We need to do this since ODE solves can lead to accumulated errors if
    +    # the model was trained on individual parts (without a data-shooting approach).
    +    opt_prob = remake(opt_prob; u0=res_lbfgs.u)
    +    res = solve(opt_prob, Optimisers.Adam(0.005); maxiters=500, callback)
    +
    +    return StatefulLuxLayer{true}(model, res.u, smodel.st)
    +end
    +
    +trained_model = train_model(dataloader)
    Iteration:     1, Loss: 1.893717e-01
    +Iteration:    26, Loss: 3.556251e-02
    +Iteration:    51, Loss: 1.288165e-01
    +Iteration:    76, Loss: 2.463205e-01
    +Iteration:     1, Loss: 2.282736e-01
    +Iteration:     1, Loss: 2.117264e-02
    +Iteration:    26, Loss: 3.948899e-02
    +Iteration:    51, Loss: 2.352137e-02
    +Iteration:    76, Loss: 2.201421e-02
    +Iteration:   101, Loss: 2.090701e-02
    +Iteration:   126, Loss: 1.977806e-02
    +Iteration:   151, Loss: 1.857129e-02
    +Iteration:   176, Loss: 1.735175e-02
    +Iteration:   201, Loss: 1.615999e-02
    +Iteration:   226, Loss: 1.493911e-02
    +Iteration:   251, Loss: 1.362476e-02
    +Iteration:   276, Loss: 1.221552e-02
    +Iteration:   301, Loss: 1.135817e-02
    +Iteration:   326, Loss: 1.075873e-02
    +Iteration:   351, Loss: 9.290738e-03
    +Iteration:   376, Loss: 8.201186e-03
    +Iteration:   401, Loss: 1.741432e-02
    +Iteration:   426, Loss: 7.620634e-03
    +Iteration:   451, Loss: 6.616297e-03
    +Iteration:   476, Loss: 5.912085e-03

    Plotting the results

    julia
    dudt(u, p, t) = trained_model(u, p)
    +prob = ODEProblem(dudt, gdev(u0), (tspan[1], tspan[2]), trained_model.ps)
    +sol = solve(prob, Tsit5(); saveat=t)
    +pred = convert(AbstractArray, sol) |> cdev
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1])
    +    lines!(ax, t, ode_data[1, :]; label=L"u_1(t)", color=:blue, linestyle=:dot, linewidth=4)
    +    lines!(ax, t, ode_data[2, :]; label=L"u_2(t)", color=:red, linestyle=:dot, linewidth=4)
    +    lines!(ax, t, pred[1, :]; label=L"\\hat{u}_1(t)", color=:blue, linewidth=4)
    +    lines!(ax, t, pred[2, :]; label=L"\\hat{u}_2(t)", color=:red, linewidth=4)
    +    axislegend(ax; position=:lt)
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.484 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,29)]))}const g=s(t,[["render",p]]);export{d as __pageData,g as default}; diff --git a/previews/PR1023/assets/tutorials_beginner_5_OptimizationIntegration.md.B9JkcgjS.lean.js b/previews/PR1023/assets/tutorials_beginner_5_OptimizationIntegration.md.B9JkcgjS.lean.js new file mode 100644 index 0000000000..2590724477 --- /dev/null +++ b/previews/PR1023/assets/tutorials_beginner_5_OptimizationIntegration.md.B9JkcgjS.lean.js @@ -0,0 +1,181 @@ +import{_ as s,c as i,a2 as a,o as n}from"./chunks/framework.DFwXuivk.js";const d=JSON.parse('{"title":"Training Lux Models using Optimization.jl","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/beginner/5_OptimizationIntegration.md","filePath":"tutorials/beginner/5_OptimizationIntegration.md","lastUpdated":null}'),t={name:"tutorials/beginner/5_OptimizationIntegration.md"};function p(l,A,h,e,k,E){return n(),i("div",null,A[0]||(A[0]=[a(`

    Training Lux Models using Optimization.jl

    Lux's native Training.TrainState is a great API for gradient-based learning of neural networks, however, it is geared towards using Optimisers.jl as the backend. However, often times we want to train the neural networks with other optimization methods like BFGS, LBFGS, etc. In this tutorial, we will show how to train Lux models with Optimization.jl that provides a simple unified interface to various optimization methods.

    We will base our tutorial on the minibatching tutorial from the official Optimization.jl docs.

    Neural ODE

    This tutorial uses a Neural ODE, however, we won't discuss that part in this tutorial. Please refer to the Neural ODE tutorial for more information.

    Imports packages

    julia
    using Lux, Optimization, OptimizationOptimisers, OptimizationOptimJL, OrdinaryDiffEqTsit5,
    +      SciMLSensitivity, Random, MLUtils, CairoMakie, ComponentArrays, Printf
    +using LuxCUDA
    +
    +const gdev = gpu_device()
    +const cdev = cpu_device()
    (::MLDataDevices.CPUDevice) (generic function with 5 methods)

    Generate some training data

    julia
    function lotka_volterra(du, u, p, t)
    +    x, y = u
    +    α, β, δ, γ = p
    +    du[1] = α * x - β * x * y
    +    du[2] = -δ * y + γ * x * y
    +    return nothing
    +end
    +
    +u0 = [1.0f0, 1.0f0]
    +
    +datasize = 32
    +tspan = (0.0f0, 2.0f0)
    +
    +const t = range(tspan[1], tspan[2]; length=datasize)
    +true_prob = ODEProblem(lotka_volterra, u0, (tspan[1], tspan[2]), [1.5, 1.0, 3.0, 1.0])
    +const ode_data = Array(solve(true_prob, Tsit5(); saveat=t))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1])
    +    lines!(ax, t, ode_data[1, :]; label=L"u_1(t)", color=:blue, linestyle=:dot, linewidth=4)
    +    lines!(ax, t, ode_data[2, :]; label=L"u_2(t)", color=:red, linestyle=:dot, linewidth=4)
    +    axislegend(ax; position=:lt)
    +    fig
    +end

    Define the DataLoader

    We will define the DataLoader to batch over the data, additionally we will pipe it through the gdev device to move the data to the GPU on each iteration.

    By default gdev will move all objects to the GPU. But we don't want to move the time vector to the GPU. So we will wrap it in a struct.

    julia
    struct TimeWrapper{T}
    +    t::T
    +end
    +
    +Base.length(t::TimeWrapper) = length(t.t)
    +
    +Base.getindex(t::TimeWrapper, i) = TimeWrapper(t.t[i])
    +
    +dataloader = DataLoader((ode_data, TimeWrapper(t)); batchsize=8) |> gdev
    MLDataDevices.DeviceIterator{MLDataDevices.CUDADevice{Nothing}, MLUtils.DataLoader{Tuple{Matrix{Float32}, Main.var"##225".TimeWrapper{StepRangeLen{Float32, Float64, Float64, Int64}}}, Random._GLOBAL_RNG, Val{nothing}}}(MLDataDevices.CUDADevice{Nothing}(nothing), DataLoader(::Tuple{Matrix{Float32}, Main.var"##225".TimeWrapper{StepRangeLen{Float32, Float64, Float64, Int64}}}, batchsize=8))

    Training the model

    Here we are using different optimization methods for demonstration purposes. This problem is trivial enough to not require this.

    Optimization.jl requires an abstract array as the parameters, hence we will construct a ComponentArray to store the parameters.

    Parameter Estimation vs State Estimation

    Optimization.jl performs state estimation, which effectively means for a function f(u, p), it is trying to compute the optimal u for a given p. This terminology might be confusing to ML practitioners, since in the ML world, we usually do parameter estimation. This effectively means that the u in Optimization.jl corresponds to our model parameters that is being optimized.

    julia
    function train_model(dataloader)
    +    model = Chain(Dense(2, 32, tanh), Dense(32, 32, tanh), Dense(32, 2))
    +    ps, st = Lux.setup(Random.default_rng(), model)
    +
    +    ps_ca = ComponentArray(ps) |> gdev
    +    st = st |> gdev
    +
    +    function callback(state, l)
    +        state.iter % 25 == 1 && @printf "Iteration: %5d, Loss: %.6e\\n" state.iter l
    +        return l < 1e-8 ## Terminate if loss is small
    +    end
    +
    +    smodel = StatefulLuxLayer{true}(model, nothing, st)
    +
    +    function loss_adjoint(θ, (u_batch, t_batch))
    +        t_batch = t_batch.t
    +        u0 = u_batch[:, 1]
    +        dudt(u, p, t) = smodel(u, p)
    +        prob = ODEProblem(dudt, u0, (t_batch[1], t_batch[end]), θ)
    +        pred = convert(AbstractArray, solve(prob, Tsit5(); saveat=t_batch))
    +        return MSELoss()(pred, u_batch)
    +    end
    +
    +    # Define the Optimization Function that takes in the optimization state (our parameters)
    +    # and optimization parameters (nothing in our case) and data from the dataloader and
    +    # returns the loss.
    +    opt_func = OptimizationFunction(loss_adjoint, Optimization.AutoZygote())
    +    opt_prob = OptimizationProblem(opt_func, ps_ca, dataloader)
    +
    +    epochs = 25
    +    res_adam = solve(opt_prob, Optimisers.Adam(0.001); callback, epochs)
    +
    +    # Let's finetune a bit with L-BFGS
    +    opt_prob = OptimizationProblem(opt_func, res_adam.u, (gdev(ode_data), TimeWrapper(t)))
    +    res_lbfgs = solve(opt_prob, LBFGS(); callback, maxiters=epochs)
    +
    +    # Now that we have a good fit, let's train it on the entire dataset without
    +    # Minibatching. We need to do this since ODE solves can lead to accumulated errors if
    +    # the model was trained on individual parts (without a data-shooting approach).
    +    opt_prob = remake(opt_prob; u0=res_lbfgs.u)
    +    res = solve(opt_prob, Optimisers.Adam(0.005); maxiters=500, callback)
    +
    +    return StatefulLuxLayer{true}(model, res.u, smodel.st)
    +end
    +
    +trained_model = train_model(dataloader)
    Iteration:     1, Loss: 1.893717e-01
    +Iteration:    26, Loss: 3.556251e-02
    +Iteration:    51, Loss: 1.288165e-01
    +Iteration:    76, Loss: 2.463205e-01
    +Iteration:     1, Loss: 2.282736e-01
    +Iteration:     1, Loss: 2.117264e-02
    +Iteration:    26, Loss: 3.948899e-02
    +Iteration:    51, Loss: 2.352137e-02
    +Iteration:    76, Loss: 2.201421e-02
    +Iteration:   101, Loss: 2.090701e-02
    +Iteration:   126, Loss: 1.977806e-02
    +Iteration:   151, Loss: 1.857129e-02
    +Iteration:   176, Loss: 1.735175e-02
    +Iteration:   201, Loss: 1.615999e-02
    +Iteration:   226, Loss: 1.493911e-02
    +Iteration:   251, Loss: 1.362476e-02
    +Iteration:   276, Loss: 1.221552e-02
    +Iteration:   301, Loss: 1.135817e-02
    +Iteration:   326, Loss: 1.075873e-02
    +Iteration:   351, Loss: 9.290738e-03
    +Iteration:   376, Loss: 8.201186e-03
    +Iteration:   401, Loss: 1.741432e-02
    +Iteration:   426, Loss: 7.620634e-03
    +Iteration:   451, Loss: 6.616297e-03
    +Iteration:   476, Loss: 5.912085e-03

    Plotting the results

    julia
    dudt(u, p, t) = trained_model(u, p)
    +prob = ODEProblem(dudt, gdev(u0), (tspan[1], tspan[2]), trained_model.ps)
    +sol = solve(prob, Tsit5(); saveat=t)
    +pred = convert(AbstractArray, sol) |> cdev
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1])
    +    lines!(ax, t, ode_data[1, :]; label=L"u_1(t)", color=:blue, linestyle=:dot, linewidth=4)
    +    lines!(ax, t, ode_data[2, :]; label=L"u_2(t)", color=:red, linestyle=:dot, linewidth=4)
    +    lines!(ax, t, pred[1, :]; label=L"\\hat{u}_1(t)", color=:blue, linewidth=4)
    +    lines!(ax, t, pred[2, :]; label=L"\\hat{u}_2(t)", color=:red, linewidth=4)
    +    axislegend(ax; position=:lt)
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.484 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,29)]))}const g=s(t,[["render",p]]);export{d as __pageData,g as default}; diff --git a/previews/PR1023/assets/tutorials_index.md.amQ7-phS.js b/previews/PR1023/assets/tutorials_index.md.amQ7-phS.js new file mode 100644 index 0000000000..f358cfd60e --- /dev/null +++ b/previews/PR1023/assets/tutorials_index.md.amQ7-phS.js @@ -0,0 +1 @@ +import{d,o as r,c as n,j as e,k as f,g as b,t as p,_ as m,F as _,C as w,b as v,K as x,a,G as s}from"./chunks/framework.DFwXuivk.js";const y={class:"img-box"},N=["href"],D=["src"],L={class:"transparent-box1"},P={class:"caption"},T={class:"transparent-box2"},I={class:"subcaption"},k={class:"opacity-low"},C=d({__name:"GalleryImage",props:{href:{},src:{},caption:{},desc:{}},setup(u){return(i,l)=>(r(),n("div",y,[e("a",{href:i.href},[e("img",{src:f(b)(i.src),height:"150px",alt:""},null,8,D),e("div",L,[e("div",P,[e("h2",null,p(i.caption),1)])]),e("div",T,[e("div",I,[e("p",k,p(i.desc),1)])])],8,N)]))}}),j=m(C,[["__scopeId","data-v-06a0366f"]]),S={class:"gallery-image"},E=d({__name:"Gallery",props:{images:{}},setup(u){return(i,l)=>(r(),n("div",S,[(r(!0),n(_,null,w(i.images,c=>(r(),v(j,x({ref_for:!0},c),null,16))),256))]))}}),o=m(E,[["__scopeId","data-v-578d61bc"]]),F=JSON.parse('{"title":"Tutorials","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/index.md","filePath":"tutorials/index.md","lastUpdated":null}'),M={name:"tutorials/index.md"},O=d({...M,setup(u){const i=[{href:"beginner/1_Basics",src:"https://picsum.photos/350/250?image=444",caption:"Julia & Lux for the Uninitiated",desc:"How to get started with Julia and Lux for those who have never used Julia before."},{href:"beginner/2_PolynomialFitting",src:"../mlp.webp",caption:"Fitting a Polynomial using MLP",desc:"Learn the Basics of Lux by fitting a Multi-Layer Perceptron to a Polynomial."},{href:"beginner/3_SimpleRNN",src:"../lstm-illustrative.webp",caption:"Training a Simple LSTM",desc:"Learn how to define custom layers and train an RNN on time-series data."},{href:"beginner/4_SimpleChains",src:"../blas_optimizations.jpg",caption:"Use SimpleChains.jl as a Backend",desc:"Learn how to train small neural networks really fast on CPU."},{href:"beginner/5_OptimizationIntegration",src:"../optimization_integration.png",caption:"Fitting with Optimization.jl",desc:"Learn how to use Optimization.jl with Lux (on GPUs)."},{href:"https://luxdl.github.io/Boltz.jl/stable/tutorials/1_GettingStarted",src:"https://production-media.paperswithcode.com/datasets/ImageNet-0000000008-f2e87edd_Y0fT5zg.jpg",caption:"Pre-Built Deep Learning Models",desc:"Use Boltz.jl to load pre-built DL and SciML models."}],l=[{href:"intermediate/1_NeuralODE",src:"../mnist.jpg",caption:"MNIST Classification using Neural ODE",desc:"Train a Neural Ordinary Differential Equations to classify MNIST Images."},{href:"intermediate/2_BayesianNN",src:"https://github.com/TuringLang.png",caption:"Bayesian Neural Networks",desc:"Figure out how to use Probabilistic Programming Frameworks like Turing with Lux."},{href:"intermediate/3_HyperNet",src:"../hypernet.jpg",caption:"Training a HyperNetwork",desc:"Train a hypernetwork to work on multiple datasets by predicting NN parameters."},{href:"intermediate/4_PINN2DPDE",src:"../pinn_nested_ad.gif",caption:"Training a PINN",desc:"Train a PINN to solve 2D PDEs (using Nested AD)."}],c=[{href:"advanced/1_GravitationalWaveForm",src:"../gravitational_waveform.png",caption:"Neural ODE to Model Gravitational Waveforms",desc:"Training a Neural ODE to fit simulated data of gravitational waveforms."},{href:"https://luxdl.github.io/Boltz.jl/stable/tutorials/2_SymbolicOptimalControl",src:"../symbolic_optimal_control.png",caption:"Optimal Control with Symbolic UDE",desc:"Train a UDE and replace a part of it with Symbolic Regression."}],h=[{href:"https://github.com/LuxDL/Lux.jl/tree/main/examples/ImageNet",src:"https://production-media.paperswithcode.com/datasets/ImageNet-0000000008-f2e87edd_Y0fT5zg.jpg",caption:"ImageNet Classification",desc:"Train Large Image Classifiers using Lux (on Distributed GPUs)."},{href:"https://github.com/LuxDL/Lux.jl/tree/main/examples/DDIM",src:"https://raw.githubusercontent.com/LuxDL/Lux.jl/main/examples/DDIM/assets/flowers_generated.png",caption:"Denoising Diffusion Implicit Model (DDIM)",desc:"Train a Diffusion Model to generate images from Gaussian noises."},{href:"https://github.com/LuxDL/Lux.jl/tree/main/examples/ConvMixer",src:"https://datasets.activeloop.ai/wp-content/uploads/2022/09/CIFAR-10-dataset-Activeloop-Platform-visualization-image-1.webp",caption:"ConvMixer on CIFAR-10",desc:"Train ConvMixer on CIFAR-10 to 90% accuracy within 10 minutes."}],g=[{href:"https://docs.sciml.ai/Overview/stable/showcase/pinngpu/",src:"../pinn.gif",caption:"GPU-Accelerated Physics-Informed Neural Networks",desc:"Use Machine Learning (PINNs) to solve the Heat Equation PDE on a GPU."},{href:"https://docs.sciml.ai/DiffEqFlux/stable/examples/neural_ode_weather_forecast/",src:"../weather-neural-ode.gif",caption:"Weather Forecasting with Neural ODEs",desc:"Train a neural ODEs to a multidimensional weather dataset and use it for weather forecasting."},{href:"https://docs.sciml.ai/SciMLSensitivity/stable/examples/sde/SDE_control/",src:"../neural-sde.png",caption:"Controlling Stochastic Differential Equations",desc:"Control the time evolution of a continuously monitored qubit described by an SDE with multiplicative scalar noise."},{href:"https://github.com/Dale-Black/ComputerVisionTutorials.jl/",src:"https://raw.githubusercontent.com/Dale-Black/ComputerVisionTutorials.jl/main/assets/image-seg-green.jpeg",caption:"Medical Image Segmentation",desc:"Explore various aspects of deep learning for medical imaging and a comprehensive overview of Julia packages."},{href:"https://github.com/agdestein/NeuralClosureTutorials",src:"https://raw.githubusercontent.com/agdestein/NeuralClosureTutorials/main/assets/navier_stokes.gif",caption:"Neural PDE closures",desc:"Learn an unknown term in a PDE using convolutional neural networks and Fourier neural operators."}];return(B,t)=>(r(),n("div",null,[t[0]||(t[0]=e("h1",{id:"tutorials",tabindex:"-1"},[a("Tutorials "),e("a",{class:"header-anchor",href:"#tutorials","aria-label":'Permalink to "Tutorials"'},"​")],-1)),t[1]||(t[1]=e("h2",{id:"beginner-tutorials",tabindex:"-1"},[a("Beginner Tutorials "),e("a",{class:"header-anchor",href:"#beginner-tutorials","aria-label":'Permalink to "Beginner Tutorials"'},"​")],-1)),s(o,{images:i}),t[2]||(t[2]=e("h2",{id:"intermediate-tutorials",tabindex:"-1"},[a("Intermediate Tutorials "),e("a",{class:"header-anchor",href:"#intermediate-tutorials","aria-label":'Permalink to "Intermediate Tutorials"'},"​")],-1)),s(o,{images:l}),t[3]||(t[3]=e("h2",{id:"advanced-tutorials",tabindex:"-1"},[a("Advanced Tutorials "),e("a",{class:"header-anchor",href:"#advanced-tutorials","aria-label":'Permalink to "Advanced Tutorials"'},"​")],-1)),s(o,{images:c}),t[4]||(t[4]=e("h2",{id:"larger-models",tabindex:"-1"},[a("Larger Models "),e("a",{class:"header-anchor",href:"#larger-models","aria-label":'Permalink to "Larger Models"'},"​")],-1)),t[5]||(t[5]=e("div",{class:"warning custom-block"},[e("p",{class:"custom-block-title"},"WARNING"),e("p",null,"These models are part of the Lux examples, however, these are larger model that cannot be run on CI and aren't frequently tested. If you find a bug in one of these models, please open an issue or PR to fix it.")],-1)),s(o,{images:h}),t[6]||(t[6]=e("h2",{id:"selected-3rd-party-tutorials",tabindex:"-1"},[a("Selected 3rd Party Tutorials "),e("a",{class:"header-anchor",href:"#selected-3rd-party-tutorials","aria-label":'Permalink to "Selected 3rd Party Tutorials"'},"​")],-1)),t[7]||(t[7]=e("div",{class:"warning custom-block"},[e("p",{class:"custom-block-title"},"WARNING"),e("p",null,[a("These tutorials are developed by the community and may not be up-to-date with the latest version of "),e("code",null,"Lux.jl"),a(". Please refer to the official documentation for the most up-to-date information.")]),e("p",null,[a("Please open an issue (ideally both at "),e("code",null,"Lux.jl"),a(" and at the downstream linked package) if any of them are non-functional and we will try to get them updated.")])],-1)),s(o,{images:g}),t[8]||(t[8]=e("div",{class:"tip custom-block"},[e("p",{class:"custom-block-title"},"TIP"),e("p",null,[a("If you found an amazing tutorial showcasing "),e("code",null,"Lux.jl"),a(" online, or wrote one yourself, please open an issue or PR to add it to the list!")])],-1))]))}});export{F as __pageData,O as default}; diff --git a/previews/PR1023/assets/tutorials_index.md.amQ7-phS.lean.js b/previews/PR1023/assets/tutorials_index.md.amQ7-phS.lean.js new file mode 100644 index 0000000000..f358cfd60e --- /dev/null +++ b/previews/PR1023/assets/tutorials_index.md.amQ7-phS.lean.js @@ -0,0 +1 @@ +import{d,o as r,c as n,j as e,k as f,g as b,t as p,_ as m,F as _,C as w,b as v,K as x,a,G as s}from"./chunks/framework.DFwXuivk.js";const y={class:"img-box"},N=["href"],D=["src"],L={class:"transparent-box1"},P={class:"caption"},T={class:"transparent-box2"},I={class:"subcaption"},k={class:"opacity-low"},C=d({__name:"GalleryImage",props:{href:{},src:{},caption:{},desc:{}},setup(u){return(i,l)=>(r(),n("div",y,[e("a",{href:i.href},[e("img",{src:f(b)(i.src),height:"150px",alt:""},null,8,D),e("div",L,[e("div",P,[e("h2",null,p(i.caption),1)])]),e("div",T,[e("div",I,[e("p",k,p(i.desc),1)])])],8,N)]))}}),j=m(C,[["__scopeId","data-v-06a0366f"]]),S={class:"gallery-image"},E=d({__name:"Gallery",props:{images:{}},setup(u){return(i,l)=>(r(),n("div",S,[(r(!0),n(_,null,w(i.images,c=>(r(),v(j,x({ref_for:!0},c),null,16))),256))]))}}),o=m(E,[["__scopeId","data-v-578d61bc"]]),F=JSON.parse('{"title":"Tutorials","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/index.md","filePath":"tutorials/index.md","lastUpdated":null}'),M={name:"tutorials/index.md"},O=d({...M,setup(u){const i=[{href:"beginner/1_Basics",src:"https://picsum.photos/350/250?image=444",caption:"Julia & Lux for the Uninitiated",desc:"How to get started with Julia and Lux for those who have never used Julia before."},{href:"beginner/2_PolynomialFitting",src:"../mlp.webp",caption:"Fitting a Polynomial using MLP",desc:"Learn the Basics of Lux by fitting a Multi-Layer Perceptron to a Polynomial."},{href:"beginner/3_SimpleRNN",src:"../lstm-illustrative.webp",caption:"Training a Simple LSTM",desc:"Learn how to define custom layers and train an RNN on time-series data."},{href:"beginner/4_SimpleChains",src:"../blas_optimizations.jpg",caption:"Use SimpleChains.jl as a Backend",desc:"Learn how to train small neural networks really fast on CPU."},{href:"beginner/5_OptimizationIntegration",src:"../optimization_integration.png",caption:"Fitting with Optimization.jl",desc:"Learn how to use Optimization.jl with Lux (on GPUs)."},{href:"https://luxdl.github.io/Boltz.jl/stable/tutorials/1_GettingStarted",src:"https://production-media.paperswithcode.com/datasets/ImageNet-0000000008-f2e87edd_Y0fT5zg.jpg",caption:"Pre-Built Deep Learning Models",desc:"Use Boltz.jl to load pre-built DL and SciML models."}],l=[{href:"intermediate/1_NeuralODE",src:"../mnist.jpg",caption:"MNIST Classification using Neural ODE",desc:"Train a Neural Ordinary Differential Equations to classify MNIST Images."},{href:"intermediate/2_BayesianNN",src:"https://github.com/TuringLang.png",caption:"Bayesian Neural Networks",desc:"Figure out how to use Probabilistic Programming Frameworks like Turing with Lux."},{href:"intermediate/3_HyperNet",src:"../hypernet.jpg",caption:"Training a HyperNetwork",desc:"Train a hypernetwork to work on multiple datasets by predicting NN parameters."},{href:"intermediate/4_PINN2DPDE",src:"../pinn_nested_ad.gif",caption:"Training a PINN",desc:"Train a PINN to solve 2D PDEs (using Nested AD)."}],c=[{href:"advanced/1_GravitationalWaveForm",src:"../gravitational_waveform.png",caption:"Neural ODE to Model Gravitational Waveforms",desc:"Training a Neural ODE to fit simulated data of gravitational waveforms."},{href:"https://luxdl.github.io/Boltz.jl/stable/tutorials/2_SymbolicOptimalControl",src:"../symbolic_optimal_control.png",caption:"Optimal Control with Symbolic UDE",desc:"Train a UDE and replace a part of it with Symbolic Regression."}],h=[{href:"https://github.com/LuxDL/Lux.jl/tree/main/examples/ImageNet",src:"https://production-media.paperswithcode.com/datasets/ImageNet-0000000008-f2e87edd_Y0fT5zg.jpg",caption:"ImageNet Classification",desc:"Train Large Image Classifiers using Lux (on Distributed GPUs)."},{href:"https://github.com/LuxDL/Lux.jl/tree/main/examples/DDIM",src:"https://raw.githubusercontent.com/LuxDL/Lux.jl/main/examples/DDIM/assets/flowers_generated.png",caption:"Denoising Diffusion Implicit Model (DDIM)",desc:"Train a Diffusion Model to generate images from Gaussian noises."},{href:"https://github.com/LuxDL/Lux.jl/tree/main/examples/ConvMixer",src:"https://datasets.activeloop.ai/wp-content/uploads/2022/09/CIFAR-10-dataset-Activeloop-Platform-visualization-image-1.webp",caption:"ConvMixer on CIFAR-10",desc:"Train ConvMixer on CIFAR-10 to 90% accuracy within 10 minutes."}],g=[{href:"https://docs.sciml.ai/Overview/stable/showcase/pinngpu/",src:"../pinn.gif",caption:"GPU-Accelerated Physics-Informed Neural Networks",desc:"Use Machine Learning (PINNs) to solve the Heat Equation PDE on a GPU."},{href:"https://docs.sciml.ai/DiffEqFlux/stable/examples/neural_ode_weather_forecast/",src:"../weather-neural-ode.gif",caption:"Weather Forecasting with Neural ODEs",desc:"Train a neural ODEs to a multidimensional weather dataset and use it for weather forecasting."},{href:"https://docs.sciml.ai/SciMLSensitivity/stable/examples/sde/SDE_control/",src:"../neural-sde.png",caption:"Controlling Stochastic Differential Equations",desc:"Control the time evolution of a continuously monitored qubit described by an SDE with multiplicative scalar noise."},{href:"https://github.com/Dale-Black/ComputerVisionTutorials.jl/",src:"https://raw.githubusercontent.com/Dale-Black/ComputerVisionTutorials.jl/main/assets/image-seg-green.jpeg",caption:"Medical Image Segmentation",desc:"Explore various aspects of deep learning for medical imaging and a comprehensive overview of Julia packages."},{href:"https://github.com/agdestein/NeuralClosureTutorials",src:"https://raw.githubusercontent.com/agdestein/NeuralClosureTutorials/main/assets/navier_stokes.gif",caption:"Neural PDE closures",desc:"Learn an unknown term in a PDE using convolutional neural networks and Fourier neural operators."}];return(B,t)=>(r(),n("div",null,[t[0]||(t[0]=e("h1",{id:"tutorials",tabindex:"-1"},[a("Tutorials "),e("a",{class:"header-anchor",href:"#tutorials","aria-label":'Permalink to "Tutorials"'},"​")],-1)),t[1]||(t[1]=e("h2",{id:"beginner-tutorials",tabindex:"-1"},[a("Beginner Tutorials "),e("a",{class:"header-anchor",href:"#beginner-tutorials","aria-label":'Permalink to "Beginner Tutorials"'},"​")],-1)),s(o,{images:i}),t[2]||(t[2]=e("h2",{id:"intermediate-tutorials",tabindex:"-1"},[a("Intermediate Tutorials "),e("a",{class:"header-anchor",href:"#intermediate-tutorials","aria-label":'Permalink to "Intermediate Tutorials"'},"​")],-1)),s(o,{images:l}),t[3]||(t[3]=e("h2",{id:"advanced-tutorials",tabindex:"-1"},[a("Advanced Tutorials "),e("a",{class:"header-anchor",href:"#advanced-tutorials","aria-label":'Permalink to "Advanced Tutorials"'},"​")],-1)),s(o,{images:c}),t[4]||(t[4]=e("h2",{id:"larger-models",tabindex:"-1"},[a("Larger Models "),e("a",{class:"header-anchor",href:"#larger-models","aria-label":'Permalink to "Larger Models"'},"​")],-1)),t[5]||(t[5]=e("div",{class:"warning custom-block"},[e("p",{class:"custom-block-title"},"WARNING"),e("p",null,"These models are part of the Lux examples, however, these are larger model that cannot be run on CI and aren't frequently tested. If you find a bug in one of these models, please open an issue or PR to fix it.")],-1)),s(o,{images:h}),t[6]||(t[6]=e("h2",{id:"selected-3rd-party-tutorials",tabindex:"-1"},[a("Selected 3rd Party Tutorials "),e("a",{class:"header-anchor",href:"#selected-3rd-party-tutorials","aria-label":'Permalink to "Selected 3rd Party Tutorials"'},"​")],-1)),t[7]||(t[7]=e("div",{class:"warning custom-block"},[e("p",{class:"custom-block-title"},"WARNING"),e("p",null,[a("These tutorials are developed by the community and may not be up-to-date with the latest version of "),e("code",null,"Lux.jl"),a(". Please refer to the official documentation for the most up-to-date information.")]),e("p",null,[a("Please open an issue (ideally both at "),e("code",null,"Lux.jl"),a(" and at the downstream linked package) if any of them are non-functional and we will try to get them updated.")])],-1)),s(o,{images:g}),t[8]||(t[8]=e("div",{class:"tip custom-block"},[e("p",{class:"custom-block-title"},"TIP"),e("p",null,[a("If you found an amazing tutorial showcasing "),e("code",null,"Lux.jl"),a(" online, or wrote one yourself, please open an issue or PR to add it to the list!")])],-1))]))}});export{F as __pageData,O as default}; diff --git a/previews/PR1023/assets/tutorials_intermediate_1_NeuralODE.md.C9riTwge.js b/previews/PR1023/assets/tutorials_intermediate_1_NeuralODE.md.C9riTwge.js new file mode 100644 index 0000000000..9ac270633b --- /dev/null +++ b/previews/PR1023/assets/tutorials_intermediate_1_NeuralODE.md.C9riTwge.js @@ -0,0 +1,272 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const E=JSON.parse('{"title":"MNIST Classification using Neural ODEs","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/intermediate/1_NeuralODE.md","filePath":"tutorials/intermediate/1_NeuralODE.md","lastUpdated":null}'),e={name:"tutorials/intermediate/1_NeuralODE.md"};function l(p,s,h,k,r,d){return t(),a("div",null,s[0]||(s[0]=[n(`

    MNIST Classification using Neural ODEs

    To understand Neural ODEs, users should look up these lecture notes. We recommend users to directly use DiffEqFlux.jl, instead of implementing Neural ODEs from scratch.

    Package Imports

    julia
    using Lux, ComponentArrays, SciMLSensitivity, LuxCUDA, Optimisers, OrdinaryDiffEqTsit5,
    +      Random, Statistics, Zygote, OneHotArrays, InteractiveUtils, Printf
    +using MLDatasets: MNIST
    +using MLUtils: DataLoader, splitobs
    +
    +CUDA.allowscalar(false)

    Loading MNIST

    julia
    function loadmnist(batchsize, train_split)
    +    # Load MNIST: Only 1500 for demonstration purposes
    +    N = 1500
    +    dataset = MNIST(; split=:train)
    +    imgs = dataset.features[:, :, 1:N]
    +    labels_raw = dataset.targets[1:N]
    +
    +    # Process images into (H,W,C,BS) batches
    +    x_data = Float32.(reshape(imgs, size(imgs, 1), size(imgs, 2), 1, size(imgs, 3)))
    +    y_data = onehotbatch(labels_raw, 0:9)
    +    (x_train, y_train), (x_test, y_test) = splitobs((x_data, y_data); at=train_split)
    +
    +    return (
    +        # Use DataLoader to automatically minibatch and shuffle the data
    +        DataLoader(collect.((x_train, y_train)); batchsize, shuffle=true),
    +        # Don't shuffle the test data
    +        DataLoader(collect.((x_test, y_test)); batchsize, shuffle=false)
    +    )
    +end
    loadmnist (generic function with 1 method)

    Define the Neural ODE Layer

    First we will use the @compact macro to define the Neural ODE Layer.

    julia
    function NeuralODECompact(
    +        model::Lux.AbstractLuxLayer; solver=Tsit5(), tspan=(0.0f0, 1.0f0), kwargs...)
    +    return @compact(; model, solver, tspan, kwargs...) do x, p
    +        dudt(u, p, t) = vec(model(reshape(u, size(x)), p))
    +        # Note the \`p.model\` here
    +        prob = ODEProblem(ODEFunction{false}(dudt), vec(x), tspan, p.model)
    +        @return solve(prob, solver; kwargs...)
    +    end
    +end
    NeuralODECompact (generic function with 1 method)

    We recommend using the compact macro for creating custom layers. The below implementation exists mostly for historical reasons when @compact was not part of the stable API. Also, it helps users understand how the layer interface of Lux works.

    The NeuralODE is a ContainerLayer, which stores a model. The parameters and states of the NeuralODE are same as those of the underlying model.

    julia
    struct NeuralODE{M <: Lux.AbstractLuxLayer, So, T, K} <: Lux.AbstractLuxWrapperLayer{:model}
    +    model::M
    +    solver::So
    +    tspan::T
    +    kwargs::K
    +end
    +
    +function NeuralODE(
    +        model::Lux.AbstractLuxLayer; solver=Tsit5(), tspan=(0.0f0, 1.0f0), kwargs...)
    +    return NeuralODE(model, solver, tspan, kwargs)
    +end
    Main.var"##225".NeuralODE

    OrdinaryDiffEq.jl can deal with non-Vector Inputs! However, certain discrete sensitivities like ReverseDiffAdjoint can't handle non-Vector inputs. Hence, we need to convert the input and output of the ODE solver to a Vector.

    julia
    function (n::NeuralODE)(x, ps, st)
    +    function dudt(u, p, t)
    +        u_, st = n.model(reshape(u, size(x)), p, st)
    +        return vec(u_)
    +    end
    +    prob = ODEProblem{false}(ODEFunction{false}(dudt), vec(x), n.tspan, ps)
    +    return solve(prob, n.solver; n.kwargs...), st
    +end
    +
    +@views diffeqsol_to_array(l::Int, x::ODESolution) = reshape(last(x.u), (l, :))
    +@views diffeqsol_to_array(l::Int, x::AbstractMatrix) = reshape(x[:, end], (l, :))
    diffeqsol_to_array (generic function with 2 methods)

    Create and Initialize the Neural ODE Layer

    julia
    function create_model(model_fn=NeuralODE; dev=gpu_device(), use_named_tuple::Bool=false,
    +        sensealg=InterpolatingAdjoint(; autojacvec=ZygoteVJP()))
    +    # Construct the Neural ODE Model
    +    model = Chain(FlattenLayer(),
    +        Dense(784 => 20, tanh),
    +        model_fn(
    +            Chain(Dense(20 => 10, tanh), Dense(10 => 10, tanh), Dense(10 => 20, tanh));
    +            save_everystep=false, reltol=1.0f-3,
    +            abstol=1.0f-3, save_start=false, sensealg),
    +        Base.Fix1(diffeqsol_to_array, 20),
    +        Dense(20 => 10))
    +
    +    rng = Random.default_rng()
    +    Random.seed!(rng, 0)
    +
    +    ps, st = Lux.setup(rng, model)
    +    ps = (use_named_tuple ? ps : ComponentArray(ps)) |> dev
    +    st = st |> dev
    +
    +    return model, ps, st
    +end
    create_model (generic function with 2 methods)

    Define Utility Functions

    julia
    const logitcrossentropy = CrossEntropyLoss(; logits=Val(true))
    +
    +function accuracy(model, ps, st, dataloader)
    +    total_correct, total = 0, 0
    +    st = Lux.testmode(st)
    +    for (x, y) in dataloader
    +        target_class = onecold(y)
    +        predicted_class = onecold(first(model(x, ps, st)))
    +        total_correct += sum(target_class .== predicted_class)
    +        total += length(target_class)
    +    end
    +    return total_correct / total
    +end
    accuracy (generic function with 1 method)

    Training

    julia
    function train(model_function; cpu::Bool=false, kwargs...)
    +    dev = cpu ? cpu_device() : gpu_device()
    +    model, ps, st = create_model(model_function; dev, kwargs...)
    +
    +    # Training
    +    train_dataloader, test_dataloader = loadmnist(128, 0.9) |> dev
    +
    +    tstate = Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    ### Lets train the model
    +    nepochs = 9
    +    for epoch in 1:nepochs
    +        stime = time()
    +        for (x, y) in train_dataloader
    +            _, _, _, tstate = Training.single_train_step!(
    +                AutoZygote(), logitcrossentropy, (x, y), tstate)
    +        end
    +        ttime = time() - stime
    +
    +        tr_acc = accuracy(model, tstate.parameters, tstate.states, train_dataloader) * 100
    +        te_acc = accuracy(model, tstate.parameters, tstate.states, test_dataloader) * 100
    +        @printf "[%d/%d]\\tTime %.4fs\\tTraining Accuracy: %.5f%%\\tTest \\
    +                 Accuracy: %.5f%%\\n" epoch nepochs ttime tr_acc te_acc
    +    end
    +end
    +
    +train(NeuralODECompact)
    [1/9]	Time 119.4158s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.4958s	Training Accuracy: 58.22222%	Test Accuracy: 57.33333%
    +[3/9]	Time 0.6961s	Training Accuracy: 67.85185%	Test Accuracy: 70.66667%
    +[4/9]	Time 0.4869s	Training Accuracy: 74.29630%	Test Accuracy: 74.66667%
    +[5/9]	Time 0.5064s	Training Accuracy: 76.29630%	Test Accuracy: 76.00000%
    +[6/9]	Time 0.7482s	Training Accuracy: 78.74074%	Test Accuracy: 80.00000%
    +[7/9]	Time 0.4736s	Training Accuracy: 82.22222%	Test Accuracy: 81.33333%
    +[8/9]	Time 0.4883s	Training Accuracy: 83.62963%	Test Accuracy: 83.33333%
    +[9/9]	Time 0.7453s	Training Accuracy: 85.18519%	Test Accuracy: 82.66667%
    julia
    train(NeuralODE)
    [1/9]	Time 36.4249s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.4793s	Training Accuracy: 57.18519%	Test Accuracy: 57.33333%
    +[3/9]	Time 0.6545s	Training Accuracy: 68.37037%	Test Accuracy: 68.00000%
    +[4/9]	Time 0.4797s	Training Accuracy: 73.77778%	Test Accuracy: 75.33333%
    +[5/9]	Time 0.4833s	Training Accuracy: 76.14815%	Test Accuracy: 77.33333%
    +[6/9]	Time 0.7233s	Training Accuracy: 79.48148%	Test Accuracy: 80.66667%
    +[7/9]	Time 0.4913s	Training Accuracy: 81.25926%	Test Accuracy: 80.66667%
    +[8/9]	Time 0.4843s	Training Accuracy: 83.40741%	Test Accuracy: 82.66667%
    +[9/9]	Time 0.7256s	Training Accuracy: 84.81481%	Test Accuracy: 82.00000%

    We can also change the sensealg and train the model! GaussAdjoint allows you to use any arbitrary parameter structure and not just a flat vector (ComponentArray).

    julia
    train(NeuralODE; sensealg=GaussAdjoint(; autojacvec=ZygoteVJP()), use_named_tuple=true)
    [1/9]	Time 42.6019s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.5487s	Training Accuracy: 57.55556%	Test Accuracy: 54.00000%
    +[3/9]	Time 0.4660s	Training Accuracy: 69.85185%	Test Accuracy: 69.33333%
    +[4/9]	Time 0.4833s	Training Accuracy: 72.51852%	Test Accuracy: 74.00000%
    +[5/9]	Time 0.4743s	Training Accuracy: 75.33333%	Test Accuracy: 76.00000%
    +[6/9]	Time 0.4944s	Training Accuracy: 78.88889%	Test Accuracy: 79.33333%
    +[7/9]	Time 0.6809s	Training Accuracy: 81.03704%	Test Accuracy: 80.00000%
    +[8/9]	Time 0.4987s	Training Accuracy: 83.77778%	Test Accuracy: 81.33333%
    +[9/9]	Time 0.5045s	Training Accuracy: 85.25926%	Test Accuracy: 82.66667%

    But remember some AD backends like ReverseDiff is not GPU compatible. For a model this size, you will notice that training time is significantly lower for training on CPU than on GPU.

    julia
    train(NeuralODE; sensealg=InterpolatingAdjoint(; autojacvec=ReverseDiffVJP()), cpu=true)
    [1/9]	Time 96.0630s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 14.0172s	Training Accuracy: 58.74074%	Test Accuracy: 56.66667%
    +[3/9]	Time 13.5410s	Training Accuracy: 69.92593%	Test Accuracy: 71.33333%
    +[4/9]	Time 13.6407s	Training Accuracy: 72.81481%	Test Accuracy: 74.00000%
    +[5/9]	Time 13.4329s	Training Accuracy: 76.37037%	Test Accuracy: 78.66667%
    +[6/9]	Time 12.0878s	Training Accuracy: 79.03704%	Test Accuracy: 80.66667%
    +[7/9]	Time 14.5981s	Training Accuracy: 81.62963%	Test Accuracy: 80.66667%
    +[8/9]	Time 13.6945s	Training Accuracy: 83.33333%	Test Accuracy: 80.00000%
    +[9/9]	Time 10.3098s	Training Accuracy: 85.40741%	Test Accuracy: 82.00000%

    For completeness, let's also test out discrete sensitivities!

    julia
    train(NeuralODE; sensealg=ReverseDiffAdjoint(), cpu=true)
    [1/9]	Time 49.7652s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 21.6687s	Training Accuracy: 58.66667%	Test Accuracy: 57.33333%
    +[3/9]	Time 21.5681s	Training Accuracy: 69.70370%	Test Accuracy: 71.33333%
    +[4/9]	Time 21.3427s	Training Accuracy: 72.74074%	Test Accuracy: 74.00000%
    +[5/9]	Time 23.9941s	Training Accuracy: 76.14815%	Test Accuracy: 78.66667%
    +[6/9]	Time 22.0233s	Training Accuracy: 79.03704%	Test Accuracy: 80.66667%
    +[7/9]	Time 22.4246s	Training Accuracy: 81.55556%	Test Accuracy: 80.66667%
    +[8/9]	Time 23.1968s	Training Accuracy: 83.40741%	Test Accuracy: 80.00000%
    +[9/9]	Time 24.0997s	Training Accuracy: 85.25926%	Test Accuracy: 81.33333%

    Alternate Implementation using Stateful Layer

    Starting v0.5.5, Lux provides a StatefulLuxLayer which can be used to avoid the Boxing of st. Using the @compact API avoids this problem entirely.

    julia
    struct StatefulNeuralODE{M <: Lux.AbstractLuxLayer, So, T, K} <:
    +       Lux.AbstractLuxWrapperLayer{:model}
    +    model::M
    +    solver::So
    +    tspan::T
    +    kwargs::K
    +end
    +
    +function StatefulNeuralODE(
    +        model::Lux.AbstractLuxLayer; solver=Tsit5(), tspan=(0.0f0, 1.0f0), kwargs...)
    +    return StatefulNeuralODE(model, solver, tspan, kwargs)
    +end
    +
    +function (n::StatefulNeuralODE)(x, ps, st)
    +    st_model = StatefulLuxLayer{true}(n.model, ps, st)
    +    dudt(u, p, t) = st_model(u, p)
    +    prob = ODEProblem{false}(ODEFunction{false}(dudt), x, n.tspan, ps)
    +    return solve(prob, n.solver; n.kwargs...), st_model.st
    +end

    Train the new Stateful Neural ODE

    julia
    train(StatefulNeuralODE)
    [1/9]	Time 38.2440s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.4759s	Training Accuracy: 58.22222%	Test Accuracy: 55.33333%
    +[3/9]	Time 0.4745s	Training Accuracy: 68.29630%	Test Accuracy: 68.66667%
    +[4/9]	Time 0.4670s	Training Accuracy: 73.11111%	Test Accuracy: 76.00000%
    +[5/9]	Time 0.5117s	Training Accuracy: 75.92593%	Test Accuracy: 76.66667%
    +[6/9]	Time 0.4779s	Training Accuracy: 78.96296%	Test Accuracy: 80.66667%
    +[7/9]	Time 0.4705s	Training Accuracy: 80.81481%	Test Accuracy: 81.33333%
    +[8/9]	Time 0.4590s	Training Accuracy: 83.25926%	Test Accuracy: 82.66667%
    +[9/9]	Time 0.4555s	Training Accuracy: 84.59259%	Test Accuracy: 82.00000%

    We might not see a significant difference in the training time, but let us investigate the type stabilities of the layers.

    Type Stability

    julia
    model, ps, st = create_model(NeuralODE)
    +
    +model_stateful, ps_stateful, st_stateful = create_model(StatefulNeuralODE)
    +
    +x = gpu_device()(ones(Float32, 28, 28, 1, 3));

    NeuralODE is not type stable due to the boxing of st

    julia
    @code_warntype model(x, ps, st)
    MethodInstance for (::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".NeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing})(::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}, ::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}, ::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}})
    +  from (c::Lux.Chain)(x, ps, st::NamedTuple) @ Lux /var/lib/buildkite-agent/builds/gpuci-13/julialang/lux-dot-jl/src/layers/containers.jl:480
    +Arguments
    +  c::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".NeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}
    +  x::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}
    +  ps::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}
    +  st::Core.Const((layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()), layer_4 = NamedTuple(), layer_5 = NamedTuple()))
    +Body::TUPLE{CUDA.CUARRAY{FLOAT32, 2, CUDA.DEVICEMEMORY}, NAMEDTUPLE{(:LAYER_1, :LAYER_2, :LAYER_3, :LAYER_4, :LAYER_5), <:TUPLE{@NAMEDTUPLE{}, @NAMEDTUPLE{}, ANY, @NAMEDTUPLE{}, @NAMEDTUPLE{}}}}
    +1 ─ %1 = Base.getproperty(c, :layers)::@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".NeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}
    +│   %2 = Lux.applychain(%1, x, ps, st)::TUPLE{CUDA.CUARRAY{FLOAT32, 2, CUDA.DEVICEMEMORY}, NAMEDTUPLE{(:LAYER_1, :LAYER_2, :LAYER_3, :LAYER_4, :LAYER_5), <:TUPLE{@NAMEDTUPLE{}, @NAMEDTUPLE{}, ANY, @NAMEDTUPLE{}, @NAMEDTUPLE{}}}}
    +└──      return %2

    We avoid the problem entirely by using StatefulNeuralODE

    julia
    @code_warntype model_stateful(x, ps_stateful, st_stateful)
    MethodInstance for (::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".StatefulNeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing})(::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}, ::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}, ::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}})
    +  from (c::Lux.Chain)(x, ps, st::NamedTuple) @ Lux /var/lib/buildkite-agent/builds/gpuci-13/julialang/lux-dot-jl/src/layers/containers.jl:480
    +Arguments
    +  c::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".StatefulNeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}
    +  x::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}
    +  ps::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}
    +  st::Core.Const((layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()), layer_4 = NamedTuple(), layer_5 = NamedTuple()))
    +Body::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +1 ─ %1 = Base.getproperty(c, :layers)::@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".StatefulNeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}
    +│   %2 = Lux.applychain(%1, x, ps, st)::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +└──      return %2

    Note, that we still recommend using this layer internally and not exposing this as the default API to the users.

    Finally checking the compact model

    julia
    model_compact, ps_compact, st_compact = create_model(NeuralODECompact)
    +
    +@code_warntype model_compact(x, ps_compact, st_compact)
    MethodInstance for (::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.CompactLuxLayer{:₋₋₋no_special_dispatch₋₋₋, Main.var"##225".var"#2#3", Nothing, @NamedTuple{model::Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Lux.CompactMacroImpl.ValueStorage{@NamedTuple{}, @NamedTuple{solver::Returns{OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}}, tspan::Returns{Tuple{Float32, Float32}}}}, Tuple{Tuple{Symbol}, Tuple{Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing})(::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}, ::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(model = ViewAxis(1:540, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))),)), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}, ::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}})
    +  from (c::Lux.Chain)(x, ps, st::NamedTuple) @ Lux /var/lib/buildkite-agent/builds/gpuci-13/julialang/lux-dot-jl/src/layers/containers.jl:480
    +Arguments
    +  c::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.CompactLuxLayer{:₋₋₋no_special_dispatch₋₋₋, Main.var"##225".var"#2#3", Nothing, @NamedTuple{model::Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Lux.CompactMacroImpl.ValueStorage{@NamedTuple{}, @NamedTuple{solver::Returns{OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}}, tspan::Returns{Tuple{Float32, Float32}}}}, Tuple{Tuple{Symbol}, Tuple{Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}
    +  x::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}
    +  ps::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(model = ViewAxis(1:540, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))),)), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}
    +  st::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}
    +Body::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +1 ─ %1 = Base.getproperty(c, :layers)::@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.CompactLuxLayer{:₋₋₋no_special_dispatch₋₋₋, Main.var"##225".var"#2#3", Nothing, @NamedTuple{model::Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Lux.CompactMacroImpl.ValueStorage{@NamedTuple{}, @NamedTuple{solver::Returns{OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}}, tspan::Returns{Tuple{Float32, Float32}}}}, Tuple{Tuple{Symbol}, Tuple{Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}
    +│   %2 = Lux.applychain(%1, x, ps, st)::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +└──      return %2

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 3.889 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,62)]))}const o=i(e,[["render",l]]);export{E as __pageData,o as default}; diff --git a/previews/PR1023/assets/tutorials_intermediate_1_NeuralODE.md.C9riTwge.lean.js b/previews/PR1023/assets/tutorials_intermediate_1_NeuralODE.md.C9riTwge.lean.js new file mode 100644 index 0000000000..9ac270633b --- /dev/null +++ b/previews/PR1023/assets/tutorials_intermediate_1_NeuralODE.md.C9riTwge.lean.js @@ -0,0 +1,272 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const E=JSON.parse('{"title":"MNIST Classification using Neural ODEs","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/intermediate/1_NeuralODE.md","filePath":"tutorials/intermediate/1_NeuralODE.md","lastUpdated":null}'),e={name:"tutorials/intermediate/1_NeuralODE.md"};function l(p,s,h,k,r,d){return t(),a("div",null,s[0]||(s[0]=[n(`

    MNIST Classification using Neural ODEs

    To understand Neural ODEs, users should look up these lecture notes. We recommend users to directly use DiffEqFlux.jl, instead of implementing Neural ODEs from scratch.

    Package Imports

    julia
    using Lux, ComponentArrays, SciMLSensitivity, LuxCUDA, Optimisers, OrdinaryDiffEqTsit5,
    +      Random, Statistics, Zygote, OneHotArrays, InteractiveUtils, Printf
    +using MLDatasets: MNIST
    +using MLUtils: DataLoader, splitobs
    +
    +CUDA.allowscalar(false)

    Loading MNIST

    julia
    function loadmnist(batchsize, train_split)
    +    # Load MNIST: Only 1500 for demonstration purposes
    +    N = 1500
    +    dataset = MNIST(; split=:train)
    +    imgs = dataset.features[:, :, 1:N]
    +    labels_raw = dataset.targets[1:N]
    +
    +    # Process images into (H,W,C,BS) batches
    +    x_data = Float32.(reshape(imgs, size(imgs, 1), size(imgs, 2), 1, size(imgs, 3)))
    +    y_data = onehotbatch(labels_raw, 0:9)
    +    (x_train, y_train), (x_test, y_test) = splitobs((x_data, y_data); at=train_split)
    +
    +    return (
    +        # Use DataLoader to automatically minibatch and shuffle the data
    +        DataLoader(collect.((x_train, y_train)); batchsize, shuffle=true),
    +        # Don't shuffle the test data
    +        DataLoader(collect.((x_test, y_test)); batchsize, shuffle=false)
    +    )
    +end
    loadmnist (generic function with 1 method)

    Define the Neural ODE Layer

    First we will use the @compact macro to define the Neural ODE Layer.

    julia
    function NeuralODECompact(
    +        model::Lux.AbstractLuxLayer; solver=Tsit5(), tspan=(0.0f0, 1.0f0), kwargs...)
    +    return @compact(; model, solver, tspan, kwargs...) do x, p
    +        dudt(u, p, t) = vec(model(reshape(u, size(x)), p))
    +        # Note the \`p.model\` here
    +        prob = ODEProblem(ODEFunction{false}(dudt), vec(x), tspan, p.model)
    +        @return solve(prob, solver; kwargs...)
    +    end
    +end
    NeuralODECompact (generic function with 1 method)

    We recommend using the compact macro for creating custom layers. The below implementation exists mostly for historical reasons when @compact was not part of the stable API. Also, it helps users understand how the layer interface of Lux works.

    The NeuralODE is a ContainerLayer, which stores a model. The parameters and states of the NeuralODE are same as those of the underlying model.

    julia
    struct NeuralODE{M <: Lux.AbstractLuxLayer, So, T, K} <: Lux.AbstractLuxWrapperLayer{:model}
    +    model::M
    +    solver::So
    +    tspan::T
    +    kwargs::K
    +end
    +
    +function NeuralODE(
    +        model::Lux.AbstractLuxLayer; solver=Tsit5(), tspan=(0.0f0, 1.0f0), kwargs...)
    +    return NeuralODE(model, solver, tspan, kwargs)
    +end
    Main.var"##225".NeuralODE

    OrdinaryDiffEq.jl can deal with non-Vector Inputs! However, certain discrete sensitivities like ReverseDiffAdjoint can't handle non-Vector inputs. Hence, we need to convert the input and output of the ODE solver to a Vector.

    julia
    function (n::NeuralODE)(x, ps, st)
    +    function dudt(u, p, t)
    +        u_, st = n.model(reshape(u, size(x)), p, st)
    +        return vec(u_)
    +    end
    +    prob = ODEProblem{false}(ODEFunction{false}(dudt), vec(x), n.tspan, ps)
    +    return solve(prob, n.solver; n.kwargs...), st
    +end
    +
    +@views diffeqsol_to_array(l::Int, x::ODESolution) = reshape(last(x.u), (l, :))
    +@views diffeqsol_to_array(l::Int, x::AbstractMatrix) = reshape(x[:, end], (l, :))
    diffeqsol_to_array (generic function with 2 methods)

    Create and Initialize the Neural ODE Layer

    julia
    function create_model(model_fn=NeuralODE; dev=gpu_device(), use_named_tuple::Bool=false,
    +        sensealg=InterpolatingAdjoint(; autojacvec=ZygoteVJP()))
    +    # Construct the Neural ODE Model
    +    model = Chain(FlattenLayer(),
    +        Dense(784 => 20, tanh),
    +        model_fn(
    +            Chain(Dense(20 => 10, tanh), Dense(10 => 10, tanh), Dense(10 => 20, tanh));
    +            save_everystep=false, reltol=1.0f-3,
    +            abstol=1.0f-3, save_start=false, sensealg),
    +        Base.Fix1(diffeqsol_to_array, 20),
    +        Dense(20 => 10))
    +
    +    rng = Random.default_rng()
    +    Random.seed!(rng, 0)
    +
    +    ps, st = Lux.setup(rng, model)
    +    ps = (use_named_tuple ? ps : ComponentArray(ps)) |> dev
    +    st = st |> dev
    +
    +    return model, ps, st
    +end
    create_model (generic function with 2 methods)

    Define Utility Functions

    julia
    const logitcrossentropy = CrossEntropyLoss(; logits=Val(true))
    +
    +function accuracy(model, ps, st, dataloader)
    +    total_correct, total = 0, 0
    +    st = Lux.testmode(st)
    +    for (x, y) in dataloader
    +        target_class = onecold(y)
    +        predicted_class = onecold(first(model(x, ps, st)))
    +        total_correct += sum(target_class .== predicted_class)
    +        total += length(target_class)
    +    end
    +    return total_correct / total
    +end
    accuracy (generic function with 1 method)

    Training

    julia
    function train(model_function; cpu::Bool=false, kwargs...)
    +    dev = cpu ? cpu_device() : gpu_device()
    +    model, ps, st = create_model(model_function; dev, kwargs...)
    +
    +    # Training
    +    train_dataloader, test_dataloader = loadmnist(128, 0.9) |> dev
    +
    +    tstate = Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    ### Lets train the model
    +    nepochs = 9
    +    for epoch in 1:nepochs
    +        stime = time()
    +        for (x, y) in train_dataloader
    +            _, _, _, tstate = Training.single_train_step!(
    +                AutoZygote(), logitcrossentropy, (x, y), tstate)
    +        end
    +        ttime = time() - stime
    +
    +        tr_acc = accuracy(model, tstate.parameters, tstate.states, train_dataloader) * 100
    +        te_acc = accuracy(model, tstate.parameters, tstate.states, test_dataloader) * 100
    +        @printf "[%d/%d]\\tTime %.4fs\\tTraining Accuracy: %.5f%%\\tTest \\
    +                 Accuracy: %.5f%%\\n" epoch nepochs ttime tr_acc te_acc
    +    end
    +end
    +
    +train(NeuralODECompact)
    [1/9]	Time 119.4158s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.4958s	Training Accuracy: 58.22222%	Test Accuracy: 57.33333%
    +[3/9]	Time 0.6961s	Training Accuracy: 67.85185%	Test Accuracy: 70.66667%
    +[4/9]	Time 0.4869s	Training Accuracy: 74.29630%	Test Accuracy: 74.66667%
    +[5/9]	Time 0.5064s	Training Accuracy: 76.29630%	Test Accuracy: 76.00000%
    +[6/9]	Time 0.7482s	Training Accuracy: 78.74074%	Test Accuracy: 80.00000%
    +[7/9]	Time 0.4736s	Training Accuracy: 82.22222%	Test Accuracy: 81.33333%
    +[8/9]	Time 0.4883s	Training Accuracy: 83.62963%	Test Accuracy: 83.33333%
    +[9/9]	Time 0.7453s	Training Accuracy: 85.18519%	Test Accuracy: 82.66667%
    julia
    train(NeuralODE)
    [1/9]	Time 36.4249s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.4793s	Training Accuracy: 57.18519%	Test Accuracy: 57.33333%
    +[3/9]	Time 0.6545s	Training Accuracy: 68.37037%	Test Accuracy: 68.00000%
    +[4/9]	Time 0.4797s	Training Accuracy: 73.77778%	Test Accuracy: 75.33333%
    +[5/9]	Time 0.4833s	Training Accuracy: 76.14815%	Test Accuracy: 77.33333%
    +[6/9]	Time 0.7233s	Training Accuracy: 79.48148%	Test Accuracy: 80.66667%
    +[7/9]	Time 0.4913s	Training Accuracy: 81.25926%	Test Accuracy: 80.66667%
    +[8/9]	Time 0.4843s	Training Accuracy: 83.40741%	Test Accuracy: 82.66667%
    +[9/9]	Time 0.7256s	Training Accuracy: 84.81481%	Test Accuracy: 82.00000%

    We can also change the sensealg and train the model! GaussAdjoint allows you to use any arbitrary parameter structure and not just a flat vector (ComponentArray).

    julia
    train(NeuralODE; sensealg=GaussAdjoint(; autojacvec=ZygoteVJP()), use_named_tuple=true)
    [1/9]	Time 42.6019s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.5487s	Training Accuracy: 57.55556%	Test Accuracy: 54.00000%
    +[3/9]	Time 0.4660s	Training Accuracy: 69.85185%	Test Accuracy: 69.33333%
    +[4/9]	Time 0.4833s	Training Accuracy: 72.51852%	Test Accuracy: 74.00000%
    +[5/9]	Time 0.4743s	Training Accuracy: 75.33333%	Test Accuracy: 76.00000%
    +[6/9]	Time 0.4944s	Training Accuracy: 78.88889%	Test Accuracy: 79.33333%
    +[7/9]	Time 0.6809s	Training Accuracy: 81.03704%	Test Accuracy: 80.00000%
    +[8/9]	Time 0.4987s	Training Accuracy: 83.77778%	Test Accuracy: 81.33333%
    +[9/9]	Time 0.5045s	Training Accuracy: 85.25926%	Test Accuracy: 82.66667%

    But remember some AD backends like ReverseDiff is not GPU compatible. For a model this size, you will notice that training time is significantly lower for training on CPU than on GPU.

    julia
    train(NeuralODE; sensealg=InterpolatingAdjoint(; autojacvec=ReverseDiffVJP()), cpu=true)
    [1/9]	Time 96.0630s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 14.0172s	Training Accuracy: 58.74074%	Test Accuracy: 56.66667%
    +[3/9]	Time 13.5410s	Training Accuracy: 69.92593%	Test Accuracy: 71.33333%
    +[4/9]	Time 13.6407s	Training Accuracy: 72.81481%	Test Accuracy: 74.00000%
    +[5/9]	Time 13.4329s	Training Accuracy: 76.37037%	Test Accuracy: 78.66667%
    +[6/9]	Time 12.0878s	Training Accuracy: 79.03704%	Test Accuracy: 80.66667%
    +[7/9]	Time 14.5981s	Training Accuracy: 81.62963%	Test Accuracy: 80.66667%
    +[8/9]	Time 13.6945s	Training Accuracy: 83.33333%	Test Accuracy: 80.00000%
    +[9/9]	Time 10.3098s	Training Accuracy: 85.40741%	Test Accuracy: 82.00000%

    For completeness, let's also test out discrete sensitivities!

    julia
    train(NeuralODE; sensealg=ReverseDiffAdjoint(), cpu=true)
    [1/9]	Time 49.7652s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 21.6687s	Training Accuracy: 58.66667%	Test Accuracy: 57.33333%
    +[3/9]	Time 21.5681s	Training Accuracy: 69.70370%	Test Accuracy: 71.33333%
    +[4/9]	Time 21.3427s	Training Accuracy: 72.74074%	Test Accuracy: 74.00000%
    +[5/9]	Time 23.9941s	Training Accuracy: 76.14815%	Test Accuracy: 78.66667%
    +[6/9]	Time 22.0233s	Training Accuracy: 79.03704%	Test Accuracy: 80.66667%
    +[7/9]	Time 22.4246s	Training Accuracy: 81.55556%	Test Accuracy: 80.66667%
    +[8/9]	Time 23.1968s	Training Accuracy: 83.40741%	Test Accuracy: 80.00000%
    +[9/9]	Time 24.0997s	Training Accuracy: 85.25926%	Test Accuracy: 81.33333%

    Alternate Implementation using Stateful Layer

    Starting v0.5.5, Lux provides a StatefulLuxLayer which can be used to avoid the Boxing of st. Using the @compact API avoids this problem entirely.

    julia
    struct StatefulNeuralODE{M <: Lux.AbstractLuxLayer, So, T, K} <:
    +       Lux.AbstractLuxWrapperLayer{:model}
    +    model::M
    +    solver::So
    +    tspan::T
    +    kwargs::K
    +end
    +
    +function StatefulNeuralODE(
    +        model::Lux.AbstractLuxLayer; solver=Tsit5(), tspan=(0.0f0, 1.0f0), kwargs...)
    +    return StatefulNeuralODE(model, solver, tspan, kwargs)
    +end
    +
    +function (n::StatefulNeuralODE)(x, ps, st)
    +    st_model = StatefulLuxLayer{true}(n.model, ps, st)
    +    dudt(u, p, t) = st_model(u, p)
    +    prob = ODEProblem{false}(ODEFunction{false}(dudt), x, n.tspan, ps)
    +    return solve(prob, n.solver; n.kwargs...), st_model.st
    +end

    Train the new Stateful Neural ODE

    julia
    train(StatefulNeuralODE)
    [1/9]	Time 38.2440s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.4759s	Training Accuracy: 58.22222%	Test Accuracy: 55.33333%
    +[3/9]	Time 0.4745s	Training Accuracy: 68.29630%	Test Accuracy: 68.66667%
    +[4/9]	Time 0.4670s	Training Accuracy: 73.11111%	Test Accuracy: 76.00000%
    +[5/9]	Time 0.5117s	Training Accuracy: 75.92593%	Test Accuracy: 76.66667%
    +[6/9]	Time 0.4779s	Training Accuracy: 78.96296%	Test Accuracy: 80.66667%
    +[7/9]	Time 0.4705s	Training Accuracy: 80.81481%	Test Accuracy: 81.33333%
    +[8/9]	Time 0.4590s	Training Accuracy: 83.25926%	Test Accuracy: 82.66667%
    +[9/9]	Time 0.4555s	Training Accuracy: 84.59259%	Test Accuracy: 82.00000%

    We might not see a significant difference in the training time, but let us investigate the type stabilities of the layers.

    Type Stability

    julia
    model, ps, st = create_model(NeuralODE)
    +
    +model_stateful, ps_stateful, st_stateful = create_model(StatefulNeuralODE)
    +
    +x = gpu_device()(ones(Float32, 28, 28, 1, 3));

    NeuralODE is not type stable due to the boxing of st

    julia
    @code_warntype model(x, ps, st)
    MethodInstance for (::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".NeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing})(::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}, ::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}, ::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}})
    +  from (c::Lux.Chain)(x, ps, st::NamedTuple) @ Lux /var/lib/buildkite-agent/builds/gpuci-13/julialang/lux-dot-jl/src/layers/containers.jl:480
    +Arguments
    +  c::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".NeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}
    +  x::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}
    +  ps::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}
    +  st::Core.Const((layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()), layer_4 = NamedTuple(), layer_5 = NamedTuple()))
    +Body::TUPLE{CUDA.CUARRAY{FLOAT32, 2, CUDA.DEVICEMEMORY}, NAMEDTUPLE{(:LAYER_1, :LAYER_2, :LAYER_3, :LAYER_4, :LAYER_5), <:TUPLE{@NAMEDTUPLE{}, @NAMEDTUPLE{}, ANY, @NAMEDTUPLE{}, @NAMEDTUPLE{}}}}
    +1 ─ %1 = Base.getproperty(c, :layers)::@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".NeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}
    +│   %2 = Lux.applychain(%1, x, ps, st)::TUPLE{CUDA.CUARRAY{FLOAT32, 2, CUDA.DEVICEMEMORY}, NAMEDTUPLE{(:LAYER_1, :LAYER_2, :LAYER_3, :LAYER_4, :LAYER_5), <:TUPLE{@NAMEDTUPLE{}, @NAMEDTUPLE{}, ANY, @NAMEDTUPLE{}, @NAMEDTUPLE{}}}}
    +└──      return %2

    We avoid the problem entirely by using StatefulNeuralODE

    julia
    @code_warntype model_stateful(x, ps_stateful, st_stateful)
    MethodInstance for (::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".StatefulNeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing})(::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}, ::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}, ::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}})
    +  from (c::Lux.Chain)(x, ps, st::NamedTuple) @ Lux /var/lib/buildkite-agent/builds/gpuci-13/julialang/lux-dot-jl/src/layers/containers.jl:480
    +Arguments
    +  c::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".StatefulNeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}
    +  x::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}
    +  ps::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}
    +  st::Core.Const((layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()), layer_4 = NamedTuple(), layer_5 = NamedTuple()))
    +Body::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +1 ─ %1 = Base.getproperty(c, :layers)::@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".StatefulNeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}
    +│   %2 = Lux.applychain(%1, x, ps, st)::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +└──      return %2

    Note, that we still recommend using this layer internally and not exposing this as the default API to the users.

    Finally checking the compact model

    julia
    model_compact, ps_compact, st_compact = create_model(NeuralODECompact)
    +
    +@code_warntype model_compact(x, ps_compact, st_compact)
    MethodInstance for (::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.CompactLuxLayer{:₋₋₋no_special_dispatch₋₋₋, Main.var"##225".var"#2#3", Nothing, @NamedTuple{model::Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Lux.CompactMacroImpl.ValueStorage{@NamedTuple{}, @NamedTuple{solver::Returns{OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}}, tspan::Returns{Tuple{Float32, Float32}}}}, Tuple{Tuple{Symbol}, Tuple{Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing})(::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}, ::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(model = ViewAxis(1:540, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))),)), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}, ::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}})
    +  from (c::Lux.Chain)(x, ps, st::NamedTuple) @ Lux /var/lib/buildkite-agent/builds/gpuci-13/julialang/lux-dot-jl/src/layers/containers.jl:480
    +Arguments
    +  c::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.CompactLuxLayer{:₋₋₋no_special_dispatch₋₋₋, Main.var"##225".var"#2#3", Nothing, @NamedTuple{model::Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Lux.CompactMacroImpl.ValueStorage{@NamedTuple{}, @NamedTuple{solver::Returns{OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}}, tspan::Returns{Tuple{Float32, Float32}}}}, Tuple{Tuple{Symbol}, Tuple{Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}
    +  x::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}
    +  ps::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(model = ViewAxis(1:540, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))),)), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}
    +  st::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}
    +Body::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +1 ─ %1 = Base.getproperty(c, :layers)::@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.CompactLuxLayer{:₋₋₋no_special_dispatch₋₋₋, Main.var"##225".var"#2#3", Nothing, @NamedTuple{model::Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Lux.CompactMacroImpl.ValueStorage{@NamedTuple{}, @NamedTuple{solver::Returns{OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}}, tspan::Returns{Tuple{Float32, Float32}}}}, Tuple{Tuple{Symbol}, Tuple{Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}
    +│   %2 = Lux.applychain(%1, x, ps, st)::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +└──      return %2

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 3.889 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,62)]))}const o=i(e,[["render",l]]);export{E as __pageData,o as default}; diff --git a/previews/PR1023/assets/tutorials_intermediate_2_BayesianNN.md.fxCpWm1u.js b/previews/PR1023/assets/tutorials_intermediate_2_BayesianNN.md.fxCpWm1u.js new file mode 100644 index 0000000000..e94e3f350d --- /dev/null +++ b/previews/PR1023/assets/tutorials_intermediate_2_BayesianNN.md.fxCpWm1u.js @@ -0,0 +1,206 @@ +import{_ as t,c as a,a2 as i,j as A,o as n}from"./chunks/framework.DFwXuivk.js";const E="/previews/PR1023/assets/results.Dm2mgseg.gif",B=JSON.parse('{"title":"Bayesian Neural Network","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/intermediate/2_BayesianNN.md","filePath":"tutorials/intermediate/2_BayesianNN.md","lastUpdated":null}'),p={name:"tutorials/intermediate/2_BayesianNN.md"},h={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},e={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-3.222ex"},xmlns:"http://www.w3.org/2000/svg",width:"46.264ex",height:"6.301ex",role:"img",focusable:"false",viewBox:"0 -1361 20448.8 2785.1","aria-hidden":"true"};function l(k,s,g,r,d,Q){return n(),a("div",null,[s[2]||(s[2]=i(`

    Bayesian Neural Network

    We borrow this tutorial from the official Turing Docs. We will show how the explicit parameterization of Lux enables first-class composability with packages which expect flattened out parameter vectors.

    Note: The tutorial in the official Turing docs is now using Lux instead of Flux.

    We will use Turing.jl with Lux.jl to implement implementing a classification algorithm. Lets start by importing the relevant libraries.

    julia
    # Import libraries
    +
    +using Lux, Turing, CairoMakie, Random, Tracker, Functors, LinearAlgebra
    +
    +# Sampling progress
    +Turing.setprogress!(true);
    [ Info: [Turing]: progress logging is enabled globally
    +[ Info: [AdvancedVI]: global PROGRESS is set as true

    Generating data

    Our goal here is to use a Bayesian neural network to classify points in an artificial dataset. The code below generates data points arranged in a box-like pattern and displays a graph of the dataset we'll be working with.

    julia
    # Number of points to generate
    +N = 80
    +M = round(Int, N / 4)
    +rng = Random.default_rng()
    +Random.seed!(rng, 1234)
    +
    +# Generate artificial data
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +xt1s = Array([[x1s[i] + 0.5f0; x2s[i] + 0.5f0] for i in 1:M])
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +append!(xt1s, Array([[x1s[i] - 5.0f0; x2s[i] - 5.0f0] for i in 1:M]))
    +
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +xt0s = Array([[x1s[i] + 0.5f0; x2s[i] - 5.0f0] for i in 1:M])
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +append!(xt0s, Array([[x1s[i] - 5.0f0; x2s[i] + 0.5f0] for i in 1:M]))
    +
    +# Store all the data for later
    +xs = [xt1s; xt0s]
    +ts = [ones(2 * M); zeros(2 * M)]
    +
    +# Plot data points
    +
    +function plot_data()
    +    x1 = first.(xt1s)
    +    y1 = last.(xt1s)
    +    x2 = first.(xt0s)
    +    y2 = last.(xt0s)
    +
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +
    +    scatter!(ax, x1, y1; markersize=16, color=:red, strokecolor=:black, strokewidth=2)
    +    scatter!(ax, x2, y2; markersize=16, color=:blue, strokecolor=:black, strokewidth=2)
    +
    +    return fig
    +end
    +
    +plot_data()

    Building the Neural Network

    The next step is to define a feedforward neural network where we express our parameters as distributions, and not single points as with traditional neural networks. For this we will use Dense to define liner layers and compose them via Chain, both are neural network primitives from Lux. The network nn we will create will have two hidden layers with tanh activations and one output layer with sigmoid activation, as shown below.

    The nn is an instance that acts as a function and can take data, parameters and current state as inputs and output predictions. We will define distributions on the neural network parameters.

    julia
    # Construct a neural network using Lux
    +nn = Chain(Dense(2 => 3, tanh), Dense(3 => 2, tanh), Dense(2 => 1, sigmoid))
    +
    +# Initialize the model weights and state
    +ps, st = Lux.setup(rng, nn)
    +
    +Lux.parameterlength(nn) # number of parameters in NN
    20

    The probabilistic model specification below creates a parameters variable, which has IID normal variables. The parameters represents all parameters of our neural net (weights and biases).

    julia
    # Create a regularization term and a Gaussian prior variance term.
    +alpha = 0.09
    +sig = sqrt(1.0 / alpha)
    3.3333333333333335

    Construct named tuple from a sampled parameter vector. We could also use ComponentArrays here and simply broadcast to avoid doing this. But let's do it this way to avoid dependencies.

    julia
    function vector_to_parameters(ps_new::AbstractVector, ps::NamedTuple)
    +    @assert length(ps_new) == Lux.parameterlength(ps)
    +    i = 1
    +    function get_ps(x)
    +        z = reshape(view(ps_new, i:(i + length(x) - 1)), size(x))
    +        i += length(x)
    +        return z
    +    end
    +    return fmap(get_ps, ps)
    +end
    vector_to_parameters (generic function with 1 method)

    To interface with external libraries it is often desirable to use the StatefulLuxLayer to automatically handle the neural network states.

    julia
    const model = StatefulLuxLayer{true}(nn, nothing, st)
    +
    +# Specify the probabilistic model.
    +@model function bayes_nn(xs, ts)
    +    # Sample the parameters
    +    nparameters = Lux.parameterlength(nn)
    +    parameters ~ MvNormal(zeros(nparameters), Diagonal(abs2.(sig .* ones(nparameters))))
    +
    +    # Forward NN to make predictions
    +    preds = Lux.apply(model, xs, vector_to_parameters(parameters, ps))
    +
    +    # Observe each prediction.
    +    for i in eachindex(ts)
    +        ts[i] ~ Bernoulli(preds[i])
    +    end
    +end
    bayes_nn (generic function with 2 methods)

    Inference can now be performed by calling sample. We use the HMC sampler here.

    julia
    # Perform inference.
    +N = 5000
    +ch = sample(bayes_nn(reduce(hcat, xs), ts), HMC(0.05, 4; adtype=AutoTracker()), N)
    Chains MCMC chain (5000×30×1 Array{Float64, 3}):
    +
    +Iterations        = 1:1:5000
    +Number of chains  = 1
    +Samples per chain = 5000
    +Wall duration     = 21.31 seconds
    +Compute duration  = 21.31 seconds
    +parameters        = parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13], parameters[14], parameters[15], parameters[16], parameters[17], parameters[18], parameters[19], parameters[20]
    +internals         = lp, n_steps, is_accept, acceptance_rate, log_density, hamiltonian_energy, hamiltonian_energy_error, numerical_error, step_size, nom_step_size
    +
    +Summary Statistics
    +      parameters      mean       std      mcse   ess_bulk   ess_tail      rhat   ess_per_sec
    +          Symbol   Float64   Float64   Float64    Float64    Float64   Float64       Float64
    +
    +   parameters[1]    2.0965    4.4644    1.3270    12.0887    23.0787    1.3335        0.5673
    +   parameters[2]    0.0843    0.3952    0.0510    79.9413    35.2287    1.0240        3.7517
    +   parameters[3]    4.9916    1.9230    0.4456    19.3935    81.5852    1.2170        0.9102
    +   parameters[4]    0.3356    2.3096    0.6117    14.3653    24.1405    1.2067        0.6742
    +   parameters[5]    5.0569    2.3192    0.6141    15.0672    34.9402    1.1058        0.7071
    +   parameters[6]    0.7127    1.2191    0.2991    21.7200    21.7891    1.1550        1.0193
    +   parameters[7]    1.7149    3.8638    1.1143    12.4420    21.7560    1.1439        0.5839
    +   parameters[8]    0.3690    1.2835    0.2555    26.1914    29.6846    1.0246        1.2292
    +   parameters[9]   -0.4968    2.2271    0.6133    14.1406    24.5983    1.2648        0.6636
    +  parameters[10]    0.0842    2.1828    0.5840    14.0865    21.8689    1.1832        0.6611
    +  parameters[11]   -1.0288    1.5663    0.3628    18.3294    27.7789    1.0536        0.8602
    +  parameters[12]   -4.1763    1.7426    0.3705    23.0782    28.1565    1.0633        1.0831
    +  parameters[13]    3.1846    1.4791    0.3401    19.4472    53.5564    1.0444        0.9127
    +  parameters[14]    2.7199    1.9547    0.5178    14.3490    46.8984    1.3048        0.6734
    +  parameters[15]   -2.0613    1.4937    0.3727    16.3035    39.2852    1.0885        0.7651
    +  parameters[16]   -2.9853    1.4059    0.2557    31.3669    31.3956    1.0012        1.4721
    +  parameters[17]   -2.4061    2.6897    0.7370    15.6752    20.0204    1.0733        0.7356
    +  parameters[18]   -5.3040    1.1943    0.1791    44.9414    68.7121    1.0867        2.1091
    +  parameters[19]   -5.1706    2.2709    0.5991    17.6788    18.3886    1.0540        0.8297
    +  parameters[20]   -5.1303    1.3008    0.2366    30.4880    60.9517    1.0163        1.4308
    +
    +Quantiles
    +      parameters      2.5%     25.0%     50.0%     75.0%     97.5%
    +          Symbol   Float64   Float64   Float64   Float64   Float64
    +
    +   parameters[1]   -7.7024    0.5794    2.9500    5.0242    8.8277
    +   parameters[2]   -0.6189   -0.1406    0.0435    0.2877    1.0813
    +   parameters[3]    1.2261    3.6852    4.9109    6.5386    8.2717
    +   parameters[4]   -3.9045   -0.9307    0.1458    1.1265    5.7834
    +   parameters[5]    1.5809    3.2130    4.8534    6.4543   10.0149
    +   parameters[6]   -0.8100   -0.0584    0.3864    1.1121    4.4225
    +   parameters[7]   -5.8787   -0.8376    1.2050    4.7533    8.9694
    +   parameters[8]   -2.3155   -0.3960    0.2950    1.1550    2.9515
    +   parameters[9]   -5.8990   -1.7942   -0.1511    1.0876    2.9460
    +  parameters[10]   -4.7703   -1.0568    0.0534    1.4673    4.2833
    +  parameters[11]   -4.5806   -1.9640   -0.8771    0.0209    1.7384
    +  parameters[12]   -8.2243   -5.3092   -4.0546   -2.7977   -1.3694
    +  parameters[13]    0.8904    2.0618    2.9913    4.0971    6.5956
    +  parameters[14]   -0.9166    1.5821    2.5812    3.9071    6.6712
    +  parameters[15]   -4.9708   -3.1310   -2.0122   -1.0256    0.7273
    +  parameters[16]   -6.2647   -3.8094   -2.8050   -1.8812   -0.8946
    +  parameters[17]   -6.2695   -3.8672   -2.6943   -1.7352    5.5834
    +  parameters[18]   -7.6970   -6.0973   -5.2714   -4.5053   -2.9747
    +  parameters[19]   -8.3524   -6.4017   -5.5673   -4.6134    2.1958
    +  parameters[20]   -7.6214   -5.9847   -5.1652   -4.2672   -2.6349

    Now we extract the parameter samples from the sampled chain as θ (this is of size 5000 x 20 where 5000 is the number of iterations and 20 is the number of parameters). We'll use these primarily to determine how good our model's classifier is.

    julia
    # Extract all weight and bias parameters.
    +θ = MCMCChains.group(ch, :parameters).value;

    Prediction Visualization

    julia
    # A helper to run the nn through data \`x\` using parameters \`θ\`
    +nn_forward(x, θ) = model(x, vector_to_parameters(θ, ps))
    +
    +# Plot the data we have.
    +fig = plot_data()
    +
    +# Find the index that provided the highest log posterior in the chain.
    +_, i = findmax(ch[:lp])
    +
    +# Extract the max row value from i.
    +i = i.I[1]
    +
    +# Plot the posterior distribution with a contour plot
    +x1_range = collect(range(-6; stop=6, length=25))
    +x2_range = collect(range(-6; stop=6, length=25))
    +Z = [nn_forward([x1, x2], θ[i, :])[1] for x1 in x1_range, x2 in x2_range]
    +contour!(x1_range, x2_range, Z; linewidth=3, colormap=:seaborn_bright)
    +fig

    The contour plot above shows that the MAP method is not too bad at classifying our data. Now we can visualize our predictions.

    `,33)),A("mjx-container",h,[(n(),a("svg",e,s[0]||(s[0]=[i('',1)]))),s[1]||(s[1]=A("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[A("mi",null,"p"),A("mo",{stretchy:"false"},"("),A("mrow",{"data-mjx-texclass":"ORD"},[A("mover",null,[A("mi",null,"x"),A("mo",{stretchy:"false"},"~")])]),A("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),A("mi",null,"X"),A("mo",null,","),A("mi",null,"α"),A("mo",{stretchy:"false"},")"),A("mo",null,"="),A("msub",null,[A("mo",{"data-mjx-texclass":"OP"},"∫"),A("mrow",{"data-mjx-texclass":"ORD"},[A("mi",null,"θ")])]),A("mi",null,"p"),A("mo",{stretchy:"false"},"("),A("mrow",{"data-mjx-texclass":"ORD"},[A("mover",null,[A("mi",null,"x"),A("mo",{stretchy:"false"},"~")])]),A("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),A("mi",null,"θ"),A("mo",{stretchy:"false"},")"),A("mi",null,"p"),A("mo",{stretchy:"false"},"("),A("mi",null,"θ"),A("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),A("mi",null,"X"),A("mo",null,","),A("mi",null,"α"),A("mo",{stretchy:"false"},")"),A("mo",null,"≈"),A("munder",null,[A("mo",{"data-mjx-texclass":"OP"},"∑"),A("mrow",{"data-mjx-texclass":"ORD"},[A("mi",null,"θ"),A("mo",null,"∼"),A("mi",null,"p"),A("mo",{stretchy:"false"},"("),A("mi",null,"θ"),A("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),A("mi",null,"X"),A("mo",null,","),A("mi",null,"α"),A("mo",{stretchy:"false"},")")])]),A("msub",null,[A("mi",null,"f"),A("mrow",{"data-mjx-texclass":"ORD"},[A("mi",null,"θ")])]),A("mo",{stretchy:"false"},"("),A("mrow",{"data-mjx-texclass":"ORD"},[A("mover",null,[A("mi",null,"x"),A("mo",{stretchy:"false"},"~")])]),A("mo",{stretchy:"false"},")")])],-1))]),s[3]||(s[3]=i(`

    The nn_predict function takes the average predicted value from a network parameterized by weights drawn from the MCMC chain.

    julia
    # Return the average predicted value across multiple weights.
    +nn_predict(x, θ, num) = mean([first(nn_forward(x, view(θ, i, :))) for i in 1:10:num])
    nn_predict (generic function with 1 method)

    Next, we use the nn_predict function to predict the value at a sample of points where the x1 and x2 coordinates range between -6 and 6. As we can see below, we still have a satisfactory fit to our data, and more importantly, we can also see where the neural network is uncertain about its predictions much easier–-those regions between cluster boundaries.

    Plot the average prediction.

    julia
    fig = plot_data()
    +
    +n_end = 1500
    +x1_range = collect(range(-6; stop=6, length=25))
    +x2_range = collect(range(-6; stop=6, length=25))
    +Z = [nn_predict([x1, x2], θ, n_end)[1] for x1 in x1_range, x2 in x2_range]
    +contour!(x1_range, x2_range, Z; linewidth=3, colormap=:seaborn_bright)
    +fig

    Suppose we are interested in how the predictive power of our Bayesian neural network evolved between samples. In that case, the following graph displays an animation of the contour plot generated from the network weights in samples 1 to 5,000.

    julia
    fig = plot_data()
    +Z = [first(nn_forward([x1, x2], θ[1, :])) for x1 in x1_range, x2 in x2_range]
    +c = contour!(x1_range, x2_range, Z; linewidth=3, colormap=:seaborn_bright)
    +record(fig, "results.gif", 1:250:size(θ, 1)) do i
    +    fig.current_axis[].title = "Iteration: $i"
    +    Z = [first(nn_forward([x1, x2], θ[i, :])) for x1 in x1_range, x2 in x2_range]
    +    c[3] = Z
    +    return fig
    +end
    "results.gif"

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 128 × AMD EPYC 7502 32-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 16 default, 0 interactive, 8 GC (on 16 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 16
    +  JULIA_DEPOT_PATH = /cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 16
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate

    This page was generated using Literate.jl.

    `,16))])}const I=t(p,[["render",l]]);export{B as __pageData,I as default}; diff --git a/previews/PR1023/assets/tutorials_intermediate_2_BayesianNN.md.fxCpWm1u.lean.js b/previews/PR1023/assets/tutorials_intermediate_2_BayesianNN.md.fxCpWm1u.lean.js new file mode 100644 index 0000000000..e94e3f350d --- /dev/null +++ b/previews/PR1023/assets/tutorials_intermediate_2_BayesianNN.md.fxCpWm1u.lean.js @@ -0,0 +1,206 @@ +import{_ as t,c as a,a2 as i,j as A,o as n}from"./chunks/framework.DFwXuivk.js";const E="/previews/PR1023/assets/results.Dm2mgseg.gif",B=JSON.parse('{"title":"Bayesian Neural Network","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/intermediate/2_BayesianNN.md","filePath":"tutorials/intermediate/2_BayesianNN.md","lastUpdated":null}'),p={name:"tutorials/intermediate/2_BayesianNN.md"},h={class:"MathJax",jax:"SVG",display:"true",style:{direction:"ltr",display:"block","text-align":"center",margin:"1em 0",position:"relative"}},e={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-3.222ex"},xmlns:"http://www.w3.org/2000/svg",width:"46.264ex",height:"6.301ex",role:"img",focusable:"false",viewBox:"0 -1361 20448.8 2785.1","aria-hidden":"true"};function l(k,s,g,r,d,Q){return n(),a("div",null,[s[2]||(s[2]=i(`

    Bayesian Neural Network

    We borrow this tutorial from the official Turing Docs. We will show how the explicit parameterization of Lux enables first-class composability with packages which expect flattened out parameter vectors.

    Note: The tutorial in the official Turing docs is now using Lux instead of Flux.

    We will use Turing.jl with Lux.jl to implement implementing a classification algorithm. Lets start by importing the relevant libraries.

    julia
    # Import libraries
    +
    +using Lux, Turing, CairoMakie, Random, Tracker, Functors, LinearAlgebra
    +
    +# Sampling progress
    +Turing.setprogress!(true);
    [ Info: [Turing]: progress logging is enabled globally
    +[ Info: [AdvancedVI]: global PROGRESS is set as true

    Generating data

    Our goal here is to use a Bayesian neural network to classify points in an artificial dataset. The code below generates data points arranged in a box-like pattern and displays a graph of the dataset we'll be working with.

    julia
    # Number of points to generate
    +N = 80
    +M = round(Int, N / 4)
    +rng = Random.default_rng()
    +Random.seed!(rng, 1234)
    +
    +# Generate artificial data
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +xt1s = Array([[x1s[i] + 0.5f0; x2s[i] + 0.5f0] for i in 1:M])
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +append!(xt1s, Array([[x1s[i] - 5.0f0; x2s[i] - 5.0f0] for i in 1:M]))
    +
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +xt0s = Array([[x1s[i] + 0.5f0; x2s[i] - 5.0f0] for i in 1:M])
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +append!(xt0s, Array([[x1s[i] - 5.0f0; x2s[i] + 0.5f0] for i in 1:M]))
    +
    +# Store all the data for later
    +xs = [xt1s; xt0s]
    +ts = [ones(2 * M); zeros(2 * M)]
    +
    +# Plot data points
    +
    +function plot_data()
    +    x1 = first.(xt1s)
    +    y1 = last.(xt1s)
    +    x2 = first.(xt0s)
    +    y2 = last.(xt0s)
    +
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +
    +    scatter!(ax, x1, y1; markersize=16, color=:red, strokecolor=:black, strokewidth=2)
    +    scatter!(ax, x2, y2; markersize=16, color=:blue, strokecolor=:black, strokewidth=2)
    +
    +    return fig
    +end
    +
    +plot_data()

    Building the Neural Network

    The next step is to define a feedforward neural network where we express our parameters as distributions, and not single points as with traditional neural networks. For this we will use Dense to define liner layers and compose them via Chain, both are neural network primitives from Lux. The network nn we will create will have two hidden layers with tanh activations and one output layer with sigmoid activation, as shown below.

    The nn is an instance that acts as a function and can take data, parameters and current state as inputs and output predictions. We will define distributions on the neural network parameters.

    julia
    # Construct a neural network using Lux
    +nn = Chain(Dense(2 => 3, tanh), Dense(3 => 2, tanh), Dense(2 => 1, sigmoid))
    +
    +# Initialize the model weights and state
    +ps, st = Lux.setup(rng, nn)
    +
    +Lux.parameterlength(nn) # number of parameters in NN
    20

    The probabilistic model specification below creates a parameters variable, which has IID normal variables. The parameters represents all parameters of our neural net (weights and biases).

    julia
    # Create a regularization term and a Gaussian prior variance term.
    +alpha = 0.09
    +sig = sqrt(1.0 / alpha)
    3.3333333333333335

    Construct named tuple from a sampled parameter vector. We could also use ComponentArrays here and simply broadcast to avoid doing this. But let's do it this way to avoid dependencies.

    julia
    function vector_to_parameters(ps_new::AbstractVector, ps::NamedTuple)
    +    @assert length(ps_new) == Lux.parameterlength(ps)
    +    i = 1
    +    function get_ps(x)
    +        z = reshape(view(ps_new, i:(i + length(x) - 1)), size(x))
    +        i += length(x)
    +        return z
    +    end
    +    return fmap(get_ps, ps)
    +end
    vector_to_parameters (generic function with 1 method)

    To interface with external libraries it is often desirable to use the StatefulLuxLayer to automatically handle the neural network states.

    julia
    const model = StatefulLuxLayer{true}(nn, nothing, st)
    +
    +# Specify the probabilistic model.
    +@model function bayes_nn(xs, ts)
    +    # Sample the parameters
    +    nparameters = Lux.parameterlength(nn)
    +    parameters ~ MvNormal(zeros(nparameters), Diagonal(abs2.(sig .* ones(nparameters))))
    +
    +    # Forward NN to make predictions
    +    preds = Lux.apply(model, xs, vector_to_parameters(parameters, ps))
    +
    +    # Observe each prediction.
    +    for i in eachindex(ts)
    +        ts[i] ~ Bernoulli(preds[i])
    +    end
    +end
    bayes_nn (generic function with 2 methods)

    Inference can now be performed by calling sample. We use the HMC sampler here.

    julia
    # Perform inference.
    +N = 5000
    +ch = sample(bayes_nn(reduce(hcat, xs), ts), HMC(0.05, 4; adtype=AutoTracker()), N)
    Chains MCMC chain (5000×30×1 Array{Float64, 3}):
    +
    +Iterations        = 1:1:5000
    +Number of chains  = 1
    +Samples per chain = 5000
    +Wall duration     = 21.31 seconds
    +Compute duration  = 21.31 seconds
    +parameters        = parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13], parameters[14], parameters[15], parameters[16], parameters[17], parameters[18], parameters[19], parameters[20]
    +internals         = lp, n_steps, is_accept, acceptance_rate, log_density, hamiltonian_energy, hamiltonian_energy_error, numerical_error, step_size, nom_step_size
    +
    +Summary Statistics
    +      parameters      mean       std      mcse   ess_bulk   ess_tail      rhat   ess_per_sec
    +          Symbol   Float64   Float64   Float64    Float64    Float64   Float64       Float64
    +
    +   parameters[1]    2.0965    4.4644    1.3270    12.0887    23.0787    1.3335        0.5673
    +   parameters[2]    0.0843    0.3952    0.0510    79.9413    35.2287    1.0240        3.7517
    +   parameters[3]    4.9916    1.9230    0.4456    19.3935    81.5852    1.2170        0.9102
    +   parameters[4]    0.3356    2.3096    0.6117    14.3653    24.1405    1.2067        0.6742
    +   parameters[5]    5.0569    2.3192    0.6141    15.0672    34.9402    1.1058        0.7071
    +   parameters[6]    0.7127    1.2191    0.2991    21.7200    21.7891    1.1550        1.0193
    +   parameters[7]    1.7149    3.8638    1.1143    12.4420    21.7560    1.1439        0.5839
    +   parameters[8]    0.3690    1.2835    0.2555    26.1914    29.6846    1.0246        1.2292
    +   parameters[9]   -0.4968    2.2271    0.6133    14.1406    24.5983    1.2648        0.6636
    +  parameters[10]    0.0842    2.1828    0.5840    14.0865    21.8689    1.1832        0.6611
    +  parameters[11]   -1.0288    1.5663    0.3628    18.3294    27.7789    1.0536        0.8602
    +  parameters[12]   -4.1763    1.7426    0.3705    23.0782    28.1565    1.0633        1.0831
    +  parameters[13]    3.1846    1.4791    0.3401    19.4472    53.5564    1.0444        0.9127
    +  parameters[14]    2.7199    1.9547    0.5178    14.3490    46.8984    1.3048        0.6734
    +  parameters[15]   -2.0613    1.4937    0.3727    16.3035    39.2852    1.0885        0.7651
    +  parameters[16]   -2.9853    1.4059    0.2557    31.3669    31.3956    1.0012        1.4721
    +  parameters[17]   -2.4061    2.6897    0.7370    15.6752    20.0204    1.0733        0.7356
    +  parameters[18]   -5.3040    1.1943    0.1791    44.9414    68.7121    1.0867        2.1091
    +  parameters[19]   -5.1706    2.2709    0.5991    17.6788    18.3886    1.0540        0.8297
    +  parameters[20]   -5.1303    1.3008    0.2366    30.4880    60.9517    1.0163        1.4308
    +
    +Quantiles
    +      parameters      2.5%     25.0%     50.0%     75.0%     97.5%
    +          Symbol   Float64   Float64   Float64   Float64   Float64
    +
    +   parameters[1]   -7.7024    0.5794    2.9500    5.0242    8.8277
    +   parameters[2]   -0.6189   -0.1406    0.0435    0.2877    1.0813
    +   parameters[3]    1.2261    3.6852    4.9109    6.5386    8.2717
    +   parameters[4]   -3.9045   -0.9307    0.1458    1.1265    5.7834
    +   parameters[5]    1.5809    3.2130    4.8534    6.4543   10.0149
    +   parameters[6]   -0.8100   -0.0584    0.3864    1.1121    4.4225
    +   parameters[7]   -5.8787   -0.8376    1.2050    4.7533    8.9694
    +   parameters[8]   -2.3155   -0.3960    0.2950    1.1550    2.9515
    +   parameters[9]   -5.8990   -1.7942   -0.1511    1.0876    2.9460
    +  parameters[10]   -4.7703   -1.0568    0.0534    1.4673    4.2833
    +  parameters[11]   -4.5806   -1.9640   -0.8771    0.0209    1.7384
    +  parameters[12]   -8.2243   -5.3092   -4.0546   -2.7977   -1.3694
    +  parameters[13]    0.8904    2.0618    2.9913    4.0971    6.5956
    +  parameters[14]   -0.9166    1.5821    2.5812    3.9071    6.6712
    +  parameters[15]   -4.9708   -3.1310   -2.0122   -1.0256    0.7273
    +  parameters[16]   -6.2647   -3.8094   -2.8050   -1.8812   -0.8946
    +  parameters[17]   -6.2695   -3.8672   -2.6943   -1.7352    5.5834
    +  parameters[18]   -7.6970   -6.0973   -5.2714   -4.5053   -2.9747
    +  parameters[19]   -8.3524   -6.4017   -5.5673   -4.6134    2.1958
    +  parameters[20]   -7.6214   -5.9847   -5.1652   -4.2672   -2.6349

    Now we extract the parameter samples from the sampled chain as θ (this is of size 5000 x 20 where 5000 is the number of iterations and 20 is the number of parameters). We'll use these primarily to determine how good our model's classifier is.

    julia
    # Extract all weight and bias parameters.
    +θ = MCMCChains.group(ch, :parameters).value;

    Prediction Visualization

    julia
    # A helper to run the nn through data \`x\` using parameters \`θ\`
    +nn_forward(x, θ) = model(x, vector_to_parameters(θ, ps))
    +
    +# Plot the data we have.
    +fig = plot_data()
    +
    +# Find the index that provided the highest log posterior in the chain.
    +_, i = findmax(ch[:lp])
    +
    +# Extract the max row value from i.
    +i = i.I[1]
    +
    +# Plot the posterior distribution with a contour plot
    +x1_range = collect(range(-6; stop=6, length=25))
    +x2_range = collect(range(-6; stop=6, length=25))
    +Z = [nn_forward([x1, x2], θ[i, :])[1] for x1 in x1_range, x2 in x2_range]
    +contour!(x1_range, x2_range, Z; linewidth=3, colormap=:seaborn_bright)
    +fig

    The contour plot above shows that the MAP method is not too bad at classifying our data. Now we can visualize our predictions.

    `,33)),A("mjx-container",h,[(n(),a("svg",e,s[0]||(s[0]=[i('',1)]))),s[1]||(s[1]=A("mjx-assistive-mml",{unselectable:"on",display:"block",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",overflow:"hidden",width:"100%"}},[A("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[A("mi",null,"p"),A("mo",{stretchy:"false"},"("),A("mrow",{"data-mjx-texclass":"ORD"},[A("mover",null,[A("mi",null,"x"),A("mo",{stretchy:"false"},"~")])]),A("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),A("mi",null,"X"),A("mo",null,","),A("mi",null,"α"),A("mo",{stretchy:"false"},")"),A("mo",null,"="),A("msub",null,[A("mo",{"data-mjx-texclass":"OP"},"∫"),A("mrow",{"data-mjx-texclass":"ORD"},[A("mi",null,"θ")])]),A("mi",null,"p"),A("mo",{stretchy:"false"},"("),A("mrow",{"data-mjx-texclass":"ORD"},[A("mover",null,[A("mi",null,"x"),A("mo",{stretchy:"false"},"~")])]),A("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),A("mi",null,"θ"),A("mo",{stretchy:"false"},")"),A("mi",null,"p"),A("mo",{stretchy:"false"},"("),A("mi",null,"θ"),A("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),A("mi",null,"X"),A("mo",null,","),A("mi",null,"α"),A("mo",{stretchy:"false"},")"),A("mo",null,"≈"),A("munder",null,[A("mo",{"data-mjx-texclass":"OP"},"∑"),A("mrow",{"data-mjx-texclass":"ORD"},[A("mi",null,"θ"),A("mo",null,"∼"),A("mi",null,"p"),A("mo",{stretchy:"false"},"("),A("mi",null,"θ"),A("mo",{"data-mjx-texclass":"ORD",stretchy:"false"},"|"),A("mi",null,"X"),A("mo",null,","),A("mi",null,"α"),A("mo",{stretchy:"false"},")")])]),A("msub",null,[A("mi",null,"f"),A("mrow",{"data-mjx-texclass":"ORD"},[A("mi",null,"θ")])]),A("mo",{stretchy:"false"},"("),A("mrow",{"data-mjx-texclass":"ORD"},[A("mover",null,[A("mi",null,"x"),A("mo",{stretchy:"false"},"~")])]),A("mo",{stretchy:"false"},")")])],-1))]),s[3]||(s[3]=i(`

    The nn_predict function takes the average predicted value from a network parameterized by weights drawn from the MCMC chain.

    julia
    # Return the average predicted value across multiple weights.
    +nn_predict(x, θ, num) = mean([first(nn_forward(x, view(θ, i, :))) for i in 1:10:num])
    nn_predict (generic function with 1 method)

    Next, we use the nn_predict function to predict the value at a sample of points where the x1 and x2 coordinates range between -6 and 6. As we can see below, we still have a satisfactory fit to our data, and more importantly, we can also see where the neural network is uncertain about its predictions much easier–-those regions between cluster boundaries.

    Plot the average prediction.

    julia
    fig = plot_data()
    +
    +n_end = 1500
    +x1_range = collect(range(-6; stop=6, length=25))
    +x2_range = collect(range(-6; stop=6, length=25))
    +Z = [nn_predict([x1, x2], θ, n_end)[1] for x1 in x1_range, x2 in x2_range]
    +contour!(x1_range, x2_range, Z; linewidth=3, colormap=:seaborn_bright)
    +fig

    Suppose we are interested in how the predictive power of our Bayesian neural network evolved between samples. In that case, the following graph displays an animation of the contour plot generated from the network weights in samples 1 to 5,000.

    julia
    fig = plot_data()
    +Z = [first(nn_forward([x1, x2], θ[1, :])) for x1 in x1_range, x2 in x2_range]
    +c = contour!(x1_range, x2_range, Z; linewidth=3, colormap=:seaborn_bright)
    +record(fig, "results.gif", 1:250:size(θ, 1)) do i
    +    fig.current_axis[].title = "Iteration: $i"
    +    Z = [first(nn_forward([x1, x2], θ[i, :])) for x1 in x1_range, x2 in x2_range]
    +    c[3] = Z
    +    return fig
    +end
    "results.gif"

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 128 × AMD EPYC 7502 32-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 16 default, 0 interactive, 8 GC (on 16 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 16
    +  JULIA_DEPOT_PATH = /cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 16
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate

    This page was generated using Literate.jl.

    `,16))])}const I=t(p,[["render",l]]);export{B as __pageData,I as default}; diff --git a/previews/PR1023/assets/tutorials_intermediate_3_HyperNet.md.D4Wex7F9.js b/previews/PR1023/assets/tutorials_intermediate_3_HyperNet.md.D4Wex7F9.js new file mode 100644 index 0000000000..a4b0ee6dc5 --- /dev/null +++ b/previews/PR1023/assets/tutorials_intermediate_3_HyperNet.md.D4Wex7F9.js @@ -0,0 +1,272 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const d=JSON.parse('{"title":"Training a HyperNetwork on MNIST and FashionMNIST","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/intermediate/3_HyperNet.md","filePath":"tutorials/intermediate/3_HyperNet.md","lastUpdated":null}'),p={name:"tutorials/intermediate/3_HyperNet.md"};function l(h,s,e,k,r,c){return t(),a("div",null,s[0]||(s[0]=[n(`

    Training a HyperNetwork on MNIST and FashionMNIST

    Package Imports

    julia
    using Lux, ADTypes, ComponentArrays, LuxCUDA, MLDatasets, MLUtils, OneHotArrays, Optimisers,
    +      Printf, Random, Setfield, Statistics, Zygote
    +
    +CUDA.allowscalar(false)

    Loading Datasets

    julia
    function load_dataset(::Type{dset}, n_train::Int, n_eval::Int, batchsize::Int) where {dset}
    +    imgs, labels = dset(:train)[1:n_train]
    +    x_train, y_train = reshape(imgs, 28, 28, 1, n_train), onehotbatch(labels, 0:9)
    +
    +    imgs, labels = dset(:test)[1:n_eval]
    +    x_test, y_test = reshape(imgs, 28, 28, 1, n_eval), onehotbatch(labels, 0:9)
    +
    +    return (
    +        DataLoader((x_train, y_train); batchsize=min(batchsize, n_train), shuffle=true),
    +        DataLoader((x_test, y_test); batchsize=min(batchsize, n_eval), shuffle=false))
    +end
    +
    +function load_datasets(n_train=1024, n_eval=32, batchsize=256)
    +    return load_dataset.((MNIST, FashionMNIST), n_train, n_eval, batchsize)
    +end
    load_datasets (generic function with 4 methods)

    Implement a HyperNet Layer

    julia
    function HyperNet(
    +        weight_generator::Lux.AbstractLuxLayer, core_network::Lux.AbstractLuxLayer)
    +    ca_axes = Lux.initialparameters(Random.default_rng(), core_network) |>
    +              ComponentArray |>
    +              getaxes
    +    return @compact(; ca_axes, weight_generator, core_network, dispatch=:HyperNet) do (x, y)
    +        # Generate the weights
    +        ps_new = ComponentArray(vec(weight_generator(x)), ca_axes)
    +        @return core_network(y, ps_new)
    +    end
    +end
    HyperNet (generic function with 1 method)

    Defining functions on the CompactLuxLayer requires some understanding of how the layer is structured, as such we don't recommend doing it unless you are familiar with the internals. In this case, we simply write it to ignore the initialization of the core_network parameters.

    julia
    function Lux.initialparameters(rng::AbstractRNG, hn::CompactLuxLayer{:HyperNet})
    +    return (; weight_generator=Lux.initialparameters(rng, hn.layers.weight_generator),)
    +end

    Create and Initialize the HyperNet

    julia
    function create_model()
    +    # Doesn't need to be a MLP can have any Lux Layer
    +    core_network = Chain(FlattenLayer(), Dense(784, 256, relu), Dense(256, 10))
    +    weight_generator = Chain(Embedding(2 => 32), Dense(32, 64, relu),
    +        Dense(64, Lux.parameterlength(core_network)))
    +
    +    model = HyperNet(weight_generator, core_network)
    +    return model
    +end
    create_model (generic function with 1 method)

    Define Utility Functions

    julia
    const loss = CrossEntropyLoss(; logits=Val(true))
    +
    +function accuracy(model, ps, st, dataloader, data_idx)
    +    total_correct, total = 0, 0
    +    st = Lux.testmode(st)
    +    for (x, y) in dataloader
    +        target_class = onecold(y)
    +        predicted_class = onecold(first(model((data_idx, x), ps, st)))
    +        total_correct += sum(target_class .== predicted_class)
    +        total += length(target_class)
    +    end
    +    return total_correct / total
    +end
    accuracy (generic function with 1 method)

    Training

    julia
    function train()
    +    model = create_model()
    +    dataloaders = load_datasets()
    +
    +    dev = gpu_device()
    +    rng = Xoshiro(0)
    +    ps, st = Lux.setup(rng, model) |> dev
    +
    +    train_state = Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    ### Lets train the model
    +    nepochs = 50
    +    for epoch in 1:nepochs, data_idx in 1:2
    +        train_dataloader, test_dataloader = dataloaders[data_idx] .|> dev
    +
    +        stime = time()
    +        for (x, y) in train_dataloader
    +            (_, _, _, train_state) = Training.single_train_step!(
    +                AutoZygote(), loss, ((data_idx, x), y), train_state)
    +        end
    +        ttime = time() - stime
    +
    +        train_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, train_dataloader, data_idx) * 100;
    +            digits=2)
    +        test_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, test_dataloader, data_idx) * 100;
    +            digits=2)
    +
    +        data_name = data_idx == 1 ? "MNIST" : "FashionMNIST"
    +
    +        @printf "[%3d/%3d]\\t%12s\\tTime %3.5fs\\tTraining Accuracy: %3.2f%%\\tTest \\
    +                 Accuracy: %3.2f%%\\n" epoch nepochs data_name ttime train_acc test_acc
    +    end
    +
    +    println()
    +
    +    test_acc_list = [0.0, 0.0]
    +    for data_idx in 1:2
    +        train_dataloader, test_dataloader = dataloaders[data_idx] .|> dev
    +        train_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, train_dataloader, data_idx) * 100;
    +            digits=2)
    +        test_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, test_dataloader, data_idx) * 100;
    +            digits=2)
    +
    +        data_name = data_idx == 1 ? "MNIST" : "FashionMNIST"
    +
    +        @printf "[FINAL]\\t%12s\\tTraining Accuracy: %3.2f%%\\tTest Accuracy: \\
    +                 %3.2f%%\\n" data_name train_acc test_acc
    +        test_acc_list[data_idx] = test_acc
    +    end
    +    return test_acc_list
    +end
    +
    +test_acc_list = train()
    [  1/ 50]	       MNIST	Time 70.85048s	Training Accuracy: 61.23%	Test Accuracy: 56.25%
    +[  1/ 50]	FashionMNIST	Time 0.02819s	Training Accuracy: 43.26%	Test Accuracy: 37.50%
    +[  2/ 50]	       MNIST	Time 0.02797s	Training Accuracy: 71.19%	Test Accuracy: 68.75%
    +[  2/ 50]	FashionMNIST	Time 0.02918s	Training Accuracy: 56.25%	Test Accuracy: 46.88%
    +[  3/ 50]	       MNIST	Time 0.02907s	Training Accuracy: 79.39%	Test Accuracy: 71.88%
    +[  3/ 50]	FashionMNIST	Time 0.02807s	Training Accuracy: 59.67%	Test Accuracy: 53.12%
    +[  4/ 50]	       MNIST	Time 0.02442s	Training Accuracy: 78.71%	Test Accuracy: 68.75%
    +[  4/ 50]	FashionMNIST	Time 0.02106s	Training Accuracy: 68.36%	Test Accuracy: 65.62%
    +[  5/ 50]	       MNIST	Time 0.02221s	Training Accuracy: 83.79%	Test Accuracy: 75.00%
    +[  5/ 50]	FashionMNIST	Time 0.02173s	Training Accuracy: 71.78%	Test Accuracy: 62.50%
    +[  6/ 50]	       MNIST	Time 0.02186s	Training Accuracy: 88.67%	Test Accuracy: 75.00%
    +[  6/ 50]	FashionMNIST	Time 0.02362s	Training Accuracy: 72.95%	Test Accuracy: 56.25%
    +[  7/ 50]	       MNIST	Time 0.02382s	Training Accuracy: 90.92%	Test Accuracy: 78.12%
    +[  7/ 50]	FashionMNIST	Time 0.02322s	Training Accuracy: 80.27%	Test Accuracy: 68.75%
    +[  8/ 50]	       MNIST	Time 0.03652s	Training Accuracy: 90.82%	Test Accuracy: 78.12%
    +[  8/ 50]	FashionMNIST	Time 0.02083s	Training Accuracy: 76.46%	Test Accuracy: 68.75%
    +[  9/ 50]	       MNIST	Time 0.02124s	Training Accuracy: 94.63%	Test Accuracy: 81.25%
    +[  9/ 50]	FashionMNIST	Time 0.02080s	Training Accuracy: 74.71%	Test Accuracy: 65.62%
    +[ 10/ 50]	       MNIST	Time 0.02075s	Training Accuracy: 94.63%	Test Accuracy: 81.25%
    +[ 10/ 50]	FashionMNIST	Time 0.02080s	Training Accuracy: 77.34%	Test Accuracy: 62.50%
    +[ 11/ 50]	       MNIST	Time 0.02030s	Training Accuracy: 96.29%	Test Accuracy: 78.12%
    +[ 11/ 50]	FashionMNIST	Time 0.02048s	Training Accuracy: 82.13%	Test Accuracy: 78.12%
    +[ 12/ 50]	       MNIST	Time 0.02080s	Training Accuracy: 97.95%	Test Accuracy: 78.12%
    +[ 12/ 50]	FashionMNIST	Time 0.02626s	Training Accuracy: 81.84%	Test Accuracy: 78.12%
    +[ 13/ 50]	       MNIST	Time 0.02091s	Training Accuracy: 98.44%	Test Accuracy: 84.38%
    +[ 13/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 84.08%	Test Accuracy: 71.88%
    +[ 14/ 50]	       MNIST	Time 0.02098s	Training Accuracy: 98.93%	Test Accuracy: 81.25%
    +[ 14/ 50]	FashionMNIST	Time 0.02068s	Training Accuracy: 85.55%	Test Accuracy: 65.62%
    +[ 15/ 50]	       MNIST	Time 0.02067s	Training Accuracy: 99.22%	Test Accuracy: 84.38%
    +[ 15/ 50]	FashionMNIST	Time 0.02068s	Training Accuracy: 86.13%	Test Accuracy: 68.75%
    +[ 16/ 50]	       MNIST	Time 0.02060s	Training Accuracy: 99.51%	Test Accuracy: 81.25%
    +[ 16/ 50]	FashionMNIST	Time 0.02051s	Training Accuracy: 86.13%	Test Accuracy: 65.62%
    +[ 17/ 50]	       MNIST	Time 0.02531s	Training Accuracy: 99.61%	Test Accuracy: 81.25%
    +[ 17/ 50]	FashionMNIST	Time 0.02054s	Training Accuracy: 87.11%	Test Accuracy: 71.88%
    +[ 18/ 50]	       MNIST	Time 0.02092s	Training Accuracy: 99.80%	Test Accuracy: 81.25%
    +[ 18/ 50]	FashionMNIST	Time 0.02098s	Training Accuracy: 88.28%	Test Accuracy: 75.00%
    +[ 19/ 50]	       MNIST	Time 0.02228s	Training Accuracy: 99.80%	Test Accuracy: 81.25%
    +[ 19/ 50]	FashionMNIST	Time 0.02067s	Training Accuracy: 89.16%	Test Accuracy: 71.88%
    +[ 20/ 50]	       MNIST	Time 0.02038s	Training Accuracy: 99.90%	Test Accuracy: 81.25%
    +[ 20/ 50]	FashionMNIST	Time 0.02079s	Training Accuracy: 89.26%	Test Accuracy: 75.00%
    +[ 21/ 50]	       MNIST	Time 0.02039s	Training Accuracy: 99.90%	Test Accuracy: 81.25%
    +[ 21/ 50]	FashionMNIST	Time 0.02023s	Training Accuracy: 89.65%	Test Accuracy: 75.00%
    +[ 22/ 50]	       MNIST	Time 0.02084s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 22/ 50]	FashionMNIST	Time 0.02039s	Training Accuracy: 89.94%	Test Accuracy: 75.00%
    +[ 23/ 50]	       MNIST	Time 0.02139s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 23/ 50]	FashionMNIST	Time 0.02072s	Training Accuracy: 90.43%	Test Accuracy: 71.88%
    +[ 24/ 50]	       MNIST	Time 0.02055s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 24/ 50]	FashionMNIST	Time 0.02085s	Training Accuracy: 90.72%	Test Accuracy: 71.88%
    +[ 25/ 50]	       MNIST	Time 0.02080s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 25/ 50]	FashionMNIST	Time 0.02870s	Training Accuracy: 92.29%	Test Accuracy: 75.00%
    +[ 26/ 50]	       MNIST	Time 0.02078s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 26/ 50]	FashionMNIST	Time 0.02083s	Training Accuracy: 92.38%	Test Accuracy: 71.88%
    +[ 27/ 50]	       MNIST	Time 0.02093s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 27/ 50]	FashionMNIST	Time 0.02037s	Training Accuracy: 91.80%	Test Accuracy: 75.00%
    +[ 28/ 50]	       MNIST	Time 0.02083s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 28/ 50]	FashionMNIST	Time 0.02035s	Training Accuracy: 92.97%	Test Accuracy: 68.75%
    +[ 29/ 50]	       MNIST	Time 0.02075s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 29/ 50]	FashionMNIST	Time 0.02075s	Training Accuracy: 93.16%	Test Accuracy: 71.88%
    +[ 30/ 50]	       MNIST	Time 0.02654s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 30/ 50]	FashionMNIST	Time 0.02034s	Training Accuracy: 92.09%	Test Accuracy: 71.88%
    +[ 31/ 50]	       MNIST	Time 0.02107s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 31/ 50]	FashionMNIST	Time 0.02075s	Training Accuracy: 94.24%	Test Accuracy: 71.88%
    +[ 32/ 50]	       MNIST	Time 0.02297s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 32/ 50]	FashionMNIST	Time 0.02142s	Training Accuracy: 93.65%	Test Accuracy: 71.88%
    +[ 33/ 50]	       MNIST	Time 0.02200s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 33/ 50]	FashionMNIST	Time 0.02105s	Training Accuracy: 94.34%	Test Accuracy: 75.00%
    +[ 34/ 50]	       MNIST	Time 0.02155s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 34/ 50]	FashionMNIST	Time 0.02781s	Training Accuracy: 93.65%	Test Accuracy: 68.75%
    +[ 35/ 50]	       MNIST	Time 0.02128s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 35/ 50]	FashionMNIST	Time 0.02310s	Training Accuracy: 95.12%	Test Accuracy: 71.88%
    +[ 36/ 50]	       MNIST	Time 0.02250s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 36/ 50]	FashionMNIST	Time 0.02097s	Training Accuracy: 95.90%	Test Accuracy: 71.88%
    +[ 37/ 50]	       MNIST	Time 0.02084s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 37/ 50]	FashionMNIST	Time 0.02062s	Training Accuracy: 95.80%	Test Accuracy: 75.00%
    +[ 38/ 50]	       MNIST	Time 0.02122s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 38/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 95.70%	Test Accuracy: 71.88%
    +[ 39/ 50]	       MNIST	Time 0.01987s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 39/ 50]	FashionMNIST	Time 0.02035s	Training Accuracy: 96.88%	Test Accuracy: 71.88%
    +[ 40/ 50]	       MNIST	Time 0.02083s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 40/ 50]	FashionMNIST	Time 0.02133s	Training Accuracy: 96.68%	Test Accuracy: 71.88%
    +[ 41/ 50]	       MNIST	Time 0.02054s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 41/ 50]	FashionMNIST	Time 0.02079s	Training Accuracy: 97.07%	Test Accuracy: 71.88%
    +[ 42/ 50]	       MNIST	Time 0.02094s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 42/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 97.36%	Test Accuracy: 71.88%
    +[ 43/ 50]	       MNIST	Time 0.02632s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 43/ 50]	FashionMNIST	Time 0.02029s	Training Accuracy: 97.36%	Test Accuracy: 71.88%
    +[ 44/ 50]	       MNIST	Time 0.02053s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 44/ 50]	FashionMNIST	Time 0.02080s	Training Accuracy: 97.75%	Test Accuracy: 71.88%
    +[ 45/ 50]	       MNIST	Time 0.02082s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 45/ 50]	FashionMNIST	Time 0.02060s	Training Accuracy: 97.85%	Test Accuracy: 75.00%
    +[ 46/ 50]	       MNIST	Time 0.02029s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 46/ 50]	FashionMNIST	Time 0.02048s	Training Accuracy: 97.75%	Test Accuracy: 71.88%
    +[ 47/ 50]	       MNIST	Time 0.02093s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 47/ 50]	FashionMNIST	Time 0.02595s	Training Accuracy: 97.66%	Test Accuracy: 75.00%
    +[ 48/ 50]	       MNIST	Time 0.02109s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 48/ 50]	FashionMNIST	Time 0.02037s	Training Accuracy: 96.97%	Test Accuracy: 68.75%
    +[ 49/ 50]	       MNIST	Time 0.02034s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 49/ 50]	FashionMNIST	Time 0.02065s	Training Accuracy: 97.36%	Test Accuracy: 75.00%
    +[ 50/ 50]	       MNIST	Time 0.02088s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 50/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 97.75%	Test Accuracy: 68.75%
    +
    +[FINAL]	       MNIST	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[FINAL]	FashionMNIST	Training Accuracy: 97.75%	Test Accuracy: 68.75%

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 2.170 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,25)]))}const y=i(p,[["render",l]]);export{d as __pageData,y as default}; diff --git a/previews/PR1023/assets/tutorials_intermediate_3_HyperNet.md.D4Wex7F9.lean.js b/previews/PR1023/assets/tutorials_intermediate_3_HyperNet.md.D4Wex7F9.lean.js new file mode 100644 index 0000000000..a4b0ee6dc5 --- /dev/null +++ b/previews/PR1023/assets/tutorials_intermediate_3_HyperNet.md.D4Wex7F9.lean.js @@ -0,0 +1,272 @@ +import{_ as i,c as a,a2 as n,o as t}from"./chunks/framework.DFwXuivk.js";const d=JSON.parse('{"title":"Training a HyperNetwork on MNIST and FashionMNIST","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/intermediate/3_HyperNet.md","filePath":"tutorials/intermediate/3_HyperNet.md","lastUpdated":null}'),p={name:"tutorials/intermediate/3_HyperNet.md"};function l(h,s,e,k,r,c){return t(),a("div",null,s[0]||(s[0]=[n(`

    Training a HyperNetwork on MNIST and FashionMNIST

    Package Imports

    julia
    using Lux, ADTypes, ComponentArrays, LuxCUDA, MLDatasets, MLUtils, OneHotArrays, Optimisers,
    +      Printf, Random, Setfield, Statistics, Zygote
    +
    +CUDA.allowscalar(false)

    Loading Datasets

    julia
    function load_dataset(::Type{dset}, n_train::Int, n_eval::Int, batchsize::Int) where {dset}
    +    imgs, labels = dset(:train)[1:n_train]
    +    x_train, y_train = reshape(imgs, 28, 28, 1, n_train), onehotbatch(labels, 0:9)
    +
    +    imgs, labels = dset(:test)[1:n_eval]
    +    x_test, y_test = reshape(imgs, 28, 28, 1, n_eval), onehotbatch(labels, 0:9)
    +
    +    return (
    +        DataLoader((x_train, y_train); batchsize=min(batchsize, n_train), shuffle=true),
    +        DataLoader((x_test, y_test); batchsize=min(batchsize, n_eval), shuffle=false))
    +end
    +
    +function load_datasets(n_train=1024, n_eval=32, batchsize=256)
    +    return load_dataset.((MNIST, FashionMNIST), n_train, n_eval, batchsize)
    +end
    load_datasets (generic function with 4 methods)

    Implement a HyperNet Layer

    julia
    function HyperNet(
    +        weight_generator::Lux.AbstractLuxLayer, core_network::Lux.AbstractLuxLayer)
    +    ca_axes = Lux.initialparameters(Random.default_rng(), core_network) |>
    +              ComponentArray |>
    +              getaxes
    +    return @compact(; ca_axes, weight_generator, core_network, dispatch=:HyperNet) do (x, y)
    +        # Generate the weights
    +        ps_new = ComponentArray(vec(weight_generator(x)), ca_axes)
    +        @return core_network(y, ps_new)
    +    end
    +end
    HyperNet (generic function with 1 method)

    Defining functions on the CompactLuxLayer requires some understanding of how the layer is structured, as such we don't recommend doing it unless you are familiar with the internals. In this case, we simply write it to ignore the initialization of the core_network parameters.

    julia
    function Lux.initialparameters(rng::AbstractRNG, hn::CompactLuxLayer{:HyperNet})
    +    return (; weight_generator=Lux.initialparameters(rng, hn.layers.weight_generator),)
    +end

    Create and Initialize the HyperNet

    julia
    function create_model()
    +    # Doesn't need to be a MLP can have any Lux Layer
    +    core_network = Chain(FlattenLayer(), Dense(784, 256, relu), Dense(256, 10))
    +    weight_generator = Chain(Embedding(2 => 32), Dense(32, 64, relu),
    +        Dense(64, Lux.parameterlength(core_network)))
    +
    +    model = HyperNet(weight_generator, core_network)
    +    return model
    +end
    create_model (generic function with 1 method)

    Define Utility Functions

    julia
    const loss = CrossEntropyLoss(; logits=Val(true))
    +
    +function accuracy(model, ps, st, dataloader, data_idx)
    +    total_correct, total = 0, 0
    +    st = Lux.testmode(st)
    +    for (x, y) in dataloader
    +        target_class = onecold(y)
    +        predicted_class = onecold(first(model((data_idx, x), ps, st)))
    +        total_correct += sum(target_class .== predicted_class)
    +        total += length(target_class)
    +    end
    +    return total_correct / total
    +end
    accuracy (generic function with 1 method)

    Training

    julia
    function train()
    +    model = create_model()
    +    dataloaders = load_datasets()
    +
    +    dev = gpu_device()
    +    rng = Xoshiro(0)
    +    ps, st = Lux.setup(rng, model) |> dev
    +
    +    train_state = Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    ### Lets train the model
    +    nepochs = 50
    +    for epoch in 1:nepochs, data_idx in 1:2
    +        train_dataloader, test_dataloader = dataloaders[data_idx] .|> dev
    +
    +        stime = time()
    +        for (x, y) in train_dataloader
    +            (_, _, _, train_state) = Training.single_train_step!(
    +                AutoZygote(), loss, ((data_idx, x), y), train_state)
    +        end
    +        ttime = time() - stime
    +
    +        train_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, train_dataloader, data_idx) * 100;
    +            digits=2)
    +        test_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, test_dataloader, data_idx) * 100;
    +            digits=2)
    +
    +        data_name = data_idx == 1 ? "MNIST" : "FashionMNIST"
    +
    +        @printf "[%3d/%3d]\\t%12s\\tTime %3.5fs\\tTraining Accuracy: %3.2f%%\\tTest \\
    +                 Accuracy: %3.2f%%\\n" epoch nepochs data_name ttime train_acc test_acc
    +    end
    +
    +    println()
    +
    +    test_acc_list = [0.0, 0.0]
    +    for data_idx in 1:2
    +        train_dataloader, test_dataloader = dataloaders[data_idx] .|> dev
    +        train_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, train_dataloader, data_idx) * 100;
    +            digits=2)
    +        test_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, test_dataloader, data_idx) * 100;
    +            digits=2)
    +
    +        data_name = data_idx == 1 ? "MNIST" : "FashionMNIST"
    +
    +        @printf "[FINAL]\\t%12s\\tTraining Accuracy: %3.2f%%\\tTest Accuracy: \\
    +                 %3.2f%%\\n" data_name train_acc test_acc
    +        test_acc_list[data_idx] = test_acc
    +    end
    +    return test_acc_list
    +end
    +
    +test_acc_list = train()
    [  1/ 50]	       MNIST	Time 70.85048s	Training Accuracy: 61.23%	Test Accuracy: 56.25%
    +[  1/ 50]	FashionMNIST	Time 0.02819s	Training Accuracy: 43.26%	Test Accuracy: 37.50%
    +[  2/ 50]	       MNIST	Time 0.02797s	Training Accuracy: 71.19%	Test Accuracy: 68.75%
    +[  2/ 50]	FashionMNIST	Time 0.02918s	Training Accuracy: 56.25%	Test Accuracy: 46.88%
    +[  3/ 50]	       MNIST	Time 0.02907s	Training Accuracy: 79.39%	Test Accuracy: 71.88%
    +[  3/ 50]	FashionMNIST	Time 0.02807s	Training Accuracy: 59.67%	Test Accuracy: 53.12%
    +[  4/ 50]	       MNIST	Time 0.02442s	Training Accuracy: 78.71%	Test Accuracy: 68.75%
    +[  4/ 50]	FashionMNIST	Time 0.02106s	Training Accuracy: 68.36%	Test Accuracy: 65.62%
    +[  5/ 50]	       MNIST	Time 0.02221s	Training Accuracy: 83.79%	Test Accuracy: 75.00%
    +[  5/ 50]	FashionMNIST	Time 0.02173s	Training Accuracy: 71.78%	Test Accuracy: 62.50%
    +[  6/ 50]	       MNIST	Time 0.02186s	Training Accuracy: 88.67%	Test Accuracy: 75.00%
    +[  6/ 50]	FashionMNIST	Time 0.02362s	Training Accuracy: 72.95%	Test Accuracy: 56.25%
    +[  7/ 50]	       MNIST	Time 0.02382s	Training Accuracy: 90.92%	Test Accuracy: 78.12%
    +[  7/ 50]	FashionMNIST	Time 0.02322s	Training Accuracy: 80.27%	Test Accuracy: 68.75%
    +[  8/ 50]	       MNIST	Time 0.03652s	Training Accuracy: 90.82%	Test Accuracy: 78.12%
    +[  8/ 50]	FashionMNIST	Time 0.02083s	Training Accuracy: 76.46%	Test Accuracy: 68.75%
    +[  9/ 50]	       MNIST	Time 0.02124s	Training Accuracy: 94.63%	Test Accuracy: 81.25%
    +[  9/ 50]	FashionMNIST	Time 0.02080s	Training Accuracy: 74.71%	Test Accuracy: 65.62%
    +[ 10/ 50]	       MNIST	Time 0.02075s	Training Accuracy: 94.63%	Test Accuracy: 81.25%
    +[ 10/ 50]	FashionMNIST	Time 0.02080s	Training Accuracy: 77.34%	Test Accuracy: 62.50%
    +[ 11/ 50]	       MNIST	Time 0.02030s	Training Accuracy: 96.29%	Test Accuracy: 78.12%
    +[ 11/ 50]	FashionMNIST	Time 0.02048s	Training Accuracy: 82.13%	Test Accuracy: 78.12%
    +[ 12/ 50]	       MNIST	Time 0.02080s	Training Accuracy: 97.95%	Test Accuracy: 78.12%
    +[ 12/ 50]	FashionMNIST	Time 0.02626s	Training Accuracy: 81.84%	Test Accuracy: 78.12%
    +[ 13/ 50]	       MNIST	Time 0.02091s	Training Accuracy: 98.44%	Test Accuracy: 84.38%
    +[ 13/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 84.08%	Test Accuracy: 71.88%
    +[ 14/ 50]	       MNIST	Time 0.02098s	Training Accuracy: 98.93%	Test Accuracy: 81.25%
    +[ 14/ 50]	FashionMNIST	Time 0.02068s	Training Accuracy: 85.55%	Test Accuracy: 65.62%
    +[ 15/ 50]	       MNIST	Time 0.02067s	Training Accuracy: 99.22%	Test Accuracy: 84.38%
    +[ 15/ 50]	FashionMNIST	Time 0.02068s	Training Accuracy: 86.13%	Test Accuracy: 68.75%
    +[ 16/ 50]	       MNIST	Time 0.02060s	Training Accuracy: 99.51%	Test Accuracy: 81.25%
    +[ 16/ 50]	FashionMNIST	Time 0.02051s	Training Accuracy: 86.13%	Test Accuracy: 65.62%
    +[ 17/ 50]	       MNIST	Time 0.02531s	Training Accuracy: 99.61%	Test Accuracy: 81.25%
    +[ 17/ 50]	FashionMNIST	Time 0.02054s	Training Accuracy: 87.11%	Test Accuracy: 71.88%
    +[ 18/ 50]	       MNIST	Time 0.02092s	Training Accuracy: 99.80%	Test Accuracy: 81.25%
    +[ 18/ 50]	FashionMNIST	Time 0.02098s	Training Accuracy: 88.28%	Test Accuracy: 75.00%
    +[ 19/ 50]	       MNIST	Time 0.02228s	Training Accuracy: 99.80%	Test Accuracy: 81.25%
    +[ 19/ 50]	FashionMNIST	Time 0.02067s	Training Accuracy: 89.16%	Test Accuracy: 71.88%
    +[ 20/ 50]	       MNIST	Time 0.02038s	Training Accuracy: 99.90%	Test Accuracy: 81.25%
    +[ 20/ 50]	FashionMNIST	Time 0.02079s	Training Accuracy: 89.26%	Test Accuracy: 75.00%
    +[ 21/ 50]	       MNIST	Time 0.02039s	Training Accuracy: 99.90%	Test Accuracy: 81.25%
    +[ 21/ 50]	FashionMNIST	Time 0.02023s	Training Accuracy: 89.65%	Test Accuracy: 75.00%
    +[ 22/ 50]	       MNIST	Time 0.02084s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 22/ 50]	FashionMNIST	Time 0.02039s	Training Accuracy: 89.94%	Test Accuracy: 75.00%
    +[ 23/ 50]	       MNIST	Time 0.02139s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 23/ 50]	FashionMNIST	Time 0.02072s	Training Accuracy: 90.43%	Test Accuracy: 71.88%
    +[ 24/ 50]	       MNIST	Time 0.02055s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 24/ 50]	FashionMNIST	Time 0.02085s	Training Accuracy: 90.72%	Test Accuracy: 71.88%
    +[ 25/ 50]	       MNIST	Time 0.02080s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 25/ 50]	FashionMNIST	Time 0.02870s	Training Accuracy: 92.29%	Test Accuracy: 75.00%
    +[ 26/ 50]	       MNIST	Time 0.02078s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 26/ 50]	FashionMNIST	Time 0.02083s	Training Accuracy: 92.38%	Test Accuracy: 71.88%
    +[ 27/ 50]	       MNIST	Time 0.02093s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 27/ 50]	FashionMNIST	Time 0.02037s	Training Accuracy: 91.80%	Test Accuracy: 75.00%
    +[ 28/ 50]	       MNIST	Time 0.02083s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 28/ 50]	FashionMNIST	Time 0.02035s	Training Accuracy: 92.97%	Test Accuracy: 68.75%
    +[ 29/ 50]	       MNIST	Time 0.02075s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 29/ 50]	FashionMNIST	Time 0.02075s	Training Accuracy: 93.16%	Test Accuracy: 71.88%
    +[ 30/ 50]	       MNIST	Time 0.02654s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 30/ 50]	FashionMNIST	Time 0.02034s	Training Accuracy: 92.09%	Test Accuracy: 71.88%
    +[ 31/ 50]	       MNIST	Time 0.02107s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 31/ 50]	FashionMNIST	Time 0.02075s	Training Accuracy: 94.24%	Test Accuracy: 71.88%
    +[ 32/ 50]	       MNIST	Time 0.02297s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 32/ 50]	FashionMNIST	Time 0.02142s	Training Accuracy: 93.65%	Test Accuracy: 71.88%
    +[ 33/ 50]	       MNIST	Time 0.02200s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 33/ 50]	FashionMNIST	Time 0.02105s	Training Accuracy: 94.34%	Test Accuracy: 75.00%
    +[ 34/ 50]	       MNIST	Time 0.02155s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 34/ 50]	FashionMNIST	Time 0.02781s	Training Accuracy: 93.65%	Test Accuracy: 68.75%
    +[ 35/ 50]	       MNIST	Time 0.02128s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 35/ 50]	FashionMNIST	Time 0.02310s	Training Accuracy: 95.12%	Test Accuracy: 71.88%
    +[ 36/ 50]	       MNIST	Time 0.02250s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 36/ 50]	FashionMNIST	Time 0.02097s	Training Accuracy: 95.90%	Test Accuracy: 71.88%
    +[ 37/ 50]	       MNIST	Time 0.02084s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 37/ 50]	FashionMNIST	Time 0.02062s	Training Accuracy: 95.80%	Test Accuracy: 75.00%
    +[ 38/ 50]	       MNIST	Time 0.02122s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 38/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 95.70%	Test Accuracy: 71.88%
    +[ 39/ 50]	       MNIST	Time 0.01987s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 39/ 50]	FashionMNIST	Time 0.02035s	Training Accuracy: 96.88%	Test Accuracy: 71.88%
    +[ 40/ 50]	       MNIST	Time 0.02083s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 40/ 50]	FashionMNIST	Time 0.02133s	Training Accuracy: 96.68%	Test Accuracy: 71.88%
    +[ 41/ 50]	       MNIST	Time 0.02054s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 41/ 50]	FashionMNIST	Time 0.02079s	Training Accuracy: 97.07%	Test Accuracy: 71.88%
    +[ 42/ 50]	       MNIST	Time 0.02094s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 42/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 97.36%	Test Accuracy: 71.88%
    +[ 43/ 50]	       MNIST	Time 0.02632s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 43/ 50]	FashionMNIST	Time 0.02029s	Training Accuracy: 97.36%	Test Accuracy: 71.88%
    +[ 44/ 50]	       MNIST	Time 0.02053s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 44/ 50]	FashionMNIST	Time 0.02080s	Training Accuracy: 97.75%	Test Accuracy: 71.88%
    +[ 45/ 50]	       MNIST	Time 0.02082s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 45/ 50]	FashionMNIST	Time 0.02060s	Training Accuracy: 97.85%	Test Accuracy: 75.00%
    +[ 46/ 50]	       MNIST	Time 0.02029s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 46/ 50]	FashionMNIST	Time 0.02048s	Training Accuracy: 97.75%	Test Accuracy: 71.88%
    +[ 47/ 50]	       MNIST	Time 0.02093s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 47/ 50]	FashionMNIST	Time 0.02595s	Training Accuracy: 97.66%	Test Accuracy: 75.00%
    +[ 48/ 50]	       MNIST	Time 0.02109s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 48/ 50]	FashionMNIST	Time 0.02037s	Training Accuracy: 96.97%	Test Accuracy: 68.75%
    +[ 49/ 50]	       MNIST	Time 0.02034s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 49/ 50]	FashionMNIST	Time 0.02065s	Training Accuracy: 97.36%	Test Accuracy: 75.00%
    +[ 50/ 50]	       MNIST	Time 0.02088s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 50/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 97.75%	Test Accuracy: 68.75%
    +
    +[FINAL]	       MNIST	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[FINAL]	FashionMNIST	Training Accuracy: 97.75%	Test Accuracy: 68.75%

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 2.170 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,25)]))}const y=i(p,[["render",l]]);export{d as __pageData,y as default}; diff --git a/previews/PR1023/assets/tutorials_intermediate_4_PINN2DPDE.md.lubVAoSP.js b/previews/PR1023/assets/tutorials_intermediate_4_PINN2DPDE.md.lubVAoSP.js new file mode 100644 index 0000000000..c6cdda4e4d --- /dev/null +++ b/previews/PR1023/assets/tutorials_intermediate_4_PINN2DPDE.md.lubVAoSP.js @@ -0,0 +1,343 @@ +import{_ as p,c as n,a2 as a,j as s,a as t,o as l}from"./chunks/framework.DFwXuivk.js";const h="/previews/PR1023/assets/pinn_nested_ad.B__JnolW.gif",m=JSON.parse('{"title":"Training a PINN on 2D PDE","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/intermediate/4_PINN2DPDE.md","filePath":"tutorials/intermediate/4_PINN2DPDE.md","lastUpdated":null}'),k={name:"tutorials/intermediate/4_PINN2DPDE.md"},e={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},r={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.586ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3795.2 1000","aria-hidden":"true"},E={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},d={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.401ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3713.2 1000","aria-hidden":"true"},g={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},y={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.109ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3584.2 1000","aria-hidden":"true"};function o(c,i,F,C,D,L){return l(),n("div",null,[i[10]||(i[10]=a(`

    Training a PINN on 2D PDE

    In this tutorial we will go over using a PINN to solve 2D PDEs. We will be using the system from NeuralPDE Tutorials. However, we will be using our custom loss function and use nested AD capabilities of Lux.jl.

    This is a demonstration of Lux.jl. For serious usecases of PINNs, please refer to the package: NeuralPDE.jl.

    Package Imports

    julia
    using ADTypes, Lux, Optimisers, Zygote, Random, Printf, Statistics, MLUtils, OnlineStats,
    +      CairoMakie
    +using LuxCUDA
    +
    +CUDA.allowscalar(false)
    +
    +const gdev = gpu_device()
    +const cdev = cpu_device()
    (::MLDataDevices.CPUDevice) (generic function with 5 methods)

    Problem Definition

    Since Lux supports efficient nested AD upto 2nd order, we will rewrite the problem with first order derivatives, so that we can compute the gradients of the loss using 2nd order AD.

    Define the Neural Networks

    All the networks take 3 input variables and output a scalar value. Here, we will define a a wrapper over the 3 networks, so that we can train them using Training.TrainState.

    julia
    struct PINN{U, V, W} <: Lux.AbstractLuxContainerLayer{(:u, :v, :w)}
    +    u::U
    +    v::V
    +    w::W
    +end
    +
    +function create_mlp(act, hidden_dims)
    +    return Chain(
    +        Dense(3 => hidden_dims, act),
    +        Dense(hidden_dims => hidden_dims, act),
    +        Dense(hidden_dims => hidden_dims, act),
    +        Dense(hidden_dims => 1)
    +    )
    +end
    +
    +function PINN(; hidden_dims::Int=32)
    +    return PINN(
    +        create_mlp(tanh, hidden_dims),
    +        create_mlp(tanh, hidden_dims),
    +        create_mlp(tanh, hidden_dims)
    +    )
    +end
    Main.var"##225".PINN

    Define the Loss Functions

    We will define a custom loss function to compute the loss using 2nd order AD. We will use the following loss function

    julia
    @views function physics_informed_loss_function(
    +        u::StatefulLuxLayer, v::StatefulLuxLayer, w::StatefulLuxLayer, xyt::AbstractArray)
    +    ∂u_∂xyt = only(Zygote.gradient(sum  u, xyt))
    +    ∂u_∂x, ∂u_∂y, ∂u_∂t = ∂u_∂xyt[1:1, :], ∂u_∂xyt[2:2, :], ∂u_∂xyt[3:3, :]
    +    ∂v_∂x = only(Zygote.gradient(sum  v, xyt))[1:1, :]
    +    v_xyt = v(xyt)
    +    ∂w_∂y = only(Zygote.gradient(sum  w, xyt))[2:2, :]
    +    w_xyt = w(xyt)
    +    return (
    +        mean(abs2, ∂u_∂t .- ∂v_∂x .- ∂w_∂y) +
    +        mean(abs2, v_xyt .- ∂u_∂x) +
    +        mean(abs2, w_xyt .- ∂u_∂y)
    +    )
    +end
    physics_informed_loss_function (generic function with 1 method)

    Additionally, we need to compute the loss wrt the boundary conditions.

    julia
    function mse_loss_function(u::StatefulLuxLayer, target::AbstractArray, xyt::AbstractArray)
    +    return MSELoss()(u(xyt), target)
    +end
    +
    +function loss_function(model, ps, st, (xyt, target_data, xyt_bc, target_bc))
    +    u_net = StatefulLuxLayer{true}(model.u, ps.u, st.u)
    +    v_net = StatefulLuxLayer{true}(model.v, ps.v, st.v)
    +    w_net = StatefulLuxLayer{true}(model.w, ps.w, st.w)
    +    physics_loss = physics_informed_loss_function(u_net, v_net, w_net, xyt)
    +    data_loss = mse_loss_function(u_net, target_data, xyt)
    +    bc_loss = mse_loss_function(u_net, target_bc, xyt_bc)
    +    loss = physics_loss + data_loss + bc_loss
    +    return (
    +        loss,
    +        (; u=u_net.st, v=v_net.st, w=w_net.st),
    +        (; physics_loss, data_loss, bc_loss)
    +    )
    +end
    loss_function (generic function with 1 method)

    Generate the Data

    `,20)),s("p",null,[i[6]||(i[6]=t("We will generate some random data to train the model on. We will take data on a square spatial and temporal domain ")),s("mjx-container",e,[(l(),n("svg",r,i[0]||(i[0]=[a('',1)]))),i[1]||(i[1]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"x"),s("mo",null,"∈"),s("mo",{stretchy:"false"},"["),s("mn",null,"0"),s("mo",null,","),s("mn",null,"2"),s("mo",{stretchy:"false"},"]")])],-1))]),i[7]||(i[7]=t(", ")),s("mjx-container",E,[(l(),n("svg",d,i[2]||(i[2]=[a('',1)]))),i[3]||(i[3]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"y"),s("mo",null,"∈"),s("mo",{stretchy:"false"},"["),s("mn",null,"0"),s("mo",null,","),s("mn",null,"2"),s("mo",{stretchy:"false"},"]")])],-1))]),i[8]||(i[8]=t(", and ")),s("mjx-container",g,[(l(),n("svg",y,i[4]||(i[4]=[a('',1)]))),i[5]||(i[5]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"t"),s("mo",null,"∈"),s("mo",{stretchy:"false"},"["),s("mn",null,"0"),s("mo",null,","),s("mn",null,"2"),s("mo",{stretchy:"false"},"]")])],-1))]),i[9]||(i[9]=t(". Typically, you want to be smarter about the sampling process, but for the sake of simplicity, we will skip that."))]),i[11]||(i[11]=a(`
    julia
    analytical_solution(x, y, t) = @. exp(x + y) * cos(x + y + 4t)
    +analytical_solution(xyt) = analytical_solution(xyt[1, :], xyt[2, :], xyt[3, :])
    +
    +begin
    +    grid_len = 16
    +
    +    grid = range(0.0f0, 2.0f0; length=grid_len)
    +    xyt = stack([[elem...] for elem in vec(collect(Iterators.product(grid, grid, grid)))])
    +
    +    target_data = reshape(analytical_solution(xyt), 1, :)
    +
    +    bc_len = 512
    +
    +    x = collect(range(0.0f0, 2.0f0; length=bc_len))
    +    y = collect(range(0.0f0, 2.0f0; length=bc_len))
    +    t = collect(range(0.0f0, 2.0f0; length=bc_len))
    +
    +    xyt_bc = hcat(
    +        stack((x, y, zeros(Float32, bc_len)); dims=1),
    +        stack((zeros(Float32, bc_len), y, t); dims=1),
    +        stack((ones(Float32, bc_len) .* 2, y, t); dims=1),
    +        stack((x, zeros(Float32, bc_len), t); dims=1),
    +        stack((x, ones(Float32, bc_len) .* 2, t); dims=1)
    +    )
    +    target_bc = reshape(analytical_solution(xyt_bc), 1, :)
    +
    +    min_target_bc, max_target_bc = extrema(target_bc)
    +    min_data, max_data = extrema(target_data)
    +    min_pde_val, max_pde_val = min(min_data, min_target_bc), max(max_data, max_target_bc)
    +
    +    xyt = (xyt .- minimum(xyt)) ./ (maximum(xyt) .- minimum(xyt))
    +    xyt_bc = (xyt_bc .- minimum(xyt_bc)) ./ (maximum(xyt_bc) .- minimum(xyt_bc))
    +    target_bc = (target_bc .- min_pde_val) ./ (max_pde_val - min_pde_val)
    +    target_data = (target_data .- min_pde_val) ./ (max_pde_val - min_pde_val)
    +end

    Training

    julia
    function train_model(xyt, target_data, xyt_bc, target_bc; seed::Int=0,
    +        maxiters::Int=50000, hidden_dims::Int=32)
    +    rng = Random.default_rng()
    +    Random.seed!(rng, seed)
    +
    +    pinn = PINN(; hidden_dims)
    +    ps, st = Lux.setup(rng, pinn) |> gdev
    +
    +    bc_dataloader = DataLoader((xyt_bc, target_bc); batchsize=32, shuffle=true) |> gdev
    +    pde_dataloader = DataLoader((xyt, target_data); batchsize=32, shuffle=true) |> gdev
    +
    +    train_state = Training.TrainState(pinn, ps, st, Adam(0.05f0))
    +    lr = i -> i < 5000 ? 0.05f0 : (i < 10000 ? 0.005f0 : 0.0005f0)
    +
    +    total_loss_tracker, physics_loss_tracker, data_loss_tracker, bc_loss_tracker = ntuple(
    +        _ -> Lag(Float32, 32), 4)
    +
    +    iter = 1
    +    for ((xyt_batch, target_data_batch), (xyt_bc_batch, target_bc_batch)) in zip(
    +        Iterators.cycle(pde_dataloader), Iterators.cycle(bc_dataloader))
    +        Optimisers.adjust!(train_state, lr(iter))
    +
    +        _, loss, stats, train_state = Training.single_train_step!(
    +            AutoZygote(), loss_function, (
    +                xyt_batch, target_data_batch, xyt_bc_batch, target_bc_batch),
    +            train_state)
    +
    +        fit!(total_loss_tracker, loss)
    +        fit!(physics_loss_tracker, stats.physics_loss)
    +        fit!(data_loss_tracker, stats.data_loss)
    +        fit!(bc_loss_tracker, stats.bc_loss)
    +
    +        mean_loss = mean(OnlineStats.value(total_loss_tracker))
    +        mean_physics_loss = mean(OnlineStats.value(physics_loss_tracker))
    +        mean_data_loss = mean(OnlineStats.value(data_loss_tracker))
    +        mean_bc_loss = mean(OnlineStats.value(bc_loss_tracker))
    +
    +        isnan(loss) && throw(ArgumentError("NaN Loss Detected"))
    +
    +        if iter % 500 == 1 || iter == maxiters
    +            @printf "Iteration: [%5d / %5d] \\t Loss: %.9f (%.9f) \\t Physics Loss: %.9f \\
    +                     (%.9f) \\t Data Loss: %.9f (%.9f) \\t BC \\
    +                     Loss: %.9f (%.9f)\\n" iter maxiters loss mean_loss stats.physics_loss mean_physics_loss stats.data_loss mean_data_loss stats.bc_loss mean_bc_loss
    +        end
    +
    +        iter += 1
    +        iter  maxiters && break
    +    end
    +
    +    return StatefulLuxLayer{true}(
    +        pinn, cdev(train_state.parameters), cdev(train_state.states))
    +end
    +
    +trained_model = train_model(xyt, target_data, xyt_bc, target_bc)
    +trained_u = Lux.testmode(StatefulLuxLayer{true}(
    +    trained_model.model.u, trained_model.ps.u, trained_model.st.u))
    ┌ Warning: \`Lag(T, b)\` is deprecated.  Use \`CircBuff(T,b,rev=true)\` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +┌ Warning: \`Lag(T, b)\` is deprecated.  Use \`CircBuff(T,b,rev=true)\` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +┌ Warning: \`Lag(T, b)\` is deprecated.  Use \`CircBuff(T,b,rev=true)\` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +┌ Warning: \`Lag(T, b)\` is deprecated.  Use \`CircBuff(T,b,rev=true)\` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +Iteration: [    1 / 50000] 	 Loss: 3.159042358 (3.159042358) 	 Physics Loss: 1.982162476 (1.982162476) 	 Data Loss: 0.578374863 (0.578374863) 	 BC Loss: 0.598505080 (0.598505080)
    +Iteration: [  501 / 50000] 	 Loss: 0.040918160 (0.025583776) 	 Physics Loss: 0.000391877 (0.000269295) 	 Data Loss: 0.014243508 (0.009196416) 	 BC Loss: 0.026282774 (0.016118063)
    +Iteration: [ 1001 / 50000] 	 Loss: 0.015340659 (0.025281426) 	 Physics Loss: 0.000071670 (0.000163182) 	 Data Loss: 0.007905648 (0.010876314) 	 BC Loss: 0.007363341 (0.014241929)
    +Iteration: [ 1501 / 50000] 	 Loss: 0.019567011 (0.026170366) 	 Physics Loss: 0.001279382 (0.001009728) 	 Data Loss: 0.003071612 (0.010452257) 	 BC Loss: 0.015216017 (0.014708381)
    +Iteration: [ 2001 / 50000] 	 Loss: 0.035556547 (0.027273500) 	 Physics Loss: 0.004061943 (0.001871931) 	 Data Loss: 0.013011228 (0.010586374) 	 BC Loss: 0.018483378 (0.014815190)
    +Iteration: [ 2501 / 50000] 	 Loss: 0.011505678 (0.022150228) 	 Physics Loss: 0.002304791 (0.001940841) 	 Data Loss: 0.005615299 (0.007885863) 	 BC Loss: 0.003585588 (0.012323526)
    +Iteration: [ 3001 / 50000] 	 Loss: 0.031768262 (0.029164422) 	 Physics Loss: 0.008404830 (0.003920683) 	 Data Loss: 0.008808360 (0.010936455) 	 BC Loss: 0.014555071 (0.014307282)
    +Iteration: [ 3501 / 50000] 	 Loss: 0.017645847 (0.042499166) 	 Physics Loss: 0.001848093 (0.001690981) 	 Data Loss: 0.005461216 (0.018073166) 	 BC Loss: 0.010336538 (0.022735020)
    +Iteration: [ 4001 / 50000] 	 Loss: 0.028128654 (0.027620461) 	 Physics Loss: 0.005112350 (0.002448601) 	 Data Loss: 0.013499700 (0.011073254) 	 BC Loss: 0.009516605 (0.014098606)
    +Iteration: [ 4501 / 50000] 	 Loss: 0.014340003 (0.033320315) 	 Physics Loss: 0.001292084 (0.004329988) 	 Data Loss: 0.008556721 (0.012002973) 	 BC Loss: 0.004491198 (0.016987354)
    +Iteration: [ 5001 / 50000] 	 Loss: 0.030331207 (0.041541956) 	 Physics Loss: 0.000723805 (0.002695386) 	 Data Loss: 0.004466736 (0.016228525) 	 BC Loss: 0.025140665 (0.022618050)
    +Iteration: [ 5501 / 50000] 	 Loss: 0.022293953 (0.021166507) 	 Physics Loss: 0.000554349 (0.000707158) 	 Data Loss: 0.004542338 (0.007950513) 	 BC Loss: 0.017197266 (0.012508835)
    +Iteration: [ 6001 / 50000] 	 Loss: 0.018723227 (0.020389127) 	 Physics Loss: 0.000442930 (0.000975201) 	 Data Loss: 0.006906096 (0.007273634) 	 BC Loss: 0.011374202 (0.012140292)
    +Iteration: [ 6501 / 50000] 	 Loss: 0.028305896 (0.020493284) 	 Physics Loss: 0.000753467 (0.001849154) 	 Data Loss: 0.011062279 (0.008014920) 	 BC Loss: 0.016490150 (0.010629211)
    +Iteration: [ 7001 / 50000] 	 Loss: 0.015494239 (0.020624701) 	 Physics Loss: 0.007333768 (0.001517879) 	 Data Loss: 0.004043682 (0.008185850) 	 BC Loss: 0.004116789 (0.010920972)
    +Iteration: [ 7501 / 50000] 	 Loss: 0.019155467 (0.018008159) 	 Physics Loss: 0.002511769 (0.001448493) 	 Data Loss: 0.009514628 (0.006572613) 	 BC Loss: 0.007129070 (0.009987052)
    +Iteration: [ 8001 / 50000] 	 Loss: 0.018706074 (0.017215939) 	 Physics Loss: 0.001792779 (0.001894138) 	 Data Loss: 0.005628760 (0.005433898) 	 BC Loss: 0.011284535 (0.009887908)
    +Iteration: [ 8501 / 50000] 	 Loss: 0.017605182 (0.019859709) 	 Physics Loss: 0.002696904 (0.003125851) 	 Data Loss: 0.007372384 (0.005978104) 	 BC Loss: 0.007535893 (0.010755754)
    +Iteration: [ 9001 / 50000] 	 Loss: 0.017614847 (0.016386209) 	 Physics Loss: 0.003162773 (0.002853032) 	 Data Loss: 0.003553676 (0.004607514) 	 BC Loss: 0.010898398 (0.008925664)
    +Iteration: [ 9501 / 50000] 	 Loss: 0.008732248 (0.014530762) 	 Physics Loss: 0.001913586 (0.002123826) 	 Data Loss: 0.003329928 (0.004253434) 	 BC Loss: 0.003488734 (0.008153505)
    +Iteration: [10001 / 50000] 	 Loss: 0.017750096 (0.017799046) 	 Physics Loss: 0.003630795 (0.003061282) 	 Data Loss: 0.003031955 (0.005044522) 	 BC Loss: 0.011087346 (0.009693242)
    +Iteration: [10501 / 50000] 	 Loss: 0.007509941 (0.011342090) 	 Physics Loss: 0.001571818 (0.001135202) 	 Data Loss: 0.001611185 (0.002613829) 	 BC Loss: 0.004326937 (0.007593059)
    +Iteration: [11001 / 50000] 	 Loss: 0.022739200 (0.011915382) 	 Physics Loss: 0.000807529 (0.001103305) 	 Data Loss: 0.002606506 (0.003132161) 	 BC Loss: 0.019325165 (0.007679918)
    +Iteration: [11501 / 50000] 	 Loss: 0.019484218 (0.011457845) 	 Physics Loss: 0.001845157 (0.001325290) 	 Data Loss: 0.002358936 (0.002806861) 	 BC Loss: 0.015280124 (0.007325693)
    +Iteration: [12001 / 50000] 	 Loss: 0.019427970 (0.011598296) 	 Physics Loss: 0.004434146 (0.001386037) 	 Data Loss: 0.008772802 (0.003136263) 	 BC Loss: 0.006221022 (0.007075997)
    +Iteration: [12501 / 50000] 	 Loss: 0.012775686 (0.011906523) 	 Physics Loss: 0.001197650 (0.001402911) 	 Data Loss: 0.001059842 (0.002556076) 	 BC Loss: 0.010518193 (0.007947534)
    +Iteration: [13001 / 50000] 	 Loss: 0.006105572 (0.011037273) 	 Physics Loss: 0.000987124 (0.001454655) 	 Data Loss: 0.001305370 (0.002395016) 	 BC Loss: 0.003813077 (0.007187600)
    +Iteration: [13501 / 50000] 	 Loss: 0.010004668 (0.011247103) 	 Physics Loss: 0.001224264 (0.001615586) 	 Data Loss: 0.002474443 (0.002668936) 	 BC Loss: 0.006305961 (0.006962581)
    +Iteration: [14001 / 50000] 	 Loss: 0.009895653 (0.009313912) 	 Physics Loss: 0.001215764 (0.001694928) 	 Data Loss: 0.002037087 (0.002155375) 	 BC Loss: 0.006642802 (0.005463609)
    +Iteration: [14501 / 50000] 	 Loss: 0.014400685 (0.008724037) 	 Physics Loss: 0.001658659 (0.001564218) 	 Data Loss: 0.003658900 (0.002201537) 	 BC Loss: 0.009083126 (0.004958282)
    +Iteration: [15001 / 50000] 	 Loss: 0.007676640 (0.008405063) 	 Physics Loss: 0.001566568 (0.001608545) 	 Data Loss: 0.002262217 (0.001837625) 	 BC Loss: 0.003847855 (0.004958895)
    +Iteration: [15501 / 50000] 	 Loss: 0.004365115 (0.009256126) 	 Physics Loss: 0.001047856 (0.002247394) 	 Data Loss: 0.000648518 (0.002218451) 	 BC Loss: 0.002668741 (0.004790282)
    +Iteration: [16001 / 50000] 	 Loss: 0.004880759 (0.007501942) 	 Physics Loss: 0.001649067 (0.001671217) 	 Data Loss: 0.000296087 (0.001492234) 	 BC Loss: 0.002935605 (0.004338491)
    +Iteration: [16501 / 50000] 	 Loss: 0.008074892 (0.007220342) 	 Physics Loss: 0.001825325 (0.001970405) 	 Data Loss: 0.001302087 (0.001730468) 	 BC Loss: 0.004947479 (0.003519468)
    +Iteration: [17001 / 50000] 	 Loss: 0.005824474 (0.005835793) 	 Physics Loss: 0.002019164 (0.001728887) 	 Data Loss: 0.000624455 (0.001011056) 	 BC Loss: 0.003180855 (0.003095849)
    +Iteration: [17501 / 50000] 	 Loss: 0.006616294 (0.005807751) 	 Physics Loss: 0.002489866 (0.001884541) 	 Data Loss: 0.001154157 (0.001245214) 	 BC Loss: 0.002972272 (0.002677995)
    +Iteration: [18001 / 50000] 	 Loss: 0.004335414 (0.005200472) 	 Physics Loss: 0.001764537 (0.002015869) 	 Data Loss: 0.000705982 (0.001058994) 	 BC Loss: 0.001864895 (0.002125610)
    +Iteration: [18501 / 50000] 	 Loss: 0.004978007 (0.005351806) 	 Physics Loss: 0.002553018 (0.002129085) 	 Data Loss: 0.000752965 (0.001336156) 	 BC Loss: 0.001672024 (0.001886566)
    +Iteration: [19001 / 50000] 	 Loss: 0.004518208 (0.004657542) 	 Physics Loss: 0.001975382 (0.001959185) 	 Data Loss: 0.000239237 (0.000983244) 	 BC Loss: 0.002303589 (0.001715113)
    +Iteration: [19501 / 50000] 	 Loss: 0.006942283 (0.004119421) 	 Physics Loss: 0.004590358 (0.001714717) 	 Data Loss: 0.001148389 (0.000894285) 	 BC Loss: 0.001203537 (0.001510418)
    +Iteration: [20001 / 50000] 	 Loss: 0.008026988 (0.003463188) 	 Physics Loss: 0.005315070 (0.001485110) 	 Data Loss: 0.001919697 (0.000688489) 	 BC Loss: 0.000792221 (0.001289588)
    +Iteration: [20501 / 50000] 	 Loss: 0.004855067 (0.003504427) 	 Physics Loss: 0.001560361 (0.001747428) 	 Data Loss: 0.000460401 (0.000618138) 	 BC Loss: 0.002834306 (0.001138862)
    +Iteration: [21001 / 50000] 	 Loss: 0.002417301 (0.003299790) 	 Physics Loss: 0.000924424 (0.001513747) 	 Data Loss: 0.000300984 (0.000659882) 	 BC Loss: 0.001191893 (0.001126162)
    +Iteration: [21501 / 50000] 	 Loss: 0.003911218 (0.002670718) 	 Physics Loss: 0.002752088 (0.001218763) 	 Data Loss: 0.000835131 (0.000637475) 	 BC Loss: 0.000323999 (0.000814481)
    +Iteration: [22001 / 50000] 	 Loss: 0.002318957 (0.002511334) 	 Physics Loss: 0.001409405 (0.001309370) 	 Data Loss: 0.000344849 (0.000535839) 	 BC Loss: 0.000564703 (0.000666125)
    +Iteration: [22501 / 50000] 	 Loss: 0.001994215 (0.002343247) 	 Physics Loss: 0.000746255 (0.001113559) 	 Data Loss: 0.000431564 (0.000577084) 	 BC Loss: 0.000816396 (0.000652603)
    +Iteration: [23001 / 50000] 	 Loss: 0.002989073 (0.002301548) 	 Physics Loss: 0.001930058 (0.001243673) 	 Data Loss: 0.000805100 (0.000536315) 	 BC Loss: 0.000253915 (0.000521560)
    +Iteration: [23501 / 50000] 	 Loss: 0.002210422 (0.002371583) 	 Physics Loss: 0.001325711 (0.001179150) 	 Data Loss: 0.000160725 (0.000516864) 	 BC Loss: 0.000723986 (0.000675569)
    +Iteration: [24001 / 50000] 	 Loss: 0.002023818 (0.002276814) 	 Physics Loss: 0.000857553 (0.001135292) 	 Data Loss: 0.000525994 (0.000580056) 	 BC Loss: 0.000640270 (0.000561465)
    +Iteration: [24501 / 50000] 	 Loss: 0.002234935 (0.002236427) 	 Physics Loss: 0.001041825 (0.001241080) 	 Data Loss: 0.000286281 (0.000510494) 	 BC Loss: 0.000906830 (0.000484853)
    +Iteration: [25001 / 50000] 	 Loss: 0.001972227 (0.001982885) 	 Physics Loss: 0.000893347 (0.000971555) 	 Data Loss: 0.000666251 (0.000537486) 	 BC Loss: 0.000412629 (0.000473843)
    +Iteration: [25501 / 50000] 	 Loss: 0.001659834 (0.002081697) 	 Physics Loss: 0.001085884 (0.001258897) 	 Data Loss: 0.000359855 (0.000474958) 	 BC Loss: 0.000214095 (0.000347842)
    +Iteration: [26001 / 50000] 	 Loss: 0.002059042 (0.001770784) 	 Physics Loss: 0.001171167 (0.000890729) 	 Data Loss: 0.000426463 (0.000447986) 	 BC Loss: 0.000461412 (0.000432069)
    +Iteration: [26501 / 50000] 	 Loss: 0.002089650 (0.002068657) 	 Physics Loss: 0.001594031 (0.001356683) 	 Data Loss: 0.000330550 (0.000420685) 	 BC Loss: 0.000165069 (0.000291289)
    +Iteration: [27001 / 50000] 	 Loss: 0.001346401 (0.001879478) 	 Physics Loss: 0.000798861 (0.001050717) 	 Data Loss: 0.000333685 (0.000522715) 	 BC Loss: 0.000213855 (0.000306047)
    +Iteration: [27501 / 50000] 	 Loss: 0.001717428 (0.001494603) 	 Physics Loss: 0.000754971 (0.000796866) 	 Data Loss: 0.000408040 (0.000351864) 	 BC Loss: 0.000554417 (0.000345872)
    +Iteration: [28001 / 50000] 	 Loss: 0.001498525 (0.001789054) 	 Physics Loss: 0.000881248 (0.001008533) 	 Data Loss: 0.000310122 (0.000482373) 	 BC Loss: 0.000307154 (0.000298148)
    +Iteration: [28501 / 50000] 	 Loss: 0.001300987 (0.001541014) 	 Physics Loss: 0.000685782 (0.000873007) 	 Data Loss: 0.000372513 (0.000378884) 	 BC Loss: 0.000242692 (0.000289123)
    +Iteration: [29001 / 50000] 	 Loss: 0.001302390 (0.001531350) 	 Physics Loss: 0.000764329 (0.000809421) 	 Data Loss: 0.000326938 (0.000448536) 	 BC Loss: 0.000211123 (0.000273393)
    +Iteration: [29501 / 50000] 	 Loss: 0.001228882 (0.001639404) 	 Physics Loss: 0.000864926 (0.000892691) 	 Data Loss: 0.000257633 (0.000503808) 	 BC Loss: 0.000106323 (0.000242905)
    +Iteration: [30001 / 50000] 	 Loss: 0.001362466 (0.001636085) 	 Physics Loss: 0.000635906 (0.000994050) 	 Data Loss: 0.000649345 (0.000412151) 	 BC Loss: 0.000077215 (0.000229884)
    +Iteration: [30501 / 50000] 	 Loss: 0.000972152 (0.001479216) 	 Physics Loss: 0.000619220 (0.000883626) 	 Data Loss: 0.000230181 (0.000379169) 	 BC Loss: 0.000122752 (0.000216420)
    +Iteration: [31001 / 50000] 	 Loss: 0.005065940 (0.001380907) 	 Physics Loss: 0.004397592 (0.000831873) 	 Data Loss: 0.000477057 (0.000344165) 	 BC Loss: 0.000191290 (0.000204869)
    +Iteration: [31501 / 50000] 	 Loss: 0.001720798 (0.001439294) 	 Physics Loss: 0.001153235 (0.000778960) 	 Data Loss: 0.000366380 (0.000444564) 	 BC Loss: 0.000201183 (0.000215771)
    +Iteration: [32001 / 50000] 	 Loss: 0.001272172 (0.001182971) 	 Physics Loss: 0.000547293 (0.000645338) 	 Data Loss: 0.000612554 (0.000330688) 	 BC Loss: 0.000112325 (0.000206944)
    +Iteration: [32501 / 50000] 	 Loss: 0.001592739 (0.001303701) 	 Physics Loss: 0.001089040 (0.000732894) 	 Data Loss: 0.000368751 (0.000377450) 	 BC Loss: 0.000134948 (0.000193357)
    +Iteration: [33001 / 50000] 	 Loss: 0.001257007 (0.001731674) 	 Physics Loss: 0.000964463 (0.001143823) 	 Data Loss: 0.000217459 (0.000395994) 	 BC Loss: 0.000075086 (0.000191858)
    +Iteration: [33501 / 50000] 	 Loss: 0.001404967 (0.001307026) 	 Physics Loss: 0.000708074 (0.000685339) 	 Data Loss: 0.000530431 (0.000435325) 	 BC Loss: 0.000166462 (0.000186362)
    +Iteration: [34001 / 50000] 	 Loss: 0.000798481 (0.001060399) 	 Physics Loss: 0.000366831 (0.000566683) 	 Data Loss: 0.000218087 (0.000317301) 	 BC Loss: 0.000213564 (0.000176415)
    +Iteration: [34501 / 50000] 	 Loss: 0.001798573 (0.001364744) 	 Physics Loss: 0.001362987 (0.000847362) 	 Data Loss: 0.000308547 (0.000354412) 	 BC Loss: 0.000127040 (0.000162970)
    +Iteration: [35001 / 50000] 	 Loss: 0.000781053 (0.001014936) 	 Physics Loss: 0.000422994 (0.000539345) 	 Data Loss: 0.000270824 (0.000311768) 	 BC Loss: 0.000087234 (0.000163823)
    +Iteration: [35501 / 50000] 	 Loss: 0.001209691 (0.001329915) 	 Physics Loss: 0.000784697 (0.000694873) 	 Data Loss: 0.000264404 (0.000425117) 	 BC Loss: 0.000160591 (0.000209925)
    +Iteration: [36001 / 50000] 	 Loss: 0.001398915 (0.001136703) 	 Physics Loss: 0.000490567 (0.000583094) 	 Data Loss: 0.000744279 (0.000401171) 	 BC Loss: 0.000164069 (0.000152438)
    +Iteration: [36501 / 50000] 	 Loss: 0.000835373 (0.001367094) 	 Physics Loss: 0.000595709 (0.000792289) 	 Data Loss: 0.000132676 (0.000426714) 	 BC Loss: 0.000106987 (0.000148092)
    +Iteration: [37001 / 50000] 	 Loss: 0.000952036 (0.001044580) 	 Physics Loss: 0.000709375 (0.000580873) 	 Data Loss: 0.000161545 (0.000334467) 	 BC Loss: 0.000081115 (0.000129240)
    +Iteration: [37501 / 50000] 	 Loss: 0.000579479 (0.001085730) 	 Physics Loss: 0.000270049 (0.000599332) 	 Data Loss: 0.000242183 (0.000348117) 	 BC Loss: 0.000067247 (0.000138281)
    +Iteration: [38001 / 50000] 	 Loss: 0.001053359 (0.001110448) 	 Physics Loss: 0.000445312 (0.000595116) 	 Data Loss: 0.000482833 (0.000353724) 	 BC Loss: 0.000125214 (0.000161607)
    +Iteration: [38501 / 50000] 	 Loss: 0.000667115 (0.001049175) 	 Physics Loss: 0.000326662 (0.000543516) 	 Data Loss: 0.000173648 (0.000387762) 	 BC Loss: 0.000166804 (0.000117897)
    +Iteration: [39001 / 50000] 	 Loss: 0.000687853 (0.001085206) 	 Physics Loss: 0.000313576 (0.000590442) 	 Data Loss: 0.000321921 (0.000367264) 	 BC Loss: 0.000052356 (0.000127500)
    +Iteration: [39501 / 50000] 	 Loss: 0.000673423 (0.001160439) 	 Physics Loss: 0.000421422 (0.000714949) 	 Data Loss: 0.000192454 (0.000300986) 	 BC Loss: 0.000059547 (0.000144504)
    +Iteration: [40001 / 50000] 	 Loss: 0.000938448 (0.001243982) 	 Physics Loss: 0.000547043 (0.000710499) 	 Data Loss: 0.000287677 (0.000374305) 	 BC Loss: 0.000103729 (0.000159178)
    +Iteration: [40501 / 50000] 	 Loss: 0.001798752 (0.001093546) 	 Physics Loss: 0.000866074 (0.000650020) 	 Data Loss: 0.000780730 (0.000305183) 	 BC Loss: 0.000151947 (0.000138344)
    +Iteration: [41001 / 50000] 	 Loss: 0.001101400 (0.001448896) 	 Physics Loss: 0.000600817 (0.000901216) 	 Data Loss: 0.000405329 (0.000389668) 	 BC Loss: 0.000095254 (0.000158011)
    +Iteration: [41501 / 50000] 	 Loss: 0.000776893 (0.000824789) 	 Physics Loss: 0.000455096 (0.000410463) 	 Data Loss: 0.000206055 (0.000317277) 	 BC Loss: 0.000115742 (0.000097049)
    +Iteration: [42001 / 50000] 	 Loss: 0.001060384 (0.001240770) 	 Physics Loss: 0.000583868 (0.000778712) 	 Data Loss: 0.000378937 (0.000335865) 	 BC Loss: 0.000097578 (0.000126193)
    +Iteration: [42501 / 50000] 	 Loss: 0.000691815 (0.000944194) 	 Physics Loss: 0.000381213 (0.000516831) 	 Data Loss: 0.000162085 (0.000307154) 	 BC Loss: 0.000148517 (0.000120209)
    +Iteration: [43001 / 50000] 	 Loss: 0.000545245 (0.000868335) 	 Physics Loss: 0.000363892 (0.000449657) 	 Data Loss: 0.000124517 (0.000324281) 	 BC Loss: 0.000056836 (0.000094398)
    +Iteration: [43501 / 50000] 	 Loss: 0.001068081 (0.001141232) 	 Physics Loss: 0.000613936 (0.000622923) 	 Data Loss: 0.000369106 (0.000392804) 	 BC Loss: 0.000085040 (0.000125504)
    +Iteration: [44001 / 50000] 	 Loss: 0.001168622 (0.000963809) 	 Physics Loss: 0.000486189 (0.000540564) 	 Data Loss: 0.000549527 (0.000306839) 	 BC Loss: 0.000132906 (0.000116407)
    +Iteration: [44501 / 50000] 	 Loss: 0.000939374 (0.000756769) 	 Physics Loss: 0.000379668 (0.000386392) 	 Data Loss: 0.000454265 (0.000277635) 	 BC Loss: 0.000105440 (0.000092742)
    +Iteration: [45001 / 50000] 	 Loss: 0.001202180 (0.000892342) 	 Physics Loss: 0.000726597 (0.000506370) 	 Data Loss: 0.000367492 (0.000280093) 	 BC Loss: 0.000108091 (0.000105879)
    +Iteration: [45501 / 50000] 	 Loss: 0.000887047 (0.000908168) 	 Physics Loss: 0.000641108 (0.000560744) 	 Data Loss: 0.000148591 (0.000263541) 	 BC Loss: 0.000097348 (0.000083883)
    +Iteration: [46001 / 50000] 	 Loss: 0.000525872 (0.000734937) 	 Physics Loss: 0.000322635 (0.000362759) 	 Data Loss: 0.000158824 (0.000288360) 	 BC Loss: 0.000044412 (0.000083818)
    +Iteration: [46501 / 50000] 	 Loss: 0.000545968 (0.000907963) 	 Physics Loss: 0.000350560 (0.000489585) 	 Data Loss: 0.000136768 (0.000312205) 	 BC Loss: 0.000058640 (0.000106173)
    +Iteration: [47001 / 50000] 	 Loss: 0.000826687 (0.000924496) 	 Physics Loss: 0.000575209 (0.000511645) 	 Data Loss: 0.000205284 (0.000314716) 	 BC Loss: 0.000046194 (0.000098134)
    +Iteration: [47501 / 50000] 	 Loss: 0.000620959 (0.001185708) 	 Physics Loss: 0.000382126 (0.000788119) 	 Data Loss: 0.000148993 (0.000271556) 	 BC Loss: 0.000089840 (0.000126034)
    +Iteration: [48001 / 50000] 	 Loss: 0.000664698 (0.000798627) 	 Physics Loss: 0.000412207 (0.000461797) 	 Data Loss: 0.000182339 (0.000250679) 	 BC Loss: 0.000070152 (0.000086152)
    +Iteration: [48501 / 50000] 	 Loss: 0.000826713 (0.000925605) 	 Physics Loss: 0.000485339 (0.000512687) 	 Data Loss: 0.000170909 (0.000314013) 	 BC Loss: 0.000170466 (0.000098905)
    +Iteration: [49001 / 50000] 	 Loss: 0.000559556 (0.000846881) 	 Physics Loss: 0.000350503 (0.000421408) 	 Data Loss: 0.000165743 (0.000346362) 	 BC Loss: 0.000043311 (0.000079111)
    +Iteration: [49501 / 50000] 	 Loss: 0.000652327 (0.000740137) 	 Physics Loss: 0.000301691 (0.000376061) 	 Data Loss: 0.000195276 (0.000275985) 	 BC Loss: 0.000155360 (0.000088090)

    Visualizing the Results

    julia
    ts, xs, ys = 0.0f0:0.05f0:2.0f0, 0.0f0:0.02f0:2.0f0, 0.0f0:0.02f0:2.0f0
    +grid = stack([[elem...] for elem in vec(collect(Iterators.product(xs, ys, ts)))])
    +
    +u_real = reshape(analytical_solution(grid), length(xs), length(ys), length(ts))
    +
    +grid_normalized = (grid .- minimum(grid)) ./ (maximum(grid) .- minimum(grid))
    +u_pred = reshape(trained_u(grid_normalized), length(xs), length(ys), length(ts))
    +u_pred = u_pred .* (max_pde_val - min_pde_val) .+ min_pde_val
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +    errs = [abs.(u_pred[:, :, i] .- u_real[:, :, i]) for i in 1:length(ts)]
    +    Colorbar(fig[1, 2]; limits=extrema(stack(errs)))
    +
    +    CairoMakie.record(fig, "pinn_nested_ad.gif", 1:length(ts); framerate=10) do i
    +        ax.title = "Abs. Predictor Error | Time: $(ts[i])"
    +        err = errs[i]
    +        contour!(ax, xs, ys, err; levels=10, linewidth=2)
    +        heatmap!(ax, xs, ys, err)
    +        return fig
    +    end
    +
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.484 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,12))])}const B=p(k,[["render",o]]);export{m as __pageData,B as default}; diff --git a/previews/PR1023/assets/tutorials_intermediate_4_PINN2DPDE.md.lubVAoSP.lean.js b/previews/PR1023/assets/tutorials_intermediate_4_PINN2DPDE.md.lubVAoSP.lean.js new file mode 100644 index 0000000000..c6cdda4e4d --- /dev/null +++ b/previews/PR1023/assets/tutorials_intermediate_4_PINN2DPDE.md.lubVAoSP.lean.js @@ -0,0 +1,343 @@ +import{_ as p,c as n,a2 as a,j as s,a as t,o as l}from"./chunks/framework.DFwXuivk.js";const h="/previews/PR1023/assets/pinn_nested_ad.B__JnolW.gif",m=JSON.parse('{"title":"Training a PINN on 2D PDE","description":"","frontmatter":{},"headers":[],"relativePath":"tutorials/intermediate/4_PINN2DPDE.md","filePath":"tutorials/intermediate/4_PINN2DPDE.md","lastUpdated":null}'),k={name:"tutorials/intermediate/4_PINN2DPDE.md"},e={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},r={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.586ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3795.2 1000","aria-hidden":"true"},E={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},d={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.401ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3713.2 1000","aria-hidden":"true"},g={class:"MathJax",jax:"SVG",style:{direction:"ltr",position:"relative"}},y={style:{overflow:"visible","min-height":"1px","min-width":"1px","vertical-align":"-0.566ex"},xmlns:"http://www.w3.org/2000/svg",width:"8.109ex",height:"2.262ex",role:"img",focusable:"false",viewBox:"0 -750 3584.2 1000","aria-hidden":"true"};function o(c,i,F,C,D,L){return l(),n("div",null,[i[10]||(i[10]=a(`

    Training a PINN on 2D PDE

    In this tutorial we will go over using a PINN to solve 2D PDEs. We will be using the system from NeuralPDE Tutorials. However, we will be using our custom loss function and use nested AD capabilities of Lux.jl.

    This is a demonstration of Lux.jl. For serious usecases of PINNs, please refer to the package: NeuralPDE.jl.

    Package Imports

    julia
    using ADTypes, Lux, Optimisers, Zygote, Random, Printf, Statistics, MLUtils, OnlineStats,
    +      CairoMakie
    +using LuxCUDA
    +
    +CUDA.allowscalar(false)
    +
    +const gdev = gpu_device()
    +const cdev = cpu_device()
    (::MLDataDevices.CPUDevice) (generic function with 5 methods)

    Problem Definition

    Since Lux supports efficient nested AD upto 2nd order, we will rewrite the problem with first order derivatives, so that we can compute the gradients of the loss using 2nd order AD.

    Define the Neural Networks

    All the networks take 3 input variables and output a scalar value. Here, we will define a a wrapper over the 3 networks, so that we can train them using Training.TrainState.

    julia
    struct PINN{U, V, W} <: Lux.AbstractLuxContainerLayer{(:u, :v, :w)}
    +    u::U
    +    v::V
    +    w::W
    +end
    +
    +function create_mlp(act, hidden_dims)
    +    return Chain(
    +        Dense(3 => hidden_dims, act),
    +        Dense(hidden_dims => hidden_dims, act),
    +        Dense(hidden_dims => hidden_dims, act),
    +        Dense(hidden_dims => 1)
    +    )
    +end
    +
    +function PINN(; hidden_dims::Int=32)
    +    return PINN(
    +        create_mlp(tanh, hidden_dims),
    +        create_mlp(tanh, hidden_dims),
    +        create_mlp(tanh, hidden_dims)
    +    )
    +end
    Main.var"##225".PINN

    Define the Loss Functions

    We will define a custom loss function to compute the loss using 2nd order AD. We will use the following loss function

    julia
    @views function physics_informed_loss_function(
    +        u::StatefulLuxLayer, v::StatefulLuxLayer, w::StatefulLuxLayer, xyt::AbstractArray)
    +    ∂u_∂xyt = only(Zygote.gradient(sum  u, xyt))
    +    ∂u_∂x, ∂u_∂y, ∂u_∂t = ∂u_∂xyt[1:1, :], ∂u_∂xyt[2:2, :], ∂u_∂xyt[3:3, :]
    +    ∂v_∂x = only(Zygote.gradient(sum  v, xyt))[1:1, :]
    +    v_xyt = v(xyt)
    +    ∂w_∂y = only(Zygote.gradient(sum  w, xyt))[2:2, :]
    +    w_xyt = w(xyt)
    +    return (
    +        mean(abs2, ∂u_∂t .- ∂v_∂x .- ∂w_∂y) +
    +        mean(abs2, v_xyt .- ∂u_∂x) +
    +        mean(abs2, w_xyt .- ∂u_∂y)
    +    )
    +end
    physics_informed_loss_function (generic function with 1 method)

    Additionally, we need to compute the loss wrt the boundary conditions.

    julia
    function mse_loss_function(u::StatefulLuxLayer, target::AbstractArray, xyt::AbstractArray)
    +    return MSELoss()(u(xyt), target)
    +end
    +
    +function loss_function(model, ps, st, (xyt, target_data, xyt_bc, target_bc))
    +    u_net = StatefulLuxLayer{true}(model.u, ps.u, st.u)
    +    v_net = StatefulLuxLayer{true}(model.v, ps.v, st.v)
    +    w_net = StatefulLuxLayer{true}(model.w, ps.w, st.w)
    +    physics_loss = physics_informed_loss_function(u_net, v_net, w_net, xyt)
    +    data_loss = mse_loss_function(u_net, target_data, xyt)
    +    bc_loss = mse_loss_function(u_net, target_bc, xyt_bc)
    +    loss = physics_loss + data_loss + bc_loss
    +    return (
    +        loss,
    +        (; u=u_net.st, v=v_net.st, w=w_net.st),
    +        (; physics_loss, data_loss, bc_loss)
    +    )
    +end
    loss_function (generic function with 1 method)

    Generate the Data

    `,20)),s("p",null,[i[6]||(i[6]=t("We will generate some random data to train the model on. We will take data on a square spatial and temporal domain ")),s("mjx-container",e,[(l(),n("svg",r,i[0]||(i[0]=[a('',1)]))),i[1]||(i[1]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"x"),s("mo",null,"∈"),s("mo",{stretchy:"false"},"["),s("mn",null,"0"),s("mo",null,","),s("mn",null,"2"),s("mo",{stretchy:"false"},"]")])],-1))]),i[7]||(i[7]=t(", ")),s("mjx-container",E,[(l(),n("svg",d,i[2]||(i[2]=[a('',1)]))),i[3]||(i[3]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"y"),s("mo",null,"∈"),s("mo",{stretchy:"false"},"["),s("mn",null,"0"),s("mo",null,","),s("mn",null,"2"),s("mo",{stretchy:"false"},"]")])],-1))]),i[8]||(i[8]=t(", and ")),s("mjx-container",g,[(l(),n("svg",y,i[4]||(i[4]=[a('',1)]))),i[5]||(i[5]=s("mjx-assistive-mml",{unselectable:"on",display:"inline",style:{top:"0px",left:"0px",clip:"rect(1px, 1px, 1px, 1px)","-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none",position:"absolute",padding:"1px 0px 0px 0px",border:"0px",display:"block",width:"auto",overflow:"hidden"}},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("mi",null,"t"),s("mo",null,"∈"),s("mo",{stretchy:"false"},"["),s("mn",null,"0"),s("mo",null,","),s("mn",null,"2"),s("mo",{stretchy:"false"},"]")])],-1))]),i[9]||(i[9]=t(". Typically, you want to be smarter about the sampling process, but for the sake of simplicity, we will skip that."))]),i[11]||(i[11]=a(`
    julia
    analytical_solution(x, y, t) = @. exp(x + y) * cos(x + y + 4t)
    +analytical_solution(xyt) = analytical_solution(xyt[1, :], xyt[2, :], xyt[3, :])
    +
    +begin
    +    grid_len = 16
    +
    +    grid = range(0.0f0, 2.0f0; length=grid_len)
    +    xyt = stack([[elem...] for elem in vec(collect(Iterators.product(grid, grid, grid)))])
    +
    +    target_data = reshape(analytical_solution(xyt), 1, :)
    +
    +    bc_len = 512
    +
    +    x = collect(range(0.0f0, 2.0f0; length=bc_len))
    +    y = collect(range(0.0f0, 2.0f0; length=bc_len))
    +    t = collect(range(0.0f0, 2.0f0; length=bc_len))
    +
    +    xyt_bc = hcat(
    +        stack((x, y, zeros(Float32, bc_len)); dims=1),
    +        stack((zeros(Float32, bc_len), y, t); dims=1),
    +        stack((ones(Float32, bc_len) .* 2, y, t); dims=1),
    +        stack((x, zeros(Float32, bc_len), t); dims=1),
    +        stack((x, ones(Float32, bc_len) .* 2, t); dims=1)
    +    )
    +    target_bc = reshape(analytical_solution(xyt_bc), 1, :)
    +
    +    min_target_bc, max_target_bc = extrema(target_bc)
    +    min_data, max_data = extrema(target_data)
    +    min_pde_val, max_pde_val = min(min_data, min_target_bc), max(max_data, max_target_bc)
    +
    +    xyt = (xyt .- minimum(xyt)) ./ (maximum(xyt) .- minimum(xyt))
    +    xyt_bc = (xyt_bc .- minimum(xyt_bc)) ./ (maximum(xyt_bc) .- minimum(xyt_bc))
    +    target_bc = (target_bc .- min_pde_val) ./ (max_pde_val - min_pde_val)
    +    target_data = (target_data .- min_pde_val) ./ (max_pde_val - min_pde_val)
    +end

    Training

    julia
    function train_model(xyt, target_data, xyt_bc, target_bc; seed::Int=0,
    +        maxiters::Int=50000, hidden_dims::Int=32)
    +    rng = Random.default_rng()
    +    Random.seed!(rng, seed)
    +
    +    pinn = PINN(; hidden_dims)
    +    ps, st = Lux.setup(rng, pinn) |> gdev
    +
    +    bc_dataloader = DataLoader((xyt_bc, target_bc); batchsize=32, shuffle=true) |> gdev
    +    pde_dataloader = DataLoader((xyt, target_data); batchsize=32, shuffle=true) |> gdev
    +
    +    train_state = Training.TrainState(pinn, ps, st, Adam(0.05f0))
    +    lr = i -> i < 5000 ? 0.05f0 : (i < 10000 ? 0.005f0 : 0.0005f0)
    +
    +    total_loss_tracker, physics_loss_tracker, data_loss_tracker, bc_loss_tracker = ntuple(
    +        _ -> Lag(Float32, 32), 4)
    +
    +    iter = 1
    +    for ((xyt_batch, target_data_batch), (xyt_bc_batch, target_bc_batch)) in zip(
    +        Iterators.cycle(pde_dataloader), Iterators.cycle(bc_dataloader))
    +        Optimisers.adjust!(train_state, lr(iter))
    +
    +        _, loss, stats, train_state = Training.single_train_step!(
    +            AutoZygote(), loss_function, (
    +                xyt_batch, target_data_batch, xyt_bc_batch, target_bc_batch),
    +            train_state)
    +
    +        fit!(total_loss_tracker, loss)
    +        fit!(physics_loss_tracker, stats.physics_loss)
    +        fit!(data_loss_tracker, stats.data_loss)
    +        fit!(bc_loss_tracker, stats.bc_loss)
    +
    +        mean_loss = mean(OnlineStats.value(total_loss_tracker))
    +        mean_physics_loss = mean(OnlineStats.value(physics_loss_tracker))
    +        mean_data_loss = mean(OnlineStats.value(data_loss_tracker))
    +        mean_bc_loss = mean(OnlineStats.value(bc_loss_tracker))
    +
    +        isnan(loss) && throw(ArgumentError("NaN Loss Detected"))
    +
    +        if iter % 500 == 1 || iter == maxiters
    +            @printf "Iteration: [%5d / %5d] \\t Loss: %.9f (%.9f) \\t Physics Loss: %.9f \\
    +                     (%.9f) \\t Data Loss: %.9f (%.9f) \\t BC \\
    +                     Loss: %.9f (%.9f)\\n" iter maxiters loss mean_loss stats.physics_loss mean_physics_loss stats.data_loss mean_data_loss stats.bc_loss mean_bc_loss
    +        end
    +
    +        iter += 1
    +        iter  maxiters && break
    +    end
    +
    +    return StatefulLuxLayer{true}(
    +        pinn, cdev(train_state.parameters), cdev(train_state.states))
    +end
    +
    +trained_model = train_model(xyt, target_data, xyt_bc, target_bc)
    +trained_u = Lux.testmode(StatefulLuxLayer{true}(
    +    trained_model.model.u, trained_model.ps.u, trained_model.st.u))
    ┌ Warning: \`Lag(T, b)\` is deprecated.  Use \`CircBuff(T,b,rev=true)\` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +┌ Warning: \`Lag(T, b)\` is deprecated.  Use \`CircBuff(T,b,rev=true)\` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +┌ Warning: \`Lag(T, b)\` is deprecated.  Use \`CircBuff(T,b,rev=true)\` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +┌ Warning: \`Lag(T, b)\` is deprecated.  Use \`CircBuff(T,b,rev=true)\` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +Iteration: [    1 / 50000] 	 Loss: 3.159042358 (3.159042358) 	 Physics Loss: 1.982162476 (1.982162476) 	 Data Loss: 0.578374863 (0.578374863) 	 BC Loss: 0.598505080 (0.598505080)
    +Iteration: [  501 / 50000] 	 Loss: 0.040918160 (0.025583776) 	 Physics Loss: 0.000391877 (0.000269295) 	 Data Loss: 0.014243508 (0.009196416) 	 BC Loss: 0.026282774 (0.016118063)
    +Iteration: [ 1001 / 50000] 	 Loss: 0.015340659 (0.025281426) 	 Physics Loss: 0.000071670 (0.000163182) 	 Data Loss: 0.007905648 (0.010876314) 	 BC Loss: 0.007363341 (0.014241929)
    +Iteration: [ 1501 / 50000] 	 Loss: 0.019567011 (0.026170366) 	 Physics Loss: 0.001279382 (0.001009728) 	 Data Loss: 0.003071612 (0.010452257) 	 BC Loss: 0.015216017 (0.014708381)
    +Iteration: [ 2001 / 50000] 	 Loss: 0.035556547 (0.027273500) 	 Physics Loss: 0.004061943 (0.001871931) 	 Data Loss: 0.013011228 (0.010586374) 	 BC Loss: 0.018483378 (0.014815190)
    +Iteration: [ 2501 / 50000] 	 Loss: 0.011505678 (0.022150228) 	 Physics Loss: 0.002304791 (0.001940841) 	 Data Loss: 0.005615299 (0.007885863) 	 BC Loss: 0.003585588 (0.012323526)
    +Iteration: [ 3001 / 50000] 	 Loss: 0.031768262 (0.029164422) 	 Physics Loss: 0.008404830 (0.003920683) 	 Data Loss: 0.008808360 (0.010936455) 	 BC Loss: 0.014555071 (0.014307282)
    +Iteration: [ 3501 / 50000] 	 Loss: 0.017645847 (0.042499166) 	 Physics Loss: 0.001848093 (0.001690981) 	 Data Loss: 0.005461216 (0.018073166) 	 BC Loss: 0.010336538 (0.022735020)
    +Iteration: [ 4001 / 50000] 	 Loss: 0.028128654 (0.027620461) 	 Physics Loss: 0.005112350 (0.002448601) 	 Data Loss: 0.013499700 (0.011073254) 	 BC Loss: 0.009516605 (0.014098606)
    +Iteration: [ 4501 / 50000] 	 Loss: 0.014340003 (0.033320315) 	 Physics Loss: 0.001292084 (0.004329988) 	 Data Loss: 0.008556721 (0.012002973) 	 BC Loss: 0.004491198 (0.016987354)
    +Iteration: [ 5001 / 50000] 	 Loss: 0.030331207 (0.041541956) 	 Physics Loss: 0.000723805 (0.002695386) 	 Data Loss: 0.004466736 (0.016228525) 	 BC Loss: 0.025140665 (0.022618050)
    +Iteration: [ 5501 / 50000] 	 Loss: 0.022293953 (0.021166507) 	 Physics Loss: 0.000554349 (0.000707158) 	 Data Loss: 0.004542338 (0.007950513) 	 BC Loss: 0.017197266 (0.012508835)
    +Iteration: [ 6001 / 50000] 	 Loss: 0.018723227 (0.020389127) 	 Physics Loss: 0.000442930 (0.000975201) 	 Data Loss: 0.006906096 (0.007273634) 	 BC Loss: 0.011374202 (0.012140292)
    +Iteration: [ 6501 / 50000] 	 Loss: 0.028305896 (0.020493284) 	 Physics Loss: 0.000753467 (0.001849154) 	 Data Loss: 0.011062279 (0.008014920) 	 BC Loss: 0.016490150 (0.010629211)
    +Iteration: [ 7001 / 50000] 	 Loss: 0.015494239 (0.020624701) 	 Physics Loss: 0.007333768 (0.001517879) 	 Data Loss: 0.004043682 (0.008185850) 	 BC Loss: 0.004116789 (0.010920972)
    +Iteration: [ 7501 / 50000] 	 Loss: 0.019155467 (0.018008159) 	 Physics Loss: 0.002511769 (0.001448493) 	 Data Loss: 0.009514628 (0.006572613) 	 BC Loss: 0.007129070 (0.009987052)
    +Iteration: [ 8001 / 50000] 	 Loss: 0.018706074 (0.017215939) 	 Physics Loss: 0.001792779 (0.001894138) 	 Data Loss: 0.005628760 (0.005433898) 	 BC Loss: 0.011284535 (0.009887908)
    +Iteration: [ 8501 / 50000] 	 Loss: 0.017605182 (0.019859709) 	 Physics Loss: 0.002696904 (0.003125851) 	 Data Loss: 0.007372384 (0.005978104) 	 BC Loss: 0.007535893 (0.010755754)
    +Iteration: [ 9001 / 50000] 	 Loss: 0.017614847 (0.016386209) 	 Physics Loss: 0.003162773 (0.002853032) 	 Data Loss: 0.003553676 (0.004607514) 	 BC Loss: 0.010898398 (0.008925664)
    +Iteration: [ 9501 / 50000] 	 Loss: 0.008732248 (0.014530762) 	 Physics Loss: 0.001913586 (0.002123826) 	 Data Loss: 0.003329928 (0.004253434) 	 BC Loss: 0.003488734 (0.008153505)
    +Iteration: [10001 / 50000] 	 Loss: 0.017750096 (0.017799046) 	 Physics Loss: 0.003630795 (0.003061282) 	 Data Loss: 0.003031955 (0.005044522) 	 BC Loss: 0.011087346 (0.009693242)
    +Iteration: [10501 / 50000] 	 Loss: 0.007509941 (0.011342090) 	 Physics Loss: 0.001571818 (0.001135202) 	 Data Loss: 0.001611185 (0.002613829) 	 BC Loss: 0.004326937 (0.007593059)
    +Iteration: [11001 / 50000] 	 Loss: 0.022739200 (0.011915382) 	 Physics Loss: 0.000807529 (0.001103305) 	 Data Loss: 0.002606506 (0.003132161) 	 BC Loss: 0.019325165 (0.007679918)
    +Iteration: [11501 / 50000] 	 Loss: 0.019484218 (0.011457845) 	 Physics Loss: 0.001845157 (0.001325290) 	 Data Loss: 0.002358936 (0.002806861) 	 BC Loss: 0.015280124 (0.007325693)
    +Iteration: [12001 / 50000] 	 Loss: 0.019427970 (0.011598296) 	 Physics Loss: 0.004434146 (0.001386037) 	 Data Loss: 0.008772802 (0.003136263) 	 BC Loss: 0.006221022 (0.007075997)
    +Iteration: [12501 / 50000] 	 Loss: 0.012775686 (0.011906523) 	 Physics Loss: 0.001197650 (0.001402911) 	 Data Loss: 0.001059842 (0.002556076) 	 BC Loss: 0.010518193 (0.007947534)
    +Iteration: [13001 / 50000] 	 Loss: 0.006105572 (0.011037273) 	 Physics Loss: 0.000987124 (0.001454655) 	 Data Loss: 0.001305370 (0.002395016) 	 BC Loss: 0.003813077 (0.007187600)
    +Iteration: [13501 / 50000] 	 Loss: 0.010004668 (0.011247103) 	 Physics Loss: 0.001224264 (0.001615586) 	 Data Loss: 0.002474443 (0.002668936) 	 BC Loss: 0.006305961 (0.006962581)
    +Iteration: [14001 / 50000] 	 Loss: 0.009895653 (0.009313912) 	 Physics Loss: 0.001215764 (0.001694928) 	 Data Loss: 0.002037087 (0.002155375) 	 BC Loss: 0.006642802 (0.005463609)
    +Iteration: [14501 / 50000] 	 Loss: 0.014400685 (0.008724037) 	 Physics Loss: 0.001658659 (0.001564218) 	 Data Loss: 0.003658900 (0.002201537) 	 BC Loss: 0.009083126 (0.004958282)
    +Iteration: [15001 / 50000] 	 Loss: 0.007676640 (0.008405063) 	 Physics Loss: 0.001566568 (0.001608545) 	 Data Loss: 0.002262217 (0.001837625) 	 BC Loss: 0.003847855 (0.004958895)
    +Iteration: [15501 / 50000] 	 Loss: 0.004365115 (0.009256126) 	 Physics Loss: 0.001047856 (0.002247394) 	 Data Loss: 0.000648518 (0.002218451) 	 BC Loss: 0.002668741 (0.004790282)
    +Iteration: [16001 / 50000] 	 Loss: 0.004880759 (0.007501942) 	 Physics Loss: 0.001649067 (0.001671217) 	 Data Loss: 0.000296087 (0.001492234) 	 BC Loss: 0.002935605 (0.004338491)
    +Iteration: [16501 / 50000] 	 Loss: 0.008074892 (0.007220342) 	 Physics Loss: 0.001825325 (0.001970405) 	 Data Loss: 0.001302087 (0.001730468) 	 BC Loss: 0.004947479 (0.003519468)
    +Iteration: [17001 / 50000] 	 Loss: 0.005824474 (0.005835793) 	 Physics Loss: 0.002019164 (0.001728887) 	 Data Loss: 0.000624455 (0.001011056) 	 BC Loss: 0.003180855 (0.003095849)
    +Iteration: [17501 / 50000] 	 Loss: 0.006616294 (0.005807751) 	 Physics Loss: 0.002489866 (0.001884541) 	 Data Loss: 0.001154157 (0.001245214) 	 BC Loss: 0.002972272 (0.002677995)
    +Iteration: [18001 / 50000] 	 Loss: 0.004335414 (0.005200472) 	 Physics Loss: 0.001764537 (0.002015869) 	 Data Loss: 0.000705982 (0.001058994) 	 BC Loss: 0.001864895 (0.002125610)
    +Iteration: [18501 / 50000] 	 Loss: 0.004978007 (0.005351806) 	 Physics Loss: 0.002553018 (0.002129085) 	 Data Loss: 0.000752965 (0.001336156) 	 BC Loss: 0.001672024 (0.001886566)
    +Iteration: [19001 / 50000] 	 Loss: 0.004518208 (0.004657542) 	 Physics Loss: 0.001975382 (0.001959185) 	 Data Loss: 0.000239237 (0.000983244) 	 BC Loss: 0.002303589 (0.001715113)
    +Iteration: [19501 / 50000] 	 Loss: 0.006942283 (0.004119421) 	 Physics Loss: 0.004590358 (0.001714717) 	 Data Loss: 0.001148389 (0.000894285) 	 BC Loss: 0.001203537 (0.001510418)
    +Iteration: [20001 / 50000] 	 Loss: 0.008026988 (0.003463188) 	 Physics Loss: 0.005315070 (0.001485110) 	 Data Loss: 0.001919697 (0.000688489) 	 BC Loss: 0.000792221 (0.001289588)
    +Iteration: [20501 / 50000] 	 Loss: 0.004855067 (0.003504427) 	 Physics Loss: 0.001560361 (0.001747428) 	 Data Loss: 0.000460401 (0.000618138) 	 BC Loss: 0.002834306 (0.001138862)
    +Iteration: [21001 / 50000] 	 Loss: 0.002417301 (0.003299790) 	 Physics Loss: 0.000924424 (0.001513747) 	 Data Loss: 0.000300984 (0.000659882) 	 BC Loss: 0.001191893 (0.001126162)
    +Iteration: [21501 / 50000] 	 Loss: 0.003911218 (0.002670718) 	 Physics Loss: 0.002752088 (0.001218763) 	 Data Loss: 0.000835131 (0.000637475) 	 BC Loss: 0.000323999 (0.000814481)
    +Iteration: [22001 / 50000] 	 Loss: 0.002318957 (0.002511334) 	 Physics Loss: 0.001409405 (0.001309370) 	 Data Loss: 0.000344849 (0.000535839) 	 BC Loss: 0.000564703 (0.000666125)
    +Iteration: [22501 / 50000] 	 Loss: 0.001994215 (0.002343247) 	 Physics Loss: 0.000746255 (0.001113559) 	 Data Loss: 0.000431564 (0.000577084) 	 BC Loss: 0.000816396 (0.000652603)
    +Iteration: [23001 / 50000] 	 Loss: 0.002989073 (0.002301548) 	 Physics Loss: 0.001930058 (0.001243673) 	 Data Loss: 0.000805100 (0.000536315) 	 BC Loss: 0.000253915 (0.000521560)
    +Iteration: [23501 / 50000] 	 Loss: 0.002210422 (0.002371583) 	 Physics Loss: 0.001325711 (0.001179150) 	 Data Loss: 0.000160725 (0.000516864) 	 BC Loss: 0.000723986 (0.000675569)
    +Iteration: [24001 / 50000] 	 Loss: 0.002023818 (0.002276814) 	 Physics Loss: 0.000857553 (0.001135292) 	 Data Loss: 0.000525994 (0.000580056) 	 BC Loss: 0.000640270 (0.000561465)
    +Iteration: [24501 / 50000] 	 Loss: 0.002234935 (0.002236427) 	 Physics Loss: 0.001041825 (0.001241080) 	 Data Loss: 0.000286281 (0.000510494) 	 BC Loss: 0.000906830 (0.000484853)
    +Iteration: [25001 / 50000] 	 Loss: 0.001972227 (0.001982885) 	 Physics Loss: 0.000893347 (0.000971555) 	 Data Loss: 0.000666251 (0.000537486) 	 BC Loss: 0.000412629 (0.000473843)
    +Iteration: [25501 / 50000] 	 Loss: 0.001659834 (0.002081697) 	 Physics Loss: 0.001085884 (0.001258897) 	 Data Loss: 0.000359855 (0.000474958) 	 BC Loss: 0.000214095 (0.000347842)
    +Iteration: [26001 / 50000] 	 Loss: 0.002059042 (0.001770784) 	 Physics Loss: 0.001171167 (0.000890729) 	 Data Loss: 0.000426463 (0.000447986) 	 BC Loss: 0.000461412 (0.000432069)
    +Iteration: [26501 / 50000] 	 Loss: 0.002089650 (0.002068657) 	 Physics Loss: 0.001594031 (0.001356683) 	 Data Loss: 0.000330550 (0.000420685) 	 BC Loss: 0.000165069 (0.000291289)
    +Iteration: [27001 / 50000] 	 Loss: 0.001346401 (0.001879478) 	 Physics Loss: 0.000798861 (0.001050717) 	 Data Loss: 0.000333685 (0.000522715) 	 BC Loss: 0.000213855 (0.000306047)
    +Iteration: [27501 / 50000] 	 Loss: 0.001717428 (0.001494603) 	 Physics Loss: 0.000754971 (0.000796866) 	 Data Loss: 0.000408040 (0.000351864) 	 BC Loss: 0.000554417 (0.000345872)
    +Iteration: [28001 / 50000] 	 Loss: 0.001498525 (0.001789054) 	 Physics Loss: 0.000881248 (0.001008533) 	 Data Loss: 0.000310122 (0.000482373) 	 BC Loss: 0.000307154 (0.000298148)
    +Iteration: [28501 / 50000] 	 Loss: 0.001300987 (0.001541014) 	 Physics Loss: 0.000685782 (0.000873007) 	 Data Loss: 0.000372513 (0.000378884) 	 BC Loss: 0.000242692 (0.000289123)
    +Iteration: [29001 / 50000] 	 Loss: 0.001302390 (0.001531350) 	 Physics Loss: 0.000764329 (0.000809421) 	 Data Loss: 0.000326938 (0.000448536) 	 BC Loss: 0.000211123 (0.000273393)
    +Iteration: [29501 / 50000] 	 Loss: 0.001228882 (0.001639404) 	 Physics Loss: 0.000864926 (0.000892691) 	 Data Loss: 0.000257633 (0.000503808) 	 BC Loss: 0.000106323 (0.000242905)
    +Iteration: [30001 / 50000] 	 Loss: 0.001362466 (0.001636085) 	 Physics Loss: 0.000635906 (0.000994050) 	 Data Loss: 0.000649345 (0.000412151) 	 BC Loss: 0.000077215 (0.000229884)
    +Iteration: [30501 / 50000] 	 Loss: 0.000972152 (0.001479216) 	 Physics Loss: 0.000619220 (0.000883626) 	 Data Loss: 0.000230181 (0.000379169) 	 BC Loss: 0.000122752 (0.000216420)
    +Iteration: [31001 / 50000] 	 Loss: 0.005065940 (0.001380907) 	 Physics Loss: 0.004397592 (0.000831873) 	 Data Loss: 0.000477057 (0.000344165) 	 BC Loss: 0.000191290 (0.000204869)
    +Iteration: [31501 / 50000] 	 Loss: 0.001720798 (0.001439294) 	 Physics Loss: 0.001153235 (0.000778960) 	 Data Loss: 0.000366380 (0.000444564) 	 BC Loss: 0.000201183 (0.000215771)
    +Iteration: [32001 / 50000] 	 Loss: 0.001272172 (0.001182971) 	 Physics Loss: 0.000547293 (0.000645338) 	 Data Loss: 0.000612554 (0.000330688) 	 BC Loss: 0.000112325 (0.000206944)
    +Iteration: [32501 / 50000] 	 Loss: 0.001592739 (0.001303701) 	 Physics Loss: 0.001089040 (0.000732894) 	 Data Loss: 0.000368751 (0.000377450) 	 BC Loss: 0.000134948 (0.000193357)
    +Iteration: [33001 / 50000] 	 Loss: 0.001257007 (0.001731674) 	 Physics Loss: 0.000964463 (0.001143823) 	 Data Loss: 0.000217459 (0.000395994) 	 BC Loss: 0.000075086 (0.000191858)
    +Iteration: [33501 / 50000] 	 Loss: 0.001404967 (0.001307026) 	 Physics Loss: 0.000708074 (0.000685339) 	 Data Loss: 0.000530431 (0.000435325) 	 BC Loss: 0.000166462 (0.000186362)
    +Iteration: [34001 / 50000] 	 Loss: 0.000798481 (0.001060399) 	 Physics Loss: 0.000366831 (0.000566683) 	 Data Loss: 0.000218087 (0.000317301) 	 BC Loss: 0.000213564 (0.000176415)
    +Iteration: [34501 / 50000] 	 Loss: 0.001798573 (0.001364744) 	 Physics Loss: 0.001362987 (0.000847362) 	 Data Loss: 0.000308547 (0.000354412) 	 BC Loss: 0.000127040 (0.000162970)
    +Iteration: [35001 / 50000] 	 Loss: 0.000781053 (0.001014936) 	 Physics Loss: 0.000422994 (0.000539345) 	 Data Loss: 0.000270824 (0.000311768) 	 BC Loss: 0.000087234 (0.000163823)
    +Iteration: [35501 / 50000] 	 Loss: 0.001209691 (0.001329915) 	 Physics Loss: 0.000784697 (0.000694873) 	 Data Loss: 0.000264404 (0.000425117) 	 BC Loss: 0.000160591 (0.000209925)
    +Iteration: [36001 / 50000] 	 Loss: 0.001398915 (0.001136703) 	 Physics Loss: 0.000490567 (0.000583094) 	 Data Loss: 0.000744279 (0.000401171) 	 BC Loss: 0.000164069 (0.000152438)
    +Iteration: [36501 / 50000] 	 Loss: 0.000835373 (0.001367094) 	 Physics Loss: 0.000595709 (0.000792289) 	 Data Loss: 0.000132676 (0.000426714) 	 BC Loss: 0.000106987 (0.000148092)
    +Iteration: [37001 / 50000] 	 Loss: 0.000952036 (0.001044580) 	 Physics Loss: 0.000709375 (0.000580873) 	 Data Loss: 0.000161545 (0.000334467) 	 BC Loss: 0.000081115 (0.000129240)
    +Iteration: [37501 / 50000] 	 Loss: 0.000579479 (0.001085730) 	 Physics Loss: 0.000270049 (0.000599332) 	 Data Loss: 0.000242183 (0.000348117) 	 BC Loss: 0.000067247 (0.000138281)
    +Iteration: [38001 / 50000] 	 Loss: 0.001053359 (0.001110448) 	 Physics Loss: 0.000445312 (0.000595116) 	 Data Loss: 0.000482833 (0.000353724) 	 BC Loss: 0.000125214 (0.000161607)
    +Iteration: [38501 / 50000] 	 Loss: 0.000667115 (0.001049175) 	 Physics Loss: 0.000326662 (0.000543516) 	 Data Loss: 0.000173648 (0.000387762) 	 BC Loss: 0.000166804 (0.000117897)
    +Iteration: [39001 / 50000] 	 Loss: 0.000687853 (0.001085206) 	 Physics Loss: 0.000313576 (0.000590442) 	 Data Loss: 0.000321921 (0.000367264) 	 BC Loss: 0.000052356 (0.000127500)
    +Iteration: [39501 / 50000] 	 Loss: 0.000673423 (0.001160439) 	 Physics Loss: 0.000421422 (0.000714949) 	 Data Loss: 0.000192454 (0.000300986) 	 BC Loss: 0.000059547 (0.000144504)
    +Iteration: [40001 / 50000] 	 Loss: 0.000938448 (0.001243982) 	 Physics Loss: 0.000547043 (0.000710499) 	 Data Loss: 0.000287677 (0.000374305) 	 BC Loss: 0.000103729 (0.000159178)
    +Iteration: [40501 / 50000] 	 Loss: 0.001798752 (0.001093546) 	 Physics Loss: 0.000866074 (0.000650020) 	 Data Loss: 0.000780730 (0.000305183) 	 BC Loss: 0.000151947 (0.000138344)
    +Iteration: [41001 / 50000] 	 Loss: 0.001101400 (0.001448896) 	 Physics Loss: 0.000600817 (0.000901216) 	 Data Loss: 0.000405329 (0.000389668) 	 BC Loss: 0.000095254 (0.000158011)
    +Iteration: [41501 / 50000] 	 Loss: 0.000776893 (0.000824789) 	 Physics Loss: 0.000455096 (0.000410463) 	 Data Loss: 0.000206055 (0.000317277) 	 BC Loss: 0.000115742 (0.000097049)
    +Iteration: [42001 / 50000] 	 Loss: 0.001060384 (0.001240770) 	 Physics Loss: 0.000583868 (0.000778712) 	 Data Loss: 0.000378937 (0.000335865) 	 BC Loss: 0.000097578 (0.000126193)
    +Iteration: [42501 / 50000] 	 Loss: 0.000691815 (0.000944194) 	 Physics Loss: 0.000381213 (0.000516831) 	 Data Loss: 0.000162085 (0.000307154) 	 BC Loss: 0.000148517 (0.000120209)
    +Iteration: [43001 / 50000] 	 Loss: 0.000545245 (0.000868335) 	 Physics Loss: 0.000363892 (0.000449657) 	 Data Loss: 0.000124517 (0.000324281) 	 BC Loss: 0.000056836 (0.000094398)
    +Iteration: [43501 / 50000] 	 Loss: 0.001068081 (0.001141232) 	 Physics Loss: 0.000613936 (0.000622923) 	 Data Loss: 0.000369106 (0.000392804) 	 BC Loss: 0.000085040 (0.000125504)
    +Iteration: [44001 / 50000] 	 Loss: 0.001168622 (0.000963809) 	 Physics Loss: 0.000486189 (0.000540564) 	 Data Loss: 0.000549527 (0.000306839) 	 BC Loss: 0.000132906 (0.000116407)
    +Iteration: [44501 / 50000] 	 Loss: 0.000939374 (0.000756769) 	 Physics Loss: 0.000379668 (0.000386392) 	 Data Loss: 0.000454265 (0.000277635) 	 BC Loss: 0.000105440 (0.000092742)
    +Iteration: [45001 / 50000] 	 Loss: 0.001202180 (0.000892342) 	 Physics Loss: 0.000726597 (0.000506370) 	 Data Loss: 0.000367492 (0.000280093) 	 BC Loss: 0.000108091 (0.000105879)
    +Iteration: [45501 / 50000] 	 Loss: 0.000887047 (0.000908168) 	 Physics Loss: 0.000641108 (0.000560744) 	 Data Loss: 0.000148591 (0.000263541) 	 BC Loss: 0.000097348 (0.000083883)
    +Iteration: [46001 / 50000] 	 Loss: 0.000525872 (0.000734937) 	 Physics Loss: 0.000322635 (0.000362759) 	 Data Loss: 0.000158824 (0.000288360) 	 BC Loss: 0.000044412 (0.000083818)
    +Iteration: [46501 / 50000] 	 Loss: 0.000545968 (0.000907963) 	 Physics Loss: 0.000350560 (0.000489585) 	 Data Loss: 0.000136768 (0.000312205) 	 BC Loss: 0.000058640 (0.000106173)
    +Iteration: [47001 / 50000] 	 Loss: 0.000826687 (0.000924496) 	 Physics Loss: 0.000575209 (0.000511645) 	 Data Loss: 0.000205284 (0.000314716) 	 BC Loss: 0.000046194 (0.000098134)
    +Iteration: [47501 / 50000] 	 Loss: 0.000620959 (0.001185708) 	 Physics Loss: 0.000382126 (0.000788119) 	 Data Loss: 0.000148993 (0.000271556) 	 BC Loss: 0.000089840 (0.000126034)
    +Iteration: [48001 / 50000] 	 Loss: 0.000664698 (0.000798627) 	 Physics Loss: 0.000412207 (0.000461797) 	 Data Loss: 0.000182339 (0.000250679) 	 BC Loss: 0.000070152 (0.000086152)
    +Iteration: [48501 / 50000] 	 Loss: 0.000826713 (0.000925605) 	 Physics Loss: 0.000485339 (0.000512687) 	 Data Loss: 0.000170909 (0.000314013) 	 BC Loss: 0.000170466 (0.000098905)
    +Iteration: [49001 / 50000] 	 Loss: 0.000559556 (0.000846881) 	 Physics Loss: 0.000350503 (0.000421408) 	 Data Loss: 0.000165743 (0.000346362) 	 BC Loss: 0.000043311 (0.000079111)
    +Iteration: [49501 / 50000] 	 Loss: 0.000652327 (0.000740137) 	 Physics Loss: 0.000301691 (0.000376061) 	 Data Loss: 0.000195276 (0.000275985) 	 BC Loss: 0.000155360 (0.000088090)

    Visualizing the Results

    julia
    ts, xs, ys = 0.0f0:0.05f0:2.0f0, 0.0f0:0.02f0:2.0f0, 0.0f0:0.02f0:2.0f0
    +grid = stack([[elem...] for elem in vec(collect(Iterators.product(xs, ys, ts)))])
    +
    +u_real = reshape(analytical_solution(grid), length(xs), length(ys), length(ts))
    +
    +grid_normalized = (grid .- minimum(grid)) ./ (maximum(grid) .- minimum(grid))
    +u_pred = reshape(trained_u(grid_normalized), length(xs), length(ys), length(ts))
    +u_pred = u_pred .* (max_pde_val - min_pde_val) .+ min_pde_val
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +    errs = [abs.(u_pred[:, :, i] .- u_real[:, :, i]) for i in 1:length(ts)]
    +    Colorbar(fig[1, 2]; limits=extrema(stack(errs)))
    +
    +    CairoMakie.record(fig, "pinn_nested_ad.gif", 1:length(ts); framerate=10) do i
    +        ax.title = "Abs. Predictor Error | Time: $(ts[i])"
    +        err = errs[i]
    +        contour!(ax, xs, ys, err; levels=10, linewidth=2)
    +        heatmap!(ax, xs, ys, err)
    +        return fig
    +    end
    +
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.484 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    `,12))])}const B=p(k,[["render",o]]);export{m as __pageData,B as default}; diff --git a/previews/PR1023/blas_optimizations.jpg b/previews/PR1023/blas_optimizations.jpg new file mode 100644 index 0000000000..d615fe7b46 Binary files /dev/null and b/previews/PR1023/blas_optimizations.jpg differ diff --git a/previews/PR1023/ecosystem.html b/previews/PR1023/ecosystem.html new file mode 100644 index 0000000000..09591ec438 --- /dev/null +++ b/previews/PR1023/ecosystem.html @@ -0,0 +1,34 @@ + + + + + + Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Ecosystem

    Frameworks Extending Lux.jl

    DiffEqFlux.jl

    DiffEqFlux.jl

    Universal neural differential equations with O(1) backprop, GPUs, and stiff+non-stiff DE solvers, demonstrating scientific machine learning (SciML) and physics-informed machine learning methods

    SciMLSensitivity.jl

    SciMLSensitivity.jl

    A component of the DiffEq ecosystem for enabling sensitivity analysis for scientific machine learning (SciML). Optimize-then-discretize, discretize-then-optimize, adjoint methods, and more for ODEs, SDEs, DDEs, DAEs, etc.

    NeuralPDE.jl

    NeuralPDE.jl

    Physics-Informed Neural Networks (PINN) and Deep BSDE Solvers of Differential Equations for Scientific Machine Learning (SciML) accelerated simulation

    NeuralLyapunov.jl

    NeuralLyapunov.jl

    A library for searching for neural Lyapunov functions in Julia

    DeepEquilibriumNetworks.jl

    DeepEquilibriumNetworks.jl

    Implicit Layer Machine Learning via Deep Equilibrium Networks, O(1) backpropagation with accelerated convergence

    AbstractCosmologicalEmulators.jl

    AbstractCosmologicalEmulators.jl

    Repository containing the abstract interface to the emulators used in the CosmologicalEmulators organization

    ContinuousNormalizingFlows.jl

    ContinuousNormalizingFlows.jl

    Implementations of Infinitesimal Continuous Normalizing Flows Algorithms in Julia

    Sophon.jl

    Sophon.jl

    Efficient, Accurate, and Streamlined Training of Physics-Informed Neural Networks

    DataDrivenDiffEq.jl

    DataDrivenDiffEq.jl

    Data driven modeling and automated discovery of dynamical systems for the SciML Scientific Machine Learning organization

    NeuralGraphPDE.jl

    NeuralGraphPDE.jl

    Integrating Neural Ordinary Differential Equations, the Method of Lines, and Graph Neural Networks

    Solaris.jl

    Solaris.jl

    Lightweight module for fusing physical and neural models

    Boltz.jl

    Boltz.jl

    Accelerate your ML research using pre-built Deep Learning Models with Lux

    GeometricMachineLearning.jl

    GeometricMachineLearning.jl

    Structure Preserving Machine Learning Models in Julia

    Automatic Differentiation

    Zygote.jl

    Zygote.jl

    Lux.jl default choice for AD

    Tracker.jl

    Tracker.jl

    Well tested and robust AD library (might fail on edge cases)

    ForwardDiff.jl

    ForwardDiff.jl

    For forward mode AD support

    ReverseDiff.jl

    ReverseDiff.jl

    Tape based reverse mode AD (might fail on edge cases and doesn't work on GPU)

    Enzyme.jl

    Enzyme.jl

    Experimental Support but will become the Future Default

    Data Manipulation, Data Loading & Datasets

    MLUtils.jl

    MLUtils.jl

    Utilities and abstractions for Machine Learning tasks

    MLDatasets.jl

    MLDatasets.jl

    Utility package for accessing common Machine Learning datasets in Julia

    Images.jl

    Images.jl

    An image library for Julia

    DataAugmentation.jl

    DataAugmentation.jl

    Flexible data augmentation library for machine and deep learning

    Neural Network Primitives

    NNlib.jl

    NNlib.jl

    Neural Network primitives with multiple backends

    LuxLib.jl

    LuxLib.jl

    Backend for Lux.jl

    Optimization

    Optimization.jl

    Optimization.jl

    Unified API for Optimization in Julia

    Optimisers.jl

    Optimisers.jl

    Optimisers.jl defines many standard optimisers and utilities for learning loops

    ParameterSchedulers.jl

    ParameterSchedulers.jl

    Common hyperparameter scheduling for ML

    Parameter Manipulation

    Functors.jl

    Functors.jl

    Parameterise all the things

    ComponentArrays.jl

    ComponentArrays.jl

    Arrays with arbitrarily nested named components

    Serialization

    Serialization.jl

    Serialization.jl

    Provides serialization of Julia objects

    JLD2.jl

    JLD2.jl

    HDF5-compatible file format in pure Julia

    Testing Utilities

    FiniteDiff.jl

    FiniteDiff.jl

    Fast non-allocating calculations of gradients, Jacobians, and Hessians with sparsity support

    FiniteDifferences.jl

    FiniteDifferences.jl

    High accuracy derivatives, estimated via numerical finite differences (formerly FDM.jl)

    JET.jl

    JET.jl

    JET employs Julia's type inference system to detect potential bugs and type instabilities

    LuxTestUtils.jl

    LuxTestUtils.jl

    Collection of Functions useful for testing various packages in the Lux Ecosystem

    Training Visualization & Logging

    MLFlowClient.jl

    MLFlowClient.jl

    Julia client for MLFlow

    TensorBoardLogger.jl

    TensorBoardLogger.jl

    Easy peasy logging to TensorBoard with Julia

    Wandb.jl

    Wandb.jl

    Unofficial Julia bindings for logging experiments to wandb.ai

    + + + + \ No newline at end of file diff --git a/previews/PR1023/gravitational_waveform.png b/previews/PR1023/gravitational_waveform.png new file mode 100644 index 0000000000..39ba221401 Binary files /dev/null and b/previews/PR1023/gravitational_waveform.png differ diff --git a/previews/PR1023/hashmap.json b/previews/PR1023/hashmap.json new file mode 100644 index 0000000000..b7240e5f0d --- /dev/null +++ b/previews/PR1023/hashmap.json @@ -0,0 +1 @@ +{"api_accelerator_support_mldatadevices.md":"Ba-hugak","api_building_blocks_luxcore.md":"CF0jvmvx","api_building_blocks_luxlib.md":"DEJmN7Bf","api_building_blocks_weightinitializers.md":"YK6sT70z","api_lux_autodiff.md":"CpXbBbTG","api_lux_contrib.md":"tcySUcib","api_lux_distributed_utils.md":"D1YsLAOX","api_lux_interop.md":"DzKzCHM4","api_lux_layers.md":"DhFbD-A5","api_lux_utilities.md":"tnFESE9C","api_testing_functionality_luxtestutils.md":"8-Wna7gT","ecosystem.md":"CN8yStnf","index.md":"B7q9VhVT","introduction_citation.md":"CC7Ayz4q","introduction_index.md":"Do6486F0","introduction_overview.md":"DDk7R0pj","introduction_resources.md":"JKo7XfzJ","introduction_updating_to_v1.md":"BI71nsoN","manual_autodiff.md":"Ba7AkbE9","manual_compiling_lux_models.md":"CpD3KwNd","manual_debugging.md":"DPbHDP8E","manual_dispatch_custom_input.md":"C-fcTpBz","manual_distributed_utils.md":"CYDIHMTo","manual_freezing_model_parameters.md":"0i6pMVyg","manual_gpu_management.md":"DNTD4_pe","manual_interface.md":"D86uezLQ","manual_migrate_from_flux.md":"UjjC2Rl6","manual_nested_autodiff.md":"BllOXIU5","manual_nn_inside_gpu_kernels.md":"egqCePx_","manual_performance_pitfalls.md":"s_yX8yPE","manual_preferences.md":"CiGO9gyg","manual_weight_initializers.md":"kYS4Pm9l","tutorials_advanced_1_gravitationalwaveform.md":"CE8fiIvN","tutorials_beginner_1_basics.md":"C9naagCh","tutorials_beginner_2_polynomialfitting.md":"sRzotb_h","tutorials_beginner_3_simplernn.md":"CxWJLH3E","tutorials_beginner_4_simplechains.md":"BJAmU5gZ","tutorials_beginner_5_optimizationintegration.md":"B9JkcgjS","tutorials_index.md":"amQ7-phS","tutorials_intermediate_1_neuralode.md":"C9riTwge","tutorials_intermediate_2_bayesiannn.md":"fxCpWm1u","tutorials_intermediate_3_hypernet.md":"D4Wex7F9","tutorials_intermediate_4_pinn2dpde.md":"lubVAoSP"} diff --git a/previews/PR1023/hypernet.jpg b/previews/PR1023/hypernet.jpg new file mode 100644 index 0000000000..7539f2f86e Binary files /dev/null and b/previews/PR1023/hypernet.jpg differ diff --git a/previews/PR1023/index.html b/previews/PR1023/index.html new file mode 100644 index 0000000000..346cbb0a92 --- /dev/null +++ b/previews/PR1023/index.html @@ -0,0 +1,60 @@ + + + + + + Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    LuxDL Docs

    Elegant & Performant Scientific Machine Learning in JuliaLang

    A Pure Julia Deep Learning Framework designed for Scientific Machine Learning

    Lux.jl

    How to Install Lux.jl?

    Its easy to install Lux.jl. Since Lux.jl is registered in the Julia General registry, you can simply run the following command in the Julia REPL:

    julia
    julia> using Pkg
    +julia> Pkg.add("Lux")

    If you want to use the latest unreleased version of Lux.jl, you can run the following command: (in most cases the released version will be same as the version on github)

    julia
    julia> using Pkg
    +julia> Pkg.add(url="https://github.com/LuxDL/Lux.jl")

    Want GPU Support?

    Install the following package(s):

    julia
    using Pkg
    +Pkg.add("LuxCUDA")
    +# or
    +Pkg.add(["CUDA", "cuDNN"])
    julia
    using Pkg
    +Pkg.add("AMDGPU")
    julia
    using Pkg
    +Pkg.add("Metal")
    julia
    using Pkg
    +Pkg.add("oneAPI")

    Run the following to access a device:

    julia
    using Lux, LuxCUDA
    +
    +const dev = gpu_device()
    julia
    using Lux, AMDGPU
    +
    +const dev = gpu_device()
    julia
    using Lux, Metal
    +
    +const dev = gpu_device()
    julia
    using Lux, oneAPI
    +
    +const dev = gpu_device()

    Want XLA Support?

    Install the following package:

    julia
    using Pkg;
    +Pkg.add("Reactant")

    Run the following to access a device:

    julia
    using Reactant, Lux
    +Reactant.set_default_backend("cpu") # default
    +
    +const dev = xla_device()
    julia
    using Reactant, Lux
    +Reactant.set_default_backend("gpu")
    +
    +const dev = xla_device()
    julia
    using Reactant, Lux
    +Reactant.set_default_backend("tpu")
    +
    +const dev = xla_device()
    + + + + \ No newline at end of file diff --git a/previews/PR1023/introduction/citation.html b/previews/PR1023/introduction/citation.html new file mode 100644 index 0000000000..34436459d5 --- /dev/null +++ b/previews/PR1023/introduction/citation.html @@ -0,0 +1,49 @@ + + + + + + Citation | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Citation

    If you found this library to be useful in academic work, then please cite:

    bibtex
    @software{pal2023lux,
    +  author    = {Pal, Avik},
    +  title     = {{Lux: Explicit Parameterization of Deep Neural Networks in Julia}},
    +  month     = {April},
    +  year      = 2023,
    +  note      = {If you use this software, please cite it as below.},
    +  publisher = {Zenodo},
    +  version   = {v0.5.0},
    +  doi       = {10.5281/zenodo.7808904},
    +  url       = {https://doi.org/10.5281/zenodo.7808904}
    +}
    bibtex
    @thesis{pal2023efficient,
    +  title     = {{On Efficient Training \& Inference of Neural Differential Equations}},
    +  author    = {Pal, Avik},
    +  year      = {2023},
    +  school    = {Massachusetts Institute of Technology}
    +}
    + + + + \ No newline at end of file diff --git a/previews/PR1023/introduction/index.html b/previews/PR1023/introduction/index.html new file mode 100644 index 0000000000..0edc04bca5 --- /dev/null +++ b/previews/PR1023/introduction/index.html @@ -0,0 +1,144 @@ + + + + + + Getting Started | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Getting Started

    Installation

    Install Julia v1.10 or above. Lux.jl is available through the Julia package manager. You can enter it by pressing ] in the REPL and then typing add Lux. Alternatively, you can also do

    julia
    import Pkg
    +Pkg.add("Lux")

    Update to v1

    If you are using a pre-v1 version of Lux.jl, please see the Updating to v1 section for instructions on how to update.

    Quickstart

    Pre-Requisites

    You need to install Optimisers and Zygote if not done already. Pkg.add(["Optimisers", "Zygote"])

    julia
    using Lux, Random, Optimisers, Zygote
    +using LuxCUDA # For CUDA support
    +# using AMDGPU, Metal, oneAPI # Other pptional packages for GPU support

    We take randomness very seriously

    julia
    # Seeding
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    Random.TaskLocalRNG()

    Build the model

    julia
    # Construct the layer
    +model = Chain(Dense(128, 256, tanh), Chain(Dense(256, 1, tanh), Dense(1, 10)))
    Chain(
    +    layer_1 = Dense(128 => 256, tanh),  # 33_024 parameters
    +    layer_2 = Chain(
    +        layer_1 = Dense(256 => 1, tanh),  # 257 parameters
    +        layer_2 = Dense(1 => 10),       # 20 parameters
    +    ),
    +)         # Total: 33_301 parameters,
    +          #        plus 0 states.

    Models don't hold parameters and states so initialize them. From there on, we can just use our standard AD and Optimisers API. However, here we will show how to use Lux's Training API that provides an uniform API over all supported AD systems.

    julia
    # Get the device determined by Lux
    +dev = gpu_device()
    +
    +# Parameter and State Variables
    +ps, st = Lux.setup(rng, model) |> dev
    +
    +# Dummy Input
    +x = rand(rng, Float32, 128, 2) |> dev
    +
    +# Run the model
    +y, st = Lux.apply(model, x, ps, st)
    +
    +# Gradients
    +## First construct a TrainState
    +train_state = Lux.Training.TrainState(model, ps, st, Adam(0.0001f0))
    +
    +## We can compute the gradients using Training.compute_gradients
    +gs, loss, stats, train_state = Lux.Training.compute_gradients(AutoZygote(), MSELoss(),
    +    (x, dev(rand(rng, Float32, 10, 2))), train_state)
    +
    +## Optimization
    +train_state = Training.apply_gradients!(train_state, gs) # or Training.apply_gradients (no `!` at the end)
    +
    +# Both these steps can be combined into a single call
    +gs, loss, stats, train_state = Training.single_train_step!(AutoZygote(), MSELoss(),
    +    (x, dev(rand(rng, Float32, 10, 2))), train_state)
    ((layer_1 = (weight = Float32[0.004144425 0.0027955552 … 0.004169049 0.0031376407; 0.002106787 0.0018510937 … 0.0024323382 0.001973281; … ; -0.0017369908 -0.0014175134 … -0.0019262917 -0.0015313211; 0.005014097 0.0012843215 … 0.00351666 0.0019504696], bias = Float32[0.0067729075, 0.0037725805, 0.0044189203, -0.008870317, 0.0024971329, 0.0034101289, 0.011739168, 0.0100971125, -0.012522168, -0.006184267  …  -0.0019153744, -0.0021203319, -0.006736353, -0.0061099795, -0.0017900232, 0.0053856913, 0.0022308934, -0.004047669, -0.003027094, 0.0065859724]), layer_2 = (layer_1 = (weight = Float32[0.009578831 3.793463f-5 … -0.047356773 0.04226003], bias = Float32[0.073442355]), layer_2 = (weight = Float32[-0.098861866; -0.09785451; … ; -0.022434518; -0.07412187;;], bias = Float32[-0.226381, -0.22459084, -0.2545935, -0.24099025, -0.07057328, -0.17239982, -0.17449912, 0.07704306, -0.050089, -0.16909766]))), 0.87143785f0, NamedTuple(), Lux.Training.TrainState{Nothing, Nothing, Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Nothing}, @NamedTuple{layer_1::@NamedTuple{weight::CuArray{Float32, 2, CUDA.DeviceMemory}, bias::CuArray{Float32, 1, CUDA.DeviceMemory}}, layer_2::@NamedTuple{layer_1::@NamedTuple{weight::CuArray{Float32, 2, CUDA.DeviceMemory}, bias::CuArray{Float32, 1, CUDA.DeviceMemory}}, layer_2::@NamedTuple{weight::CuArray{Float32, 2, CUDA.DeviceMemory}, bias::CuArray{Float32, 1, CUDA.DeviceMemory}}}}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}}}, Adam, @NamedTuple{layer_1::@NamedTuple{weight::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 2, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}, bias::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}}, layer_2::@NamedTuple{layer_1::@NamedTuple{weight::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 2, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}, bias::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}}, layer_2::@NamedTuple{weight::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 2, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}, bias::Optimisers.Leaf{Adam, Tuple{CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{Float32, Float32}}}}}}}(nothing, nothing, Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Nothing}((layer_1 = Dense(128 => 256, tanh), layer_2 = Chain{@NamedTuple{layer_1::Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}((layer_1 = Dense(256 => 1, tanh), layer_2 = Dense(1 => 10)), nothing)), nothing), (layer_1 = (weight = Float32[-0.22543387 0.2237958 … 0.19975941 -0.018701272; -0.023031702 0.15451166 … -0.065317236 0.181208; … ; 0.03804328 -0.07125676 … -0.03306928 0.039132368; -0.18811704 -0.09692798 … -0.18102339 0.019236464], bias = Float32[0.03094203, -0.06026962, 0.08456781, 0.0003920444, -0.06550143, -0.08526564, -0.026516732, 0.063480526, 0.04224006, 0.027702922  …  -0.06053336, 0.0350433, -0.028251555, 0.067872316, 0.0027386106, -0.06942138, 0.006432486, 0.014100174, -0.029290024, 0.011734666]), layer_2 = (layer_1 = (weight = Float32[0.11984776 0.060364496 … -0.07058401 0.1577715], bias = Float32[0.026851978]), layer_2 = (weight = Float32[0.5345716; -0.28289196; … ; -0.32984197; -0.45298263;;], bias = Float32[-0.5975106, -0.70330536, -0.84576, -0.5378918, -0.3147238, 0.1746128, -0.82945824, 0.6784163, 0.35836592, -0.14941669]))), (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple())), Adam(0.0001, (0.9, 0.999), 1.0e-8), (layer_1 = (weight = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.00139126 0.00077649 … 0.00128162 0.000910802; 0.000699265 0.000510198 … 0.000731462 0.000563284; … ; -0.000574894 -0.000391076 … -0.000580705 -0.000438132; 0.00170922 0.000374875 … 0.00115296 0.000609521], Float32[1.34855f-7 3.8271f-8 … 1.09599f-7 5.38068f-8; 3.38798f-8 1.64605f-8 … 3.53144f-8 2.04108f-8; … ; 2.28682f-8 9.67595f-9 … 2.22846f-8 1.23626f-8; 2.05058f-7 9.13988f-9 … 9.15542f-8 2.49913f-8], (0.729, 0.997003))), bias = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.00214946, 0.00117228, 0.00145586, -0.00270753, 0.00077338, 0.00106574, 0.00364828, 0.00306169, -0.0038745, -0.00198767  …  -0.000612726, -0.000689046, -0.00209504, -0.00187748, -0.000554918, 0.00175152, 0.000667028, -0.00126273, -0.000942026, 0.00219681], Float32[3.13168f-7, 9.21856f-8, 1.46327f-7, 4.87431f-7, 4.00564f-8, 7.64058f-8, 8.929f-7, 6.21252f-7, 1.00488f-6, 2.69472f-7  …  2.55476f-8, 3.25587f-8, 2.94557f-7, 2.35152f-7, 2.06325f-8, 2.10458f-7, 2.92832f-8, 1.07167f-7, 5.9572f-8, 3.35188f-7], (0.729, 0.997003)))), layer_2 = (layer_1 = (weight = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.0018058 -0.000936727 … -0.0146587 0.0123139], Float32[1.80423f-7 1.09098f-7 … 1.43866f-5 9.85344f-6], (0.729, 0.997003))), bias = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[0.0227737], Float32[3.47551f-5], (0.729, 0.997003)))), layer_2 = (weight = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[-0.0207926; -0.0231775; … ; -0.00706411; -0.0158726;;], Float32[2.44439f-5; 3.16946f-5; … ; 3.36938f-6; 1.4322f-5;;], (0.729, 0.997003))), bias = Leaf(Adam(0.0001, (0.9, 0.999), 1.0e-8), (Float32[-0.0435721, -0.0480501, -0.0540537, -0.0420834, -0.0105465, -0.0302464, -0.0315817, 0.0244214, -0.0142814, -0.0330944], Float32[0.000105296, 0.00013121, 0.000165657, 9.79656f-5, 6.48203f-6, 5.0585f-5, 5.50798f-5, 4.04019f-5, 1.31128f-5, 6.08993f-5], (0.729, 0.997003)))))), 2))

    Defining Custom Layers

    julia
    using Lux, Random, Optimisers, Zygote
    +using LuxCUDA # For CUDA support
    +# using AMDGPU, Metal, oneAPI # Other pptional packages for GPU support
    +using Printf # For pretty printing
    +
    +dev = gpu_device()
    (::CUDADevice{Nothing}) (generic function with 4 methods)

    We will define a custom MLP using the @compact macro. The macro takes in a list of parameters, layers and states, and a function defining the forward pass of the neural network.

    julia
    n_in = 1
    +n_out = 1
    +nlayers = 3
    +
    +model = @compact(w1=Dense(n_in => 32),
    +    w2=[Dense(32 => 32) for i in 1:nlayers],
    +    w3=Dense(32 => n_out),
    +    act=relu) do x
    +    embed = act(w1(x))
    +    for w in w2
    +        embed = act(w(embed))
    +    end
    +    out = w3(embed)
    +    @return out
    +end
    @compact(
    +    w1 = Dense(1 => 32),                # 64 parameters
    +    w2 = NamedTuple(
    +        1 = Dense(32 => 32),            # 1_056 parameters
    +        2 = Dense(32 => 32),            # 1_056 parameters
    +        3 = Dense(32 => 32),            # 1_056 parameters
    +    ),
    +    w3 = Dense(32 => 1),                # 33 parameters
    +    act = relu,
    +) do x 
    +    embed = act(w1(x))
    +    for w = w2
    +        embed = act(w(embed))
    +    end
    +    out = w3(embed)
    +    return out
    +end       # Total: 3_265 parameters,
    +          #        plus 1 states.

    We can initialize the model and train it with the same code as before!

    julia
    rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +ps, st = Lux.setup(Xoshiro(0), model) |> dev
    +
    +x = rand(rng, Float32, n_in, 32) |> dev
    +
    +model(x, ps, st)  # 1×32 Matrix and updated state as output.
    +
    +x_data = reshape(collect(-2.0f0:0.1f0:2.0f0), 1, :) |> dev
    +y_data = 2 .* x_data .- x_data .^ 3
    +
    +function train_model!(model, ps, st, x_data, y_data)
    +    train_state = Lux.Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    for iter in 1:1000
    +        _, loss, _, train_state = Lux.Training.single_train_step!(AutoZygote(), MSELoss(),
    +            (x_data, y_data), train_state)
    +        if iter % 100 == 1 || iter == 1000
    +            @printf "Iteration: %04d \t Loss: %10.9g\n" iter loss
    +        end
    +    end
    +
    +    return model, ps, st
    +end
    +
    +train_model!(model, ps, st, x_data, y_data)
    Iteration: 0001 	 Loss: 2.08085155
    +Iteration: 0101 	 Loss: 0.131583631
    +Iteration: 0201 	 Loss: 0.00390526722
    +Iteration: 0301 	 Loss: 0.000871024327
    +Iteration: 0401 	 Loss: 0.000441076729
    +Iteration: 0501 	 Loss: 0.000454922556
    +Iteration: 0601 	 Loss: 0.00036629336
    +Iteration: 0701 	 Loss: 0.00015113852
    +Iteration: 0801 	 Loss: 0.000239130808
    +Iteration: 0901 	 Loss: 0.00140763051
    +Iteration: 1000 	 Loss: 0.000214067404

    Training with Optimization.jl

    If you are coming from the SciML ecosystem and want to use Optimization.jl, please refer to the Optimization.jl Tutorial.

    Additional Packages

    LuxDL hosts various packages that provide additional functionality for Lux.jl. All packages mentioned in this documentation are available via the Julia General Registry.

    You can install all those packages via import Pkg; Pkg.add(<package name>).

    GPU Support

    GPU Support for Lux.jl requires loading additional packages:

    + + + + \ No newline at end of file diff --git a/previews/PR1023/introduction/overview.html b/previews/PR1023/introduction/overview.html new file mode 100644 index 0000000000..b3839aac94 --- /dev/null +++ b/previews/PR1023/introduction/overview.html @@ -0,0 +1,34 @@ + + + + + + Why we wrote Lux? | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Why we wrote Lux?

    Julia already has quite a few well established Neural Network Frameworks – Flux & KNet. However, certain design elements – Coupled Model and Parameters & Internal Mutations – associated with these frameworks make them less compiler and user friendly. Making changes to address these problems in the respective frameworks would be too disruptive for users. Here comes in Lux: a neural network framework built completely using pure functions to make it both compiler and autodiff friendly.

    Design Principles

    • Layers must be immutable – cannot store any parameter/state but rather store the information to construct them

    • Layers are pure functions

    • Layers return a Tuple containing the result and the updated state

    • Given same inputs the outputs must be same – yes this must hold true even for stochastic functions. Randomness must be controlled using rngs passed in the state.

    • Easily extensible

    • Extensive Testing – All layers and features are tested across all supported AD backends across all supported hardware backends.

    Why use Lux over Flux?

    • Neural Networks for SciML: For SciML Applications (Neural ODEs, Deep Equilibrium Models) solvers typically expect a monolithic parameter vector. Flux enables this via its destructure mechanism, but destructure comes with various edge cases and limitations. Lux forces users to make an explicit distinction between state variables and parameter variables to avoid these issues. Also, it comes battery-included for distributed training.

    • Sensible display of Custom Layers – Ever wanted to see Pytorch like Network printouts or wondered how to extend the pretty printing of Flux's layers? Lux handles all of that by default.

    • Truly immutable models - No unexpected internal mutations since all layers are implemented as pure functions. All layers are also deterministic given the parameters and state: if a layer is supposed to be stochastic (say Dropout), the state must contain a seed which is then updated after the function call.

    • Easy Parameter Manipulation – By separating parameter data and layer structures, Lux makes implementing WeightNorm, SpectralNorm, etc. downright trivial. Without this separation, it is much harder to pass such parameters around without mutations which AD systems don't like.

    • Wider AD Support – Lux has extensive support for most AD systems in julia, while Flux is mostly tied to Zygote (with some initial support for Enzyme).

    • Small Neural Networks on CPU – Lux is developed for training large neural networks. For smaller architectures, we recommend using SimpleChains.jl or even better use it in conjunction with Lux via ToSimpleChainsAdaptor.

    • Reliability – We have learned from the mistakes of the past with Flux and everything in our core framework is extensively tested, along with downstream CI to ensure that everything works as expected.

    Revising Previous Recommendation about Large Models

    Previously we recommended not using Lux for very large models. But we have been making a lot of head-way with Reactant.jl and it would be worthwhile to test larger models with Lux. See compiling Lux models for more information.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/introduction/resources.html b/previews/PR1023/introduction/resources.html new file mode 100644 index 0000000000..8bbfd66fd1 --- /dev/null +++ b/previews/PR1023/introduction/resources.html @@ -0,0 +1,34 @@ + + + + + + Resources to Get Started | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Resources to Get Started

    • Go through the Quickstart Example.

    • Read the introductory tutorials on Julia and Lux.

    • Go through the examples sorted based on their complexity in the documentation.

    Have More Questions?

    For usage related questions, please use Github Discussions which allows questions and answers to be indexed. To report bugs use Github Issues or even better send in a Pull Request.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/introduction/updating_to_v1.html b/previews/PR1023/introduction/updating_to_v1.html new file mode 100644 index 0000000000..a6ef228763 --- /dev/null +++ b/previews/PR1023/introduction/updating_to_v1.html @@ -0,0 +1,34 @@ + + + + + + Updating to Lux v1 | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Updating to Lux v1

    Lux v1 is a Major Release, mostly to signify the stability of the API. In this page, we list out a concrete set of changes that need to be made to your code to update to Lux v1. We also list out some new exciting features that were added as part of this release.

    LuxLib.jl

    Breaking Changes

    • Old deprecated API with keyword arguments has been removed. See the new docs in LuxLib API for more details.

    • Default for layernorm dims has been changed to exclude the batch dimension.

    New Major Features

    • Dense layers now support CUDA backend for Enzyme (starting v1.1). Wider support for other operations with Enzyme + CUDA is being actively worked on.

    LuxCore.jl

    Breaking Changes

    • AbstractExplicitLayer has been renamed to AbstractLuxLayer.

    • AbstractExplicitContainerLayer behaviour

      • This has been renamed to AbstractLuxContainerLayer.

      • Previously, AbstractExplicitContainerLayer{(:a,)} (i.e. singleton containers) would produce default initial parameters and states without wrapping them in a NamedTuple{(:a,)}. This was inconsistent with non-singleton containers, and was a source of confusion. With v we return (; a = <parameters>) and (; a = <states>) by default. See AbstractLuxWrapperLayer for a replacement of this functionality.

    • inputsize has been removed since it was ambiguous and not used anywhere.

    • Changes to outputsize:

      • Single argument version has been removed. See LuxCore.jl Pull Request 43 for more details on the rationale behind this change.

      • Fallback implementation has been moved to Lux.jl. (i.e. users using Lux shouldn't see a difference, but if Lux.jl isn't loaded, this function has error.)

        • Internally this uses a NilArray that is able to compute sizes without actually running the computation.
    • Functors and Setfield have been made into optional dependencies. Certain LuxCore functionality that rely on these functions, will throw an error if these packages are not loaded.

    New Major Features

    • Introduction of AbstractLuxWrapperLayer. This behaves exactly like the old singleton container. For example, the old AbstractExplicitContainerLayer{(:a,)} is equivalent to AbstractLuxWrapperLayer{:a}.

    WeightInitializers.jl

    This was a major release to signify the stability of the API. There were no breaking changes. We do support a wider range of RNG types, see Supported RNG Types for more details.

    MLDataDevices.jl

    This is the most aggressive change that was made. We renamed the LuxDeviceUtils.jl package to MLDataDevices.jl, to allow for non-Lux packages to use this shared device management abstraction.

    Deprecation of LuxDeviceUtils.jl

    This also marks the deprecation of the LuxDeviceUtils.jl package. We won't be making any updates to that package, including fixing any bugs. All users should switch to MLDataDevices.jl instead.

    Breaking Changes

    • Lux(___)Device objects have been renamed to (___)Device. For example, LuxCUDADevice has been renamed to CUDADevice.

    • Lux(___)Adaptor objects have been removed. The corresponding Device objects should be used directly instead.

    New Major Features

    • DeviceIterator provides a generalization of CUDA.CuIterator and works for all backends and more data types (using Functors.jl). MLUtils.DataLoader |> gdev now returns a DeviceIterator instead of being a no-op.

    Lux.jl

    Breaking Changes (Removed Functionality)

    • Direct reexport of NNlib has been removed. We reexport selected functionality from NNlib. Direactly load NNlib if you need to use the other functions.

    • Flattening of Chain layers has been removed, and the corresponding disable_optimizations kwarg has been removed.

    • Some layers overloaded Base.keys, these have been removed. These were mostly un-documented and weren't supposed to be used outside of the Lux.jl package.

    • Training.TrainState construction with rng has been removed.

    • Older versions of Preferences have been removed.

    • disable_stacktrace_truncation! has been removed. From Julia 1.9 onwards, stacktrace truncation is enabled by default.

    • Certain Experimental features were present outside the Lux.Experimental module. These have been removed, use them via Lux.Experimental instead. Run Julia with with depwarn as error and Lux v0.5 to see the deprecations.

    • Lux.Experimental.@layer_map is not longer needed and has been removed. The name of the variable prevents writing generic functions and is no longer pre-pended to the KeyPath. See the docstring of Lux.Experimental.layer_map for more details.

    • allow_fast_activation kwarg has been removed completely. Pass an anonymous function as the activation to prevent internal modivations to the activation function.

    Breaking Changes (Moved Functionality)

    • Lux.Experimental.Training has been moved to Lux.Training. We guarantee SemVar on this new module.

    • Lux.cpu and Lux.gpu have been removed. Use cpu_device and gpu_device instead.

    • Experimental.@compact can be directly used via @compact now.

    • Experimental.StatefulLuxLayer has been moved to Lux.StatefulLuxLayer.

    • st_fixed_path kwarg has been removed from Lux.StatefulLuxLayer, instead use it as StatefulLuxLayer{st_fixed_path}(...).

    • Strings as inputs to Lux.Experimental.layer_map and Lux.Experimental.@debug_mode are removed, use Functors.KeyPath instead.

    • CrossCor has been removed. Use Conv(args...; kwargs..., cross_correlation=true) instead.

    Breaking Changes (Changes in Defaults)

    • Conv and ConvTranspose use an initialization based on the activation function, taken from Pytorch. Pytorch assumes the activation function is leakyrelu to compute the gain, however, we compute the gain based on the activation function passed in to the layer.

    • Upsample now has an align_corners keyword argument, which defaults to false. Previously this was always true.

    • Dense and Bilinear have updated default initializations to align with the defaults from Pytorch. See the documentation for more details.

    • InstanceNorm now defaults to affine=false instead of affine=true.

    • Embedding now defaults to init_weight=rand32 instead of init_weight=randn32.

    • Recurrent Cells - RNNCell, LSTMCell, and GRUCell now have different default initializations. See the documentation for more details.

    New Features

    • InstanceNorm now supports tracking statistics.

    • RNNCell and LSTMCell add bias_ih and bias_hh to the parameters to align with Pytorch. Both are controlled using init_bias and use_bias.

    • ConvTranspose allows flipkernel=true via cross_correlation=true. This makes it efficient for MIOpen.

    • ConvTranspose now has an outpad keyword argument, which is used to increase the size of the output in the desired dimensions.

    • Pooling Layers based on lpnorm have been added – LPPool, GlobalLPPool, and AdaptiveLPPool.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/lstm-illustrative.webp b/previews/PR1023/lstm-illustrative.webp new file mode 100644 index 0000000000..d5353deeb9 Binary files /dev/null and b/previews/PR1023/lstm-illustrative.webp differ diff --git a/previews/PR1023/lux-logo-dark.svg b/previews/PR1023/lux-logo-dark.svg new file mode 100644 index 0000000000..ae8cbe3d91 --- /dev/null +++ b/previews/PR1023/lux-logo-dark.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR1023/lux-logo.svg b/previews/PR1023/lux-logo.svg new file mode 100644 index 0000000000..0ba3c90000 --- /dev/null +++ b/previews/PR1023/lux-logo.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR1023/manual/autodiff.html b/previews/PR1023/manual/autodiff.html new file mode 100644 index 0000000000..036a5d9046 --- /dev/null +++ b/previews/PR1023/manual/autodiff.html @@ -0,0 +1,34 @@ + + + + + + Automatic Differentiation | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Automatic Differentiation

    Lux is not an AD package, but it composes well with most of the AD packages available in the Julia ecosystem. This document lists the current level of support for various AD packages in Lux. Additionally, we provide some convenience functions for working with AD.

    Overview

    AD PackageModeCPUGPUNested 2nd Order ADSupport Class
    ChainRules.jl[1]Reverse✔️✔️✔️Tier I
    Enzyme.jlReverse✔️[2][2:1]Tier I[3]
    Zygote.jlReverse✔️✔️✔️Tier I
    ForwardDiff.jlForward✔️✔️✔️Tier I
    ReverseDiff.jlReverse✔️Tier II
    Tracker.jlReverse✔️✔️Tier II
    Mooncake.jlReverse[2:2]Tier III
    Diffractor.jlForward[2:3][2:4][2:5]Tier III

    Recommendations

    • For CPU Usacases:

      1. Use Zygote.jl for the best performance. This is the most reliable and fastest option for CPU for the time-being. (We are working on faster Enzyme support for CPU)

      2. Use Enzyme.jl, if there are mutations in the code and/or Zygote.jl fails.

      3. If Enzyme.jl fails for some reason, (open an issue and) try ReverseDiff.jl (possibly with compiled mode).

    • For GPU Usacases:

      1. Use Zygote.jl for the best performance. This is the most reliable and fastest option for GPU for the time-being. We are working on supporting Enzyme.jl for GPU as well.

    Support Class

    1. Tier I: These packages are fully supported and have been tested extensively. Often have special rules to enhance performance. Issues for these backends take the highest priority.

    2. Tier II: These packages are supported and extensively tested but often don't have the best performance. Issues against these backends are less critical, but we fix them when possible. (Some specific edge cases, especially with AMDGPU, are known to fail here)

    3. Tier III: We don't know if these packages currently work with Lux. We'd love to add tests for these backends, but currently these are not our priority.

    Footnotes


    1. Note that ChainRules.jl is not really an AD package, but we have first-class support for packages that use rrules. ↩︎

    2. This feature is supported downstream, but we don't extensively test it to ensure that it works with Lux. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

    3. Currently Enzyme outperforms other AD packages in terms of CPU performance. However, there are some edge cases where it might not work with Lux. We are working on improving the compatibility. Please report any issues you encounter. ↩︎

    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/compiling_lux_models.html b/previews/PR1023/manual/compiling_lux_models.html new file mode 100644 index 0000000000..c9ca6ac424 --- /dev/null +++ b/previews/PR1023/manual/compiling_lux_models.html @@ -0,0 +1,108 @@ + + + + + + Compiling Lux Models using Reactant.jl | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Compiling Lux Models using Reactant.jl

    Quoting the Reactant.jl Readme:

    Reactant takes Julia function and compile it into MLIR and run fancy optimizations on top of it, including using EnzymeMLIR for automatic differentiation, and create relevant executables for CPU/GPU/TPU via XLA. It presently operates as a tracing system. Compiled functions will assume the same control flow pattern as was original taken by objects used at compile time, and control flow (e.g. if, for) as well as any type instabilities will be removed. The benefits of this approach is immediately making all such code available for advanced optimization with little developer effort.

    Experimental

    Reactant compilation is a very new feature and is currently experimental. Certain models might not be compilable yet, but we are actively working on it. Open an issue if you encounter any problems.

    julia
    using Lux, Reactant, Enzyme, Random, Zygote
    +using Functors, Optimisers, Printf

    Using the TrainState API

    If you are using the Training.TrainState API, skip to the bottom of this page to see how to train the model without any of this boilerplate.

    We start by defining a simple MLP model:

    julia
    model = Chain(
    +    Dense(2 => 32, gelu),
    +    Dense(32 => 32, gelu),
    +    Dense(32 => 2)
    +)
    +ps, st = Lux.setup(Random.default_rng(), model)
    ((layer_1 = (weight = Float32[-1.2228831 -0.87702435; 0.5031421 -0.15133555; … ; -0.31550723 -0.7672513; 0.111552626 0.6064619], bias = Float32[-0.63795453, 0.62450767, -0.014877922, 0.25385493, -0.20188306, 0.21950458, 0.109203495, 0.23021114, -0.26657984, 0.16187939  …  -0.6409691, 0.4391564, 0.14488737, 0.49998975, -0.04566476, -0.56069607, -0.33442986, -0.1549292, -0.42669478, 0.636308]), layer_2 = (weight = Float32[0.293211 0.19084926 … 0.2464001 0.2913357; -0.116796836 0.09926938 … -0.26311737 -0.15802455; … ; -0.2042089 -0.22406094 … 0.13504265 0.09289699; 0.25389904 0.28355134 … 0.28725442 0.13343152], bias = Float32[0.12992674, 0.14568081, -0.10754459, -0.15686738, -0.14118214, 0.088205874, -0.06301335, 0.06027697, 0.14445141, 0.08791955  …  0.053627778, -0.06618893, 0.1124609, 0.037500158, 0.12827216, -0.13913931, -0.17048413, -0.1032465, -0.15493166, -0.0069942693]), layer_3 = (weight = Float32[-0.031503614 -0.23162955 … 0.097182155 -0.099906564; 0.05729505 0.28042415 … 0.1293236 -0.18089005], bias = Float32[-0.16409892, 0.042256515])), (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()))

    We then create a random input and output data:

    julia
    x = randn(Float32, 2, 32)
    +y = x .^ 2
    2×32 Matrix{Float32}:
    + 0.203036   0.362593  0.354464   0.0320963  …  0.0954186  0.713316  0.438519
    + 0.0155126  1.13864   0.0187668  0.142251      2.24169    4.16407   0.415858

    We will use xla_device similar to gpu_device to move the arrays to Reactant.

    julia
    const xdev = xla_device()
    +
    +x_ra = x |> xdev
    +y_ra = y |> xdev
    +ps_ra = ps |> xdev
    +st_ra = st |> xdev
    +nothing

    First let's run the model as we would normally:

    julia
    pred_lux, _ = model(x, ps, Lux.testmode(st))
    (Float32[-0.20053944 -0.8147778 … -2.3903124 -0.15544322; 0.1585735 0.4981351 … 1.2586653 0.27545732], (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()))

    To run it using XLA we need to compile the model. We can do this using the Reactant.@compile macro. Note that the inputs need to be moved to the device using xla_device first.

    julia
    model_compiled = @compile model(x_ra, ps_ra, Lux.testmode(st_ra))
    Reactant.Compiler.Thunk{Symbol("##Chain{@NamedTuple{layer_1::Dense{typeof(gelu), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Dense{typeof(gelu), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}((layer_1 = Dense(2 => 32, gelu), layer_2 = Dense(32 => 32, gelu), layer_3 = Dense(32 => 2)), nothing)_reactant#1069")}()

    Now we can test the difference between the results:

    julia
    pred_compiled, _ = model_compiled(x_ra, ps_ra, Lux.testmode(st_ra))
    +
    +pred_lux .- Array(pred_compiled)
    2×32 Matrix{Float32}:
    + 0.0  -1.19209f-7  -2.98023f-8  2.98023f-8  …  2.98023f-8  0.0  -1.49012f-8
    + 0.0   1.19209f-7   8.9407f-8   1.78814f-7     1.49012f-8  0.0   2.98023f-8

    The difference is very small as we would expect. Now, let's try to differentiate the output of the model. We need to use Enzyme.jl to do this.

    julia
    function loss_function(model, ps, st, x, y)
    +    pred, _ = model(x, ps, st)
    +    return MSELoss()(pred, y)
    +end
    loss_function (generic function with 1 method)

    We will use Zygote.jl to compute the gradient of the loss function for the vanilla model.

    julia
    loss_function(model, ps, st, x, y)
    +
    +∂ps_zyg = only(Zygote.gradient(ps -> loss_function(model, ps, st, x, y), ps))
    (layer_1 = (weight = Float32[-0.011611392 -0.12556516; -0.09724939 0.11515345; … ; 0.08667634 -0.2689521; -0.09643307 0.030881835], bias = Float32[0.048133414, -0.106884085, 0.097701035, 0.105524555, -0.039647065, -0.018338889, -0.019115759, -0.15107606, 0.013992601, -0.014150472  …  0.0041674753, 0.032615878, 0.031403527, 0.13760866, -0.04225484, 0.049417753, -0.00059220614, -0.03242131, 0.18807876, -0.07640441]), layer_2 = (weight = Float32[-0.004287243 0.028275706 … -0.0073489705 0.0028297475; 0.016479947 0.030926052 … -0.0036810301 0.019791333; … ; 0.010637202 -0.002057937 … 0.010218928 -0.047897488; 0.13518015 0.25378025 … 0.0903271 0.048811335], bias = Float32[0.018884761, 0.053747915, -0.17435724, -0.059518166, -0.10950818, 0.13725635, -0.048533253, -0.11365668, -0.3891182, 0.26477236  …  0.2236399, 0.1377298, -0.027226413, -0.09919551, -0.12902719, 0.0072498624, -0.012183794, 0.066751055, -0.017432783, 0.26700422]), layer_3 = (weight = Float32[-2.5994074 0.07425845 … 0.08953094 -0.9130077; -1.1187928 0.0062888456 … -0.032405674 -0.4112945], bias = Float32[-1.6541586, -0.61384505]))

    Now we will compile the gradient function using Reactant.@compile.

    julia
    function enzyme_gradient(model, ps, st, x, y)
    +    return Enzyme.gradient(Enzyme.Reverse, Const(loss_function), Const(model),
    +        ps, Const(st), Const(x), Const(y))[2]
    +end
    +
    +enzyme_gradient_compiled = @compile enzyme_gradient(model, ps_ra, st_ra, x_ra, y_ra)
    +
    +∂ps_enzyme = enzyme_gradient_compiled(model, ps_ra, st_ra, x_ra, y_ra)
    (layer_1 = (weight = Float32[-0.011611394 -0.12556516; -0.09724942 0.11515346; … ; 0.08667634 -0.2689521; -0.09643307 0.030881835], bias = Float32[0.048133414, -0.10688411, 0.097701035, 0.10552457, -0.039647065, -0.018338893, -0.01911576, -0.15107603, 0.013992591, -0.01415047  …  0.0041674743, 0.03261588, 0.031403534, 0.13760868, -0.042254835, 0.049417756, -0.0005922087, -0.0324213, 0.18807876, -0.076404385]), layer_2 = (weight = Float32[-0.004287243 0.02827571 … -0.0073489705 0.0028297466; 0.016479947 0.030926049 … -0.0036810287 0.019791335; … ; 0.010637204 -0.0020579377 … 0.0102189295 -0.047897488; 0.13518013 0.25378025 … 0.0903271 0.048811335], bias = Float32[0.018884756, 0.053747915, -0.17435724, -0.059518166, -0.1095082, 0.13725637, -0.04853325, -0.11365668, -0.38911813, 0.26477236  …  0.22363997, 0.1377298, -0.027226416, -0.0991955, -0.12902719, 0.007249862, -0.012183795, 0.06675106, -0.017432783, 0.26700416]), layer_3 = (weight = Float32[-2.5994072 0.07425846 … 0.089530945 -0.9130077; -1.1187928 0.006288857 … -0.032405667 -0.4112944], bias = Float32[-1.6541584, -0.6138451]))

    Now we check the difference:

    julia
    fmap(Broadcast.BroadcastFunction(-), ∂ps_zyg, ∂ps_enzyme)
    (layer_1 = (weight = Float32[1.8626451f-9 0.0; 2.9802322f-8 -1.4901161f-8; … ; 0.0 0.0; 0.0 0.0], bias = Float32[0.0, 2.2351742f-8, 0.0, -1.4901161f-8, 0.0, 3.7252903f-9, 1.8626451f-9, -2.9802322f-8, 1.0244548f-8, -2.7939677f-9  …  9.313226f-10, -3.7252903f-9, -7.450581f-9, -1.4901161f-8, -3.7252903f-9, -3.7252903f-9, 2.561137f-9, -1.1175871f-8, 0.0, -2.2351742f-8]), layer_2 = (weight = Float32[0.0 -3.7252903f-9 … 0.0 9.313226f-10; 0.0 3.7252903f-9 … -1.3969839f-9 -1.8626451f-9; … ; -1.8626451f-9 6.9849193f-10 … -1.8626451f-9 0.0; 1.4901161f-8 0.0 … 0.0 0.0], bias = Float32[5.5879354f-9, 0.0, 0.0, 0.0, 2.2351742f-8, -1.4901161f-8, -3.7252903f-9, 0.0, -5.9604645f-8, 0.0  …  -5.9604645f-8, 0.0, 3.7252903f-9, -7.450581f-9, 0.0, 4.656613f-10, 9.313226f-10, -7.450581f-9, 0.0, 5.9604645f-8]), layer_3 = (weight = Float32[-2.3841858f-7 -1.4901161f-8 … -7.450581f-9 0.0; 0.0 -1.1641532f-8 … -7.450581f-9 -8.940697f-8], bias = Float32[-2.3841858f-7, 5.9604645f-8]))

    Using the TrainState API

    Now that we saw the low-level API let's see how to train the model without any of this boilerplate. Simply follow the following steps:

    1. Create a device using xla_device. Remember to load Reactant.jl before doing this.

    2. Similar to other device functions move the model, parameters, states and data to the device. Note that you might want to use DeviceIterator to move the data loader to the device with an iterator.

    3. Construct a TrainState using Training.TrainState.

    4. And most importantly use AutoEnzyme while calling Training.single_train_step! or Training.single_train_step.

    julia
    model = Chain(
    +    Dense(2 => 4, gelu),
    +    Dense(4 => 4, gelu),
    +    Dense(4 => 2)
    +)
    +ps, st = Lux.setup(Random.default_rng(), model)
    +
    +x_ra = [randn(Float32, 2, 32) for _ in 1:32]
    +y_ra = [xᵢ .^ 2 for xᵢ in x_ra]
    +ps_ra = ps |> xdev
    +st_ra = st |> xdev
    +
    +dataloader = DeviceIterator(xdev, zip(x_ra, y_ra))
    +
    +function train_model(model, ps, st, dataloader)
    +    train_state = Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    for iteration in 1:1000
    +        for (xᵢ, yᵢ) in dataloader
    +            grads, loss, stats, train_state = Training.single_train_step!(
    +                AutoEnzyme(), MSELoss(), (xᵢ, yᵢ), train_state)
    +        end
    +        if iteration % 100 == 0 || iteration == 1
    +            # We need to do this since scalar outputs are currently expressed as a zero-dim
    +            # array
    +            loss = Array(loss)[]
    +            @printf("Iter: [%4d/%4d]\tLoss: %.8f\n", iteration, 1000, loss)
    +        end
    +    end
    +
    +    return train_state
    +end
    +
    +train_model(model, ps_ra, st_ra, dataloader)
    Iter: [   1/1000]	Loss: 3.07964921
    +Iter: [ 100/1000]	Loss: 1.06519687
    +Iter: [ 200/1000]	Loss: 0.44807646
    +Iter: [ 300/1000]	Loss: 0.24150778
    +Iter: [ 400/1000]	Loss: 0.14340512
    +Iter: [ 500/1000]	Loss: 0.09299411
    +Iter: [ 600/1000]	Loss: 0.06612328
    +Iter: [ 700/1000]	Loss: 0.04551310
    +Iter: [ 800/1000]	Loss: 0.03070261
    +Iter: [ 900/1000]	Loss: 0.02143306
    +Iter: [1000/1000]	Loss: 0.01542492
    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/debugging.html b/previews/PR1023/manual/debugging.html new file mode 100644 index 0000000000..8369a54645 --- /dev/null +++ b/previews/PR1023/manual/debugging.html @@ -0,0 +1,153 @@ + + + + + + Debugging Lux Models | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Debugging Lux Models

    Debugging DNNs can be very painful. Especially with the gigantic stacktraces for Lux, it is even harder to pin-point to which particular layer errored out. This page describes some useful tools that ship with Lux, that can help you debug your models.

    TL;DR

    Simply wrap your model with Lux.Experimental.@debug_mode!!

    Don't Forget

    Remember to use the non Debug mode model after you finish debugging. Debug mode models are way slower.

    Let us construct a model which has an obviously incorrect dimension. In this example, you will see how easy it is to pin-point the problematic layer.

    Incorrect Model Specification: Dimension Mismatch Problems

    julia
    using Lux, Random
    +
    +model = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 3), Dense(1 => 1)), BatchNorm(1))
    +
    +model_debug = Lux.Experimental.@debug_mode model
    Chain(
    +    layer_1 = DebugLayer(
    +        layer = Dense(1 => 16, relu),   # 32 parameters
    +    ),
    +    layer_2 = Chain(
    +        layer_1 = DebugLayer(
    +            layer = Dense(16 => 3),     # 51 parameters
    +        ),
    +        layer_2 = DebugLayer(
    +            layer = Dense(1 => 1),      # 2 parameters
    +        ),
    +    ),
    +    layer_3 = DebugLayer(
    +        layer = BatchNorm(1, affine=true, track_stats=true),  # 2 parameters, plus 3
    +    ),
    +)         # Total: 87 parameters,
    +          #        plus 3 states.

    Note that we can use the parameters and states for model itself in model_debug, no need to make any changes. If you ran the original model this is the kind of error you would see:

    julia
    rng = Xoshiro(0)
    +
    +ps, st = Lux.setup(rng, model)
    +x = randn(rng, Float32, 1, 2)
    +
    +try
    +    model(x, ps, st)
    +catch e
    +    println(e)
    +end
    DimensionMismatch("A has shape (1, 1) but B has shape (3, 2)")

    Ofcourse, this error will come with a detailed stacktrace, but it is still not very useful. Now let's try using the debug mode model:

    julia
    try
    +    model_debug(x, ps, st)
    +catch e
    +    println(e)
    +end
    [ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 16, relu) at location KeyPath(:model, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (16, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (16, 2).
    +[ Info: Running Layer: Dense(16 => 3) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (3, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (3, 2).
    +[ Info: Running Layer: Dense(1 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2)!
    +┌ Error: Layer Dense(1 => 1) failed!! This layer is present at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2).
    +└ @ Lux.Experimental /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/src/contrib/debug.jl:102
    +DimensionMismatch("A has shape (1, 1) but B has shape (3, 2)")

    See now we know that model.layers.layer_2.layers.layer_2 is the problematic layer. Let us fix that layer and see what happens:

    julia
    model = Chain(Dense(1 => 16, relu),
    +    Chain(
    +        Dense(16 => 3),  
    +        Dense(16 => 1),  
    +        Dense(1 => 1)),
    +    BatchNorm(1))
    julia
    model_fixed = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 1), Dense(1 => 1)),
    +    BatchNorm(1))
    +
    +ps, st = Lux.setup(rng, model_fixed)
    +
    +model_fixed(x, ps, st)
    (Float32[-0.99998605 0.999986], (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_3 = (running_mean = Float32[0.07133968], running_var = Float32[0.971899], training = Val{true}())))

    Voila!! We have tracked down and fixed the problem.

    Tracking down NaNs

    Have you encountered those pesky little NaNs in your training? They are very hard to track down. We will create an artificially simulate NaNs in our model and see how we can track the offending layer.

    We can set nan_check to :forward, :backward or :both to check for NaNs in the debug model. (or even disable it by setting it to :none)

    julia
    model = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 1), Dense(1 => 1)),
    +    BatchNorm(1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model_debug = Lux.Experimental.@debug_mode model nan_check=:both
    Chain(
    +    layer_1 = DebugLayer(
    +        layer = Dense(1 => 16, relu),   # 32 parameters
    +    ),
    +    layer_2 = Chain(
    +        layer_1 = DebugLayer(
    +            layer = Dense(16 => 1),     # 17 parameters
    +        ),
    +        layer_2 = DebugLayer(
    +            layer = Dense(1 => 1),      # 2 parameters
    +        ),
    +    ),
    +    layer_3 = DebugLayer(
    +        layer = BatchNorm(1, affine=true, track_stats=true),  # 2 parameters, plus 3
    +    ),
    +)         # Total: 53 parameters,
    +          #        plus 3 states.

    Let us set a value in the parameter to NaN:

    julia
    ps.layer_2.layer_2.weight[1, 1] = NaN
    NaN

    Now let us run the model

    julia
    model(x, ps, st)
    (Float32[NaN NaN], (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_3 = (running_mean = Float32[NaN], running_var = Float32[NaN], training = Val{true}())))

    Ah as expected our output is NaN. But is is not very clear how to track where the first NaN occurred. Let's run the debug model and check:

    julia
    try
    +    model_debug(x, ps, st)
    +catch e
    +    println(e)
    +end
    [ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 16, relu) at location KeyPath(:model, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (16, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (16, 2).
    +[ Info: Running Layer: Dense(16 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2)!
    +DomainError(Float32[NaN;;], "NaNs detected in parameters (@ KeyPath(:weight,))  of layer Dense(1 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2).")

    And we have figured it out! The first NaN occurred in the parameters of model.layers.layer_2.layers.layer_2! But what if NaN occurs in the reverse pass! Let us define a custom layer and introduce a fake NaN in the backward pass.

    julia
    using ChainRulesCore, Zygote
    +
    +const CRC = ChainRulesCore
    +
    +offending_layer(x) = 2 .* x
    offending_layer (generic function with 1 method)
    julia
    model = Chain(Dense(1 => 16, relu), Chain(Dense(16 => 1), offending_layer), BatchNorm(1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(x, ps, st)
    (Float32[0.9999881 -0.9999881], (layer_1 = NamedTuple(), layer_2 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_3 = (running_mean = Float32[0.0026271285], running_var = Float32[0.98396176], training = Val{true}())))

    Let us define a custom backward pass to introduce some NaNs:

    julia
    function CRC.rrule(::typeof(offending_layer), x)
    +    y = offending_layer(x)
    +    function ∇offending_layer(Δ)
    +        Δ[1] = NaN
    +        return NoTangent(), Δ
    +    end
    +    return y, ∇offending_layer
    +end

    Let us compute the gradient of the layer now:

    julia
    Zygote.gradient(ps -> sum(first(model(x, ps, st))), ps)
    ((layer_1 = (weight = Float32[0.0; 0.0; … ; 0.0; 0.0;;], bias = Float32[0.0, 0.0, 0.0, 0.0, NaN, 0.0, NaN, NaN, 0.0, 0.0, 0.0, NaN, NaN, NaN, 0.0, 0.0]), layer_2 = (layer_1 = (weight = Float32[NaN NaN … NaN NaN], bias = Float32[NaN]), layer_2 = nothing), layer_3 = (scale = Float32[0.0], bias = Float32[2.0])),)

    Oh no!! A NaN is present in the gradient of ps. Let us run the debug model and see where the NaN occurred:

    julia
    model_debug = Lux.Experimental.@debug_mode model nan_check=:both
    +
    +try
    +    Zygote.gradient(ps -> sum(first(model_debug(x, ps, st))), ps)
    +catch e
    +    println(e)
    +end
    [ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: Dense(1 => 16, relu) at location KeyPath(:model, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (16, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (16, 2).
    +[ Info: Running Layer: Dense(16 => 1) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_1)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: WrappedFunction(offending_layer) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +[ Info: Input Type: Matrix{Float32} | Input Structure: (1, 2).
    +[ Info: Running Layer: BatchNorm(1, affine=true, track_stats=true) at location KeyPath(:model, :layers, :layer_3)!
    +[ Info: Output Type: Matrix{Float32} | Output Structure: (1, 2).
    +DomainError(Float32[NaN 0.0], "NaNs detected in pullback output (x)  of layer WrappedFunction(offending_layer) at location KeyPath(:model, :layers, :layer_2, :layers, :layer_2).")

    And there you go our debug layer prints that the problem is in WrappedFunction(offending_layer) at location model.layers.layer_2.layers.layer_2! Once we fix the pullback of the layer, we will fix the NaNs.

    Conclusion

    In this manual section, we have discussed tracking down errors in Lux models. We have covered tracking incorrect model specifications and NaNs in forward and backward passes. However, remember that this is an Experimental feature, and there might be edge cases that don't work correctly. If you find any such cases, please open an issue on GitHub!

    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/dispatch_custom_input.html b/previews/PR1023/manual/dispatch_custom_input.html new file mode 100644 index 0000000000..e6c974aa5b --- /dev/null +++ b/previews/PR1023/manual/dispatch_custom_input.html @@ -0,0 +1,94 @@ + + + + + + Dispatching on Custom Input Types | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Dispatching on Custom Input Types

    Which function should participate in dispatch?

    • Defining a dispatch on (::Layer)(x::MyInputType, ps, st::NamedTuple) is inconvenient, since it requires the user to define a new method for every layer type.

    • (::AbstractLuxLayer)(x::MyInputType, ps, st::NamedTuple) doesn't work.

    • Instead, we need to define the dispatch on Lux.apply(::AbstractLuxLayer, x::MyInputType, ps, st::NamedTuple).

    Concrete Example

    Consider Neural ODEs. In these models, often time we want to every iteration of the neural network to take the current time as input. Here, we won't go through implementing an entire Neural ODE model. Instead we will define a time dependent version of Chain.

    Time-Dependent Chain Implementation

    julia
    using Lux, Random
    +
    +struct TDChain{L <: NamedTuple} <: Lux.AbstractLuxWrapperLayer{:layers}
    +    layers::L
    +end
    +
    +function (l::TDChain)((x, t)::Tuple, ps, st::NamedTuple)
    +    # Concatenate along the 2nd last dimension
    +    sz = ntuple(i -> i == ndims(x) - 1 ? 1 : size(x, i), ndims(x))
    +    t_ = ones(eltype(x), sz) .* t  # Needs to be modified for GPU
    +    for name in keys(l.layers)
    +        x, st_ = Lux.apply(getfield(l.layers, name), cat(x, t_; dims=ndims(x) - 1),
    +                           getfield(ps, name), getfield(st, name))
    +        st = merge(st, NamedTuple{(name,)}((st_,)))
    +    end
    +    return x, st
    +end
    +
    +model = Chain(Dense(3, 4), TDChain((; d1=Dense(5, 4), d2=Dense(5, 4))), Dense(4, 1))
    Chain(
    +    layer_1 = Dense(3 => 4),            # 16 parameters
    +    layer_2 = TDChain(
    +        d1 = Dense(5 => 4),             # 24 parameters
    +        d2 = Dense(5 => 4),             # 24 parameters
    +    ),
    +    layer_3 = Dense(4 => 1),            # 5 parameters
    +)         # Total: 69 parameters,
    +          #        plus 0 states.

    Running the TDChain

    julia
    rng = MersenneTwister(0)
    +ps, st = Lux.setup(rng, model)
    +x = randn(rng, Float32, 3, 2)
    +
    +try
    +    model(x, ps, st)
    +catch e
    +    Base.showerror(stdout, e)
    +end
    MethodError: no method matching apply(::@NamedTuple{d1::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}, d2::Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, ::Matrix{Float32}, ::@NamedTuple{d1::@NamedTuple{weight::Matrix{Float32}, bias::Vector{Float32}}, d2::@NamedTuple{weight::Matrix{Float32}, bias::Vector{Float32}}}, ::@NamedTuple{d1::@NamedTuple{}, d2::@NamedTuple{}})
    +
    +Closest candidates are:
    +  apply(!Matched::AbstractLuxLayer, ::Any, ::Any, ::Any)
    +   @ LuxCore /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxCore/src/LuxCore.jl:154
    +  apply(!Matched::AbstractLuxLayer, !Matched::Tracker.TrackedArray, ::Any, ::Any)
    +   @ LuxCoreArrayInterfaceTrackerExt /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxCore/ext/LuxCoreArrayInterfaceTrackerExt.jl:19
    +  apply(!Matched::AbstractLuxLayer, !Matched::ReverseDiff.TrackedArray, ::Any, ::Any)
    +   @ LuxCoreArrayInterfaceReverseDiffExt /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxCore/ext/LuxCoreArrayInterfaceReverseDiffExt.jl:20
    +  ...

    Writing the Correct Dispatch Rules

    • Create a Custom Layer storing the time.
    julia
    struct ArrayAndTime{A <: AbstractArray, T <: Real}
    +    array::A
    +    time::T
    +end
    • Define the dispatch on Lux.apply(::AbstractLuxLayer, x::ArrayAndTime, ps, st::NamedTuple).
    julia
    function Lux.apply(layer::Lux.AbstractLuxLayer, x::ArrayAndTime, ps, st::NamedTuple)
    +    y, st = layer(x.array, ps, st)
    +    return ArrayAndTime(y, x.time), st
    +end
    +
    +function Lux.apply(layer::TDChain, x::ArrayAndTime, ps, st::NamedTuple)
    +    y, st = layer((x.array, x.time), ps, st)
    +    return ArrayAndTime(y, x.time), st
    +end
    • Run the model.
    julia
    xt = ArrayAndTime(x, 10.0f0)
    +
    +model(xt, ps, st)[1]
    Main.ArrayAndTime{Matrix{Float32}, Float32}(Float32[-2.1488175 -2.401215], 10.0f0)

    Using the Same Input for Non-TD Models

    Writing proper dispatch means we can simply replace the TDChain with a Chain (of course with dimension corrections) and the pipeline still works.

    julia
    model = Chain(Dense(3, 4), Chain((; d1=Dense(4, 4), d2=Dense(4, 4))), Dense(4, 1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(xt, ps, st)[1]
    Main.ArrayAndTime{Matrix{Float32}, Float32}(Float32[0.33758628 -0.079208925], 10.0f0)
    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/distributed_utils.html b/previews/PR1023/manual/distributed_utils.html new file mode 100644 index 0000000000..e6455f8113 --- /dev/null +++ b/previews/PR1023/manual/distributed_utils.html @@ -0,0 +1,37 @@ + + + + + + Distributed Data Parallel Training | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Distributed Data Parallel Training

    Tip

    For a fully functional example, see the ImageNet Training Example.

    DDP Training using Lux.DistributedUtils is a spiritual successor to FluxMPI.jl, but has some key differences.

    Guide to Integrating DistributedUtils into your code

    • Initialize the respective backend with DistributedUtils.initialize, by passing in a backend type. It is important that you pass in the type, i.e. NCCLBackend and not the object NCCLBackend().
    julia
    DistributedUtils.initialize(NCCLBackend)
    julia
    backend = DistributedUtils.get_distributed_backend(NCCLBackend)

    It is important that you use this function instead of directly constructing the backend, since there are certain internal states that need to be synchronized.

    • Next synchronize the parameters and states of the model. This is done by calling DistributedUtils.synchronize!! with the backend and the respective input.
    julia
    ps = DistributedUtils.synchronize!!(backend, ps)
    +st = DistributedUtils.synchronize!!(backend, st)
    julia
    data = DistributedUtils.DistributedDataContainer(backend, data)
    • Wrap the optimizer in DistributedUtils.DistributedOptimizer to ensure that the optimizer is correctly synchronized across all processes before parameter updates. After initializing the state of the optimizer, synchronize the state across all processes.
    julia
    opt = DistributedUtils.DistributedOptimizer(backend, opt)
    +opt_state = Optimisers.setup(opt, ps)
    +opt_state = DistributedUtils.synchronize!!(backend, opt_state)
    • Finally change all logging and serialization code to trigger on local_rank(backend) == 0. This ensures that only the master process logs and serializes the model.

    Migration Guide from FluxMPI.jl

    Let's compare the changes we need to make wrt the FluxMPI.jl integration guide.

    1. FluxMPI.Init is now DistributedUtils.initialize.

    2. FluxMPI.synchronize!(x) needs to be changed to x_new = DistributedUtils.synchronize!!(backend, x).

    3. DistributedUtils.DistributedDataContainer, DistributedUtils.local_rank, and DistributedUtils.DistributedOptimizer need backend as the first input.

    And that's pretty much it!

    Removed Functionality

    1. FluxMPI.allreduce_gradients no longer exists. Previously this was needed when CUDA communication was flaky, with NCCL.jl this is no longer the case.

    2. FluxMPIFluxModel has been removed. DistributedUtils no longer works with Flux.

    Key Differences

    1. FluxMPI.synchronize! is now DistributedUtils.synchronize!! to highlight the fact that some of the inputs are not updated in-place.

    2. All of the functions now require a communication backend as input.

    3. We don't automatically determine if the MPI Implementation is CUDA or ROCM aware. See GPU-aware MPI for more information.

    4. Older (now non-existent) Lux.gpu implementations used to "just work" with FluxMPI.jl. We expect gpu_device to continue working as expected, however, we recommend using gpu_device after calling DistributedUtils.initialize to avoid any mismatch between the device set via DistributedUtils and the device stores in CUDADevice or AMDGPUDevice.

    Known Shortcomings

    1. Currently we don't run tests with CUDA or ROCM aware MPI, use those features at your own risk. We are working on adding tests for these features.

    2. AMDGPU support is mostly experimental and causes deadlocks in certain situations, this is being investigated. If you have a minimal reproducer for this, please open an issue.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/freezing_model_parameters.html b/previews/PR1023/manual/freezing_model_parameters.html new file mode 100644 index 0000000000..34ae92985c --- /dev/null +++ b/previews/PR1023/manual/freezing_model_parameters.html @@ -0,0 +1,84 @@ + + + + + + Freezing Model Parameters | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Freezing Model Parameters

    Warning

    API for freezing parameters should be considered experimental at this point.

    In this manual entry, we will go over how to freeze certain parameters in a model.

    Freezing Layers of a Particular Kind

    To freeze a particular kind of layer, let's say Dense in the following example. We can use Lux.Experimental.layer_map and freeze layers if they are of type Dense.

    julia
    using Lux, Random, Functors
    +
    +rng = Xoshiro(0)
    +
    +model = Chain(Dense(3, 4), Chain(Dense(4, 4), Dropout(0.5f0), BatchNorm(4)), Dense(4, 1))
    +
    +ps, st = Lux.setup(rng, model)
    +
    +x = randn(rng, Float32, 3, 2)
    +
    +model(x, ps, st)
    +
    +function freeze_dense(d::Lux.Dense, ps, st, path)
    +    return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +end
    +freeze_dense(l, ps, st, path) = (l, ps, st)
    +
    +model_frozen, ps_frozen, st_frozen = Lux.Experimental.layer_map(freeze_dense, model, ps, st)
    +
    +model_frozen(x, ps_frozen, st_frozen)
    (Float32[0.6886741 -1.2361472], (layer_1 = (frozen_params = (weight = Float32[-0.028461456 -0.5999714 -0.3850993; -0.18860114 0.72428167 0.32322538; -0.965117 -0.4585489 -0.32623518; -0.86290836 -0.82805836 -0.7673453], bias = Float32[0.4216236, -0.4510427, -0.097253, 0.23325463]), states = NamedTuple()), layer_2 = (layer_1 = (frozen_params = (weight = Float32[-0.680748 0.1764085 0.34383082 0.6469914; -0.13819042 -0.109261915 -0.6143286 -0.21672015; -0.20881107 0.70390546 0.48137343 0.25662464; 0.38187847 0.05779423 -0.35181466 -0.096988946], bias = Float32[0.41246277, 0.4318977, -0.4305781, 0.3367505]), states = NamedTuple()), layer_2 = (rng = Random.Xoshiro(0x4fa3403dd074e603, 0x12c522b8034ae186, 0x8e0c3a65079041bb, 0x21617f7747d97206, 0x22a21880af5dc689), training = Val{true}()), layer_3 = (running_mean = Float32[0.01965834, 0.0, 0.0, 0.015937408], running_var = Float32[0.90772897, 0.9, 0.9, 0.90508], training = Val{true}())), layer_3 = (frozen_params = (weight = Float32[0.7794657 0.8337032 0.6323408 -0.18308182], bias = Float32[-0.27373654]), states = NamedTuple())))

    Freezing by Layer Name

    When the function in layer_map is called, the 4th argument is the name of the layer. For example, if you want to freeze the 1st layer inside the inner Chain. The name for this would be layer_2.layer_1.

    julia
    
    +function freeze_by_name(d, ps, st, name::KeyPath)
    +    name == KeyPath(:layer_2, :layer_1) &&
    +        return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +    return d, ps, st
    +end
    julia
    
    +function freeze_dense(d::Dense, ps, st, _)
    +    return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +end
    +freeze_dense(l, ps, st, _) = (l, ps, st)

    Freezing Part of the Parameters

    Instead of freezing all the parameters, we can simply specify (:weight,) to freeze only the weight parameter while training the bias parameter.

    julia
    
    +function freeze_by_name(d, ps, st, name::KeyPath)
    +    name == KeyPath(:layer_2, :layer_1) &&
    +        return Lux.Experimental.freeze(d, ps, st, (:weight,))
    +    return d, ps, st
    +end
    julia
    
    +function freeze_by_name(d, ps, st, name::KeyPath)
    +    name == KeyPath(:layer_2, :layer_1) &&
    +        return Lux.Experimental.freeze(d, ps, st, (:weight, :bias))
    +    return d, ps, st
    +end

    Freezing Part of a Chain

    julia
    using Lux, Random
    +
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +model = Chain(Dense(3, 4), Dense(4, 4), Dropout(0.5f0), BatchNorm(4), Dense(4, 1))
    +
    +model_frozen = Chain(model[1:2], Lux.Experimental.freeze(model[3:4]), model[5])
    +ps, st = Lux.setup(rng, model_frozen)
    +
    +x = randn(rng, Float32, 3, 2)
    +
    +model_frozen(x, ps, st)
    (Float32[0.7429947 -1.2904677], (layer_1 = (layer_1 = NamedTuple(), layer_2 = NamedTuple()), layer_2 = (frozen_params = (layer_3 = NamedTuple(), layer_4 = (scale = Float32[1.0, 1.0, 1.0, 1.0], bias = Float32[0.0, 0.0, 0.0, 0.0])), states = (layer_3 = (rng = Random.TaskLocalRNG(), training = Val{true}()), layer_4 = (running_mean = Float32[0.0, 0.048522998, 0.0, 0.015937408], running_var = Float32[0.9, 0.9470896, 0.9, 0.90508], training = Val{true}()))), layer_3 = NamedTuple()))
    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/gpu_management.html b/previews/PR1023/manual/gpu_management.html new file mode 100644 index 0000000000..f9ce5fc0b6 --- /dev/null +++ b/previews/PR1023/manual/gpu_management.html @@ -0,0 +1,53 @@ + + + + + + GPU Management | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    GPU Management

    Info

    Starting from v0.5, Lux has transitioned to a new GPU management system. The old system using cpu and gpu functions is still in place but will be removed in v1. Using the old functions might lead to performance regressions if used inside performance critical code.

    Lux.jl can handle multiple GPU backends. Currently, the following backends are supported:

    julia
    # Important to load trigger packages
    +using Lux, LuxCUDA #, AMDGPU, Metal, oneAPI
    +
    +supported_gpu_backends()
    ("CUDA", "AMDGPU", "Metal", "oneAPI")

    Metal Support

    Support for Metal GPUs should be considered extremely experimental at this point.

    Automatic Backend Management (Recommended Approach)

    Automatic Backend Management is done by two simple functions: cpu_device and gpu_device.

    • cpu_device: This is a simple function and just returns a CPUDevice object. @example gpu_management cdev = cpu_device()@example gpu_management x_cpu = randn(Float32, 3, 2)

    • gpu_device: This function performs automatic GPU device selection and returns an object.

      1. If no GPU is available, it returns a CPUDevice object.

      2. If a LocalPreferences file is present, then the backend specified in the file is used. To set a backend, use Lux.gpu_backend!(<backend_name>). (a) If the trigger package corresponding to the device is not loaded, then a warning is displayed. (b) If no LocalPreferences file is present, then the first working GPU with loaded trigger package is used.

      @example
      x_gpu = x_cpu |&gt; gdev  ```
      +`@example gpu_management  (x_gpu |> cdev) ≈ x_cpu`

    Manual Backend Management

    Automatic Device Selection can be circumvented by directly using CPUDevice and AbstractGPUDevice objects.

    julia
    cdev = cpu_device()
    +
    +x_cpu = randn(Float32, 3, 2)
    +
    +if MLDataDevices.functional(CUDADevice)
    +    gdev = CUDADevice()
    +    x_gpu = x_cpu |> gdev
    +elseif MLDataDevices.functional(AMDGPUDevice)
    +    gdev = AMDGPUDevice()
    +    x_gpu = x_cpu |> gdev
    +else
    +    @info "No GPU is available. Using CPU."
    +    x_gpu = x_cpu
    +end
    +
    +(x_gpu |> cdev)  x_cpu
    true
    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/interface.html b/previews/PR1023/manual/interface.html new file mode 100644 index 0000000000..3422ad7dc5 --- /dev/null +++ b/previews/PR1023/manual/interface.html @@ -0,0 +1,124 @@ + + + + + + Lux Interface | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Lux Interface

    Lux.jl vs LuxCore.jl

    If you just want to define compatibility with Lux without actually using any of the other functionality provided by Lux (like layers), it is recommended to depend on LuxCore.jl instead of Lux.jl. LuxCore.jl is a significantly lighter dependency.

    Following this interface provides the ability for frameworks built on top of Lux to be cross compatible. Additionally, any new functionality built into Lux, will just work for your framework.

    @compact macro

    While writing out a custom struct and defining dispatches manually is a good way to understand the interface, it is not the most concise way. We recommend using the Lux.@compact macro to define layers which makes handling the states and parameters downright trivial.

    Layer Interface

    Singular Layer

    If the layer doesn't contain any other Lux layer, then it is a Singular Layer. This means it should optionally subtype Lux.AbstractLuxLayer but mandatorily define all the necessary functions mentioned in the docstrings. Consider a simplified version of Dense called Linear.

    First, setup the architectural details for this layer. Note, that the architecture doesn't contain any mutable structure like arrays. When in doubt, remember, once constructed a model architecture cannot change.

    Tip

    For people coming from Flux.jl background, this might be weird. We recommend checking out the Flux to Lux migration guide first before proceeding.

    julia
    using LuxCore, Random, WeightInitializers # Importing `Lux` also gives you access to `LuxCore`
    +
    +struct Linear{F1, F2} <: LuxCore.AbstractLuxLayer
    +    in_dims::Int
    +    out_dims::Int
    +    init_weight::F1
    +    init_bias::F2
    +end
    +
    +function Linear(in_dims::Int, out_dims::Int; init_weight=glorot_uniform, init_bias=zeros32)
    +    return Linear{typeof(init_weight), typeof(init_bias)}(in_dims, out_dims, init_weight,
    +        init_bias)
    +end
    +
    +l = Linear(2, 4)
    Main.Linear{typeof(glorot_uniform), typeof(zeros32)}(2, 4, WeightInitializers.glorot_uniform, WeightInitializers.zeros32)

    Next, we need to implement functions which return the parameters and states for the layer. In case of Linear, the parameters are weight and bias while the states are empty. States become important when defining layers like BatchNorm, WeightNorm, etc. The recommended data structure for returning parameters is a NamedTuple, though anything satisfying the Parameter Interface is valid.

    julia
    function LuxCore.initialparameters(rng::AbstractRNG, l::Linear)
    +    return (weight=l.init_weight(rng, l.out_dims, l.in_dims),
    +            bias=l.init_bias(rng, l.out_dims, 1))
    +end
    +
    +LuxCore.initialstates(::AbstractRNG, ::Linear) = NamedTuple()

    You could also implement LuxCore.parameterlength and LuxCore.statelength to prevent wasteful reconstruction of the parameters and states.

    julia
    # This works
    +println("Parameter Length: ", LuxCore.parameterlength(l), "; State Length: ",
    +    LuxCore.statelength(l))
    +
    +# But still recommended to define these
    +LuxCore.parameterlength(l::Linear) = l.out_dims * l.in_dims + l.out_dims
    +
    +LuxCore.statelength(::Linear) = 0
    Parameter Length: 12; State Length: 0

    No RNG in initialparameters and initialstates

    You might notice that we don't pass in a RNG for these functions. If your parameter length and/or state length depend on a random number generator, you should think really hard about what you are trying to do and why.

    Now, we need to define how the layer works. For this you make your layer a function with exactly 3 arguments – x the input, ps the parameters, and st the states. This function must return two things – y the output, and st_new the updated state.

    julia
    function (l::Linear)(x::AbstractMatrix, ps, st::NamedTuple)
    +    y = ps.weight * x .+ ps.bias
    +    return y, st
    +end

    Finally, let's run this layer. If you have made this far into the documentation, we don't feel you need a refresher on that.

    julia
    rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +ps, st = LuxCore.setup(rng, l)
    +
    +println("Parameter Length: ", LuxCore.parameterlength(l), "; State Length: ",
    +    LuxCore.statelength(l))
    +
    +x = randn(rng, Float32, 2, 1)
    +
    +LuxCore.apply(l, x, ps, st) # or `l(x, ps, st)`
    (Float32[-0.15276335; 0.45325348; 1.0207279; 0.78226817;;], NamedTuple())

    Container Layer

    If your layer comprises of other Lux layers, then it is a Container Layer. Note that you could treat it as a Singular Layer, and it is still fine. FWIW, if you cannot subtype your layer with LuxCore.AbstractLuxContainerLayer then you should go down the Singular Layer route. But subtyping allows us to bypass some of these common definitions. Let us now define a layer, which is basically a composition of two linear layers.

    Wrapper Layer

    If you are defining a layer that is a wrapper around another layer, then you should subtype LuxCore.AbstractLuxWrapperLayer instead of LuxCore.AbstractLuxContainerLayer. The only difference from a container layer is that it can wrap a single layer and the parameter/state structure is exactly the same as the wrapped layer.

    julia
    struct ComposedLinear{L1, L2} <: LuxCore.AbstractLuxContainerLayer{(:linear_1, :linear_2)}
    +    linear_1::L1
    +    linear_2::L2
    +end
    +
    +function (cl::ComposedLinear)(x::AbstractMatrix, ps, st::NamedTuple)
    +    # To access the parameters and states for `linear_1` we do `ps.linear_1` and
    +    # `st.linear_1`. Similarly for `linear_2`
    +    y, st_l1 = cl.linear_1(x, ps.linear_1, st.linear_1)
    +    y, st_l2 = cl.linear_2(y, ps.linear_2, st.linear_2)
    +    # Finally, we need to return the new state which has the exact structure as `st`
    +    return y, (linear_1 = st_l1, linear_2 = st_l2)
    +end

    Here, you will notice we have passed (:linear_1, :linear_2) to the supertype. It essentially informs the type that, <obj>.linear_1 and <obj>.linear_2 are Lux layers and we need to construct parameters and states for those. Let's construct these and see:

    julia
    model = ComposedLinear(Linear(2, 4), Linear(4, 2))
    +display(model)
    +
    +ps, st = LuxCore.setup(rng, model)
    +
    +println("Parameters: ", ps)
    +println("States: ", st)
    +
    +println("Parameter Length: ", LuxCore.parameterlength(model), "; State Length: ",
    +    LuxCore.statelength(model))
    +
    +x = randn(rng, Float32, 2, 1)
    +
    +LuxCore.apply(model, x, ps, st) # or `model(x, ps, st)`
    (Float32[1.3410565; 0.78000563;;], (linear_1 = NamedTuple(), linear_2 = NamedTuple()))

    Parameter Interface

    We accept any parameter type as long as we can fetch the parameters using getproperty(obj, :parameter_name). This allows us to simultaneously support NamedTuples and ComponentArrays. Let us go through a concrete example of what it means. Consider Dense which expects two parameters named weight and bias.

    Automatic Differentiation

    If you are defining your own parameter type, it is your responsibility to make sure that it works with the AutoDiff System you are using.

    julia
    using Lux, Random
    +
    +d = Dense(2, 3)
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    +
    +ps_default, st = LuxCore.setup(rng, d)
    +
    +x = randn(rng, Float32, 2, 1)
    +
    +println("Result with `NamedTuple` parameters: ", first(d(x, ps_default, st)))
    Result with `NamedTuple` parameters: Float32[-0.08713347; -0.4851346; -0.8490221;;]

    Let, us define a custom parameter type with fields myweight and mybias but if we try to access weight we get back myweight, similar for bias.

    Beware!

    This is for demonstrative purposes, don't try this at home!

    julia
    struct DenseLayerParameters{W, B}
    +    myweight::W
    +    mybias::B
    +end
    +
    +function Base.getproperty(ps::DenseLayerParameters, x::Symbol)
    +    if x == :weight
    +        return getfield(ps, :myweight)
    +    elseif x == :bias
    +        return getfield(ps, :mybias)
    +    end
    +    return getfield(ps, x)
    +end
    +
    +ps = DenseLayerParameters(ps_default.weight, ps_default.bias)
    +
    +println("Result with `DenseLayerParameters` parameters: ", first(d(x, ps, st)))
    Result with `DenseLayerParameters` parameters: Float32[0.23710957; 0.1003911; -0.57671577;;]

    The takeaway from this shouldn't be – lets define weird parameter types. Simply because you can do weird things like this doesn't mean you should, since it only leads to bugs.

    Instead this shows the flexibility you have for how your parameters can be structured.

    State Interface

    States are always type constrained to be NamedTuple. The structure of the input state must match that of the output state, i.e. keys(st_in) == keys(st_out). This doesn't imply that types of the input and output state match. To generate efficient code, we often do dispatch on the state, for example, Dropout, BatchNorm, etc.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/migrate_from_flux.html b/previews/PR1023/manual/migrate_from_flux.html new file mode 100644 index 0000000000..ccd9652ed8 --- /dev/null +++ b/previews/PR1023/manual/migrate_from_flux.html @@ -0,0 +1,108 @@ + + + + + + Migrating from Flux to Lux | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Migrating from Flux to Lux

    For the core library layers like Dense, Conv, etc. we have intentionally kept the API very similar to Flux. In most cases, replacing using Flux with using Lux should be enough to get you started. We cover the additional changes that you will have to make in the following example.

    julia
    using Lux, Random, NNlib, Zygote
    +
    +model = Chain(Dense(2 => 4), BatchNorm(4, relu), Dense(4 => 2))
    +rng = Random.default_rng()
    +x = randn(rng, Float32, 2, 4)
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(x, ps, st)
    +
    +gradient(ps -> sum(first(model(x, ps, st))), ps)
    julia
    using Flux, Random, NNlib, Zygote
    +
    +model = Chain(Dense(2 => 4), BatchNorm(4, relu), Dense(4 => 2))
    +rng = Random.default_rng()
    +x = randn(rng, Float32, 2, 4)
    +
    +
    +
    +model(x)
    +
    +gradient(model -> sum(model(x)), model)

    Implementing Custom Layers

    Flux and Lux operate under extremely different design philosophies regarding how layers should be implemented. A summary of the differences would be:

    • Flux stores everything in a single struct and relies on Functors.@functor and Flux.trainable to distinguish between trainable and non-trainable parameters.

    • Lux relies on the user to define Lux.initialparameters and Lux.initialstates to distinguish between trainable parameters (called "parameters") and non-trainable parameters (called "states"). Additionally, Lux layers define the model architecture, hence device transfer utilities like gpu_device, cpu_device, etc. cannot be applied on Lux layers, instead they need to be applied on the parameters and states.

    Let's work through a concrete example to demonstrate this. We will implement a very simple layer that computes A×B×x where A is not trainable and B is trainable.

    julia
    using Lux, Random, NNlib, Zygote
    +
    +struct LuxLinear <: Lux.AbstractLuxLayer
    +    init_A
    +    init_B
    +end
    +
    +function LuxLinear(A::AbstractArray, B::AbstractArray)
    +    # Storing Arrays or any mutable structure inside a Lux Layer is not recommended
    +    # instead we will convert this to a function to perform lazy initialization
    +    return LuxLinear(() -> copy(A), () -> copy(B))
    +end
    +
    +# `B` is a parameter
    +Lux.initialparameters(::AbstractRNG, layer::LuxLinear) = (B=layer.init_B(),)
    +
    +# `A` is a state
    +Lux.initialstates(::AbstractRNG, layer::LuxLinear) = (A=layer.init_A(),)
    +
    +(l::LuxLinear)(x, ps, st) = st.A * ps.B * x, st
    julia
    using Flux, Random, NNlib, Zygote, Optimisers
    +
    +struct FluxLinear
    +    A
    +    B
    +end
    +
    +
    +
    +
    +
    +
    +
    +# `A` is not trainable
    +Optimisers.trainable(f::FluxLinear) = (B=f.B,)
    +
    +# Needed so that both `A` and `B` can be transferred between devices
    +Flux.@functor FluxLinear
    +
    +(l::FluxLinear)(x) = l.A * l.B * x

    Now let us run the model.

    julia
    rng = Random.default_rng()
    +model = LuxLinear(randn(rng, 2, 4), randn(rng, 4, 2))
    +x = randn(rng, 2, 1)
    +
    +ps, st = Lux.setup(rng, model)
    +
    +model(x, ps, st)
    +
    +gradient(ps -> sum(first(model(x, ps, st))), ps)
    julia
    rng = Random.default_rng()
    +model = FluxLinear(randn(rng, 2, 4), randn(rng, 4, 2))
    +x = randn(rng, 2, 1)
    +
    +
    +
    +model(x)
    +
    +gradient(model -> sum(model(x)), model)

    To reiterate some important points:

    • Don't store mutables like Arrays inside a Lux Layer.

    • Parameters and States should be constructured inside the respective initial* functions.

    Certain Important Implementation Details

    Training/Inference Mode

    Flux supports a mode called :auto which automatically decides if the user is training the model or running inference. This is the default mode for Flux.BatchNorm, Flux.GroupNorm, Flux.Dropout, etc. Lux doesn't support this mode (specifically to keep code simple and do exactly what the user wants), hence our default mode is training. This can be changed using Lux.testmode.

    Can we still use Flux Layers?

    If you have Flux loaded in your code, you can use the function FromFluxAdaptor to automatically convert your model to Lux. Note that in case a native Lux counterpart isn't available, we fallback to using Optimisers.destructure.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/nested_autodiff.html b/previews/PR1023/manual/nested_autodiff.html new file mode 100644 index 0000000000..0e5642e27e --- /dev/null +++ b/previews/PR1023/manual/nested_autodiff.html @@ -0,0 +1,152 @@ + + + + + + Nested Automatic Differentiation | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Nested Automatic Differentiation

    Note

    This is a relatively new feature in Lux, so there might be some rough edges. If you encounter any issues, please let us know by opening an issue on the GitHub repository.

    In this manual, we will explore how to use automatic differentiation (AD) inside your layers or loss functions and have Lux automatically switch the AD backend with a faster one when needed.

    Tip

    Don't wan't Lux to do this switching for you? You can disable it by setting the automatic_nested_ad_switching Preference to false.

    Remember that if you are using ForwardDiff inside a Zygote call, it will drop gradients (with a warning message), so it is not recommended to use this combination.

    Let's explore this using some questions that were posted on the Julia Discourse forum.

    julia
    using ADTypes, Lux, LinearAlgebra, Zygote, ForwardDiff, Random, StableRNGs
    +using ComponentArrays, FiniteDiff

    First let's set the stage using some minor changes that need to be made for this feature to work:

    • Switching only works if a StatefulLuxLayer is being used, with the following function calls:

      • For operations on the inputs:

        • (<some-function> ∘ <StatefulLuxLayer>)(x::AbstractArray)

        • (<StatefulLuxLayer> ∘ <some-function>)(x::AbstractArray)

        • (<StatefulLuxLayer>)(x::AbstractArray)

      • For operations on the parameters:

        • (<some-function> ∘ Base.Fix1(<StatefulLuxLayer>, x))(ps)

        • (Base.Fix1(<StatefulLuxLayer>, x) ∘ <some-function>)(ps)

        • (Base.Fix1(<StatefulLuxLayer>, x))(ps)

    • Currently we have custom routines implemented for:

    • Switching only happens for ChainRules compatible AD libraries.

    We plan to capture DifferentiationInterface, and Enzyme.autodiff calls in the future (PRs are welcome).

    Tip

    @compact uses StatefulLuxLayers internally, so you can directly use these features inside a layer generated by @compact.

    Loss Function containing Jacobian Computation

    This problem comes from @facusapienza on Discourse. In this case, we want to add a regularization term to the neural DE based on first-order derivatives. The neural DE part is not important here and we can demonstrate this easily with a standard neural network.

    julia
    function loss_function1(model, x, ps, st, y)
    +    # Make it a stateful layer
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    += smodel(x)
    +    loss_emp = sum(abs2, ŷ .- y)
    +    # You can use `Zygote.jacobian` as well but ForwardDiff tends to be more efficient here
    +    J = ForwardDiff.jacobian(smodel, x)
    +    loss_reg = abs2(norm(J .* 0.01f0))
    +    return loss_emp + loss_reg
    +end
    +
    +# Using Batchnorm to show that it is possible
    +model = Chain(Dense(2 => 4, tanh), BatchNorm(4), Dense(4 => 2))
    +ps, st = Lux.setup(StableRNG(0), model)
    +x = randn(StableRNG(0), Float32, 2, 10)
    +y = randn(StableRNG(11), Float32, 2, 10)
    +
    +loss_function1(model, x, ps, st, y)
    14.883664f0

    So our loss function works, let's take the gradient (forward diff doesn't nest nicely here):

    julia
    _, ∂x, ∂ps, _, _ = Zygote.gradient(loss_function1, model, x, ps, st, y)
    (nothing, Float32[-1.6702257 0.9043228 … 0.16094846 -4.992662; -8.010404 0.8541596 … 3.3928175 -7.1936812], (layer_1 = (weight = Float32[-4.3707023 -4.9076533; 22.199387 1.867202; 0.47872233 -0.9734574; -0.36428708 0.31861955], bias = Float32[-1.0168695, -0.16566901, 1.0829282, 1.4810884]), layer_2 = (scale = Float32[4.2774315, 3.1984668, 6.840588, 3.7018592], bias = Float32[-2.6477456, 4.9094505, -4.987689, -0.7292344]), layer_3 = (weight = Float32[11.395306 1.9206433 9.744489 -7.6726513; 2.5979974 7.106069 -7.869632 -1.787159], bias = Float32[0.041031003, 7.928609])), nothing, Float32[0.48193252 1.4007905 … -0.19124654 -1.7181164; 1.7811481 0.6913705 … -1.5627227 1.4397957])

    Now let's verify the gradients using finite differences:

    julia
    ∂x_fd = FiniteDiff.finite_difference_gradient(x -> loss_function1(model, x, ps, st, y), x)
    +∂ps_fd = FiniteDiff.finite_difference_gradient(ps -> loss_function1(model, x, ps, st, y),
    +    ComponentArray(ps))
    +
    +println("∞-norm(∂x - ∂x_fd): ", norm(∂x .- ∂x_fd, Inf))
    +println("∞-norm(∂ps - ∂ps_fd): ", norm(ComponentArray(∂ps) .- ∂ps_fd, Inf))
    ┌ Warning: `training` is set to `Val{true}()` but is not being used within an autodiff call (gradient, jacobian, etc...). This will be slow. If you are using a `Lux.jl` model, set it to inference (test) mode using `LuxCore.testmode`. Reliance on this behavior is discouraged, and is not guaranteed by Semantic Versioning, and might be removed without a deprecation cycle. It is recommended to fix this issue in your code.
    +└ @ LuxLib.Utils /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxLib/src/utils.jl:309
    +┌ Warning: `training` is set to `Val{true}()` but is not being used within an autodiff call (gradient, jacobian, etc...). This will be slow. If you are using a `Lux.jl` model, set it to inference (test) mode using `LuxCore.testmode`. Reliance on this behavior is discouraged, and is not guaranteed by Semantic Versioning, and might be removed without a deprecation cycle. It is recommended to fix this issue in your code.
    +└ @ LuxLib.Utils /var/lib/buildkite-agent/builds/gpuci-5/julialang/lux-dot-jl/lib/LuxLib/src/utils.jl:309
    +∞-norm(∂x - ∂x_fd): 0.00046014786
    +∞-norm(∂ps - ∂ps_fd): 0.00068473816

    That's pretty good, of course you will have some error from the finite differences calculation.

    Using Batched Jacobian for Multiple Inputs

    Notice that in this example the Jacobian J consists on the full matrix of derivatives of smodel with respect the different inputs in x. In many cases, we are interested in computing the Jacobian with respect to each input individually, avoiding the unnecessary calculation of zero entries of the Jacobian. This can be achieved with batched_jacobian to parse the calculation of the Jacobian per each single input. Using the same example from the previous section:

    julia
    model = Chain(Dense(2 => 4, tanh), Dense(4 => 2))
    +ps, st = Lux.setup(StableRNG(0), model)
    +x = randn(StableRNG(0), Float32, 2, 10)
    +y = randn(StableRNG(11), Float32, 2, 10)
    +
    +function loss_function_batched(model, x, ps, st, y)
    +    # Make it a stateful layer
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    += smodel(x)
    +    loss_emp = sum(abs2, ŷ .- y)
    +    # You can use `AutoZygote()` as well but `AutoForwardDiff()` tends to be more efficient here
    +    J = batched_jacobian(smodel, AutoForwardDiff(), x)
    +    loss_reg = abs2(norm(J .* 0.01f0))
    +    return loss_emp + loss_reg
    +end
    +
    +loss_function_batched(model, x, ps, st, y)
    11.380777f0

    Notice that in this last example we removed BatchNorm() from the neural network. This is done so outputs corresponding to differern inputs don't have an algebraic dependency due to the batch normalization happening in the neural network. We can now verify again the value of the Jacobian:

    julia
    ∂x_fd = FiniteDiff.finite_difference_gradient(x -> loss_function_batched(model, x, ps, st, y), x)
    +∂ps_fd = FiniteDiff.finite_difference_gradient(ps -> loss_function_batched(model, x, ps, st, y),
    +    ComponentArray(ps))
    +
    +_, ∂x_b, ∂ps_b, _, _ = Zygote.gradient(loss_function_batched, model, x, ps, st, y)
    +println("∞-norm(∂x_b - ∂x_fd): ", norm(∂x_b .- ∂x_fd, Inf))
    +println("∞-norm(∂ps_b - ∂ps_fd): ", norm(ComponentArray(∂ps_b) .- ∂ps_fd, Inf))
    ∞-norm(∂x_b - ∂x_fd): 0.00020849705
    +∞-norm(∂ps_b - ∂ps_fd): 0.00025326014

    In this example, it is important to remark that now batched_jacobian returns a 3D array with the Jacobian calculation for each independent input value in x.

    Loss Function contains Gradient Computation

    Ok here I am going to cheat a bit. This comes from a discussion on nested AD for PINNs on Discourse. As the consensus there, we shouldn't use nested AD for 3rd or higher order differentiation. Note that in the example there, the user uses ForwardDiff.derivative but we will use ForwardDiff.gradient instead, as we typically deal with array inputs and outputs.

    julia
    function loss_function2(model, t, ps, st)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    += only(Zygote.gradient(Base.Fix1(sum, abs2)  smodel, t)) # Zygote returns a tuple
    +    return sum(abs2, ŷ .- cos.(t))
    +end
    +
    +model = Chain(Dense(1 => 12,tanh), Dense(12 => 12,tanh), Dense(12 => 12,tanh),
    +    Dense(12 => 1))
    +ps, st = Lux.setup(StableRNG(0), model)
    +t = rand(StableRNG(0), Float32, 1, 16)
    1×16 Matrix{Float32}:
    + 0.420698  0.488105  0.267644  0.784768  …  0.305844  0.131726  0.859405

    Now the moment of truth:

    julia
    _, ∂t, ∂ps, _ = Zygote.gradient(loss_function2, model, t, ps, st)
    (nothing, Float32[-0.5530689 0.15707001 … -8.553631 0.075135306], (layer_1 = (weight = Float32[-1.3108876; -2.4101033; … ; 0.43676835; 1.9626998;;], bias = Float32[-1.77037, 1.7834251, -7.1079326, -3.4437156, 3.2615936, -1.9511775, 11.52717, -1.8003627, 6.751377, -4.7700396, -3.183307, 6.5878153]), layer_2 = (weight = Float32[-0.23921265 -0.20668754 … -0.63838756 -2.23242; -1.666682 1.0425432 … -1.6409345 -3.4007292; … ; -0.3602331 -0.086429894 … -0.7054554 -2.1921258; 3.1173706 -1.9727281 … 3.0402095 6.1137304], bias = Float32[0.3729234, -2.9340093, 3.6637242, -0.72471225, -0.79250443, -1.1245008, -0.89858943, -0.032846544, -2.7296474, -8.446214, 0.062079933, 5.5367613]), layer_3 = (weight = Float32[-0.7262075 1.0381727 … -1.5016017 -1.6798847; 2.2896142 0.43350348 … -1.6663244 -1.8067698; … ; -2.185124 -0.6424197 … 1.9577397 2.1489007; 0.36542922 -0.09699093 … 0.02535769 0.028738942], bias = Float32[1.1350521, -2.1769385, 4.114975, 3.2842, 0.35638642, 3.7911112, -0.007984845, -2.0338569, -1.1642133, -2.9500444, 2.0285962, -0.41238892]), layer_4 = (weight = Float32[15.794908 -20.65178 … -7.798027 -9.910251], bias = Float32[11.4614])), nothing)

    Boom that worked! Let's verify the gradient using forward diff:

    julia
    ∂t_fd = ForwardDiff.gradient(t -> loss_function2(model, t, ps, st), t)
    +∂ps_fd = ForwardDiff.gradient(ps -> loss_function2(model, t, ps, st), ComponentArray(ps))
    +
    +println("∞-norm(∂t - ∂t_fd): ", norm(∂t .- ∂t_fd, Inf))
    +println("∞-norm(∂ps - ∂ps_fd): ", norm(ComponentArray(∂ps) .- ∂ps_fd, Inf))
    ∞-norm(∂t - ∂t_fd): 3.8146973e-6
    +∞-norm(∂ps - ∂ps_fd): 3.8146973e-6

    Loss Function computing the Jacobian of the Parameters

    The above example shows how to compute the gradient/jacobian wrt the inputs in the loss function. However, what if we want to compute the jacobian wrt the parameters? This problem has been taken from Issue 610.

    We resolve these setups by using the Base.Fix1 wrapper around the stateful layer and fixing the input to the stateful layer.

    julia
    function loss_function3(model, x, ps, st)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    J = only(Zygote.jacobian(Base.Fix1(smodel, x), ps)) # Zygote returns a tuple
    +    return sum(abs2, J)
    +end
    +
    +model = Chain(Dense(1 => 12,tanh), Dense(12 => 12,tanh), Dense(12 => 12,tanh),
    +    Dense(12 => 1))
    +ps, st = Lux.setup(StableRNG(0), model)
    +ps = ComponentArray(ps)  # needs to be an AbstractArray for most jacobian functions
    +x = rand(StableRNG(0), Float32, 1, 16)
    1×16 Matrix{Float32}:
    + 0.420698  0.488105  0.267644  0.784768  …  0.305844  0.131726  0.859405

    We can as usual compute the gradient/jacobian of the loss function:

    julia
    _, ∂x, ∂ps, _ = Zygote.gradient(loss_function3, model, x, ps, st)
    (nothing, Float32[6.846457 6.2111273 … 1.9693878 -1.959182], (layer_1 = (weight = Float32[-3.6867142; -1.6853896; … ; 2.9501405; -6.6372185;;], bias = Float32[-6.488623, -7.066128, 1.3344351, 2.6049256, 0.72908926, -15.730941, -5.4314566, 7.4604845, -1.186451, 15.522139, 0.44571686, -15.376383]), layer_2 = (weight = Float32[0.39800483 -4.3071294 … -1.0914626 -4.759412; 0.8852221 -2.2523673 … 0.3977319 0.1306755; … ; -2.2192001 0.88214725 … -0.55989707 1.3939896; -3.1545162 4.594261 … -1.7649314 -0.38242024], bias = Float32[7.524781, 4.252925, -17.252985, 3.2606924, -7.4066515, 1.1126356, 2.847106, 6.754463, -9.815336, 0.18652338, -4.5365157, -10.048109]), layer_3 = (weight = Float32[1.0462954 4.8999977 … 1.1557574 -2.2849667; -2.3719285 8.687264 … -3.1904755 -8.841231; … ; -10.298787 -2.9139614 … -9.754747 -4.0381317; 1.2221465 -0.4687857 … 1.0469301 0.90910274], bias = Float32[2.837991, 8.345025, 2.9214196, -2.2415948, -11.139433, -3.8340728, -2.8454118, -7.9164896, 4.222528, -1.2864522, 6.9338737, -1.4144732]), layer_4 = (weight = Float32[-59.44397 -12.688665 … 99.77207 -3.339079], bias = Float32[0.0])), nothing)

    Now let's verify the gradient using forward diff:

    julia
    ∂x_fd = ForwardDiff.gradient(x -> loss_function3(model, x, ps, st), x)
    +∂ps_fd = ForwardDiff.gradient(ps -> loss_function3(model, x, ps, st), ComponentArray(ps))
    +
    +println("∞-norm(∂x - ∂x_fd): ", norm(∂x .- ∂x_fd, Inf))
    +println("∞-norm(∂ps - ∂ps_fd): ", norm(ComponentArray(∂ps) .- ∂ps_fd, Inf))
    ∞-norm(∂x - ∂x_fd): 4.172325e-6
    +∞-norm(∂ps - ∂ps_fd): 4.5776367e-5

    Hutchinson Trace Estimation

    Hutchinson Trace Estimation often shows up in machine learning literature to provide a fast estimate of the trace of a Jacobian Matrix. This is based off of Hutchinson 1990 which computes the estimated trace of a matrix ARD×D using random vectors vRD s.t. E[vvT]=I.

    Tr(A)=E[vTAv]=1Vi=1VviTAvi

    We can use this to compute the trace of a Jacobian Matrix JRD×D using the following algorithm:

    Tr(J)=1Vi=1VviTJvi

    Note that we can compute this using two methods:

    1. Compute viTJ using a Vector-Jacobian product and then do a matrix-vector product to get the trace.

    2. Compute Jvi using a Jacobian-Vector product and then do a matrix-vector product to get the trace.

    For simplicity, we will use a single sample of vi to compute the trace. Additionally, we will fix the sample to ensure that our tests against the finite difference implementation are not affected by the randomness in the sample.

    Computing using the Vector-Jacobian Product

    julia
    function hutchinson_trace_vjp(model, x, ps, st, v)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    vjp = vector_jacobian_product(smodel, AutoZygote(), x, v)
    +    return sum(batched_matmul(reshape(vjp, 1, :, size(vjp, ndims(vjp))),
    +               reshape(v, :, 1, size(v, ndims(v)))))
    +end
    hutchinson_trace_vjp (generic function with 1 method)

    This vjp version will be the fastest and most scalable and hence is the recommended way for computing hutchinson trace.

    Computing using the Jacobian-Vector Product

    julia
    function hutchinson_trace_jvp(model, x, ps, st, v)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    jvp = jacobian_vector_product(smodel, AutoForwardDiff(), x, v)
    +    return sum(batched_matmul(reshape(v, 1, :, size(v, ndims(v))),
    +               reshape(jvp, :, 1, size(jvp, ndims(jvp)))))
    +end
    hutchinson_trace_jvp (generic function with 1 method)

    Computing using the Full Jacobian

    This is definitely not recommended, but we are showing it for completeness.

    julia
    function hutchinson_trace_full_jacobian(model, x, ps, st, v)
    +    smodel = StatefulLuxLayer{true}(model, ps, st)
    +    J = ForwardDiff.jacobian(smodel, x)
    +    return vec(v)' * J * vec(v)
    +end
    hutchinson_trace_full_jacobian (generic function with 1 method)

    Now let's compute the trace and compare the results:

    julia
    model = Chain(Dense(4 => 12,tanh), Dense(12 => 12,tanh), Dense(12 => 12,tanh),
    +    Dense(12 => 4))
    +ps, st = Lux.setup(StableRNG(0), model)
    +x = rand(StableRNG(0), Float32, 4, 12)
    +v = (rand(StableRNG(12), Float32, 4, 12) .> 0.5f0) * 2.0f0 .- 1.0f0  # rademacher sample
    julia
    tr_vjp = hutchinson_trace_vjp(model, x, ps, st, v)
    +tr_jvp = hutchinson_trace_jvp(model, x, ps, st, v)
    +tr_full_jacobian = hutchinson_trace_full_jacobian(model, x, ps, st, v)
    +println("Tr(J) using vjp: ", tr_vjp)
    +println("Tr(J) using jvp: ", tr_jvp)
    +println("Tr(J) using full jacobian: ", tr_full_jacobian)
    Tr(J) using vjp: 4.9127817
    +Tr(J) using jvp: 4.912782
    +Tr(J) using full jacobian: 4.912781

    Now that we have verified that the results are the same, let's try to differentiate the trace estimate. This often shows up as a regularization term in neural networks.

    julia
    _, ∂x_vjp, ∂ps_vjp, _, _ = Zygote.gradient(hutchinson_trace_vjp, model, x, ps, st, v)
    +_, ∂x_jvp, ∂ps_jvp, _, _ = Zygote.gradient(hutchinson_trace_jvp, model, x, ps, st, v)
    +_, ∂x_full_jacobian, ∂ps_full_jacobian, _, _ = Zygote.gradient(hutchinson_trace_full_jacobian,
    +    model, x, ps, st, v)

    For sanity check, let's verify that the gradients are the same:

    julia
    println("∞-norm(∂x using vjp): ", norm(∂x_vjp .- ∂x_jvp, Inf))
    +println("∞-norm(∂ps using vjp): ",
    +    norm(ComponentArray(∂ps_vjp) .- ComponentArray(∂ps_jvp), Inf))
    +println("∞-norm(∂x using full jacobian): ", norm(∂x_full_jacobian .- ∂x_vjp, Inf))
    +println("∞-norm(∂ps using full jacobian): ",
    +    norm(ComponentArray(∂ps_full_jacobian) .- ComponentArray(∂ps_vjp), Inf))
    ∞-norm(∂x using vjp): 0.0
    +∞-norm(∂ps using vjp): 0.0
    +∞-norm(∂x using full jacobian): 9.536743e-7
    +∞-norm(∂ps using full jacobian): 1.4305115e-6
    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/nn_inside_gpu_kernels.html b/previews/PR1023/manual/nn_inside_gpu_kernels.html new file mode 100644 index 0000000000..b72546d101 --- /dev/null +++ b/previews/PR1023/manual/nn_inside_gpu_kernels.html @@ -0,0 +1,136 @@ + + + + + + Neural Networks Inside GPU Kernels | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Neural Networks Inside GPU Kernels

    In this page, we will describe how to embed neural networks inside GPU kernels. We will use KernelAbstractions.jl to do this, making it compatible with multiple GPU backends.

    Experimental Feature

    This is a relatively new and experimental feature. Expect edge cases and open issues on GitHub if you find any.

    Inference Only

    Currently this works only for inference. We will eventually test automatic differentiation using Enzyme.jl

    Batching

    In most usecases, this form of batching via embedding the neural network inside a GPU kernel is not recommended and will lead to suboptimal performance. Instead, batch the input data and let Lux handle the batching internally.

    julia
    using Lux, LuxCUDA, Random
    +using KernelAbstractions, StaticArrays

    First thing to remember is that we can't use regular high-level operations inside the kernels, instead we will use Static Arrays. Leveraging Julia's multiple dispatch Lux will use specialized operations that are compatible with GPU kernels.

    julia
    @kernel function nn_eval_single_batch!(output, model, input, ps, st)
    +    i = @index(Global, Linear)
    +    y, st_ = Lux.apply(model, input[i], ps, st)
    +    output[i] = y
    +end
    nn_eval_single_batch! (generic function with 4 methods)

    We define and initialize the neural network as usual, but we need to additionally convert the Arrays into SArrays.

    julia
    nn = Chain(Dense(4, 4, relu), Dense(4, 4))
    +ps, st = Lux.setup(Xoshiro(123), nn)
    +
    +to_sarray(x) = SArray{Tuple{size(x)...}}(x)
    +ps_static = Lux.recursive_map(to_sarray, ps)
    +st_static = Lux.recursive_map(to_sarray, st)
    (layer_1 = NamedTuple(), layer_2 = NamedTuple())

    First we will run it on CPU.

    Warning

    Currently due to a minor bug, we cannot call the Lux models with vector input. As a workaround we make them into Matrix with batch size 1.

    julia
    input = [@SArray(rand(Float64, 4, 1)) for i in 1:1024]
    +output = [@SArray(zeros(Float64, 4, 1)) for i in 1:1024] # Allocate the output
    1024-element Vector{StaticArraysCore.SMatrix{4, 1, Float64, 4}}:
    + [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.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; 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.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; 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.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; 0.0;;]

    Now run the model using KernelAbstractions.jl

    julia
    backend = KernelAbstractions.get_backend(output)
    +cpu_kernel! = nn_eval_single_batch!(backend)
    +cpu_kernel!(output, nn, input, ps_static, st_static; ndrange=length(output))
    +KernelAbstractions.synchronize(backend)
    +output
    1024-element Vector{StaticArraysCore.SMatrix{4, 1, Float64, 4}}:
    + [2.0564903986057956; 1.1188200246206075; -1.2227837233928576; -0.8173783982243132;;]
    + [1.9721554734769875; 1.3940224213371761; -1.297959481822617; -0.7195462169922175;;]
    + [2.5680085614623662; 1.713567516238075; -1.7165512278088038; -1.009963844931984;;]
    + [1.800792614736468; 0.36222499022985155; -1.1204217935313214; -1.1836515766351254;;]
    + [1.486550215883336; 0.32839986131789933; -0.9019142280758281; -0.9452923791531558;;]
    + [2.716134755899883; 1.1617228180412864; -1.902982902377702; -1.5865265807660498;;]
    + [1.0228109822209213; 0.2525357728685884; -0.4376572711003852; -0.4500963619011972;;]
    + [2.2771862617010155; 0.5381101016248151; -1.4730743722547668; -1.488028235902512;;]
    + [3.2791573282471997; 1.3436353225087703; -2.4619778701480337; -2.1239749674027375;;]
    + [1.2290224145974982; 0.4158693023143286; -0.6370531107315014; -0.5779067839062536;;]
    +
    + [1.8674763752817416; 1.6423511984038721; -1.1477053709248992; -0.3834447782571344;;]
    + [2.091359335844565; 1.0621559246995447; -1.4763277207638008; -1.142470881033475;;]
    + [2.712979078066394; 0.42005835019799886; -1.717863343114228; -1.8601870861800127;;]
    + [0.7701346738750905; 0.2869913410456831; -0.1586047939092094; -0.10140238162746013;;]
    + [1.611584190904272; 1.2797048270773437; -0.923950547913545; -0.3558193508137715;;]
    + [2.0884834705765853; 0.862480861009647; -1.3942307655311696; -1.179584495291061;;]
    + [2.390200114697191; 0.5267549745189349; -1.657670184695808; -1.7089496198123055;;]
    + [2.1846486482317626; -0.031414255389526885; -1.3279041356366077; -1.6909446526419574;;]
    + [1.3650193059617517; 0.5210742834996898; -0.7689272356710357; -0.6642563709240284;;]

    Now we will run the same model on GPU.

    julia
    gdev = gpu_device()
    +
    +input_gpu = input |> gdev
    +output_gpu = [@SArray(zeros(Float64, 4, 1)) for i in 1:1024] |> gdev
    1024-element CuArray{StaticArraysCore.SMatrix{4, 1, Float64, 4}, 1, CUDA.DeviceMemory}:
    + [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.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; 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.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; 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.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; 0.0;;]
    julia
    backend = KernelAbstractions.get_backend(output_gpu)
    +gpu_kernel! = nn_eval_single_batch!(backend)
    +gpu_kernel!(output_gpu, nn, input_gpu, ps_static, st_static; ndrange=length(output_gpu))
    +KernelAbstractions.synchronize(backend)
    +output_gpu
    1024-element CuArray{StaticArraysCore.SMatrix{4, 1, Float64, 4}, 1, CUDA.DeviceMemory}:
    + [2.0564903986057956; 1.1188200246206075; -1.2227837233928576; -0.8173783982243132;;]
    + [1.9721554734769875; 1.3940224213371761; -1.297959481822617; -0.7195462169922173;;]
    + [2.5680085614623662; 1.713567516238075; -1.7165512278088038; -1.009963844931984;;]
    + [1.800792614736468; 0.36222499022985155; -1.1204217935313214; -1.1836515766351254;;]
    + [1.486550215883336; 0.32839986131789933; -0.9019142280758281; -0.9452923791531558;;]
    + [2.716134755899883; 1.1617228180412864; -1.902982902377702; -1.5865265807660498;;]
    + [1.0228109822209213; 0.2525357728685884; -0.4376572711003852; -0.4500963619011972;;]
    + [2.2771862617010155; 0.5381101016248151; -1.4730743722547668; -1.488028235902512;;]
    + [3.2791573282471997; 1.3436353225087703; -2.4619778701480337; -2.1239749674027375;;]
    + [1.2290224145974982; 0.4158693023143286; -0.6370531107315014; -0.5779067839062536;;]
    +
    + [1.8674763752817414; 1.6423511984038721; -1.147705370924899; -0.3834447782571341;;]
    + [2.0913593358445652; 1.062155924699545; -1.4763277207638013; -1.142470881033475;;]
    + [2.712979078066394; 0.420058350197999; -1.717863343114228; -1.8601870861800127;;]
    + [0.7701346738750905; 0.2869913410456831; -0.1586047939092094; -0.10140238162746013;;]
    + [1.611584190904272; 1.2797048270773437; -0.923950547913545; -0.3558193508137715;;]
    + [2.0884834705765853; 0.862480861009647; -1.3942307655311696; -1.179584495291061;;]
    + [2.390200114697191; 0.5267549745189349; -1.657670184695808; -1.7089496198123055;;]
    + [2.1846486482317626; -0.031414255389526885; -1.3279041356366077; -1.6909446526419574;;]
    + [1.3650193059617517; 0.5210742834996898; -0.7689272356710357; -0.6642563709240284;;]
    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/performance_pitfalls.html b/previews/PR1023/manual/performance_pitfalls.html new file mode 100644 index 0000000000..18a0982ea3 --- /dev/null +++ b/previews/PR1023/manual/performance_pitfalls.html @@ -0,0 +1,61 @@ + + + + + + Performance Pitfalls & How to Catch Them | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Performance Pitfalls & How to Catch Them

    Go through the following documentations for general performance tips:

    1. Official Julia Performance Tips.

    2. Recommendations for selecting AD packages.

    Spurious Type-Promotion

    Lux by-default uses Julia semantics for type-promotions, while this means that we do the "correct" numerical thing, this can often come as a surprise to users coming from a more deep learning background. For example, consider the following code:

    julia
    using Lux, Random
    +
    +rng = Xoshiro(0)
    +
    +model = Dense(2 => 2, gelu)
    +ps, st = Lux.setup(rng, model)
    +Lux.recursive_eltype((ps, st))
    Float32

    As we can see that ps and st are structures with the highest precision being Float32. Now let's run the model using some random data:

    julia
    x = rand(rng, 2, 4)
    +
    +eltype(first(model(x, ps, st)))
    Float64

    Oops our output became Float64. This will be bad on CPUs but an absolute performance disaster on GPUs. The reason this happened is that our input x was Float64. Instead, we should have used Float32 input:

    julia
    x = rand(rng, Float32, 2, 4)
    +
    +eltype(first(model(x, ps, st)))
    Float32

    This was easy to fix for a small model. But certain layers might incorrectly promote objects to a higher precision. This will cause a regression in performance. There are 2 recommendations to fix this or track them down:

    1. Use Lux.Experimental.@debug_mode to see which layer is causing the type-promotion.

    2. Alternatively to control the global behavior of eltypes in Lux and allow it to auto-correct the precision use match_eltype and the eltype_mismatch_handling preference.

    Scalar Indexing on GPU Arrays

    When running code on GPUs, it is recommended to disallow scalar indexing. Note that this is disabled by default except in REPL. You can disable it even in REPL mode using:

    julia
    using GPUArraysCore
    +GPUArraysCore.allowscalar(false)

    Type Instabilities

    Lux.jl is integrated with DispatchDoctor.jl to catch type instabilities. You can easily enable it by setting the instability_check preference. This will help you catch type instabilities in your code. For more information on how to set preferences, check out Lux.set_dispatch_doctor_preferences!.

    Faster Primitives

    Prefer to use deep learning primitives and their fused variants from LuxLib.jl instead of NNlib.jl. Some of the alternatives are:

    1. Replace NNlib.batched_mul with LuxLib.batched_matmul.

    2. Replace NNlib.conv with bias and activation with LuxLib.fused_conv_bias_activation.

    3. Replace σ.(w * x .+ b) with LuxLib.fused_dense_bias_activation.

    4. Replace uses of σ.(x) with LuxLib.fast_activation or LuxLib.fast_activation!! (the latter one is often faster).

    5. Replace uses of σ.(x .+ b) with LuxLib.bias_activation or LuxLib.bias_activation!! (the latter one is often faster).

    Optional Dependencies for Performance

    For faster performance on CPUs load the following packages:

    1. LoopVectorization.jl

    2. Octavian.jl

    If these are available, we automatically use optimized versions of the layers. Though there are cases where this might be an issue (see #980 and disabling loop vectorization).

    Data Loading and Device Transfer

    A common pattern for loading data and transferring data to GPUs looks like this:

    julia
    dataloader = DataLoader(dataset; parallel=true, batchsize=12)  # from MLUtils.jl
    +gdev = gpu_device()
    +
    +for (X, y) in dataloader
    +    X = X |> gdev
    +    y = y |> gdev
    +    # ...
    +    # do some computation
    +    # ...
    +end

    This is typically fast enough, but the data transfer to the device is happening in main process, not exploiting the parallelism in the dataloader. Instead, we can do this:

    julia
    dataloader = DataLoader(dataset; parallel=true, batchsize=12)  # from MLUtils.jl
    +gdev = gpu_device()
    +
    +for (X, y) in gdev(dataloader)
    +    # ...
    +    # do some computation
    +    # ...
    +end

    Here, X and y are on the gpu device gdev and the data transfer happens in the worker processes. Additionally, it behaves similar to CuIterator from CUDA.jl and eagerly frees the data after every iteration (this is device agnostic and works on all supported GPU backends).

    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/preferences.html b/previews/PR1023/manual/preferences.html new file mode 100644 index 0000000000..92dbf8a0ca --- /dev/null +++ b/previews/PR1023/manual/preferences.html @@ -0,0 +1,36 @@ + + + + + + Preferences for Lux.jl | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Preferences for Lux.jl

    How to set Preferences

    PreferenceTools.jl provides an interactive way to set preferences. First run the following command:

    julia
    using PreferenceTools

    Then in the pkg mode (press ] in the REPL), run the following command:

    julia
    pkg> preference add Lux <preference-name>=<value>
    +pkg> preference add LuxLib <preference-name>=<value>
    +pkg> preference add LuxCore <preference-name>=<value>

    Lux.jl relies on several preferences to make decision on how to run your code. Here is an exhaustive list of preferences that Lux.jl uses.

    Nested Automatic Differentiation

    1. automatic_nested_ad_switching - Set this to false to disable automatic switching of backends for nested automatic differentiation. See the manual section on nested automatic differentiation for more details.

    GPU-Aware MPI Support

    If you are using a custom MPI build that supports CUDA or ROCM, you can use the following preferences with Preferences.jl:

    1. cuda_aware_mpi - Set this to true if your MPI build is CUDA aware.

    2. rocm_aware_mpi - Set this to true if your MPI build is ROCM aware.

    By default, both of these preferences are set to false.

    GPU Backend Selection

    1. gpu_backend - Set this to bypass the automatic backend selection and use a specific gpu backend. Valid options are "cuda", "rocm", "metal", and "oneapi". This preference needs to be set for MLDataDevices package. It is recommended to use MLDataDevices.gpu_backend! to set this preference.

    Automatic Eltype Conversion

    1. eltype_mismatch_handling - Preference controlling what happens when layers get different eltypes as input. See the documentation on match_eltype for more details.

    Dispatch Doctor

    1. instability_check - Preference controlling the dispatch doctor. See the documentation on Lux.set_dispatch_doctor_preferences! for more details. The preferences need to be set for LuxCore and LuxLib packages. Both of them default to disable.
    • Setting the LuxCore preference sets the check at the level of LuxCore.apply. This essentially activates the dispatch doctor for all Lux layers.

    • Setting the LuxLib preference sets the check at the level of functional layer of Lux, for example, fused_dense_bias_activation. These functions are supposed to be type stable for common input types and can be used to guarantee type stability.

    Disabling Loop Vectorization / Octavian

    LoopVectorization.jl and Octavian.jl are optional dependencies that are used to accelerate certain CPU operations. However, these packages are tightly coupled with julia and might not work with all julia versions and systems. If these packages are loaded in any form LuxLib will use the optimized versions of the functions. But it might be desirable to disable these packages and use the default implementations instead. This can be done by setting the disable_loop_vectorization preference to true for LuxLib.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/manual/weight_initializers.html b/previews/PR1023/manual/weight_initializers.html new file mode 100644 index 0000000000..d9216958c8 --- /dev/null +++ b/previews/PR1023/manual/weight_initializers.html @@ -0,0 +1,63 @@ + + + + + + Initializing Weights | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Initializing Weights

    WeightInitializers.jl provides common weight initialization schemes for deep learning models.

    julia
    using WeightInitializers, Random
    +
    +# Fixing rng
    +rng = Random.MersenneTwister(42)
    Random.MersenneTwister(42)
    julia
    # Explicit rng call
    +weights = kaiming_normal(rng, 2, 5)
    2×5 Matrix{Float32}:
    + -0.351662   0.0171745   1.12442   -0.296372   -1.67094
    + -0.281053  -0.18941    -0.724099   0.0987538   0.634549
    julia
    # Default rng call
    +weights = kaiming_normal(2, 5)
    2×5 Matrix{Float32}:
    + -0.227513  -0.265372   0.265788  1.29955  -0.192836
    +  0.687611   0.454679  -0.433656  0.20548   0.292002
    julia
    # Passing kwargs (if needed) with explicit rng call
    +weights_cl = kaiming_normal(rng; gain=1.0)
    +weights = weights_cl(2, 5)
    2×5 Matrix{Float32}:
    + 0.484056   0.231723   0.164379   0.306147   0.18365
    + 0.0836414  0.666965  -0.396323  -0.711329  -0.382971
    julia
    # Passing kwargs (if needed) with default rng call
    +weights_cl = kaiming_normal(; gain=1.0)
    +weights = weights_cl(2, 5)
    2×5 Matrix{Float32}:
    + -0.160876  -0.187646   0.18794   0.918918  -0.136356
    +  0.486214   0.321506  -0.306641  0.145296   0.206476

    To generate weights directly on GPU, pass in a CUDA.RNG. For a complete list of supported RNG types, see Supported RNG Types.

    julia
    using LuxCUDA
    +
    +weights = kaiming_normal(CUDA.default_rng(), 2, 5)
    2×5 CuArray{Float32, 2, CUDA.DeviceMemory}:
    + -0.0722369  -0.00913097  -0.200837  -0.200958  -0.39841
    +  0.131664   -0.634591     0.577344  -0.738118   0.502413

    You can also generate Complex Numbers:

    julia
    weights = kaiming_normal(CUDA.default_rng(), ComplexF32, 2, 5)
    2×5 CuArray{ComplexF32, 2, CUDA.DeviceMemory}:
    +   1.38353+0.0474757im   0.303938-0.0469896im  …   -1.46088-0.283445im
    + 0.0479814-0.435768im   -0.427741-0.0129954im     -0.910244+0.175707im

    Quick examples

    The package is meant to be working with deep learning libraries such as (F)Lux. All the methods take as input the chosen rng type and the dimension for the array.

    julia
    weights = init(rng, dims...)

    The rng is optional, if not specified a default one will be used.

    julia
    weights = init(dims...)

    If there is the need to use keyword arguments the methods can be called with just the rng (optionally) and the keywords to get in return a function behaving like the two examples above.

    julia
    weights_init = init(rng; kwargs...)
    +weights = weights_init(rng, dims...)
    +
    +# Or
    +
    +weights_init = init(; kwargs...)
    +weights = weights_init(dims...)
    + + + + \ No newline at end of file diff --git a/previews/PR1023/mlp.webp b/previews/PR1023/mlp.webp new file mode 100644 index 0000000000..62446654d6 Binary files /dev/null and b/previews/PR1023/mlp.webp differ diff --git a/previews/PR1023/mnist.jpg b/previews/PR1023/mnist.jpg new file mode 100644 index 0000000000..07ff1edd03 Binary files /dev/null and b/previews/PR1023/mnist.jpg differ diff --git a/previews/PR1023/neural-sde.png b/previews/PR1023/neural-sde.png new file mode 100644 index 0000000000..90cc19d23d Binary files /dev/null and b/previews/PR1023/neural-sde.png differ diff --git a/previews/PR1023/optimization_integration.png b/previews/PR1023/optimization_integration.png new file mode 100644 index 0000000000..ce16c6f288 Binary files /dev/null and b/previews/PR1023/optimization_integration.png differ diff --git a/previews/PR1023/pinn.gif b/previews/PR1023/pinn.gif new file mode 100644 index 0000000000..0f790ecb89 Binary files /dev/null and b/previews/PR1023/pinn.gif differ diff --git a/previews/PR1023/pinn_nested_ad.gif b/previews/PR1023/pinn_nested_ad.gif new file mode 100644 index 0000000000..dfebb45b6e Binary files /dev/null and b/previews/PR1023/pinn_nested_ad.gif differ diff --git a/previews/PR1023/siteinfo.js b/previews/PR1023/siteinfo.js new file mode 100644 index 0000000000..aba03dfaf9 --- /dev/null +++ b/previews/PR1023/siteinfo.js @@ -0,0 +1 @@ +var DOCUMENTER_CURRENT_VERSION = "previews/PR1023"; diff --git a/previews/PR1023/symbolic_optimal_control.png b/previews/PR1023/symbolic_optimal_control.png new file mode 100644 index 0000000000..82fd14ffe9 Binary files /dev/null and b/previews/PR1023/symbolic_optimal_control.png differ diff --git a/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm.html b/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm.html new file mode 100644 index 0000000000..1bbb68abde --- /dev/null +++ b/previews/PR1023/tutorials/advanced/1_GravitationalWaveForm.html @@ -0,0 +1,319 @@ + + + + + + Training a Neural ODE to Model Gravitational Waveforms | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Training a Neural ODE to Model Gravitational Waveforms

    This code is adapted from Astroinformatics/ScientificMachineLearning

    The code has been minimally adapted from Keith et. al. 2021 which originally used Flux.jl

    Package Imports

    julia
    using Lux, ComponentArrays, LineSearches, OrdinaryDiffEqLowOrderRK, Optimization,
    +      OptimizationOptimJL, Printf, Random, SciMLSensitivity
    +using CairoMakie

    Define some Utility Functions

    Tip

    This section can be skipped. It defines functions to simulate the model, however, from a scientific machine learning perspective, isn't super relevant.

    We need a very crude 2-body path. Assume the 1-body motion is a newtonian 2-body position vector r=r1r2 and use Newtonian formulas to get r1, r2 (e.g. Theoretical Mechanics of Particles and Continua 4.3)

    julia
    function one2two(path, m₁, m₂)
    +    M = m₁ + m₂
    +    r₁ = m₂ / M .* path
    +    r₂ = -m₁ / M .* path
    +    return r₁, r₂
    +end
    one2two (generic function with 1 method)

    Next we define a function to perform the change of variables: (χ(t),ϕ(t))(x(t),y(t))

    julia
    @views function soln2orbit(soln, model_params=nothing)
    +    @assert size(soln, 1)  [2, 4] "size(soln,1) must be either 2 or 4"
    +
    +    if size(soln, 1) == 2
    +        χ = soln[1, :]
    +        ϕ = soln[2, :]
    +
    +        @assert length(model_params)==3 "model_params must have length 3 when size(soln,2) = 2"
    +        p, M, e = model_params
    +    else
    +        χ = soln[1, :]
    +        ϕ = soln[2, :]
    +        p = soln[3, :]
    +        e = soln[4, :]
    +    end
    +
    +    r = p ./ (1 .+ e .* cos.(χ))
    +    x = r .* cos.(ϕ)
    +    y = r .* sin.(ϕ)
    +
    +    orbit = vcat(x', y')
    +    return orbit
    +end
    soln2orbit (generic function with 2 methods)

    This function uses second-order one-sided difference stencils at the endpoints; see https://doi.org/10.1090/S0025-5718-1988-0935077-0

    julia
    function d_dt(v::AbstractVector, dt)
    +    a = -3 / 2 * v[1] + 2 * v[2] - 1 / 2 * v[3]
    +    b = (v[3:end] .- v[1:(end - 2)]) / 2
    +    c = 3 / 2 * v[end] - 2 * v[end - 1] + 1 / 2 * v[end - 2]
    +    return [a; b; c] / dt
    +end
    d_dt (generic function with 1 method)

    This function uses second-order one-sided difference stencils at the endpoints; see https://doi.org/10.1090/S0025-5718-1988-0935077-0

    julia
    function d2_dt2(v::AbstractVector, dt)
    +    a = 2 * v[1] - 5 * v[2] + 4 * v[3] - v[4]
    +    b = v[1:(end - 2)] .- 2 * v[2:(end - 1)] .+ v[3:end]
    +    c = 2 * v[end] - 5 * v[end - 1] + 4 * v[end - 2] - v[end - 3]
    +    return [a; b; c] / (dt^2)
    +end
    d2_dt2 (generic function with 1 method)

    Now we define a function to compute the trace-free moment tensor from the orbit

    julia
    function orbit2tensor(orbit, component, mass=1)
    +    x = orbit[1, :]
    +    y = orbit[2, :]
    +
    +    Ixx = x .^ 2
    +    Iyy = y .^ 2
    +    Ixy = x .* y
    +    trace = Ixx .+ Iyy
    +
    +    if component[1] == 1 && component[2] == 1
    +        tmp = Ixx .- trace ./ 3
    +    elseif component[1] == 2 && component[2] == 2
    +        tmp = Iyy .- trace ./ 3
    +    else
    +        tmp = Ixy
    +    end
    +
    +    return mass .* tmp
    +end
    +
    +function h_22_quadrupole_components(dt, orbit, component, mass=1)
    +    mtensor = orbit2tensor(orbit, component, mass)
    +    mtensor_ddot = d2_dt2(mtensor, dt)
    +    return 2 * mtensor_ddot
    +end
    +
    +function h_22_quadrupole(dt, orbit, mass=1)
    +    h11 = h_22_quadrupole_components(dt, orbit, (1, 1), mass)
    +    h22 = h_22_quadrupole_components(dt, orbit, (2, 2), mass)
    +    h12 = h_22_quadrupole_components(dt, orbit, (1, 2), mass)
    +    return h11, h12, h22
    +end
    +
    +function h_22_strain_one_body(dt::T, orbit) where {T}
    +    h11, h12, h22 = h_22_quadrupole(dt, orbit)
    +
    +    h₊ = h11 - h22
    +    hₓ = T(2) * h12
    +
    +    scaling_const =(T(π) / 5)
    +    return scaling_const * h₊, -scaling_const * hₓ
    +end
    +
    +function h_22_quadrupole_two_body(dt, orbit1, mass1, orbit2, mass2)
    +    h11_1, h12_1, h22_1 = h_22_quadrupole(dt, orbit1, mass1)
    +    h11_2, h12_2, h22_2 = h_22_quadrupole(dt, orbit2, mass2)
    +    h11 = h11_1 + h11_2
    +    h12 = h12_1 + h12_2
    +    h22 = h22_1 + h22_2
    +    return h11, h12, h22
    +end
    +
    +function h_22_strain_two_body(dt::T, orbit1, mass1, orbit2, mass2) where {T}
    +    # compute (2,2) mode strain from orbits of BH 1 of mass1 and BH2 of mass 2
    +
    +    @assert abs(mass1 + mass2 - 1.0)<1e-12 "Masses do not sum to unity"
    +
    +    h11, h12, h22 = h_22_quadrupole_two_body(dt, orbit1, mass1, orbit2, mass2)
    +
    +    h₊ = h11 - h22
    +    hₓ = T(2) * h12
    +
    +    scaling_const =(T(π) / 5)
    +    return scaling_const * h₊, -scaling_const * hₓ
    +end
    +
    +function compute_waveform(dt::T, soln, mass_ratio, model_params=nothing) where {T}
    +    @assert mass_ratio1 "mass_ratio must be <= 1"
    +    @assert mass_ratio0 "mass_ratio must be non-negative"
    +
    +    orbit = soln2orbit(soln, model_params)
    +    if mass_ratio > 0
    +        m₂ = inv(T(1) + mass_ratio)
    +        m₁ = mass_ratio * m₂
    +
    +        orbit₁, orbit₂ = one2two(orbit, m₁, m₂)
    +        waveform = h_22_strain_two_body(dt, orbit₁, m₁, orbit₂, m₂)
    +    else
    +        waveform = h_22_strain_one_body(dt, orbit)
    +    end
    +    return waveform
    +end
    compute_waveform (generic function with 2 methods)

    Simulating the True Model

    RelativisticOrbitModel defines system of odes which describes motion of point like particle in schwarzschild background, uses

    u[1]=χu[2]=ϕ

    where, p, M, and e are constants

    julia
    function RelativisticOrbitModel(u, (p, M, e), t)
    +    χ, ϕ = u
    +
    +    numer = (p - 2 - 2 * e * cos(χ)) * (1 + e * cos(χ))^2
    +    denom = sqrt((p - 2)^2 - 4 * e^2)
    +
    +    χ̇ = numer * sqrt(p - 6 - 2 * e * cos(χ)) / (M * (p^2) * denom)
    +    ϕ̇ = numer / (M * (p^(3 / 2)) * denom)
    +
    +    return [χ̇, ϕ̇]
    +end
    +
    +mass_ratio = 0.0         # test particle
    +u0 = Float64[π, 0.0]     # initial conditions
    +datasize = 250
    +tspan = (0.0f0, 6.0f4)   # timespace for GW waveform
    +tsteps = range(tspan[1], tspan[2]; length=datasize)  # time at each timestep
    +dt_data = tsteps[2] - tsteps[1]
    +dt = 100.0
    +const ode_model_params = [100.0, 1.0, 0.5]; # p, M, e

    Let's simulate the true model and plot the results using OrdinaryDiffEq.jl

    julia
    prob = ODEProblem(RelativisticOrbitModel, u0, tspan, ode_model_params)
    +soln = Array(solve(prob, RK4(); saveat=tsteps, dt, adaptive=false))
    +waveform = first(compute_waveform(dt_data, soln, mass_ratio, ode_model_params))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Time", ylabel="Waveform")
    +
    +    l = lines!(ax, tsteps, waveform; linewidth=2, alpha=0.75)
    +    s = scatter!(ax, tsteps, waveform; marker=:circle, markersize=12, alpha=0.5)
    +
    +    axislegend(ax, [[l, s]], ["Waveform Data"])
    +
    +    fig
    +end

    Defiing a Neural Network Model

    Next, we define the neural network model that takes 1 input (time) and has two outputs. We'll make a function ODE_model that takes the initial conditions, neural network parameters and a time as inputs and returns the derivatives.

    It is typically never recommended to use globals but incase you do use them, make sure to mark them as const.

    We will deviate from the standard Neural Network initialization and use WeightInitializers.jl,

    julia
    const nn = Chain(Base.Fix1(fast_activation, cos),
    +    Dense(1 => 32, cos; init_weight=truncated_normal(; std=1e-4), init_bias=zeros32),
    +    Dense(32 => 32, cos; init_weight=truncated_normal(; std=1e-4), init_bias=zeros32),
    +    Dense(32 => 2; init_weight=truncated_normal(; std=1e-4), init_bias=zeros32))
    +ps, st = Lux.setup(Random.default_rng(), nn)
    ((layer_1 = NamedTuple(), layer_2 = (weight = Float32[0.00014798867; 0.0001283755; -0.0001917945; 3.3228196f-5; -2.6541045f-5; -7.975404f-5; -7.092557f-5; -9.0006855f-5; -0.00010432666; -0.0001582305; 0.00011267975; -3.444654f-5; -9.600945f-5; 2.8409087f-5; 5.7547153f-5; -4.970076f-5; 2.046465f-5; 8.749019f-6; 0.00013897507; -8.843735f-6; 5.8316316f-5; 1.33647545f-5; -2.3945151f-5; -0.00019256481; 2.0440255f-6; 7.665036f-5; 7.0418944f-5; -1.478229f-5; 9.342598f-5; -0.00015591538; -4.5475575f-5; -0.00012614082;;], bias = Float32[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.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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), layer_3 = (weight = Float32[6.289329f-5 -0.00012899227 -7.0849266f-5 3.424427f-5 -0.00014294294 9.092271f-5 1.9861705f-5 -0.00020486339 0.00014140282 -5.7926198f-5 0.00012580563 3.976018f-5 1.100778f-5 7.652588f-5 -0.00015733847 -1.979117f-5 -2.0289622f-6 -6.7930196f-6 -4.5295787f-5 2.2391352f-5 -3.927852f-5 0.00018191025 0.0001640962 0.00010366936 -4.4512766f-5 -7.5653224f-5 0.00010830701 8.7929953f-7 0.00012046669 2.4013454f-5 0.00014076312 -0.00013183871; -4.7972153f-5 0.00011150861 -3.7190406f-5 9.121937f-5 -0.00010013644 2.8713104f-5 4.641554f-5 -1.5365074f-5 -2.0453728f-5 -0.00013698272 -2.3076393f-5 -5.7660716f-5 3.585004f-6 8.321239f-5 -0.00013441942 2.9746785f-5 2.0607064f-5 8.571386f-5 9.492374f-5 3.4114895f-5 -5.762854f-5 -9.081341f-5 -6.314866f-5 7.2077423f-6 0.00023802661 5.7517093f-5 -4.9155748f-5 1.2719572f-5 7.161465f-5 -0.00016839153 -4.1478852f-5 -5.9046262f-5; -2.9938063f-5 5.5241326f-5 1.1746462f-5 -6.0956474f-5 -4.192573f-5 3.8743932f-5 -5.3232892f-5 7.759226f-5 2.684328f-5 0.00011954861 3.9134986f-5 0.00013964466 4.1704818f-5 0.000106225416 -4.9426613f-5 0.00010018988 -6.675354f-5 -0.00010403922 -0.00017239648 -0.00013530202 -2.4472069f-5 9.1792914f-5 0.00014092802 -0.00014417266 6.6564055f-5 2.9273719f-5 -7.643671f-6 -8.035956f-5 -1.8555611f-5 7.823969f-5 -0.00012648669 -5.176932f-5; -0.00018445784 -0.00016699555 -2.1285985f-5 9.4690876f-7 0.0001585242 -1.0795486f-5 -1.1848228f-5 4.74355f-5 8.790459f-6 -8.956207f-5 -0.00019490978 0.00021997328 -9.609839f-8 -0.00010916037 -3.892144f-5 6.3916494f-5 7.681881f-5 -0.00011807908 -0.00017212381 -0.00018349661 8.6814776f-5 6.0045826f-5 7.09515f-5 9.022243f-5 -7.049568f-5 -0.00013075661 -0.0001992019 3.3228356f-5 4.2630118f-6 -1.41205355f-5 -0.00018963483 0.00015777664; 0.00018126491 2.3202228f-5 -5.495445f-5 -4.946576f-7 -0.00020756968 0.00022925969 5.503714f-5 -6.6733686f-5 -3.9605053f-5 8.9995505f-5 0.00016215538 -0.00014901724 -0.000113528695 9.1734364f-5 0.00013460332 3.164675f-5 0.00011464552 1.3743814f-5 -9.705088f-6 -1.5063842f-5 -0.000105181956 -8.101596f-5 -1.4773998f-5 -4.7479796f-5 -7.020212f-5 -1.2936013f-5 -5.8906862f-5 -4.3236964f-6 -0.00013548507 0.000110176996 -5.2493553f-5 -8.339872f-6; 0.00014380175 -3.5924462f-5 -4.52999f-5 2.1514736f-5 -0.00020766298 -1.7351893f-5 7.9613244f-5 0.0001905701 3.0340694f-5 5.0138933f-5 -3.984415f-6 -0.00015125364 0.00015956702 -1.392205f-5 -3.635585f-5 0.00022001681 5.91466f-5 -0.00015853895 7.022997f-5 -1.8219034f-5 -3.6560552f-5 0.00013926311 -6.6375236f-5 6.2436798f-6 -3.8841477f-5 5.4191773f-5 -4.7340418f-5 8.6398664f-5 -6.0206105f-5 1.4901871f-5 -3.557371f-5 -3.2751283f-5; 0.00015866013 -0.00018365905 0.00019000433 3.928957f-5 0.000100898724 0.00019121302 0.00011651945 1.9493575f-5 0.00014185574 -6.381918f-5 9.468081f-5 -5.449231f-5 -3.1079664f-5 -7.316235f-5 -1.46296725f-5 -8.44827f-5 -2.324579f-5 9.611487f-5 -0.00018836417 -0.00014876756 4.4095086f-5 3.3882204f-6 -8.825502f-5 3.1465417f-5 0.00012619214 6.1826584f-5 0.00010061589 -9.284439f-5 6.107f-5 -0.00018807476 6.4877626f-5 -0.000121999954; -8.5641674f-5 -1.3133318f-5 3.1929572f-5 -5.934451f-5 7.0588656f-5 0.0002013159 -0.00016559058 -2.233838f-5 -1.4553927f-5 4.1629923f-5 0.00024530233 0.00012909896 0.00018083502 -0.000119821285 -0.0001745207 -0.00013740954 -5.5037024f-5 9.581295f-5 0.0001602952 0.00013878937 -8.0092905f-5 -0.00010669961 6.486757f-5 4.6803184f-6 -0.00010437932 5.5193468f-5 1.9592484f-5 3.52069f-5 -0.00012098054 2.8355807f-6 -4.223768f-5 5.9603328f-5; 6.647512f-5 -7.651593f-5 -7.045441f-5 -6.9189075f-5 2.1325188f-5 3.5744788f-6 -1.3802712f-5 2.5542184f-5 -2.9736013f-5 6.44827f-5 -0.00010273267 -9.560108f-5 -0.00014832508 6.260054f-5 -5.1025545f-5 -6.963479f-5 -4.299914f-5 -4.3417534f-5 0.0001540578 3.5573554f-5 3.2626234f-5 -9.97229f-5 -3.444653f-5 -5.6763725f-5 -7.5928234f-5 -3.071837f-5 -0.00021853072 2.5228403f-5 -3.6620877f-5 0.00012246045 -1.4872443f-5 1.841769f-5; -0.0001188636 -6.524213f-5 -2.2877752f-5 4.632825f-5 -1.1418591f-5 9.142981f-5 0.0001675149 -1.9919431f-5 -0.00011349276 -0.00013851613 -1.757684f-5 -0.00014613128 0.0001068853 7.522353f-5 -9.3130104f-5 6.484308f-5 -8.492532f-5 -4.397045f-5 -9.0616435f-5 5.6238932f-5 0.00011258058 6.7984714f-5 4.3041862f-5 5.8434587f-5 6.9005415f-5 0.00011230302 -4.809528f-5 1.3548491f-5 -4.926104f-5 -1.7329085f-5 -0.00028108715 -0.00012603487; -4.171165f-5 0.00010611511 3.4812806f-6 -0.00012482349 -5.3257183f-5 0.00016939598 2.9564746f-5 4.8874685f-6 -0.00011994621 -0.00026434002 3.6563153f-5 -0.000108040615 -7.026481f-5 2.7034612f-5 3.3245436f-5 5.518623f-5 0.00015428747 -2.83204f-5 5.0359064f-5 -0.00024188824 7.56617f-5 -7.7807505f-5 3.4013906f-6 8.007004f-6 3.9183702f-5 7.3195915f-5 3.231583f-5 7.934296f-6 0.00022212125 8.448415f-5 4.1704367f-5 -5.398324f-5; -8.224716f-5 5.6144036f-5 0.00010965635 3.7896003f-5 4.7579024f-6 3.596343f-5 0.0001756822 8.707022f-5 2.3367626f-5 8.813453f-6 0.00012343613 -3.068682f-6 -6.350598f-6 3.4608598f-5 4.112685f-5 -0.000109935296 3.6222606f-5 -2.7707993f-5 5.5938457f-5 -9.080702f-5 0.00010973305 -0.00040191333 -0.000121186655 -1.7417953f-5 -2.886204f-5 7.5300995f-5 6.176085f-5 5.0990384f-6 -2.4672994f-5 0.00010083148 -0.00017672713 -0.00010527357; -7.6542325f-5 -4.887439f-5 4.4795204f-5 -5.118064f-5 2.2101027f-5 -8.722431f-5 -1.5876874f-5 3.2201962f-5 7.430702f-5 9.7987635f-5 5.678952f-5 4.103541f-5 6.1897146f-5 5.9394017f-5 0.00017383661 -4.654219f-5 5.272721f-5 -0.00016875502 -1.3612849f-5 -3.7497615f-5 -4.8632966f-5 -9.375605f-5 3.0336598f-5 0.00016506345 6.448615f-5 -2.2019703f-5 -0.0001863126 -0.00012096228 -0.00014580866 -6.976547f-5 -0.00015476714 -7.5878204f-5; 5.084713f-5 -0.00021186467 2.1613598f-5 -4.6291356f-5 3.004238f-5 0.00016760328 -4.9907212f-5 9.497809f-5 -1.6691067f-5 -0.00013202691 0.00014834417 0.00012773061 3.0298817f-5 -1.1706837f-5 -1.42734325f-5 2.5085385f-5 8.448661f-5 6.0359416f-5 -2.4104298f-5 8.7597575f-5 0.000121300895 -8.5296175f-5 -1.31261595f-5 -0.0002458211 0.00011386037 8.230593f-5 9.957604f-5 -0.000109471024 -0.000101480946 0.00014499597 -9.220983f-6 2.2058508f-5; 4.8723276f-5 -1.6514532f-5 -0.0002468032 -4.9717022f-5 -7.79167f-5 -6.1969775f-5 0.0001073215 0.00018630148 -0.00021227564 1.0337452f-5 -0.000110470944 -5.334019f-5 0.000112096546 -0.00013046447 6.6720764f-5 -5.432939f-5 1.0038856f-5 -4.29304f-6 6.0018825f-5 -5.820133f-5 -2.3095005f-5 -5.657121f-5 -0.00012440086 -8.591388f-5 -0.00012554288 0.00010523489 -0.000111681264 0.00021312517 2.1284488f-7 0.00010232037 0.00013876813 0.0001451994; -7.494194f-5 -0.00019951252 0.00015804444 -7.931216f-5 3.0945268f-6 -0.00021899202 -0.00019707732 3.6243835f-6 -0.00015080615 -5.8808688f-5 8.493303f-6 0.00010061238 9.35891f-5 -8.0895166f-5 -7.4010213f-6 9.68475f-5 -6.619761f-5 0.00019664227 5.1728017f-5 -3.5319747f-5 -1.8978888f-5 4.020748f-5 -0.00015314738 -6.8800975f-5 -9.088428f-5 6.2876315f-6 -1.0762799f-5 0.0001739711 -0.00012083959 -7.6869735f-5 -1.8775695f-6 0.0002110241; 0.00020664533 -3.8356404f-5 -3.639981f-5 6.6069056f-6 0.0002150255 -1.105098f-5 9.458304f-5 3.5168116f-5 4.1931882f-5 -3.794645f-5 5.109525f-5 8.714127f-5 7.221925f-5 5.057045f-6 0.00011038904 -0.00018290084 2.3290859f-5 -3.6203204f-5 -3.981772f-5 -0.00013440159 8.675202f-5 -5.4943102f-6 7.266125f-5 -3.9068636f-5 -2.5095518f-5 4.3375676f-5 9.906182f-6 -8.512961f-6 -0.00012463176 -2.8709976f-5 -0.0001875602 -9.898851f-5; 0.0002062297 -1.7319557f-5 -0.00016271313 -1.2332152f-5 4.4490756f-5 -7.7858436f-5 -2.1417101f-5 8.3703315f-5 0.0001557044 -0.00011835118 5.8567413f-5 3.918367f-5 -2.3871171f-5 -9.139766f-5 0.00027838128 -0.0001281093 0.000112045745 6.355378f-5 0.00013682224 -6.740831f-5 8.912105f-5 4.103716f-5 4.492756f-5 -6.26335f-5 0.00025819617 6.9468864f-5 -3.5967318f-5 -3.032951f-5 8.049461f-5 -1.25148f-5 -2.2473672f-5 2.1698948f-5; -7.269528f-5 -0.00012516121 6.7834335f-5 3.5365916f-5 9.4599854f-5 5.065827f-5 -0.00011152873 0.0001427831 -0.00021785761 -4.7557187f-6 6.365417f-5 7.37164f-5 7.1094975f-5 -1.8372193f-5 0.00011231499 8.884766f-5 -3.1563144f-5 4.6293702f-5 -5.124871f-5 0.0002186435 3.342431f-5 3.2399035f-5 -8.354723f-5 3.765436f-5 -5.6786386f-5 3.4903765f-5 -0.00012040491 -0.00015075131 -1.5091981f-5 4.4941695f-5 6.308678f-5 4.3056505f-5; 3.351414f-5 -0.00014271175 0.00017131938 -0.00010088954 2.9894476f-5 -0.000113792055 2.7023705f-5 1.28059455f-5 -4.983779f-7 -0.000112544185 2.0941325f-6 -5.2774485f-5 -0.000106039486 -3.205883f-5 2.7262116f-5 -5.2474334f-5 -0.00012837445 1.6826858f-5 -7.145139f-5 0.00013343793 -9.974608f-5 0.00017567938 8.4046085f-5 -0.00014363631 0.00012854532 -0.00013070022 -3.172005f-5 1.76047f-5 -9.0335736f-5 -1.754041f-5 8.696777f-5 0.00012956029; -0.00018782426 0.00017699254 3.149139f-5 -4.99698f-5 7.8038574f-5 2.818771f-5 0.00022553114 9.590483f-6 7.341247f-5 -0.00014300141 0.0002734399 -0.00013367516 -1.2282188f-5 -3.070524f-5 -4.0326096f-5 7.698534f-5 -0.00012843356 -5.6019122f-5 1.1880202f-6 -6.780416f-5 -4.288794f-5 -5.121403f-5 -0.00019581003 -9.3209295f-5 6.6032386f-5 -8.8718843f-7 5.1536685f-5 -0.00014158712 7.121518f-5 -8.5905245f-5 0.00015030308 -5.6274668f-5; -5.91273f-5 2.667418f-5 0.00012173791 1.00059415f-5 -8.0069556f-5 -9.820306f-5 -0.00012170542 8.378669f-5 0.00016907272 7.989081f-5 -9.078782f-6 0.00026348335 9.293973f-5 4.040083f-5 -0.00018577027 -0.00019673149 -5.740228f-5 -7.330596f-5 0.00016787944 6.829441f-5 4.410893f-5 2.1007763f-5 -0.00015965947 4.5795405f-5 -0.00018885931 -0.00017394606 -0.00010925013 -5.149483f-5 -0.00020355567 -6.1030503f-5 -5.1728937f-5 2.9340394f-5; 0.00013693758 -0.00014005817 0.00010481041 -5.797798f-5 -4.048482f-5 -7.644748f-5 -3.0935473f-5 5.6017776f-5 -0.00014096715 6.812392f-5 -1.9517864f-5 1.2078835f-5 5.2177766f-5 4.231554f-5 0.000116617644 -0.00012488794 -4.1700772f-5 0.00011917023 -0.00015670038 -0.000103008395 5.9587246f-6 -8.658024f-5 4.2958178f-5 5.402395f-5 -0.00013350612 -0.00012053447 0.000101511156 8.700682f-5 -1.5777901f-5 -3.3261258f-5 -5.280248f-5 5.8354533f-5; -0.00020004802 4.2591022f-5 -3.7916545f-6 5.848705f-6 -3.4376142f-5 -2.5124384f-5 -1.1709151f-5 4.7170077f-5 -9.483936f-6 2.1743093f-5 -7.2951654f-5 1.35000455f-5 7.552683f-5 9.084621f-5 -8.024526f-6 -2.131134f-5 -7.918156f-5 -4.9303988f-5 0.00015841947 -7.639694f-5 -6.701421f-5 0.00020400074 8.10917f-6 -0.00013003442 -6.820468f-5 -1.9383338f-5 6.901344f-5 -0.00010831981 -2.5970878f-5 3.8305636f-5 6.564423f-5 3.1417763f-5; -0.00016382785 -8.254858f-5 0.00012010008 -0.00014978845 9.3223725f-6 -7.65836f-5 -0.0001389151 2.3776574f-6 0.00010048893 -1.0069865f-5 0.00011513229 7.9882484f-5 5.657715f-5 2.2221302f-5 3.65756f-5 -0.00020418508 0.00016715754 -0.0002513969 2.255126f-5 0.00014347043 -0.00012792795 -3.7204714f-5 -0.00012602791 0.0001213054 9.629434f-6 8.668678f-5 -7.264592f-5 0.0001709462 0.00014189305 -2.8030583f-5 9.5291936f-5 1.6033402f-5; 9.873253f-5 -0.00016460502 5.3794003f-5 3.08519f-5 -7.868859f-5 -1.7641012f-5 8.791397f-5 -0.000101237405 1.5865027f-5 0.00017055974 0.00033521306 -8.547244f-5 -4.3114323f-5 7.744298f-5 -8.7189655f-5 5.8678976f-5 0.00011043076 4.333132f-5 -0.00014446281 5.1741783f-5 -3.813609f-5 -6.0597315f-5 -9.771785f-5 0.00016370777 -8.8192515f-5 -0.00011716584 8.827072f-6 -4.4404693f-5 3.727705f-7 -2.924044f-5 0.00015301318 7.6967f-5; -2.7693168f-5 0.0001663314 0.00018915265 -6.367479f-5 0.00011415843 -9.113931f-5 -5.885339f-5 2.3013947f-5 -8.5922205f-5 -9.334885f-5 -3.864745f-5 -0.00012202202 -0.0001209435 -3.7900256f-5 -3.813278f-5 -0.00014817737 0.00013423587 4.8620004f-5 -0.00021318468 -0.00021753427 -4.258982f-5 -9.925543f-5 -1.3697903f-5 -8.00122f-5 2.6809148f-5 0.00015645399 0.00012051571 -1.0606383f-7 -1.7874921f-5 3.831381f-5 -1.197501f-5 5.2063097f-5; 2.8714978f-6 6.90757f-5 -0.00015171764 0.00020949625 4.6531713f-6 0.00015994276 -8.393382f-5 -9.581163f-6 -9.736687f-5 0.00017050117 -0.00015886013 -0.00027448655 6.217103f-5 0.00017041352 -1.0683171f-5 -0.00013700667 -1.4040064f-5 1.1740796f-6 -1.6264146f-5 -9.725939f-6 6.1090526f-5 -5.4130665f-5 9.185083f-5 -8.574102f-5 -8.912103f-5 3.5294725f-5 5.8031135f-5 2.407458f-6 0.00017823472 0.00012349125 9.97671f-5 9.889217f-5; 5.0403345f-5 6.829975f-5 -0.00011087512 -0.0002034794 -0.00016650361 9.249765f-5 3.2089847f-5 0.00015634432 6.094444f-5 4.1363404f-5 7.436349f-6 0.00013688966 -0.00013218693 7.99489f-5 -3.936639f-5 -2.6110276f-5 0.0003528559 7.467061f-5 5.594828f-5 -0.00019002314 -2.7961547f-5 -0.00028334607 -4.4637447f-5 5.3465246f-5 0.00014880052 -3.1073043f-5 -3.7360107f-5 5.2465195f-5 -2.292667f-6 3.222533f-5 -3.659026f-5 1.6538628f-5; -0.00013727378 -0.00022803275 8.518639f-5 0.0001404138 0.00016037932 -0.0001381259 3.6358913f-5 2.7000491f-5 0.00011553917 2.4459045f-5 1.7618628f-5 0.00017882141 0.0001968822 0.00013338713 2.3761932f-5 3.2353735f-5 0.00022275365 -1.5661397f-5 -0.00014963915 8.59156f-5 -3.295399f-5 -7.559035f-5 -6.74688f-5 1.868308f-5 -3.1442137f-6 -2.7208916f-5 -0.00014883529 0.00013670279 4.0551837f-5 -0.00018453944 -9.6279626f-5 1.5015081f-5; -0.00021324691 1.9568513f-5 2.8413555f-5 -6.08873f-5 6.632513f-5 -0.00014127647 3.4786794f-5 -7.8905505f-5 1.604637f-5 -6.833524f-5 8.2607505f-5 -0.00018783257 0.00013860513 8.130636f-5 -5.675258f-5 0.0002921465 -0.00011495117 0.00010721372 -0.00010607168 9.358432f-5 -3.543438f-5 -8.053401f-5 5.4574848f-5 -0.0001098857 -0.00013411244 -0.0001522711 0.00016539948 -5.7681238f-5 2.9871584f-5 -0.00014114701 6.3481284f-6 0.00013794337; 8.3092156f-5 2.7902099f-5 -9.75656f-5 -1.8865496f-5 7.323678f-5 0.000262229 -7.489286f-5 -1.1426142f-5 0.00022319547 -5.055722f-5 -9.105156f-6 3.4471059f-6 -0.00015784599 0.00014489138 -5.668865f-5 -0.00012680284 6.851014f-5 0.00023398332 3.717287f-6 5.8330512f-5 -0.000120279605 -2.2869315f-5 -0.0001467045 8.990784f-5 -6.7251385f-6 0.0001507413 7.4212396f-5 0.000113473805 -9.460157f-5 5.04164f-5 -9.531469f-5 8.755353f-5], bias = Float32[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.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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), layer_4 = (weight = Float32[-4.5658362f-5 -6.7949f-5 3.798372f-5 -8.829764f-5 -1.3014227f-5 1.2838754f-5 -1.4072927f-5 -4.885181f-5 3.5925146f-5 2.4817182f-5 7.282435f-5 7.9797835f-5 7.235881f-5 2.2705874f-5 -7.128685f-5 -7.052428f-5 6.427351f-5 8.168424f-5 -5.3329717f-5 6.197203f-5 -7.5120886f-5 9.8776116f-5 -2.0051406f-5 -7.375525f-5 0.000106042826 -8.089046f-5 -6.8328445f-5 -6.412571f-5 5.7237332f-5 1.3227511f-5 -0.00020962827 0.00015985763; -0.00011662117 1.582265f-5 6.975102f-5 5.797877f-5 -0.00010437497 -5.1038278f-5 -4.0289066f-5 -7.176196f-5 -5.352049f-5 2.6909376f-5 0.00011169085 0.00011102239 -0.000107661435 5.041146f-5 -6.310288f-5 3.518474f-5 1.0684749f-5 -0.00013644567 -6.9206294f-6 6.371999f-5 -2.6431774f-6 -0.0001470346 6.3890766f-5 9.16673f-6 3.4269528f-5 -5.0108138f-5 -3.493495f-6 -0.00015794244 3.472015f-5 -6.379643f-5 -4.7585076f-5 -0.000110352164], bias = Float32[0.0, 0.0])), (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple(), layer_4 = NamedTuple()))

    Similar to most DL frameworks, Lux defaults to using Float32, however, in this case we need Float64

    julia
    const params = ComponentArray(ps |> f64)
    +
    +const nn_model = StatefulLuxLayer{true}(nn, nothing, st)
    StatefulLuxLayer{true}(
    +    Chain(
    +        layer_1 = WrappedFunction(Base.Fix1{typeof(LuxLib.API.fast_activation), typeof(cos)}(LuxLib.API.fast_activation, cos)),
    +        layer_2 = Dense(1 => 32, cos),  # 64 parameters
    +        layer_3 = Dense(32 => 32, cos),  # 1_056 parameters
    +        layer_4 = Dense(32 => 2),       # 66 parameters
    +    ),
    +)         # Total: 1_186 parameters,
    +          #        plus 0 states.

    Now we define a system of odes which describes motion of point like particle with Newtonian physics, uses

    u[1]=χu[2]=ϕ

    where, p, M, and e are constants

    julia
    function ODE_model(u, nn_params, t)
    +    χ, ϕ = u
    +    p, M, e = ode_model_params
    +
    +    # In this example we know that `st` is am empty NamedTuple hence we can safely ignore
    +    # it, however, in general, we should use `st` to store the state of the neural network.
    +    y = 1 .+ nn_model([first(u)], nn_params)
    +
    +    numer = (1 + e * cos(χ))^2
    +    denom = M * (p^(3 / 2))
    +
    +    χ̇ = (numer / denom) * y[1]
    +    ϕ̇ = (numer / denom) * y[2]
    +
    +    return [χ̇, ϕ̇]
    +end
    ODE_model (generic function with 1 method)

    Let us now simulate the neural network model and plot the results. We'll use the untrained neural network parameters to simulate the model.

    julia
    prob_nn = ODEProblem(ODE_model, u0, tspan, params)
    +soln_nn = Array(solve(prob_nn, RK4(); u0, p=params, saveat=tsteps, dt, adaptive=false))
    +waveform_nn = first(compute_waveform(dt_data, soln_nn, mass_ratio, ode_model_params))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Time", ylabel="Waveform")
    +
    +    l1 = lines!(ax, tsteps, waveform; linewidth=2, alpha=0.75)
    +    s1 = scatter!(
    +        ax, tsteps, waveform; marker=:circle, markersize=12, alpha=0.5, strokewidth=2)
    +
    +    l2 = lines!(ax, tsteps, waveform_nn; linewidth=2, alpha=0.75)
    +    s2 = scatter!(
    +        ax, tsteps, waveform_nn; marker=:circle, markersize=12, alpha=0.5, strokewidth=2)
    +
    +    axislegend(ax, [[l1, s1], [l2, s2]],
    +        ["Waveform Data", "Waveform Neural Net (Untrained)"]; position=:lb)
    +
    +    fig
    +end

    Setting Up for Training the Neural Network

    Next, we define the objective (loss) function to be minimized when training the neural differential equations.

    julia
    const mseloss = MSELoss()
    +
    +function loss(θ)
    +    pred = Array(solve(prob_nn, RK4(); u0, p=θ, saveat=tsteps, dt, adaptive=false))
    +    pred_waveform = first(compute_waveform(dt_data, pred, mass_ratio, ode_model_params))
    +    return mseloss(pred_waveform, waveform)
    +end
    loss (generic function with 1 method)

    Warmup the loss function

    julia
    loss(params)
    0.0007031695500064645

    Now let us define a callback function to store the loss over time

    julia
    const losses = Float64[]
    +
    +function callback(θ, l)
    +    push!(losses, l)
    +    @printf "Training \t Iteration: %5d \t Loss: %.10f\n" θ.iter l
    +    return false
    +end
    callback (generic function with 1 method)

    Training the Neural Network

    Training uses the BFGS optimizers. This seems to give good results because the Newtonian model seems to give a very good initial guess

    julia
    adtype = Optimization.AutoZygote()
    +optf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)
    +optprob = Optimization.OptimizationProblem(optf, params)
    +res = Optimization.solve(
    +    optprob, BFGS(; initial_stepnorm=0.01, linesearch=LineSearches.BackTracking());
    +    callback, maxiters=1000)
    retcode: Success
    +u: ComponentVector{Float64}(layer_1 = Float64[], layer_2 = (weight = [0.0001479886705053106; 0.00012837549729740222; -0.00019179450464456877; 3.322819611637084e-5; -2.6541045372146618e-5; -7.975404150768842e-5; -7.092556916177105e-5; -9.000685531646908e-5; -0.00010432666022084597; -0.00015823049761818606; 0.0001126797506002084; -3.444654066698e-5; -9.600944758858865e-5; 2.8409087462921232e-5; 5.754715311919196e-5; -4.9700760428110564e-5; 2.0464649423930583e-5; 8.749018888913114e-6; 0.0001389750686939419; -8.843734576651803e-6; 5.831631642649848e-5; 1.3364754522626191e-5; -2.3945151042422434e-5; -0.00019256481027693886; 2.0440254502292897e-6; 7.66503580961444e-5; 7.041894423301891e-5; -1.4782290236328528e-5; 9.342598059437742e-5; -0.00015591537521681518; -4.547557546171363e-5; -0.00012614081788351716;;], bias = [3.1618821547760237e-16, -2.239715669473555e-17, 2.538697890277846e-16, 3.0756254592508004e-17, 5.928300473541879e-18, -1.755045016605607e-16, -1.9693294904156052e-18, 1.0816634619367045e-17, -1.5099870307573793e-16, -2.3770075837870637e-17, 1.7961534013830336e-16, 3.740195902526728e-18, 3.8268793412463466e-18, 1.3398236140253248e-17, 4.480848124758183e-17, 1.813701563686835e-17, 3.0287440289475135e-17, 8.56756171288473e-18, 4.4199278980586825e-17, -7.040194979405464e-18, 4.937424637028749e-19, 7.950769350341129e-19, -4.37353035495063e-18, -2.860529948821097e-17, 2.9720407135201326e-18, 9.958207788192736e-17, 9.01360056680392e-17, 2.970758097357983e-18, 1.1322895285109382e-16, -5.67468551327775e-17, -4.3152995329292506e-17, 1.0725677217871096e-16]), layer_3 = (weight = [6.289465276899174e-5 -0.00012899090320893898 -7.084790373079785e-5 3.424563150879349e-5 -0.00014294157695580832 9.092407166867638e-5 1.986306783187381e-5 -0.00020486202807255978 0.00014140418538267642 -5.792483530564015e-5 0.00012580699153153993 3.976154225206352e-5 1.1009142367080704e-5 7.65272434768583e-5 -0.00015733710275121706 -1.9789807952793187e-5 -2.0275997081162693e-6 -6.791657102029507e-6 -4.5294424085621645e-5 2.2392714567514397e-5 -3.9277156206981564e-5 0.00018191160965620935 0.00016409756248726888 0.00010367071994954402 -4.451140371706867e-5 -7.565186202150628e-5 0.00010830837167709316 8.806619980087237e-7 0.00012046805390532141 2.4014816558009666e-5 0.0001407644831892413 -0.00013183734513909863; -4.797249286049889e-5 0.00011150827257231838 -3.7190746037156566e-5 9.121903193452253e-5 -0.00010013678339739477 2.8712764366426587e-5 4.641519834556517e-5 -1.536541432280625e-5 -2.0454068102045332e-5 -0.00013698306221478497 -2.3076732498812634e-5 -5.7661056156141256e-5 3.584664033477361e-6 8.321205158288444e-5 -0.00013441975689922577 2.9746445112757968e-5 2.0606723670860167e-5 8.5713518534683e-5 9.492339657888808e-5 3.411455535249629e-5 -5.762887823359229e-5 -9.081374966037613e-5 -6.314900175632126e-5 7.207402437854578e-6 0.00023802626882250268 5.7516752609879734e-5 -4.9156087437515224e-5 1.2719231823646323e-5 7.16143133890716e-5 -0.00016839187238794638 -4.147919181698136e-5 -5.904660221269333e-5; -2.9938078753612105e-5 5.524130965307436e-5 1.1746446304759924e-5 -6.095649014502691e-5 -4.192574642990644e-5 3.874391613601782e-5 -5.323290834246129e-5 7.759224381255062e-5 2.6843263455821043e-5 0.00011954859500940973 3.9134969753949765e-5 0.00013964464442063195 4.170480160349125e-5 0.00010622539984718038 -4.9426629359795904e-5 0.00010018986203897818 -6.675355844242426e-5 -0.00010403923961609531 -0.0001723964976034678 -0.0001353020358718552 -2.447208471755424e-5 9.17928976351775e-5 0.00014092800692845208 -0.00014417267966825424 6.656403847694467e-5 2.927370250939e-5 -7.643686970250403e-6 -8.035957735307443e-5 -1.855562705065513e-5 7.823967307297597e-5 -0.00012648670390523896 -5.1769334916453e-5; -0.00018446107866088244 -0.0001669987949387632 -2.1289227206331026e-5 9.436665347784126e-7 0.00015852095670218798 -1.0798727871371625e-5 -1.1851469807664616e-5 4.743225794321932e-5 8.787216884450972e-6 -8.956531097259353e-5 -0.0001949130208774972 0.0002199700421808594 -9.934061075320488e-8 -0.00010916361212345545 -3.892468235768816e-5 6.391325145180741e-5 7.681556884584203e-5 -0.00011808232089585478 -0.00017212704993630417 -0.00018349985190049597 8.681153407472689e-5 6.0042583882232845e-5 7.094825845363752e-5 9.021918516761999e-5 -7.04989187031691e-5 -0.00013075985485535278 -0.00019920513737794275 3.322511396639211e-5 4.259769539422367e-6 -1.412377774589985e-5 -0.0001896380680225474 0.00015777339571309255; 0.00018126487184791354 2.320218691612119e-5 -5.495449085710086e-5 -4.946991870318129e-7 -0.00020756972453081547 0.00022925964940814742 5.503709899504179e-5 -6.673372781360077e-5 -3.9605094294431785e-5 8.999546326240993e-5 0.00016215534042576774 -0.00014901728508984237 -0.00011352873634304405 9.173432254475044e-5 0.0001346032825532413 3.164670697888798e-5 0.00011464547633668842 1.3743772164259254e-5 -9.705129465048722e-6 -1.50638831618315e-5 -0.00010518199787465417 -8.10160033287437e-5 -1.4774039933302285e-5 -4.74798377544105e-5 -7.020216225636689e-5 -1.2936054823415126e-5 -5.890690381046875e-5 -4.323737990391989e-6 -0.00013548510987301847 0.00011017695424389561 -5.2493594644959365e-5 -8.339913343563779e-6; 0.00014380303581491364 -3.59231762668163e-5 -4.52986150885597e-5 2.1516021650309755e-5 -0.00020766168928458141 -1.7350606878614316e-5 7.961453046663694e-5 0.00019057139251162198 3.0341980153017373e-5 5.014021916211703e-5 -3.9831288741057685e-6 -0.00015125235405503577 0.00015956830428694228 -1.39207641150316e-5 -3.63545641557769e-5 0.00022001809519496887 5.914788743029572e-5 -0.00015853766855071058 7.023125907652439e-5 -1.8217748231112443e-5 -3.655926594729437e-5 0.00013926439531860177 -6.6373950186975e-5 6.244965778004472e-6 -3.8840191347848076e-5 5.419305852046229e-5 -4.733913193559242e-5 8.639995029443175e-5 -6.02048185210222e-5 1.4903156614295779e-5 -3.557242417810331e-5 -3.2749996546054805e-5; 0.00015866126997585836 -0.0001836579110966653 0.00019000546964540016 3.9290712462545305e-5 0.00010089986537074956 0.00019121416627619492 0.0001165205896688079 1.9494716267371664e-5 0.00014185687834121196 -6.381803612733881e-5 9.468194840898577e-5 -5.449116796064852e-5 -3.107852242813476e-5 -7.316120971502455e-5 -1.4628530865437775e-5 -8.448155930075574e-5 -2.3244648022071265e-5 9.611601055091557e-5 -0.00018836302550319988 -0.00014876642015572325 4.4096227808196114e-5 3.389362033133095e-6 -8.825388138923504e-5 3.146655873584421e-5 0.0001261932841008933 6.182772560002377e-5 0.00010061703434636945 -9.284324986204202e-5 6.107114242346946e-5 -0.00018807361701314002 6.487876745829595e-5 -0.0001219988123774184; -8.564073420716439e-5 -1.3132378691852178e-5 3.1930511729973555e-5 -5.934357165828628e-5 7.058959538695134e-5 0.00020131683498034742 -0.0001655896404118224 -2.2337440052111937e-5 -1.455298758814693e-5 4.1630862076952195e-5 0.00024530327293901074 0.00012909989975738056 0.00018083596017091005 -0.0001198203454551221 -0.00017451975788575945 -0.0001374086051073796 -5.5036084697388845e-5 9.581389251976027e-5 0.00016029613555288032 0.00013879031114625496 -8.009196523930294e-5 -0.0001066986724909327 6.486850991491895e-5 4.6812578402239385e-6 -0.00010437838415968476 5.5194407585035466e-5 1.959342346522558e-5 3.520783950803548e-5 -0.00012097960195391954 2.836520186927469e-6 -4.2236740293487285e-5 5.960426726956115e-5; 6.647209725259526e-5 -7.651895079845446e-5 -7.045743054559194e-5 -6.9192097860775e-5 2.132216454980387e-5 3.571455501395316e-6 -1.3805734986938413e-5 2.553916042586079e-5 -2.97390362430873e-5 6.447967812336081e-5 -0.00010273569582579912 -9.560410048665009e-5 -0.00014832810497694322 6.259751885578468e-5 -5.1028568257729236e-5 -6.96378157482609e-5 -4.300216473724298e-5 -4.342055776591052e-5 0.00015405477083903202 3.557053046448518e-5 3.262321101998668e-5 -9.972592319912836e-5 -3.444955304815956e-5 -5.676674859214285e-5 -7.59312571500579e-5 -3.072139238441361e-5 -0.00021853374723662707 2.522537929677314e-5 -3.662390022157407e-5 0.00012245742605217693 -1.4875466284262025e-5 1.8414666421339533e-5; -0.00011886521815564398 -6.524374612150913e-5 -2.2879368316582974e-5 4.6326631945454614e-5 -1.1420208011508104e-5 9.142819044402994e-5 0.00016751327939321407 -1.9921047624183742e-5 -0.00011349437545529134 -0.00013851774701857685 -1.757845666385657e-5 -0.00014613289522483094 0.00010688368502063092 7.52219116290928e-5 -9.313172040517409e-5 6.484146297200571e-5 -8.492693586983839e-5 -4.397206566888977e-5 -9.061805167244798e-5 5.623731567513991e-5 0.00011257896267100275 6.798309777852946e-5 4.304024560017399e-5 5.843297049045521e-5 6.900379821647747e-5 0.0001123014067158958 -4.8096896989837945e-5 1.3546874015197246e-5 -4.926265819473804e-5 -1.7330701212140458e-5 -0.0002810887685884818 -0.0001260364820157201; -4.171135321317918e-5 0.00010611540904559503 3.4815772158581993e-6 -0.00012482319459028085 -5.325688641110906e-5 0.00016939627506129852 2.9565042615867675e-5 4.887765164166148e-6 -0.00011994591647468147 -0.0002643397254979961 3.6563449731910304e-5 -0.00010804031796229549 -7.026451373181859e-5 2.7034908391069555e-5 3.324573311314421e-5 5.5186525179887896e-5 0.00015428776362736243 -2.8320104200392956e-5 5.03593602223536e-5 -0.00024188793929002712 7.566199759079577e-5 -7.780720795213713e-5 3.4016872012579864e-6 8.00730061367726e-6 3.9183998644002725e-5 7.319621193513683e-5 3.2316127664525524e-5 7.934592878737014e-6 0.00022212154556822418 8.448444544395662e-5 4.17046632099662e-5 -5.398294330749349e-5; -8.224721432633562e-5 5.61439842349583e-5 0.00010965629871498955 3.789595166018335e-5 4.7578509984385065e-6 3.596337728232256e-5 0.00017568215070787923 8.707016922563427e-5 2.3367574154698542e-5 8.813401560482127e-6 0.0001234360747694236 -3.068733352839627e-6 -6.350649531660612e-6 3.4608546680837024e-5 4.112679698301585e-5 -0.00010993534715816276 3.622255416849729e-5 -2.7708043948215367e-5 5.59384056905484e-5 -9.0807072869203e-5 0.00010973300186015771 -0.0004019133853071172 -0.00012118670611379568 -1.7418004521451195e-5 -2.8862090861358614e-5 7.530094398681183e-5 6.176080159640047e-5 5.098986999663594e-6 -2.467304557648373e-5 0.00010083142796794092 -0.0001767271828648438 -0.00010527361928688237; -7.654431041909667e-5 -4.8876375645610345e-5 4.4793218561715685e-5 -5.118262501665159e-5 2.2099041101766958e-5 -8.722629658759928e-5 -1.5878860127399476e-5 3.219997657115324e-5 7.430503378973277e-5 9.798564920321022e-5 5.678753282527489e-5 4.10334256722243e-5 6.189516048298042e-5 5.939203097486151e-5 0.00017383462605184317 -4.6544176571757114e-5 5.2725223808094874e-5 -0.00016875701052950528 -1.3614834957383448e-5 -3.7499601008592375e-5 -4.863495209602258e-5 -9.375803287721997e-5 3.033461203275912e-5 0.0001650614655355806 6.448416448082938e-5 -2.202168920657988e-5 -0.00018631458019254248 -0.00012096426448434415 -0.0001458106483786667 -6.976745439341422e-5 -0.00015476912753538866 -7.588019011190834e-5; 5.084889967158913e-5 -0.0002118628977327435 2.1615366175426974e-5 -4.628958736380742e-5 3.0044148341895383e-5 0.000167605052819033 -4.9905443621775474e-5 9.497985633837404e-5 -1.6689298310180207e-5 -0.00013202513905659954 0.00014834594226025125 0.00012773238308776916 3.0300585830023534e-5 -1.170506816511903e-5 -1.427166403251309e-5 2.5087153015683612e-5 8.448837656809808e-5 6.036118470414422e-5 -2.4102529597685917e-5 8.759934321327946e-5 0.0001213026629998597 -8.529440633670552e-5 -1.3124391035907058e-5 -0.00024581934080877734 0.00011386213777636062 8.230769931154801e-5 9.95778104411677e-5 -0.00010946925572303252 -0.00010147917742093715 0.00014499773574109525 -9.219214508866447e-6 2.206027643163116e-5; 4.872209719202946e-5 -1.6515710383585896e-5 -0.00024680436727769566 -4.971820054173809e-5 -7.791788048756661e-5 -6.197095318178782e-5 0.00010732032423426213 0.00018630029843940332 -0.0002122768197366312 1.0336273946695764e-5 -0.00011047212284005137 -5.33413691371061e-5 0.00011209536786942717 -0.00013046564673253685 6.671958580433138e-5 -5.4330568316563104e-5 1.0037677741147184e-5 -4.294218440682454e-6 6.00176466762311e-5 -5.820250917871861e-5 -2.3096182856296826e-5 -5.657238908292169e-5 -0.00012440203827985923 -8.59150601242843e-5 -0.00012554405803506647 0.00010523371055775168 -0.0001116824420093857 0.00021312398929900116 2.1166653290328563e-7 0.00010231919476816056 0.00013876694755914318 0.0001451982247019862; -7.494417764139279e-5 -0.00019951475656018904 0.00015804220060926176 -7.931439427087599e-5 3.0922906254648934e-6 -0.00021899425587510813 -0.00019707955175439121 3.622147232060664e-6 -0.00015080839034529197 -5.881092397505103e-5 8.491066409234073e-6 0.0001006101422255249 9.358686406737273e-5 -8.089740254112125e-5 -7.4032575419883154e-6 9.684526344168517e-5 -6.619984446919158e-5 0.00019664003525500526 5.1725780621542454e-5 -3.5321982751010306e-5 -1.8981124186062922e-5 4.020524397597996e-5 -0.00015314961888256108 -6.880321120734988e-5 -9.088651381793096e-5 6.285395328782717e-6 -1.0765035541076204e-5 0.00017396886437305597 -0.00012084182776637331 -7.687197171509937e-5 -1.8798057233994109e-6 0.00021102186769819464; 0.00020664584287765776 -3.8355891705979897e-5 -3.6399299392038005e-5 6.607417686210196e-6 0.00021502601437128844 -1.1050467878194525e-5 9.458355186830901e-5 3.5168627687707705e-5 4.193239426564024e-5 -3.794593878814658e-5 5.109576075079418e-5 8.714178245605662e-5 7.221976109172776e-5 5.0575573146133675e-6 0.0001103895511510568 -0.00018290032760381962 2.3291370849220616e-5 -3.6202692103360195e-5 -3.9817209585128185e-5 -0.00013440107879836335 8.675253327561265e-5 -5.49379812986347e-6 7.266176096487563e-5 -3.906812428289934e-5 -2.509500602576635e-5 4.337618800087514e-5 9.90669384515076e-6 -8.512449243825297e-6 -0.00012463124305617427 -2.870946348088488e-5 -0.0001875596907888751 -9.898799628394211e-5; 0.00020623337629364102 -1.7315879385597635e-5 -0.00016270945045985903 -1.2328475104014735e-5 4.449443374177408e-5 -7.785475893762671e-5 -2.1413424046492117e-5 8.370699221848523e-5 0.000155708078882868 -0.0001183475003287118 5.857109069472575e-5 3.91873466200093e-5 -2.3867493591407574e-5 -9.139398455737204e-5 0.0002783849588653411 -0.00012810562177911647 0.00011204942281473427 6.355745724285063e-5 0.0001368259211361555 -6.740463571041781e-5 8.912472846567275e-5 4.104083861456283e-5 4.493123858118412e-5 -6.262982490594223e-5 0.0002581998517329251 6.94725415727431e-5 -3.596364033875597e-5 -3.0325831839591016e-5 8.049828763467198e-5 -1.251112255853661e-5 -2.246999495547461e-5 2.170262566357397e-5; -7.269410690885596e-5 -0.0001251600404585374 6.783550650917726e-5 3.5367087714739696e-5 9.460102608766662e-5 5.065944076971189e-5 -0.00011152755889004006 0.00014278427277797807 -0.00021785643895516307 -4.754547096199631e-6 6.365534516855869e-5 7.371757254343718e-5 7.109614687845041e-5 -1.8371021557932062e-5 0.00011231616388879872 8.884882862087531e-5 -3.156197255254455e-5 4.629487392133382e-5 -5.124753790103359e-5 0.0002186446728800824 3.3425480235499926e-5 3.2400206858192544e-5 -8.354605944720767e-5 3.7655532817475244e-5 -5.6785214671499055e-5 3.490493707697897e-5 -0.00012040373969018368 -0.00015075013636039298 -1.5090809772185105e-5 4.494286639139337e-5 6.308795144189355e-5 4.305767668749807e-5; 3.351272907782971e-5 -0.00014271316531487365 0.00017131796566862998 -0.00010089095367259683 2.9893063856043093e-5 -0.00011379346751748679 2.7022292942612736e-5 1.2804533343636294e-5 -4.997900877469654e-7 -0.00011254559713089998 2.0927202964011898e-6 -5.2775897257042654e-5 -0.00010604089829978496 -3.2060241847311866e-5 2.7260704245755892e-5 -5.247574581556296e-5 -0.00012837586173230223 1.6825445799958772e-5 -7.14528002394406e-5 0.00013343652180953494 -9.974749327778115e-5 0.00017567796685359055 8.404467307588655e-5 -0.00014363772124889842 0.00012854390597528387 -0.00013070163613558867 -3.1721462346857146e-5 1.7603287505671327e-5 -9.033714804938979e-5 -1.7541821489811035e-5 8.696635568373544e-5 0.00012955887295863943; -0.0001878250669456718 0.00017699173886778834 3.1490583665283875e-5 -4.9970604863645144e-5 7.803776944039973e-5 2.8186904187735986e-5 0.0002255303360520187 9.589678398173646e-6 7.341166465760129e-5 -0.0001430022140035097 0.00027343908268942475 -0.00013367596429323178 -1.2282993424901562e-5 -3.0706044612614154e-5 -4.0326901484674764e-5 7.69845381959591e-5 -0.00012843436442797423 -5.60199269735477e-5 1.1872151894090286e-6 -6.780496650624453e-5 -4.288874433275588e-5 -5.121483363343764e-5 -0.00019581083788087008 -9.321010028958637e-5 6.603158081399841e-5 -8.879934235450455e-7 5.153587963416006e-5 -0.00014158792791438645 7.121437638982065e-5 -8.590605020305797e-5 0.00015030227487425012 -5.627547315686887e-5; -5.912982921471255e-5 2.6671649930003353e-5 0.0001217353794618502 1.0003410561690304e-5 -8.007208704839708e-5 -9.820559241234105e-5 -0.00012170795414022059 8.378415916922863e-5 0.00016907019128666848 7.98882767685585e-5 -9.081312573465576e-6 0.00026348081994910527 9.293719743255049e-5 4.0398300579904996e-5 -0.0001857728045888528 -0.00019673402018270558 -5.740481244175033e-5 -7.330848781748973e-5 0.00016787690513411888 6.829187735092528e-5 4.4106397790526715e-5 2.10052323654917e-5 -0.0001596619975043766 4.579287381605193e-5 -0.00018886184149778757 -0.00017394858766238031 -0.00010925266430604168 -5.149736059138837e-5 -0.00020355819903670398 -6.10330341896618e-5 -5.1731468165602006e-5 2.933786275208068e-5; 0.00013693632350120444 -0.00014005942652650644 0.00010480915075684338 -5.797923954154539e-5 -4.048608029328477e-5 -7.644874135215723e-5 -3.093673153265391e-5 5.601651715047773e-5 -0.0001409684119112487 6.81226592446107e-5 -1.951912240250197e-5 1.2077576643115068e-5 5.2176506828313445e-5 4.231428097633459e-5 0.0001166163855982284 -0.00012488920042009213 -4.170203105380961e-5 0.00011916897342822298 -0.0001567016370659357 -0.00010300965372656689 5.957465832090611e-6 -8.658150186014573e-5 4.295691901867082e-5 5.402269012345384e-5 -0.00013350738303919544 -0.00012053572576909303 0.00010150989688050917 8.700555913897953e-5 -1.5779160135512695e-5 -3.326251684987132e-5 -5.28037381132333e-5 5.8353274611788524e-5; -0.00020004856283175256 4.259047550168292e-5 -3.792201099155815e-6 5.848158295162834e-6 -3.4376688703008655e-5 -2.5124930246777475e-5 -1.1709697858707859e-5 4.716953030457042e-5 -9.484482646614072e-6 2.1742546820506443e-5 -7.295220071081669e-5 1.3499498933566629e-5 7.55262799853952e-5 9.08456632229046e-5 -8.025072887351924e-6 -2.1311886442520993e-5 -7.918210845072637e-5 -4.9304534471406444e-5 0.000158418922225437 -7.639748305645662e-5 -6.701475736317054e-5 0.00020400019188546685 8.10862370290679e-6 -0.00013003496219733888 -6.820522772013102e-5 -1.938388500402002e-5 6.901289366088074e-5 -0.0001083203541869752 -2.5971424250558162e-5 3.8305089262040196e-5 6.564368145209885e-5 3.141721667508057e-5; -0.00016382765105970868 -8.254837966103736e-5 0.00012010027486086995 -0.00014978825428568356 9.322569629714677e-6 -7.658340408977685e-5 -0.00013891490315598058 2.3778545333899853e-6 0.00010048912436888892 -1.0069668216036951e-5 0.00011513248383255072 7.988268108294746e-5 5.657734864928179e-5 2.2221499155987366e-5 3.6575795737574026e-5 -0.0002041848850161636 0.00016715774173337443 -0.0002513967113294505 2.2551456557831785e-5 0.00014347062888975663 -0.00012792775604919142 -3.72045172219962e-5 -0.00012602771247782337 0.00012130559544732033 9.629631411937894e-6 8.668697474479114e-5 -7.264572131259922e-5 0.00017094639107074062 0.00014189324493474678 -2.8030385957553316e-5 9.529213339976429e-5 1.6033599157364382e-5; 9.873387646805597e-5 -0.00016460367875694885 5.379534671375904e-5 3.085324463612487e-5 -7.868724311989627e-5 -1.763966862924076e-5 8.791531329919498e-5 -0.0001012360614986088 1.586637084258842e-5 0.00017056108229737688 0.0003352144023956782 -8.547109861680222e-5 -4.3112979954427944e-5 7.744432262555797e-5 -8.718831192524184e-5 5.868031915455153e-5 0.00011043210291248863 4.3332665183731736e-5 -0.00014446147067062346 5.174312648890671e-5 -3.8134747926928233e-5 -6.059597105191893e-5 -9.77165061776422e-5 0.00016370910928528192 -8.81911717151185e-5 -0.00011716449332012918 8.828415258935756e-6 -4.4403349209426575e-5 3.741140353969072e-7 -2.9239096664218282e-5 0.00015301452843417457 7.696834403034666e-5; -2.7695354106393765e-5 0.00016632921699478355 0.00018915046177849762 -6.367697994880486e-5 0.00011415624260246616 -9.11414934993136e-5 -5.885557754969983e-5 2.30117603902139e-5 -8.592439178333956e-5 -9.335103447970256e-5 -3.864963571264616e-5 -0.00012202420828122748 -0.0001209456858081137 -3.790244215940256e-5 -3.813496721283482e-5 -0.0001481795515022614 0.00013423368739006882 4.861781792408604e-5 -0.00021318687129256048 -0.00021753645330624839 -4.259200784451272e-5 -9.925761321516884e-5 -1.3700089653294145e-5 -8.001438607183606e-5 2.6806961727405877e-5 0.00015645179894330214 0.00012051352325637061 -1.0825014163252523e-7 -1.7877107780226786e-5 3.8311624052447006e-5 -1.1977196550441838e-5 5.2060910206493225e-5; 2.8731227105327503e-6 6.907732547757515e-5 -0.00015171601755514588 0.00020949787956694324 4.6547962285971415e-6 0.0001599443881589351 -8.393219233924548e-5 -9.579538001829758e-6 -9.736524718549436e-5 0.0001705027921873409 -0.00015885850500284198 -0.00027448492384949514 6.217265270448975e-5 0.0001704151460019333 -1.0681546356619121e-5 -0.0001370050498933148 -1.4038439459663462e-5 1.175704440602927e-6 -1.626252144136782e-5 -9.724314096937818e-6 6.109215117091378e-5 -5.412904049237955e-5 9.185245524192443e-5 -8.573939469147337e-5 -8.911940442133451e-5 3.529634939538247e-5 5.8032760151279896e-5 2.4090828249161067e-6 0.00017823634932780417 0.00012349287369784785 9.976872622998566e-5 9.889379232687275e-5; 5.0404076179055e-5 6.830047991223153e-5 -0.00011087438556735437 -0.00020347867044057805 -0.00016650287957765261 9.249837953228266e-5 3.2090578175650714e-5 0.00015634505311589412 6.094517070430916e-5 4.136413540088819e-5 7.437079917672853e-6 0.00013689039392027894 -0.00013218620384015446 7.994963002255082e-5 -3.9365659316733255e-5 -2.610954484572779e-5 0.00035285661928918116 7.467133750304492e-5 5.594901071724866e-5 -0.0001900224125655004 -2.7960815854218598e-5 -0.0002833453437722856 -4.463671589639137e-5 5.346597740406128e-5 0.0001488012529500193 -3.1072311825316805e-5 -3.73593758502623e-5 5.246592613383105e-5 -2.291935883311706e-6 3.2226060144401e-5 -3.65895286029777e-5 1.6539359281687062e-5; -0.00013727221734980522 -0.00022803118840484076 8.518794570890029e-5 0.0001404153598317011 0.00016038087856332518 -0.00013812434840174004 3.6360471179527155e-5 2.700204900366091e-5 0.00011554073066990985 2.44606024837531e-5 1.7620185511350382e-5 0.00017882297184160633 0.00019688376128515473 0.00013338869107729496 2.376348934677044e-5 3.235529298154295e-5 0.00022275520391604623 -1.5659839070115587e-5 -0.00014963759089978677 8.591715673292766e-5 -3.2952432908764275e-5 -7.558879510424328e-5 -6.746724024805487e-5 1.868463810140957e-5 -3.1426558477441617e-6 -2.7207358604479152e-5 -0.0001488337285506493 0.00013670434496207865 4.055339454980837e-5 -0.00018453788574943842 -9.627806789166615e-5 1.501663869321251e-5; -0.00021324839605452688 1.9567026296011234e-5 2.8412067816565533e-5 -6.088878859968207e-5 6.632363959711673e-5 -0.00014127795572361934 3.4785306464488654e-5 -7.890699186331531e-5 1.6044882553123984e-5 -6.833672802398019e-5 8.260601765274357e-5 -0.00018783405818480347 0.0001386036428206891 8.130487270450853e-5 -5.675406561435374e-5 0.00029214500403527884 -0.0001149526606846353 0.00010721222946217883 -0.00010607316932376794 9.35828328997143e-5 -3.543586632671935e-5 -8.053549669652573e-5 5.457336095192161e-5 -0.0001098871899253261 -0.00013411393144137563 -0.000152272582514836 0.00016539799701918752 -5.768272518848395e-5 2.9870096962857977e-5 -0.00014114850188573898 6.3466413243580365e-6 0.0001379418799237672; 8.309488175216532e-5 2.7904824214768077e-5 -9.756287482090278e-5 -1.8862770325360788e-5 7.323950257632361e-5 0.000262231730353226 -7.489013233208069e-5 -1.1423416531041828e-5 0.00022319819681359897 -5.0554495196434365e-5 -9.102430617361763e-6 3.449831360919828e-6 -0.00015784326688372873 0.00014489410813912218 -5.668592285001469e-5 -0.00012680011723641984 6.851286588716759e-5 0.00023398604088942988 3.720012450849063e-6 5.8333237298210174e-5 -0.00012027687926529734 -2.2866589738261037e-5 -0.00014670176761210474 8.99105622876621e-5 -6.722413040553145e-6 0.00015074402171666687 7.421512118089048e-5 0.0001134765304370363 -9.459884613971525e-5 5.0419127269538136e-5 -9.531196274547547e-5 8.755625885458661e-5], bias = [1.362463491334985e-9, -3.398904685654539e-10, -1.610066669886397e-11, -3.242221072784985e-9, -4.156017242074563e-11, 1.2860145909590977e-9, 1.141612458391299e-9, 9.394425035937008e-10, -3.0232951195917684e-9, -1.616627081790752e-9, 2.966151805736721e-10, -5.1390080646152605e-11, -1.9857415354524423e-9, 1.7684656463219359e-9, -1.1783483755736966e-9, -2.236220861232494e-9, 5.121142395241432e-10, 3.6773329978313097e-9, 1.1715955501843653e-9, -1.4121728149894085e-9, -8.049888293545121e-10, -2.5309145760393373e-9, -1.2587820853669075e-9, -5.465639278681154e-10, 1.9709534420796504e-10, 1.3435347112437137e-9, -2.1863119136768887e-9, 1.6248834716321566e-9, 7.310938454045174e-10, 1.557831007680469e-9, -1.4870843604346265e-9, 2.725478406142474e-9]), layer_4 = (weight = [-0.0007374361934195449 -0.0007597268657267519 -0.0006537941531990138 -0.0007800752735170239 -0.0007047920986039328 -0.000678939082443919 -0.0007058507704826389 -0.0007406296612836417 -0.0006558525313057186 -0.0006669606334663165 -0.0006189535229626955 -0.0006119800360087953 -0.0006194189803236911 -0.0006690719304301911 -0.000763064690569369 -0.0007623020384361817 -0.0006275043556428826 -0.0006100933551841793 -0.0007451075583788393 -0.0006298057986045238 -0.0007668987434951661 -0.0005930016240738988 -0.0007118292427099427 -0.0007655331122073681 -0.000585735044956384 -0.0007726682904175011 -0.0007601062108833979 -0.0007559035208590189 -0.0006345405282430247 -0.0006785503088444641 -0.0009014060900150451 -0.000531920086844552; 0.00013594893440536723 0.00026839277162856644 0.0003223211408476348 0.000310548806501568 0.00014819514965658817 0.00020153183148601252 0.00021228104648558522 0.0001808081529319296 0.00019904956265658853 0.00027947947796219696 0.00036426097493794357 0.00036359251154835363 0.00014490865705834625 0.0003029815590890083 0.0001894672295971893 0.00028775482287253247 0.0002632548694413957 0.00011612435116104449 0.0002456494818520329 0.00031629009864845084 0.0002499269396489655 0.00010553547110531008 0.0003164608754771367 0.0002617368496312524 0.0002868396494856868 0.00020246197007451418 0.0002490765888576313 9.462765896848049e-5 0.00028729026752222437 0.000188773670293046 0.00020498502796661137 0.00014221790314839118], bias = [-0.0006917778715618791, 0.0002525701222495951]))

    Visualizing the Results

    Let us now plot the loss over time

    julia
    begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Iteration", ylabel="Loss")
    +
    +    lines!(ax, losses; linewidth=4, alpha=0.75)
    +    scatter!(ax, 1:length(losses), losses; marker=:circle, markersize=12, strokewidth=2)
    +
    +    fig
    +end

    Finally let us visualize the results

    julia
    prob_nn = ODEProblem(ODE_model, u0, tspan, res.u)
    +soln_nn = Array(solve(prob_nn, RK4(); u0, p=res.u, saveat=tsteps, dt, adaptive=false))
    +waveform_nn_trained = first(compute_waveform(
    +    dt_data, soln_nn, mass_ratio, ode_model_params))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="Time", ylabel="Waveform")
    +
    +    l1 = lines!(ax, tsteps, waveform; linewidth=2, alpha=0.75)
    +    s1 = scatter!(
    +        ax, tsteps, waveform; marker=:circle, alpha=0.5, strokewidth=2, markersize=12)
    +
    +    l2 = lines!(ax, tsteps, waveform_nn; linewidth=2, alpha=0.75)
    +    s2 = scatter!(
    +        ax, tsteps, waveform_nn; marker=:circle, alpha=0.5, strokewidth=2, markersize=12)
    +
    +    l3 = lines!(ax, tsteps, waveform_nn_trained; linewidth=2, alpha=0.75)
    +    s3 = scatter!(ax, tsteps, waveform_nn_trained; marker=:circle,
    +        alpha=0.5, strokewidth=2, markersize=12)
    +
    +    axislegend(ax, [[l1, s1], [l2, s2], [l3, s3]],
    +        ["Waveform Data", "Waveform Neural Net (Untrained)", "Waveform Neural Net"];
    +        position=:lb)
    +
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 128 × AMD EPYC 7502 32-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 16 default, 0 interactive, 8 GC (on 16 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 16
    +  JULIA_DEPOT_PATH = /cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 16
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate

    This page was generated using Literate.jl.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/tutorials/beginner/1_Basics.html b/previews/PR1023/tutorials/beginner/1_Basics.html new file mode 100644 index 0000000000..52234918ca --- /dev/null +++ b/previews/PR1023/tutorials/beginner/1_Basics.html @@ -0,0 +1,250 @@ + + + + + + Julia & Lux for the Uninitiated | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Julia & Lux for the Uninitiated

    This is a quick intro to Lux loosely based on:

    1. PyTorch's tutorial.

    2. Flux's tutorial (the link for which has now been lost to abyss).

    3. Jax's tutorial.

    It introduces basic Julia programming, as well Zygote, a source-to-source automatic differentiation (AD) framework in Julia. We'll use these tools to build a very simple neural network. Let's start with importing Lux.jl

    julia
    using Lux, Random

    Now let us control the randomness in our code using proper Pseudo Random Number Generator (PRNG)

    julia
    rng = Random.default_rng()
    +Random.seed!(rng, 0)
    Random.TaskLocalRNG()

    Arrays

    The starting point for all of our models is the Array (sometimes referred to as a Tensor in other frameworks). This is really just a list of numbers, which might be arranged into a shape like a square. Let's write down an array with three elements.

    julia
    x = [1, 2, 3]
    3-element Vector{Int64}:
    + 1
    + 2
    + 3

    Here's a matrix – a square array with four elements.

    julia
    x = [1 2; 3 4]
    2×2 Matrix{Int64}:
    + 1  2
    + 3  4

    We often work with arrays of thousands of elements, and don't usually write them down by hand. Here's how we can create an array of 5×3 = 15 elements, each a random number from zero to one.

    julia
    x = rand(rng, 5, 3)
    5×3 Matrix{Float64}:
    + 0.455238   0.746943   0.193291
    + 0.547642   0.746801   0.116989
    + 0.773354   0.97667    0.899766
    + 0.940585   0.0869468  0.422918
    + 0.0296477  0.351491   0.707534

    There's a few functions like this; try replacing rand with ones, zeros, or randn.

    By default, Julia works stores numbers is a high-precision format called Float64. In ML we often don't need all those digits, and can ask Julia to work with Float32 instead. We can even ask for more digits using BigFloat.

    julia
    x = rand(BigFloat, 5, 3)
    5×3 Matrix{BigFloat}:
    + 0.981339    0.793159  0.459019
    + 0.043883    0.624384  0.56055
    + 0.164786    0.524008  0.0355555
    + 0.414769    0.577181  0.621958
    + 0.00823197  0.30215   0.655881
    julia
    x = rand(Float32, 5, 3)
    5×3 Matrix{Float32}:
    + 0.567794   0.369178   0.342539
    + 0.0985227  0.201145   0.587206
    + 0.776598   0.148248   0.0851708
    + 0.723731   0.0770206  0.839303
    + 0.404728   0.230954   0.679087

    We can ask the array how many elements it has.

    julia
    length(x)
    15

    Or, more specifically, what size it has.

    julia
    size(x)
    (5, 3)

    We sometimes want to see some elements of the array on their own.

    julia
    x
    5×3 Matrix{Float32}:
    + 0.567794   0.369178   0.342539
    + 0.0985227  0.201145   0.587206
    + 0.776598   0.148248   0.0851708
    + 0.723731   0.0770206  0.839303
    + 0.404728   0.230954   0.679087
    julia
    x[2, 3]
    0.58720636f0

    This means get the second row and the third column. We can also get every row of the third column.

    julia
    x[:, 3]
    5-element Vector{Float32}:
    + 0.34253937
    + 0.58720636
    + 0.085170805
    + 0.8393034
    + 0.67908657

    We can add arrays, and subtract them, which adds or subtracts each element of the array.

    julia
    x + x
    5×3 Matrix{Float32}:
    + 1.13559   0.738356  0.685079
    + 0.197045  0.40229   1.17441
    + 1.5532    0.296496  0.170342
    + 1.44746   0.154041  1.67861
    + 0.809456  0.461908  1.35817
    julia
    x - x
    5×3 Matrix{Float32}:
    + 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.0  0.0  0.0

    Julia supports a feature called broadcasting, using the . syntax. This tiles small arrays (or single numbers) to fill bigger ones.

    julia
    x .+ 1
    5×3 Matrix{Float32}:
    + 1.56779  1.36918  1.34254
    + 1.09852  1.20114  1.58721
    + 1.7766   1.14825  1.08517
    + 1.72373  1.07702  1.8393
    + 1.40473  1.23095  1.67909

    We can see Julia tile the column vector 1:5 across all rows of the larger array.

    julia
    zeros(5, 5) .+ (1:5)
    5×5 Matrix{Float64}:
    + 1.0  1.0  1.0  1.0  1.0
    + 2.0  2.0  2.0  2.0  2.0
    + 3.0  3.0  3.0  3.0  3.0
    + 4.0  4.0  4.0  4.0  4.0
    + 5.0  5.0  5.0  5.0  5.0

    The x' syntax is used to transpose a column 1:5 into an equivalent row, and Julia will tile that across columns.

    julia
    zeros(5, 5) .+ (1:5)'
    5×5 Matrix{Float64}:
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0
    + 1.0  2.0  3.0  4.0  5.0

    We can use this to make a times table.

    julia
    (1:5) .* (1:5)'
    5×5 Matrix{Int64}:
    + 1   2   3   4   5
    + 2   4   6   8  10
    + 3   6   9  12  15
    + 4   8  12  16  20
    + 5  10  15  20  25

    Finally, and importantly for machine learning, we can conveniently do things like matrix multiply.

    julia
    W = randn(5, 10)
    +x = rand(10)
    +W * x
    5-element Vector{Float64}:
    +  1.2197981041108443
    + -2.62625877100596
    + -2.8573820474674845
    + -2.4319346874291314
    +  1.0108668577150213

    Julia's arrays are very powerful, and you can learn more about what they can do here.

    CUDA Arrays

    CUDA functionality is provided separately by the CUDA.jl package. If you have a GPU and LuxCUDA is installed, Lux will provide CUDA capabilities. For additional details on backends see the manual section.

    You can manually add CUDA. Once CUDA is loaded you can move any array to the GPU with the cu function (or the gpu function exported by `Lux``), and it supports all of the above operations with the same syntax.

    julia
    using LuxCUDA
    +
    +if LuxCUDA.functional()
    +    x_cu = cu(rand(5, 3))
    +    @show x_cu
    +end
    5×3 CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}:
    + 0.857126  0.681728  0.73806
    + 0.191956  0.506485  0.622865
    + 0.857257  0.663036  0.239756
    + 0.54452   0.503186  0.27993
    + 0.833518  0.975649  0.967811

    (Im)mutability

    Lux as you might have read is Immutable by convention which means that the core library is built without any form of mutation and all functions are pure. However, we don't enforce it in any form. We do strongly recommend that users extending this framework for their respective applications don't mutate their arrays.

    julia
    x = reshape(1:8, 2, 4)
    2×4 reshape(::UnitRange{Int64}, 2, 4) with eltype Int64:
    + 1  3  5  7
    + 2  4  6  8

    To update this array, we should first copy the array.

    julia
    x_copy = copy(x)
    +view(x_copy, :, 1) .= 0
    +
    +println("Original Array ", x)
    +println("Mutated Array ", x_copy)
    Original Array [1 3 5 7; 2 4 6 8]
    +Mutated Array [0 3 5 7; 0 4 6 8]

    Note that our current default AD engine (Zygote) is unable to differentiate through this mutation, however, for these specialized cases it is quite trivial to write custom backward passes. (This problem will be fixed once we move towards Enzyme.jl)

    Managing Randomness

    We rely on the Julia StdLib Random for managing the randomness in our execution. First, we create an PRNG (pseudorandom number generator) and seed it.

    julia
    rng = Xoshiro(0)     # Creates a Xoshiro PRNG with seed 0
    Random.Xoshiro(0xdb2fa90498613fdf, 0x48d73dc42d195740, 0x8c49bc52dc8a77ea, 0x1911b814c02405e8, 0x22a21880af5dc689)

    If we call any function that relies on rng and uses it via randn, rand, etc. rng will be mutated. As we have already established we care a lot about immutability, hence we should use Lux.replicate on PRNGs before using them.

    First, let us run a random number generator 3 times with the replicated rng.

    julia
    random_vectors = Vector{Vector{Float64}}(undef, 3)
    +for i in 1:3
    +    random_vectors[i] = rand(Lux.replicate(rng), 10)
    +    println("Iteration $i ", random_vectors[i])
    +end
    +@assert random_vectors[1]  random_vectors[2]  random_vectors[3]
    Iteration 1 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]
    +Iteration 2 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]
    +Iteration 3 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]

    As expected we get the same output. We can remove the replicate call and we will get different outputs.

    julia
    for i in 1:3
    +    println("Iteration $i ", rand(rng, 10))
    +end
    Iteration 1 [0.4552384158732863, 0.5476424498276177, 0.7733535276924052, 0.9405848223512736, 0.02964765308691042, 0.74694291453392, 0.7468008914093891, 0.9766699015845924, 0.08694684883050086, 0.35149138733595564]
    +Iteration 2 [0.018743665453639813, 0.8601828553599953, 0.6556360448565952, 0.7746656838366666, 0.7817315740767116, 0.5553797706980106, 0.1261990389976131, 0.4488101521328277, 0.624383955429775, 0.05657739601024536]
    +Iteration 3 [0.19597391412112541, 0.6830945313415872, 0.6776220912718907, 0.6456416023530093, 0.6340362477836592, 0.5595843665394066, 0.5675557670686644, 0.34351700231383653, 0.7237308297251812, 0.3691778381831775]

    Automatic Differentiation

    Julia has quite a few (maybe too many) AD tools. For the purpose of this tutorial, we will use:

    1. ForwardDiff.jl – For Jacobian-Vector Product (JVP)

    2. Zygote.jl – For Vector-Jacobian Product (VJP)

    Slight Detour: We have had several questions regarding if we will be considering any other AD system for the reverse-diff backend. For now we will stick to Zygote.jl, however once we have tested Lux extensively with Enzyme.jl, we will make the switch.

    Even though, theoretically, a VJP (Vector-Jacobian product - reverse autodiff) and a JVP (Jacobian-Vector product - forward-mode autodiff) are similar—they compute a product of a Jacobian and a vector—they differ by the computational complexity of the operation. In short, when you have a large number of parameters (hence a wide matrix), a JVP is less efficient computationally than a VJP, and, conversely, a JVP is more efficient when the Jacobian matrix is a tall matrix.

    julia
    using ComponentArrays, ForwardDiff, Zygote

    Gradients

    For our first example, consider a simple function computing f(x)=12xTx, where f(x)=x

    julia
    f(x) = x' * x / 2
    +∇f(x) = x  # `∇` can be typed as `\nabla<TAB>`
    +v = randn(rng, Float32, 4)
    4-element Vector{Float32}:
    + -0.4051151
    + -0.4593922
    +  0.92155594
    +  1.1871622

    Let's use ForwardDiff and Zygote to compute the gradients.

    julia
    println("Actual Gradient: ", ∇f(v))
    +println("Computed Gradient via Reverse Mode AD (Zygote): ", only(Zygote.gradient(f, v)))
    +println("Computed Gradient via Forward Mode AD (ForwardDiff): ", ForwardDiff.gradient(f, v))
    Actual Gradient: Float32[-0.4051151, -0.4593922, 0.92155594, 1.1871622]
    +Computed Gradient via Reverse Mode AD (Zygote): Float32[-0.4051151, -0.4593922, 0.92155594, 1.1871622]
    +Computed Gradient via Forward Mode AD (ForwardDiff): Float32[-0.4051151, -0.4593922, 0.92155594, 1.1871622]

    Note that AD.gradient will only work for scalar valued outputs.

    Jacobian-Vector Product

    I will defer the discussion on forward-mode AD to https://book.sciml.ai/notes/08-Forward-Mode_Automatic_Differentiation_(AD)_via_High_Dimensional_Algebras/. Here let us just look at a mini example on how to use it.

    julia
    f(x) = x .* x ./ 2
    +x = randn(rng, Float32, 5)
    +v = ones(Float32, 5)
    5-element Vector{Float32}:
    + 1.0
    + 1.0
    + 1.0
    + 1.0
    + 1.0

    Using DifferentiationInterface

    While DifferentiationInterface provides these functions for a wider range of backends, we currently don't recommend using them with Lux models, since the functions presented here come with additional goodies like fast second-order derivatives.

    Compute the jvp. AutoForwardDiff specifies that we want to use ForwardDiff.jl for the Jacobian-Vector Product

    julia
    jvp = jacobian_vector_product(f, AutoForwardDiff(), x, v)
    +println("JVP: ", jvp)
    JVP: Float32[-0.877497, 1.1953009, -0.057005208, 0.25055695, 0.09351656]

    Vector-Jacobian Product

    Using the same function and inputs, let us compute the VJP.

    julia
    vjp = vector_jacobian_product(f, AutoZygote(), x, v)
    +println("VJP: ", vjp)
    VJP: Float32[-0.877497, 1.1953009, -0.057005208, 0.25055695, 0.09351656]

    Linear Regression

    Finally, now let us consider a linear regression problem. From a set of data-points {(xi,yi),i{1,,k},xiRn,yiRm}, we try to find a set of parameters W and b, s.t. fW,b(x)=Wx+b, which minimizes the mean squared error:

    L(W,b)i=1k12yifW,b(xi)22

    We can write f from scratch, but to demonstrate Lux, let us use the Dense layer.

    julia
    model = Dense(10 => 5)
    +
    +rng = Random.default_rng()
    +Random.seed!(rng, 0)
    Random.TaskLocalRNG()

    Let us initialize the parameters and states (in this case it is empty) for the model.

    julia
    ps, st = Lux.setup(rng, model)
    +ps = ps |> ComponentArray
    ComponentVector{Float32}(weight = Float32[-0.48351598 0.29944375 0.44048917 0.5221656 0.20001543 0.1437841 4.8317274f-6 0.5310851 -0.30674052 0.034259234; -0.04903387 -0.4242767 0.27051234 0.40789893 -0.43846482 -0.17706361 -0.03258145 0.46514034 0.1958431 0.23992883; 0.45016125 0.48263642 -0.2990853 -0.18695377 -0.11023762 -0.4418456 0.40354207 0.25278285 0.18056087 -0.3523193; 0.05218964 -0.09701932 0.27035674 0.12589 -0.29561827 0.34717593 -0.42189494 -0.13073668 0.36829436 -0.3097294; 0.20277858 -0.51524514 -0.22635892 0.18841726 0.29828635 0.21690917 -0.04265762 -0.41919118 0.071482725 -0.45247704], bias = Float32[-0.04199602, -0.093925126, -0.0007736237, -0.19397983, 0.0066712513])

    Set problem dimensions.

    julia
    n_samples = 20
    +x_dim = 10
    +y_dim = 5
    5

    Generate random ground truth W and b.

    julia
    W = randn(rng, Float32, y_dim, x_dim)
    +b = randn(rng, Float32, y_dim)
    5-element Vector{Float32}:
    + -0.9436797
    +  1.5164032
    +  0.011937321
    +  1.4339262
    + -0.2771789

    Generate samples with additional noise.

    julia
    x_samples = randn(rng, Float32, x_dim, n_samples)
    +y_samples = W * x_samples .+ b .+ 0.01f0 .* randn(rng, Float32, y_dim, n_samples)
    +println("x shape: ", size(x_samples), "; y shape: ", size(y_samples))
    x shape: (10, 20); y shape: (5, 20)

    For updating our parameters let's use Optimisers.jl. We will use Stochastic Gradient Descent (SGD) with a learning rate of 0.01.

    julia
    using Optimisers, Printf

    Define the loss function

    julia
    lossfn = MSELoss()
    +
    +println("Loss Value with ground true parameters: ", lossfn(W * x_samples .+ b, y_samples))
    Loss Value with ground true parameters: 9.3742405e-5

    We will train the model using our training API.

    julia
    function train_model!(model, ps, st, opt, nepochs::Int)
    +    tstate = Training.TrainState(model, ps, st, opt)
    +    for i in 1:nepochs
    +        grads, loss, _, tstate = Training.single_train_step!(
    +            AutoZygote(), lossfn, (x_samples, y_samples), tstate)
    +        if i % 1000 == 1 || i == nepochs
    +            @printf "Loss Value after %6d iterations: %.8f\n" i loss
    +        end
    +    end
    +    return tstate.model, tstate.parameters, tstate.states
    +end
    +
    +model, ps, st = train_model!(model, ps, st, Descent(0.01f0), 10000)
    +
    +println("Loss Value after training: ", lossfn(first(model(x_samples, ps, st)), y_samples))
    Loss Value after      1 iterations: 7.80465555
    +Loss Value after   1001 iterations: 0.12477568
    +Loss Value after   2001 iterations: 0.02535537
    +Loss Value after   3001 iterations: 0.00914141
    +Loss Value after   4001 iterations: 0.00407581
    +Loss Value after   5001 iterations: 0.00198415
    +Loss Value after   6001 iterations: 0.00101147
    +Loss Value after   7001 iterations: 0.00053332
    +Loss Value after   8001 iterations: 0.00029203
    +Loss Value after   9001 iterations: 0.00016878
    +Loss Value after  10000 iterations: 0.00010551
    +Loss Value after training: 0.00010546855

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.627 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/tutorials/beginner/2_PolynomialFitting.html b/previews/PR1023/tutorials/beginner/2_PolynomialFitting.html new file mode 100644 index 0000000000..62e6c5c701 --- /dev/null +++ b/previews/PR1023/tutorials/beginner/2_PolynomialFitting.html @@ -0,0 +1,157 @@ + + + + + + Fitting a Polynomial using MLP | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Fitting a Polynomial using MLP

    In this tutorial we will fit a MultiLayer Perceptron (MLP) on data generated from a polynomial.

    Package Imports

    julia
    using Lux, ADTypes, LuxCUDA, Optimisers, Printf, Random, Statistics, Zygote
    +using CairoMakie

    Dataset

    Generate 128 datapoints from the polynomial y=x22x.

    julia
    function generate_data(rng::AbstractRNG)
    +    x = reshape(collect(range(-2.0f0, 2.0f0, 128)), (1, 128))
    +    y = evalpoly.(x, ((0, -2, 1),)) .+ randn(rng, Float32, (1, 128)) .* 0.1f0
    +    return (x, y)
    +end
    generate_data (generic function with 1 method)

    Initialize the random number generator and fetch the dataset.

    julia
    rng = MersenneTwister()
    +Random.seed!(rng, 12345)
    +
    +(x, y) = generate_data(rng)
    (Float32[-2.0 -1.968504 -1.9370079 -1.9055119 -1.8740157 -1.8425196 -1.8110236 -1.7795275 -1.7480315 -1.7165354 -1.6850394 -1.6535434 -1.6220472 -1.5905511 -1.5590551 -1.527559 -1.496063 -1.464567 -1.4330709 -1.4015749 -1.3700787 -1.3385826 -1.3070866 -1.2755905 -1.2440945 -1.2125984 -1.1811024 -1.1496063 -1.1181102 -1.0866141 -1.0551181 -1.023622 -0.992126 -0.96062994 -0.92913383 -0.8976378 -0.86614174 -0.8346457 -0.8031496 -0.77165353 -0.7401575 -0.70866144 -0.6771653 -0.6456693 -0.61417323 -0.5826772 -0.5511811 -0.51968503 -0.48818898 -0.4566929 -0.42519686 -0.39370078 -0.36220473 -0.33070865 -0.2992126 -0.26771653 -0.23622048 -0.20472442 -0.17322835 -0.14173229 -0.11023622 -0.07874016 -0.047244094 -0.015748031 0.015748031 0.047244094 0.07874016 0.11023622 0.14173229 0.17322835 0.20472442 0.23622048 0.26771653 0.2992126 0.33070865 0.36220473 0.39370078 0.42519686 0.4566929 0.48818898 0.51968503 0.5511811 0.5826772 0.61417323 0.6456693 0.6771653 0.70866144 0.7401575 0.77165353 0.8031496 0.8346457 0.86614174 0.8976378 0.92913383 0.96062994 0.992126 1.023622 1.0551181 1.0866141 1.1181102 1.1496063 1.1811024 1.2125984 1.2440945 1.2755905 1.3070866 1.3385826 1.3700787 1.4015749 1.4330709 1.464567 1.496063 1.527559 1.5590551 1.5905511 1.6220472 1.6535434 1.6850394 1.7165354 1.7480315 1.7795275 1.8110236 1.8425196 1.8740157 1.9055119 1.9370079 1.968504 2.0], Float32[8.117236 7.8972864 7.667572 7.4936414 7.328542 7.108145 6.7541456 6.7384486 6.6983237 6.3637495 6.2701178 6.241937 5.816281 5.7183194 5.741348 5.2581186 5.2681656 5.195746 5.032705 4.73341 4.52024 4.3693867 4.107888 4.1828456 4.0022497 3.8969011 3.9108207 3.64644 3.3343754 3.398038 3.1887817 2.9930804 3.0189805 2.6904922 2.8576512 2.4778283 2.4524014 2.4018757 2.2896426 2.281252 1.9742292 1.7663455 1.8424188 1.6920981 1.6389992 1.7001468 1.4353992 1.3645461 1.2354317 0.9803549 0.9767632 0.9418648 1.0686756 0.6448233 0.6202136 0.57882756 0.44078717 0.48027995 0.35653025 0.39588368 0.21940619 0.17816184 -0.03322105 0.11007148 0.08922641 0.009766437 -0.06433817 -0.14132261 -0.22807482 -0.35395628 -0.6003383 -0.33544478 -0.49804282 -0.4382721 -0.52628386 -0.64495987 -0.46061087 -0.5594571 -0.82293516 -0.76425457 -0.8688824 -0.9489941 -0.90779305 -0.7559453 -0.8499767 -0.9161865 -0.9856883 -0.88951594 -1.0803379 -1.18564 -0.9934639 -0.9253495 -0.9679338 -0.9079035 -1.1395766 -1.1286439 -0.9248211 -1.0428307 -0.95401394 -1.0709 -1.0742047 -1.0277897 -0.8821303 -0.875082 -0.85050875 -0.97378695 -0.8013359 -0.78818554 -0.7897024 -0.7123551 -0.6859683 -0.76158035 -0.82030004 -0.8031547 -0.45583528 -0.61155146 -0.55658394 -0.4371308 -0.48983693 -0.37275374 -0.5424696 -0.2922556 -0.38200346 -0.30673835 -0.08820387 -0.3170582 0.0010350421 -0.13475561])

    Let's visualize the dataset

    julia
    begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +
    +    l = lines!(ax, x[1, :], x -> evalpoly(x, (0, -2, 1)); linewidth=3, color=:blue)
    +    s = scatter!(ax, x[1, :], y[1, :]; markersize=12, alpha=0.5,
    +        color=:orange, strokecolor=:black, strokewidth=2)
    +
    +    axislegend(ax, [l, s], ["True Quadratic Function", "Data Points"])
    +
    +    fig
    +end

    Neural Network

    For this problem, you should not be using a neural network. But let's still do that!

    julia
    model = Chain(Dense(1 => 16, relu), Dense(16 => 1))
    Chain(
    +    layer_1 = Dense(1 => 16, relu),     # 32 parameters
    +    layer_2 = Dense(16 => 1),           # 17 parameters
    +)         # Total: 49 parameters,
    +          #        plus 0 states.

    Optimizer

    We will use Adam from Optimisers.jl

    julia
    opt = Adam(0.03f0)
    Adam(0.03, (0.9, 0.999), 1.0e-8)

    Loss Function

    We will use the Training API so we need to ensure that our loss function takes 4 inputs – model, parameters, states and data. The function must return 3 values – loss, updated_state, and any computed statistics. This is already satisfied by the loss functions provided by Lux.

    julia
    const loss_function = MSELoss()
    +
    +const dev_cpu = cpu_device()
    +const dev_gpu = gpu_device()
    +
    +ps, st = Lux.setup(rng, model) |> dev_gpu
    ((layer_1 = (weight = Float32[2.9076505; -1.0578545; 0.7990667; -2.965008; -0.8048109; -0.20579764; -1.260598; 0.28946856; 3.2899156; -2.6431484; 0.51165134; 3.2938747; -3.0690823; -0.44096947; 0.8374606; -2.2932029;;], bias = Float32[0.30569053, -0.94259596, 0.9971247, -0.5167208, 0.6571946, -0.81446123, -0.66852736, 0.9849229, -0.40727592, 0.59543324, -0.17111921, 0.5009556, 0.58263564, -0.09693718, -0.2058456, -0.26793814]), layer_2 = (weight = Float32[-0.095568806 -0.3871873 0.07565363 0.18535946 -0.39300445 0.40623155 0.1490868 0.18481395 0.29315922 0.07375115 -0.23234403 0.015478307 -0.29206026 -0.3291591 0.27471745 0.3050475], bias = Float32[-0.12096125])), (layer_1 = NamedTuple(), layer_2 = NamedTuple()))

    Training

    First we will create a Training.TrainState which is essentially a convenience wrapper over parameters, states and optimizer states.

    julia
    tstate = Training.TrainState(model, ps, st, opt)
    TrainState
    +    model: Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(NNlib.relu), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}((layer_1 = Dense(1 => 16, relu), layer_2 = Dense(16 => 1)), nothing)
    +    # of parameters: 49
    +    # of states: 0
    +    optimizer: Adam(0.03, (0.9, 0.999), 1.0e-8)
    +    step: 0

    Now we will use Zygote for our AD requirements.

    julia
    vjp_rule = AutoZygote()
    ADTypes.AutoZygote()

    Finally the training loop.

    julia
    function main(tstate::Training.TrainState, vjp, data, epochs)
    +    data = data .|> gpu_device()
    +    for epoch in 1:epochs
    +        _, loss, _, tstate = Training.single_train_step!(vjp, loss_function, data, tstate)
    +        if epoch % 50 == 1 || epoch == epochs
    +            @printf "Epoch: %3d \t Loss: %.5g\n" epoch loss
    +        end
    +    end
    +    return tstate
    +end
    +
    +tstate = main(tstate, vjp_rule, (x, y), 250)
    +y_pred = dev_cpu(Lux.apply(tstate.model, dev_gpu(x), tstate.parameters, tstate.states)[1])
    Epoch:   1 	 Loss: 11.713
    +Epoch:  51 	 Loss: 0.082086
    +Epoch: 101 	 Loss: 0.062907
    +Epoch: 151 	 Loss: 0.04416
    +Epoch: 201 	 Loss: 0.030016
    +Epoch: 250 	 Loss: 0.022215

    Let's plot the results

    julia
    begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +
    +    l = lines!(ax, x[1, :], x -> evalpoly(x, (0, -2, 1)); linewidth=3)
    +    s1 = scatter!(ax, x[1, :], y[1, :]; markersize=12, alpha=0.5,
    +        color=:orange, strokecolor=:black, strokewidth=2)
    +    s2 = scatter!(ax, x[1, :], y_pred[1, :]; markersize=12, alpha=0.5,
    +        color=:green, strokecolor=:black, strokewidth=2)
    +
    +    axislegend(ax, [l, s1, s2], ["True Quadratic Function", "Actual Data", "Predictions"])
    +
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.609 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/tutorials/beginner/3_SimpleRNN.html b/previews/PR1023/tutorials/beginner/3_SimpleRNN.html new file mode 100644 index 0000000000..31fbac52d1 --- /dev/null +++ b/previews/PR1023/tutorials/beginner/3_SimpleRNN.html @@ -0,0 +1,644 @@ + + + + + + Training a Simple LSTM | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Training a Simple LSTM

    In this tutorial we will go over using a recurrent neural network to classify clockwise and anticlockwise spirals. By the end of this tutorial you will be able to:

    1. Create custom Lux models.

    2. Become familiar with the Lux recurrent neural network API.

    3. Training using Optimisers.jl and Zygote.jl.

    Package Imports

    julia
    using ADTypes, Lux, LuxCUDA, JLD2, MLUtils, Optimisers, Zygote, Printf, Random, Statistics

    Dataset

    We will use MLUtils to generate 500 (noisy) clockwise and 500 (noisy) anticlockwise spirals. Using this data we will create a MLUtils.DataLoader. Our dataloader will give us sequences of size 2 × seq_len × batch_size and we need to predict a binary value whether the sequence is clockwise or anticlockwise.

    julia
    function get_dataloaders(; dataset_size=1000, sequence_length=50)
    +    # Create the spirals
    +    data = [MLUtils.Datasets.make_spiral(sequence_length) for _ in 1:dataset_size]
    +    # Get the labels
    +    labels = vcat(repeat([0.0f0], dataset_size ÷ 2), repeat([1.0f0], dataset_size ÷ 2))
    +    clockwise_spirals = [reshape(d[1][:, 1:sequence_length], :, sequence_length, 1)
    +                         for d in data[1:(dataset_size ÷ 2)]]
    +    anticlockwise_spirals = [reshape(
    +                                 d[1][:, (sequence_length + 1):end], :, sequence_length, 1)
    +                             for d in data[((dataset_size ÷ 2) + 1):end]]
    +    x_data = Float32.(cat(clockwise_spirals..., anticlockwise_spirals...; dims=3))
    +    # Split the dataset
    +    (x_train, y_train), (x_val, y_val) = splitobs((x_data, labels); at=0.8, shuffle=true)
    +    # Create DataLoaders
    +    return (
    +        # Use DataLoader to automatically minibatch and shuffle the data
    +        DataLoader(collect.((x_train, y_train)); batchsize=128, shuffle=true),
    +        # Don't shuffle the validation data
    +        DataLoader(collect.((x_val, y_val)); batchsize=128, shuffle=false))
    +end
    get_dataloaders (generic function with 1 method)

    Creating a Classifier

    We will be extending the Lux.AbstractLuxContainerLayer type for our custom model since it will contain a lstm block and a classifier head.

    We pass the fieldnames lstm_cell and classifier to the type to ensure that the parameters and states are automatically populated and we don't have to define Lux.initialparameters and Lux.initialstates.

    To understand more about container layers, please look at Container Layer.

    julia
    struct SpiralClassifier{L, C} <: Lux.AbstractLuxContainerLayer{(:lstm_cell, :classifier)}
    +    lstm_cell::L
    +    classifier::C
    +end

    We won't define the model from scratch but rather use the Lux.LSTMCell and Lux.Dense.

    julia
    function SpiralClassifier(in_dims, hidden_dims, out_dims)
    +    return SpiralClassifier(
    +        LSTMCell(in_dims => hidden_dims), Dense(hidden_dims => out_dims, sigmoid))
    +end
    Main.var"##225".SpiralClassifier

    We can use default Lux blocks – Recurrence(LSTMCell(in_dims => hidden_dims) – instead of defining the following. But let's still do it for the sake of it.

    Now we need to define the behavior of the Classifier when it is invoked.

    julia
    function (s::SpiralClassifier)(
    +        x::AbstractArray{T, 3}, ps::NamedTuple, st::NamedTuple) where {T}
    +    # First we will have to run the sequence through the LSTM Cell
    +    # The first call to LSTM Cell will create the initial hidden state
    +    # See that the parameters and states are automatically populated into a field called
    +    # `lstm_cell` We use `eachslice` to get the elements in the sequence without copying,
    +    # and `Iterators.peel` to split out the first element for LSTM initialization.
    +    x_init, x_rest = Iterators.peel(LuxOps.eachslice(x, Val(2)))
    +    (y, carry), st_lstm = s.lstm_cell(x_init, ps.lstm_cell, st.lstm_cell)
    +    # Now that we have the hidden state and memory in `carry` we will pass the input and
    +    # `carry` jointly
    +    for x in x_rest
    +        (y, carry), st_lstm = s.lstm_cell((x, carry), ps.lstm_cell, st_lstm)
    +    end
    +    # After running through the sequence we will pass the output through the classifier
    +    y, st_classifier = s.classifier(y, ps.classifier, st.classifier)
    +    # Finally remember to create the updated state
    +    st = merge(st, (classifier=st_classifier, lstm_cell=st_lstm))
    +    return vec(y), st
    +end

    Using the @compact API

    We can also define the model using the Lux.@compact API, which is a more concise way of defining models. This macro automatically handles the boilerplate code for you and as such we recommend this way of defining custom layers

    julia
    function SpiralClassifierCompact(in_dims, hidden_dims, out_dims)
    +    lstm_cell = LSTMCell(in_dims => hidden_dims)
    +    classifier = Dense(hidden_dims => out_dims, sigmoid)
    +    return @compact(; lstm_cell, classifier) do x::AbstractArray{T, 3} where {T}
    +        x_init, x_rest = Iterators.peel(LuxOps.eachslice(x, Val(2)))
    +        y, carry = lstm_cell(x_init)
    +        for x in x_rest
    +            y, carry = lstm_cell((x, carry))
    +        end
    +        @return vec(classifier(y))
    +    end
    +end
    SpiralClassifierCompact (generic function with 1 method)

    Defining Accuracy, Loss and Optimiser

    Now let's define the binarycrossentropy loss. Typically it is recommended to use logitbinarycrossentropy since it is more numerically stable, but for the sake of simplicity we will use binarycrossentropy.

    julia
    const lossfn = BinaryCrossEntropyLoss()
    +
    +function compute_loss(model, ps, st, (x, y))
    +    ŷ, st_ = model(x, ps, st)
    +    loss = lossfn(ŷ, y)
    +    return loss, st_, (; y_pred=ŷ)
    +end
    +
    +matches(y_pred, y_true) = sum((y_pred .> 0.5f0) .== y_true)
    +accuracy(y_pred, y_true) = matches(y_pred, y_true) / length(y_pred)
    accuracy (generic function with 1 method)

    Training the Model

    julia
    function main(model_type)
    +    dev = gpu_device()
    +
    +    # Get the dataloaders
    +    train_loader, val_loader = get_dataloaders() .|> dev
    +
    +    # Create the model
    +    model = model_type(2, 8, 1)
    +    rng = Xoshiro(0)
    +    ps, st = Lux.setup(rng, model) |> dev
    +
    +    train_state = Training.TrainState(model, ps, st, Adam(0.01f0))
    +
    +    for epoch in 1:25
    +        # Train the model
    +        for (x, y) in train_loader
    +            (_, loss, _, train_state) = Training.single_train_step!(
    +                AutoZygote(), lossfn, (x, y), train_state)
    +
    +            @printf "Epoch [%3d]: Loss %4.5f\n" epoch loss
    +        end
    +
    +        # Validate the model
    +        st_ = Lux.testmode(train_state.states)
    +        for (x, y) in val_loader
    +            ŷ, st_ = model(x, train_state.parameters, st_)
    +            loss = lossfn(ŷ, y)
    +            acc = accuracy(ŷ, y)
    +            @printf "Validation: Loss %4.5f Accuracy %4.5f\n" loss acc
    +        end
    +    end
    +
    +    return (train_state.parameters, train_state.states) |> cpu_device()
    +end
    +
    +ps_trained, st_trained = main(SpiralClassifier)
    Epoch [  1]: Loss 0.60926
    +Epoch [  1]: Loss 0.60205
    +Epoch [  1]: Loss 0.56447
    +Epoch [  1]: Loss 0.53935
    +Epoch [  1]: Loss 0.51961
    +Epoch [  1]: Loss 0.50630
    +Epoch [  1]: Loss 0.48399
    +Validation: Loss 0.46956 Accuracy 1.00000
    +Validation: Loss 0.47794 Accuracy 1.00000
    +Epoch [  2]: Loss 0.47301
    +Epoch [  2]: Loss 0.45405
    +Epoch [  2]: Loss 0.43968
    +Epoch [  2]: Loss 0.43054
    +Epoch [  2]: Loss 0.40202
    +Epoch [  2]: Loss 0.39666
    +Epoch [  2]: Loss 0.40138
    +Validation: Loss 0.37273 Accuracy 1.00000
    +Validation: Loss 0.38210 Accuracy 1.00000
    +Epoch [  3]: Loss 0.36731
    +Epoch [  3]: Loss 0.36875
    +Epoch [  3]: Loss 0.34892
    +Epoch [  3]: Loss 0.33812
    +Epoch [  3]: Loss 0.31629
    +Epoch [  3]: Loss 0.30792
    +Epoch [  3]: Loss 0.27809
    +Validation: Loss 0.28817 Accuracy 1.00000
    +Validation: Loss 0.29822 Accuracy 1.00000
    +Epoch [  4]: Loss 0.28662
    +Epoch [  4]: Loss 0.27989
    +Epoch [  4]: Loss 0.27278
    +Epoch [  4]: Loss 0.25235
    +Epoch [  4]: Loss 0.23497
    +Epoch [  4]: Loss 0.23847
    +Epoch [  4]: Loss 0.23192
    +Validation: Loss 0.21844 Accuracy 1.00000
    +Validation: Loss 0.22858 Accuracy 1.00000
    +Epoch [  5]: Loss 0.21529
    +Epoch [  5]: Loss 0.21660
    +Epoch [  5]: Loss 0.21147
    +Epoch [  5]: Loss 0.18347
    +Epoch [  5]: Loss 0.18387
    +Epoch [  5]: Loss 0.16418
    +Epoch [  5]: Loss 0.18488
    +Validation: Loss 0.16251 Accuracy 1.00000
    +Validation: Loss 0.17173 Accuracy 1.00000
    +Epoch [  6]: Loss 0.15106
    +Epoch [  6]: Loss 0.15557
    +Epoch [  6]: Loss 0.15604
    +Epoch [  6]: Loss 0.12610
    +Epoch [  6]: Loss 0.14466
    +Epoch [  6]: Loss 0.13525
    +Epoch [  6]: Loss 0.13401
    +Validation: Loss 0.11923 Accuracy 1.00000
    +Validation: Loss 0.12679 Accuracy 1.00000
    +Epoch [  7]: Loss 0.11300
    +Epoch [  7]: Loss 0.11270
    +Epoch [  7]: Loss 0.11182
    +Epoch [  7]: Loss 0.10579
    +Epoch [  7]: Loss 0.10077
    +Epoch [  7]: Loss 0.09092
    +Epoch [  7]: Loss 0.08957
    +Validation: Loss 0.08530 Accuracy 1.00000
    +Validation: Loss 0.09085 Accuracy 1.00000
    +Epoch [  8]: Loss 0.08321
    +Epoch [  8]: Loss 0.07613
    +Epoch [  8]: Loss 0.07561
    +Epoch [  8]: Loss 0.07250
    +Epoch [  8]: Loss 0.06895
    +Epoch [  8]: Loss 0.07155
    +Epoch [  8]: Loss 0.06246
    +Validation: Loss 0.05935 Accuracy 1.00000
    +Validation: Loss 0.06304 Accuracy 1.00000
    +Epoch [  9]: Loss 0.06135
    +Epoch [  9]: Loss 0.05983
    +Epoch [  9]: Loss 0.05429
    +Epoch [  9]: Loss 0.04415
    +Epoch [  9]: Loss 0.04965
    +Epoch [  9]: Loss 0.04801
    +Epoch [  9]: Loss 0.04264
    +Validation: Loss 0.04389 Accuracy 1.00000
    +Validation: Loss 0.04647 Accuracy 1.00000
    +Epoch [ 10]: Loss 0.04243
    +Epoch [ 10]: Loss 0.04109
    +Epoch [ 10]: Loss 0.04136
    +Epoch [ 10]: Loss 0.04201
    +Epoch [ 10]: Loss 0.03979
    +Epoch [ 10]: Loss 0.03471
    +Epoch [ 10]: Loss 0.03760
    +Validation: Loss 0.03546 Accuracy 1.00000
    +Validation: Loss 0.03756 Accuracy 1.00000
    +Epoch [ 11]: Loss 0.03545
    +Epoch [ 11]: Loss 0.03571
    +Epoch [ 11]: Loss 0.03202
    +Epoch [ 11]: Loss 0.03209
    +Epoch [ 11]: Loss 0.03134
    +Epoch [ 11]: Loss 0.03114
    +Epoch [ 11]: Loss 0.03593
    +Validation: Loss 0.03006 Accuracy 1.00000
    +Validation: Loss 0.03189 Accuracy 1.00000
    +Epoch [ 12]: Loss 0.03210
    +Epoch [ 12]: Loss 0.02768
    +Epoch [ 12]: Loss 0.02955
    +Epoch [ 12]: Loss 0.02631
    +Epoch [ 12]: Loss 0.02720
    +Epoch [ 12]: Loss 0.02667
    +Epoch [ 12]: Loss 0.03031
    +Validation: Loss 0.02612 Accuracy 1.00000
    +Validation: Loss 0.02773 Accuracy 1.00000
    +Epoch [ 13]: Loss 0.02589
    +Epoch [ 13]: Loss 0.02454
    +Epoch [ 13]: Loss 0.02716
    +Epoch [ 13]: Loss 0.02579
    +Epoch [ 13]: Loss 0.02323
    +Epoch [ 13]: Loss 0.02301
    +Epoch [ 13]: Loss 0.02099
    +Validation: Loss 0.02307 Accuracy 1.00000
    +Validation: Loss 0.02452 Accuracy 1.00000
    +Epoch [ 14]: Loss 0.02105
    +Epoch [ 14]: Loss 0.02170
    +Epoch [ 14]: Loss 0.02234
    +Epoch [ 14]: Loss 0.02238
    +Epoch [ 14]: Loss 0.02259
    +Epoch [ 14]: Loss 0.02282
    +Epoch [ 14]: Loss 0.01795
    +Validation: Loss 0.02066 Accuracy 1.00000
    +Validation: Loss 0.02199 Accuracy 1.00000
    +Epoch [ 15]: Loss 0.02140
    +Epoch [ 15]: Loss 0.02017
    +Epoch [ 15]: Loss 0.01932
    +Epoch [ 15]: Loss 0.02011
    +Epoch [ 15]: Loss 0.01752
    +Epoch [ 15]: Loss 0.02006
    +Epoch [ 15]: Loss 0.01963
    +Validation: Loss 0.01866 Accuracy 1.00000
    +Validation: Loss 0.01988 Accuracy 1.00000
    +Epoch [ 16]: Loss 0.01796
    +Epoch [ 16]: Loss 0.01636
    +Epoch [ 16]: Loss 0.01900
    +Epoch [ 16]: Loss 0.01740
    +Epoch [ 16]: Loss 0.01782
    +Epoch [ 16]: Loss 0.01824
    +Epoch [ 16]: Loss 0.01976
    +Validation: Loss 0.01696 Accuracy 1.00000
    +Validation: Loss 0.01810 Accuracy 1.00000
    +Epoch [ 17]: Loss 0.01745
    +Epoch [ 17]: Loss 0.01579
    +Epoch [ 17]: Loss 0.01777
    +Epoch [ 17]: Loss 0.01630
    +Epoch [ 17]: Loss 0.01578
    +Epoch [ 17]: Loss 0.01468
    +Epoch [ 17]: Loss 0.01627
    +Validation: Loss 0.01549 Accuracy 1.00000
    +Validation: Loss 0.01656 Accuracy 1.00000
    +Epoch [ 18]: Loss 0.01608
    +Epoch [ 18]: Loss 0.01398
    +Epoch [ 18]: Loss 0.01425
    +Epoch [ 18]: Loss 0.01537
    +Epoch [ 18]: Loss 0.01504
    +Epoch [ 18]: Loss 0.01471
    +Epoch [ 18]: Loss 0.01496
    +Validation: Loss 0.01423 Accuracy 1.00000
    +Validation: Loss 0.01523 Accuracy 1.00000
    +Epoch [ 19]: Loss 0.01355
    +Epoch [ 19]: Loss 0.01489
    +Epoch [ 19]: Loss 0.01364
    +Epoch [ 19]: Loss 0.01253
    +Epoch [ 19]: Loss 0.01360
    +Epoch [ 19]: Loss 0.01343
    +Epoch [ 19]: Loss 0.01639
    +Validation: Loss 0.01313 Accuracy 1.00000
    +Validation: Loss 0.01405 Accuracy 1.00000
    +Epoch [ 20]: Loss 0.01377
    +Epoch [ 20]: Loss 0.01183
    +Epoch [ 20]: Loss 0.01194
    +Epoch [ 20]: Loss 0.01194
    +Epoch [ 20]: Loss 0.01292
    +Epoch [ 20]: Loss 0.01361
    +Epoch [ 20]: Loss 0.01227
    +Validation: Loss 0.01211 Accuracy 1.00000
    +Validation: Loss 0.01297 Accuracy 1.00000
    +Epoch [ 21]: Loss 0.01212
    +Epoch [ 21]: Loss 0.01138
    +Epoch [ 21]: Loss 0.01102
    +Epoch [ 21]: Loss 0.01238
    +Epoch [ 21]: Loss 0.01200
    +Epoch [ 21]: Loss 0.01130
    +Epoch [ 21]: Loss 0.01082
    +Validation: Loss 0.01112 Accuracy 1.00000
    +Validation: Loss 0.01190 Accuracy 1.00000
    +Epoch [ 22]: Loss 0.01134
    +Epoch [ 22]: Loss 0.01031
    +Epoch [ 22]: Loss 0.01060
    +Epoch [ 22]: Loss 0.01130
    +Epoch [ 22]: Loss 0.01009
    +Epoch [ 22]: Loss 0.01053
    +Epoch [ 22]: Loss 0.00940
    +Validation: Loss 0.01002 Accuracy 1.00000
    +Validation: Loss 0.01071 Accuracy 1.00000
    +Epoch [ 23]: Loss 0.00886
    +Epoch [ 23]: Loss 0.01026
    +Epoch [ 23]: Loss 0.01005
    +Epoch [ 23]: Loss 0.00853
    +Epoch [ 23]: Loss 0.01033
    +Epoch [ 23]: Loss 0.00902
    +Epoch [ 23]: Loss 0.00969
    +Validation: Loss 0.00888 Accuracy 1.00000
    +Validation: Loss 0.00947 Accuracy 1.00000
    +Epoch [ 24]: Loss 0.00903
    +Epoch [ 24]: Loss 0.00856
    +Epoch [ 24]: Loss 0.00866
    +Epoch [ 24]: Loss 0.00883
    +Epoch [ 24]: Loss 0.00830
    +Epoch [ 24]: Loss 0.00781
    +Epoch [ 24]: Loss 0.00662
    +Validation: Loss 0.00795 Accuracy 1.00000
    +Validation: Loss 0.00846 Accuracy 1.00000
    +Epoch [ 25]: Loss 0.00830
    +Epoch [ 25]: Loss 0.00742
    +Epoch [ 25]: Loss 0.00822
    +Epoch [ 25]: Loss 0.00791
    +Epoch [ 25]: Loss 0.00721
    +Epoch [ 25]: Loss 0.00726
    +Epoch [ 25]: Loss 0.00582
    +Validation: Loss 0.00730 Accuracy 1.00000
    +Validation: Loss 0.00775 Accuracy 1.00000

    We can also train the compact model with the exact same code!

    julia
    ps_trained2, st_trained2 = main(SpiralClassifierCompact)
    Epoch [  1]: Loss 0.62249
    +Epoch [  1]: Loss 0.58988
    +Epoch [  1]: Loss 0.57122
    +Epoch [  1]: Loss 0.54145
    +Epoch [  1]: Loss 0.51676
    +Epoch [  1]: Loss 0.49941
    +Epoch [  1]: Loss 0.48712
    +Validation: Loss 0.46707 Accuracy 1.00000
    +Validation: Loss 0.46650 Accuracy 1.00000
    +Epoch [  2]: Loss 0.46435
    +Epoch [  2]: Loss 0.45555
    +Epoch [  2]: Loss 0.45454
    +Epoch [  2]: Loss 0.42345
    +Epoch [  2]: Loss 0.41436
    +Epoch [  2]: Loss 0.38527
    +Epoch [  2]: Loss 0.37442
    +Validation: Loss 0.36940 Accuracy 1.00000
    +Validation: Loss 0.36858 Accuracy 1.00000
    +Epoch [  3]: Loss 0.36752
    +Epoch [  3]: Loss 0.36360
    +Epoch [  3]: Loss 0.34430
    +Epoch [  3]: Loss 0.32734
    +Epoch [  3]: Loss 0.31783
    +Epoch [  3]: Loss 0.31825
    +Epoch [  3]: Loss 0.28565
    +Validation: Loss 0.28440 Accuracy 1.00000
    +Validation: Loss 0.28337 Accuracy 1.00000
    +Epoch [  4]: Loss 0.28307
    +Epoch [  4]: Loss 0.27199
    +Epoch [  4]: Loss 0.26836
    +Epoch [  4]: Loss 0.26051
    +Epoch [  4]: Loss 0.24528
    +Epoch [  4]: Loss 0.23063
    +Epoch [  4]: Loss 0.22536
    +Validation: Loss 0.21475 Accuracy 1.00000
    +Validation: Loss 0.21368 Accuracy 1.00000
    +Epoch [  5]: Loss 0.21305
    +Epoch [  5]: Loss 0.21531
    +Epoch [  5]: Loss 0.19616
    +Epoch [  5]: Loss 0.18414
    +Epoch [  5]: Loss 0.18294
    +Epoch [  5]: Loss 0.17875
    +Epoch [  5]: Loss 0.17815
    +Validation: Loss 0.15941 Accuracy 1.00000
    +Validation: Loss 0.15850 Accuracy 1.00000
    +Epoch [  6]: Loss 0.16464
    +Epoch [  6]: Loss 0.14669
    +Epoch [  6]: Loss 0.14234
    +Epoch [  6]: Loss 0.14785
    +Epoch [  6]: Loss 0.13936
    +Epoch [  6]: Loss 0.13121
    +Epoch [  6]: Loss 0.11054
    +Validation: Loss 0.11688 Accuracy 1.00000
    +Validation: Loss 0.11621 Accuracy 1.00000
    +Epoch [  7]: Loss 0.11895
    +Epoch [  7]: Loss 0.11755
    +Epoch [  7]: Loss 0.11153
    +Epoch [  7]: Loss 0.10806
    +Epoch [  7]: Loss 0.08931
    +Epoch [  7]: Loss 0.08989
    +Epoch [  7]: Loss 0.08885
    +Validation: Loss 0.08377 Accuracy 1.00000
    +Validation: Loss 0.08332 Accuracy 1.00000
    +Epoch [  8]: Loss 0.08392
    +Epoch [  8]: Loss 0.07975
    +Epoch [  8]: Loss 0.07711
    +Epoch [  8]: Loss 0.07462
    +Epoch [  8]: Loss 0.06929
    +Epoch [  8]: Loss 0.06475
    +Epoch [  8]: Loss 0.06222
    +Validation: Loss 0.05835 Accuracy 1.00000
    +Validation: Loss 0.05808 Accuracy 1.00000
    +Epoch [  9]: Loss 0.05835
    +Epoch [  9]: Loss 0.05645
    +Epoch [  9]: Loss 0.05303
    +Epoch [  9]: Loss 0.04974
    +Epoch [  9]: Loss 0.04989
    +Epoch [  9]: Loss 0.04836
    +Epoch [  9]: Loss 0.04374
    +Validation: Loss 0.04304 Accuracy 1.00000
    +Validation: Loss 0.04283 Accuracy 1.00000
    +Epoch [ 10]: Loss 0.04373
    +Epoch [ 10]: Loss 0.03963
    +Epoch [ 10]: Loss 0.04024
    +Epoch [ 10]: Loss 0.03893
    +Epoch [ 10]: Loss 0.04085
    +Epoch [ 10]: Loss 0.03933
    +Epoch [ 10]: Loss 0.02782
    +Validation: Loss 0.03470 Accuracy 1.00000
    +Validation: Loss 0.03451 Accuracy 1.00000
    +Epoch [ 11]: Loss 0.03413
    +Epoch [ 11]: Loss 0.03603
    +Epoch [ 11]: Loss 0.03246
    +Epoch [ 11]: Loss 0.03142
    +Epoch [ 11]: Loss 0.03040
    +Epoch [ 11]: Loss 0.03279
    +Epoch [ 11]: Loss 0.03336
    +Validation: Loss 0.02942 Accuracy 1.00000
    +Validation: Loss 0.02924 Accuracy 1.00000
    +Epoch [ 12]: Loss 0.03113
    +Epoch [ 12]: Loss 0.02712
    +Epoch [ 12]: Loss 0.02845
    +Epoch [ 12]: Loss 0.02904
    +Epoch [ 12]: Loss 0.02709
    +Epoch [ 12]: Loss 0.02722
    +Epoch [ 12]: Loss 0.02449
    +Validation: Loss 0.02555 Accuracy 1.00000
    +Validation: Loss 0.02540 Accuracy 1.00000
    +Epoch [ 13]: Loss 0.02730
    +Epoch [ 13]: Loss 0.02638
    +Epoch [ 13]: Loss 0.02358
    +Epoch [ 13]: Loss 0.02337
    +Epoch [ 13]: Loss 0.02417
    +Epoch [ 13]: Loss 0.02397
    +Epoch [ 13]: Loss 0.02159
    +Validation: Loss 0.02258 Accuracy 1.00000
    +Validation: Loss 0.02243 Accuracy 1.00000
    +Epoch [ 14]: Loss 0.02377
    +Epoch [ 14]: Loss 0.02260
    +Epoch [ 14]: Loss 0.02070
    +Epoch [ 14]: Loss 0.02170
    +Epoch [ 14]: Loss 0.02060
    +Epoch [ 14]: Loss 0.02212
    +Epoch [ 14]: Loss 0.02141
    +Validation: Loss 0.02019 Accuracy 1.00000
    +Validation: Loss 0.02006 Accuracy 1.00000
    +Epoch [ 15]: Loss 0.02146
    +Epoch [ 15]: Loss 0.01937
    +Epoch [ 15]: Loss 0.02047
    +Epoch [ 15]: Loss 0.01826
    +Epoch [ 15]: Loss 0.01953
    +Epoch [ 15]: Loss 0.01824
    +Epoch [ 15]: Loss 0.02201
    +Validation: Loss 0.01821 Accuracy 1.00000
    +Validation: Loss 0.01809 Accuracy 1.00000
    +Epoch [ 16]: Loss 0.01872
    +Epoch [ 16]: Loss 0.01647
    +Epoch [ 16]: Loss 0.01868
    +Epoch [ 16]: Loss 0.01763
    +Epoch [ 16]: Loss 0.01802
    +Epoch [ 16]: Loss 0.01730
    +Epoch [ 16]: Loss 0.01691
    +Validation: Loss 0.01653 Accuracy 1.00000
    +Validation: Loss 0.01642 Accuracy 1.00000
    +Epoch [ 17]: Loss 0.01638
    +Epoch [ 17]: Loss 0.01693
    +Epoch [ 17]: Loss 0.01747
    +Epoch [ 17]: Loss 0.01530
    +Epoch [ 17]: Loss 0.01570
    +Epoch [ 17]: Loss 0.01579
    +Epoch [ 17]: Loss 0.01431
    +Validation: Loss 0.01511 Accuracy 1.00000
    +Validation: Loss 0.01501 Accuracy 1.00000
    +Epoch [ 18]: Loss 0.01395
    +Epoch [ 18]: Loss 0.01493
    +Epoch [ 18]: Loss 0.01631
    +Epoch [ 18]: Loss 0.01388
    +Epoch [ 18]: Loss 0.01496
    +Epoch [ 18]: Loss 0.01520
    +Epoch [ 18]: Loss 0.01366
    +Validation: Loss 0.01390 Accuracy 1.00000
    +Validation: Loss 0.01381 Accuracy 1.00000
    +Epoch [ 19]: Loss 0.01337
    +Epoch [ 19]: Loss 0.01481
    +Epoch [ 19]: Loss 0.01359
    +Epoch [ 19]: Loss 0.01293
    +Epoch [ 19]: Loss 0.01317
    +Epoch [ 19]: Loss 0.01404
    +Epoch [ 19]: Loss 0.01416
    +Validation: Loss 0.01286 Accuracy 1.00000
    +Validation: Loss 0.01277 Accuracy 1.00000
    +Epoch [ 20]: Loss 0.01286
    +Epoch [ 20]: Loss 0.01335
    +Epoch [ 20]: Loss 0.01259
    +Epoch [ 20]: Loss 0.01343
    +Epoch [ 20]: Loss 0.01294
    +Epoch [ 20]: Loss 0.01124
    +Epoch [ 20]: Loss 0.01124
    +Validation: Loss 0.01194 Accuracy 1.00000
    +Validation: Loss 0.01186 Accuracy 1.00000
    +Epoch [ 21]: Loss 0.01159
    +Epoch [ 21]: Loss 0.01229
    +Epoch [ 21]: Loss 0.01273
    +Epoch [ 21]: Loss 0.01021
    +Epoch [ 21]: Loss 0.01159
    +Epoch [ 21]: Loss 0.01191
    +Epoch [ 21]: Loss 0.01311
    +Validation: Loss 0.01111 Accuracy 1.00000
    +Validation: Loss 0.01104 Accuracy 1.00000
    +Epoch [ 22]: Loss 0.01112
    +Epoch [ 22]: Loss 0.01155
    +Epoch [ 22]: Loss 0.01068
    +Epoch [ 22]: Loss 0.01120
    +Epoch [ 22]: Loss 0.00993
    +Epoch [ 22]: Loss 0.01129
    +Epoch [ 22]: Loss 0.01098
    +Validation: Loss 0.01033 Accuracy 1.00000
    +Validation: Loss 0.01026 Accuracy 1.00000
    +Epoch [ 23]: Loss 0.00950
    +Epoch [ 23]: Loss 0.01102
    +Epoch [ 23]: Loss 0.01060
    +Epoch [ 23]: Loss 0.01058
    +Epoch [ 23]: Loss 0.00987
    +Epoch [ 23]: Loss 0.01006
    +Epoch [ 23]: Loss 0.00747
    +Validation: Loss 0.00952 Accuracy 1.00000
    +Validation: Loss 0.00945 Accuracy 1.00000
    +Epoch [ 24]: Loss 0.00960
    +Epoch [ 24]: Loss 0.00995
    +Epoch [ 24]: Loss 0.00883
    +Epoch [ 24]: Loss 0.00888
    +Epoch [ 24]: Loss 0.00955
    +Epoch [ 24]: Loss 0.00915
    +Epoch [ 24]: Loss 0.00884
    +Validation: Loss 0.00861 Accuracy 1.00000
    +Validation: Loss 0.00856 Accuracy 1.00000
    +Epoch [ 25]: Loss 0.00958
    +Epoch [ 25]: Loss 0.00920
    +Epoch [ 25]: Loss 0.00803
    +Epoch [ 25]: Loss 0.00769
    +Epoch [ 25]: Loss 0.00804
    +Epoch [ 25]: Loss 0.00784
    +Epoch [ 25]: Loss 0.00760
    +Validation: Loss 0.00766 Accuracy 1.00000
    +Validation: Loss 0.00762 Accuracy 1.00000

    Saving the Model

    We can save the model using JLD2 (and any other serialization library of your choice) Note that we transfer the model to CPU before saving. Additionally, we recommend that you don't save the model struct and only save the parameters and states.

    julia
    @save "trained_model.jld2" ps_trained st_trained

    Let's try loading the model

    julia
    @load "trained_model.jld2" ps_trained st_trained
    2-element Vector{Symbol}:
    + :ps_trained
    + :st_trained

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +2 devices:
    +  0: Quadro RTX 5000 (sm_75, 15.227 GiB / 16.000 GiB available)
    +  1: Quadro RTX 5000 (sm_75, 15.549 GiB / 16.000 GiB available)

    This page was generated using Literate.jl.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/tutorials/beginner/4_SimpleChains.html b/previews/PR1023/tutorials/beginner/4_SimpleChains.html new file mode 100644 index 0000000000..a9fd8b7720 --- /dev/null +++ b/previews/PR1023/tutorials/beginner/4_SimpleChains.html @@ -0,0 +1,176 @@ + + + + + + MNIST Classification with SimpleChains | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    MNIST Classification with SimpleChains

    SimpleChains.jl is an excellent framework for training small neural networks. In this tutorial we will demonstrate how to use the same API as Lux.jl to train a model using SimpleChains.jl. We will use the tutorial from SimpleChains.jl as a reference.

    Package Imports

    julia
    using Lux, ADTypes, MLUtils, Optimisers, Zygote, OneHotArrays, Random, Statistics, Printf
    +using MLDatasets: MNIST
    +using SimpleChains: SimpleChains

    Loading MNIST

    julia
    function loadmnist(batchsize, train_split)
    +    # Load MNIST
    +    N = 2000
    +    dataset = MNIST(; split=:train)
    +    imgs = dataset.features[:, :, 1:N]
    +    labels_raw = dataset.targets[1:N]
    +
    +    # Process images into (H, W, C, BS) batches
    +    x_data = Float32.(reshape(imgs, size(imgs, 1), size(imgs, 2), 1, size(imgs, 3)))
    +    y_data = onehotbatch(labels_raw, 0:9)
    +    (x_train, y_train), (x_test, y_test) = splitobs((x_data, y_data); at=train_split)
    +
    +    return (
    +        # Use DataLoader to automatically minibatch and shuffle the data
    +        DataLoader(collect.((x_train, y_train)); batchsize, shuffle=true),
    +        # Don't shuffle the test data
    +        DataLoader(collect.((x_test, y_test)); batchsize, shuffle=false))
    +end
    loadmnist (generic function with 1 method)

    Define the Model

    julia
    lux_model = Chain(Conv((5, 5), 1 => 6, relu), MaxPool((2, 2)),
    +    Conv((5, 5), 6 => 16, relu), MaxPool((2, 2)), FlattenLayer(3),
    +    Chain(Dense(256 => 128, relu), Dense(128 => 84, relu), Dense(84 => 10)))
    Chain(
    +    layer_1 = Conv((5, 5), 1 => 6, relu),  # 156 parameters
    +    layer_2 = MaxPool((2, 2)),
    +    layer_3 = Conv((5, 5), 6 => 16, relu),  # 2_416 parameters
    +    layer_4 = MaxPool((2, 2)),
    +    layer_5 = Lux.FlattenLayer{Static.StaticInt{3}}(static(3)),
    +    layer_6 = Chain(
    +        layer_1 = Dense(256 => 128, relu),  # 32_896 parameters
    +        layer_2 = Dense(128 => 84, relu),  # 10_836 parameters
    +        layer_3 = Dense(84 => 10),      # 850 parameters
    +    ),
    +)         # Total: 47_154 parameters,
    +          #        plus 0 states.

    We now need to convert the lux_model to SimpleChains.jl. We need to do this by defining the ToSimpleChainsAdaptor and providing the input dimensions.

    julia
    adaptor = ToSimpleChainsAdaptor((28, 28, 1))
    +simple_chains_model = adaptor(lux_model)
    SimpleChainsLayer(
    +    Chain(
    +        layer_1 = Conv((5, 5), 1 => 6, relu),  # 156 parameters
    +        layer_2 = MaxPool((2, 2)),
    +        layer_3 = Conv((5, 5), 6 => 16, relu),  # 2_416 parameters
    +        layer_4 = MaxPool((2, 2)),
    +        layer_5 = Lux.FlattenLayer{Static.StaticInt{3}}(static(3)),
    +        layer_6 = Chain(
    +            layer_1 = Dense(256 => 128, relu),  # 32_896 parameters
    +            layer_2 = Dense(128 => 84, relu),  # 10_836 parameters
    +            layer_3 = Dense(84 => 10),  # 850 parameters
    +        ),
    +    ),
    +)         # Total: 47_154 parameters,
    +          #        plus 0 states.

    Helper Functions

    julia
    const loss = CrossEntropyLoss(; logits=Val(true))
    +
    +function accuracy(model, ps, st, dataloader)
    +    total_correct, total = 0, 0
    +    st = Lux.testmode(st)
    +    for (x, y) in dataloader
    +        target_class = onecold(y)
    +        predicted_class = onecold(Array(first(model(x, ps, st))))
    +        total_correct += sum(target_class .== predicted_class)
    +        total += length(target_class)
    +    end
    +    return total_correct / total
    +end
    accuracy (generic function with 1 method)

    Define the Training Loop

    julia
    function train(model; rng=Xoshiro(0), kwargs...)
    +    train_dataloader, test_dataloader = loadmnist(128, 0.9)
    +    ps, st = Lux.setup(rng, model)
    +
    +    train_state = Training.TrainState(model, ps, st, Adam(3.0f-4))
    +
    +    ### Warmup the model
    +    x_proto = randn(rng, Float32, 28, 28, 1, 1)
    +    y_proto = onehotbatch([1], 0:9)
    +    Training.compute_gradients(AutoZygote(), loss, (x_proto, y_proto), train_state)
    +
    +    ### Lets train the model
    +    nepochs = 10
    +    tr_acc, te_acc = 0.0, 0.0
    +    for epoch in 1:nepochs
    +        stime = time()
    +        for (x, y) in train_dataloader
    +            gs, _, _, train_state = Training.single_train_step!(
    +                AutoZygote(), loss, (x, y), train_state)
    +        end
    +        ttime = time() - stime
    +
    +        tr_acc = accuracy(
    +            model, train_state.parameters, train_state.states, train_dataloader) * 100
    +        te_acc = accuracy(
    +            model, train_state.parameters, train_state.states, test_dataloader) * 100
    +
    +        @printf "[%2d/%2d] \t Time %.2fs \t Training Accuracy: %.2f%% \t Test Accuracy: \
    +                 %.2f%%\n" epoch nepochs ttime tr_acc te_acc
    +    end
    +
    +    return tr_acc, te_acc
    +end
    train (generic function with 1 method)

    Finally Training the Model

    First we will train the Lux model

    julia
    tr_acc, te_acc = train(lux_model)
    [ 1/10] 	 Time 106.58s 	 Training Accuracy: 22.44% 	 Test Accuracy: 19.50%
    +[ 2/10] 	 Time 106.61s 	 Training Accuracy: 47.06% 	 Test Accuracy: 45.50%
    +[ 3/10] 	 Time 112.24s 	 Training Accuracy: 61.50% 	 Test Accuracy: 61.00%
    +[ 4/10] 	 Time 115.93s 	 Training Accuracy: 69.89% 	 Test Accuracy: 65.00%
    +[ 5/10] 	 Time 118.22s 	 Training Accuracy: 75.22% 	 Test Accuracy: 74.00%
    +[ 6/10] 	 Time 112.80s 	 Training Accuracy: 78.44% 	 Test Accuracy: 77.50%
    +[ 7/10] 	 Time 108.41s 	 Training Accuracy: 81.22% 	 Test Accuracy: 81.00%
    +[ 8/10] 	 Time 112.49s 	 Training Accuracy: 83.94% 	 Test Accuracy: 80.50%
    +[ 9/10] 	 Time 113.54s 	 Training Accuracy: 85.89% 	 Test Accuracy: 84.50%
    +[10/10] 	 Time 113.99s 	 Training Accuracy: 87.11% 	 Test Accuracy: 84.50%

    Now we will train the SimpleChains model

    julia
    train(simple_chains_model)
    [ 1/10] 	 Time 18.70s 	 Training Accuracy: 29.06% 	 Test Accuracy: 23.50%
    +[ 2/10] 	 Time 17.64s 	 Training Accuracy: 45.83% 	 Test Accuracy: 43.00%
    +[ 3/10] 	 Time 17.64s 	 Training Accuracy: 62.72% 	 Test Accuracy: 57.50%
    +[ 4/10] 	 Time 17.64s 	 Training Accuracy: 65.67% 	 Test Accuracy: 61.50%
    +[ 5/10] 	 Time 17.65s 	 Training Accuracy: 74.72% 	 Test Accuracy: 68.50%
    +[ 6/10] 	 Time 17.63s 	 Training Accuracy: 79.61% 	 Test Accuracy: 77.00%
    +[ 7/10] 	 Time 17.64s 	 Training Accuracy: 81.83% 	 Test Accuracy: 77.00%
    +[ 8/10] 	 Time 17.63s 	 Training Accuracy: 83.94% 	 Test Accuracy: 79.50%
    +[ 9/10] 	 Time 17.65s 	 Training Accuracy: 84.50% 	 Test Accuracy: 84.50%
    +[10/10] 	 Time 17.63s 	 Training Accuracy: 87.78% 	 Test Accuracy: 83.50%

    On my local machine we see a 3-4x speedup when using SimpleChains.jl. The conditions of the server this documentation is being built on is not ideal for CPU benchmarking hence, the speedup may not be as significant and even there might be regressions.

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate

    This page was generated using Literate.jl.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/tutorials/beginner/5_OptimizationIntegration.html b/previews/PR1023/tutorials/beginner/5_OptimizationIntegration.html new file mode 100644 index 0000000000..8fea5b190d --- /dev/null +++ b/previews/PR1023/tutorials/beginner/5_OptimizationIntegration.html @@ -0,0 +1,214 @@ + + + + + + Training Lux Models using Optimization.jl | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Training Lux Models using Optimization.jl

    Lux's native Training.TrainState is a great API for gradient-based learning of neural networks, however, it is geared towards using Optimisers.jl as the backend. However, often times we want to train the neural networks with other optimization methods like BFGS, LBFGS, etc. In this tutorial, we will show how to train Lux models with Optimization.jl that provides a simple unified interface to various optimization methods.

    We will base our tutorial on the minibatching tutorial from the official Optimization.jl docs.

    Neural ODE

    This tutorial uses a Neural ODE, however, we won't discuss that part in this tutorial. Please refer to the Neural ODE tutorial for more information.

    Imports packages

    julia
    using Lux, Optimization, OptimizationOptimisers, OptimizationOptimJL, OrdinaryDiffEqTsit5,
    +      SciMLSensitivity, Random, MLUtils, CairoMakie, ComponentArrays, Printf
    +using LuxCUDA
    +
    +const gdev = gpu_device()
    +const cdev = cpu_device()
    (::MLDataDevices.CPUDevice) (generic function with 5 methods)

    Generate some training data

    julia
    function lotka_volterra(du, u, p, t)
    +    x, y = u
    +    α, β, δ, γ = p
    +    du[1] = α * x - β * x * y
    +    du[2] = -δ * y + γ * x * y
    +    return nothing
    +end
    +
    +u0 = [1.0f0, 1.0f0]
    +
    +datasize = 32
    +tspan = (0.0f0, 2.0f0)
    +
    +const t = range(tspan[1], tspan[2]; length=datasize)
    +true_prob = ODEProblem(lotka_volterra, u0, (tspan[1], tspan[2]), [1.5, 1.0, 3.0, 1.0])
    +const ode_data = Array(solve(true_prob, Tsit5(); saveat=t))
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1])
    +    lines!(ax, t, ode_data[1, :]; label=L"u_1(t)", color=:blue, linestyle=:dot, linewidth=4)
    +    lines!(ax, t, ode_data[2, :]; label=L"u_2(t)", color=:red, linestyle=:dot, linewidth=4)
    +    axislegend(ax; position=:lt)
    +    fig
    +end

    Define the DataLoader

    We will define the DataLoader to batch over the data, additionally we will pipe it through the gdev device to move the data to the GPU on each iteration.

    By default gdev will move all objects to the GPU. But we don't want to move the time vector to the GPU. So we will wrap it in a struct.

    julia
    struct TimeWrapper{T}
    +    t::T
    +end
    +
    +Base.length(t::TimeWrapper) = length(t.t)
    +
    +Base.getindex(t::TimeWrapper, i) = TimeWrapper(t.t[i])
    +
    +dataloader = DataLoader((ode_data, TimeWrapper(t)); batchsize=8) |> gdev
    MLDataDevices.DeviceIterator{MLDataDevices.CUDADevice{Nothing}, MLUtils.DataLoader{Tuple{Matrix{Float32}, Main.var"##225".TimeWrapper{StepRangeLen{Float32, Float64, Float64, Int64}}}, Random._GLOBAL_RNG, Val{nothing}}}(MLDataDevices.CUDADevice{Nothing}(nothing), DataLoader(::Tuple{Matrix{Float32}, Main.var"##225".TimeWrapper{StepRangeLen{Float32, Float64, Float64, Int64}}}, batchsize=8))

    Training the model

    Here we are using different optimization methods for demonstration purposes. This problem is trivial enough to not require this.

    Optimization.jl requires an abstract array as the parameters, hence we will construct a ComponentArray to store the parameters.

    Parameter Estimation vs State Estimation

    Optimization.jl performs state estimation, which effectively means for a function f(u, p), it is trying to compute the optimal u for a given p. This terminology might be confusing to ML practitioners, since in the ML world, we usually do parameter estimation. This effectively means that the u in Optimization.jl corresponds to our model parameters that is being optimized.

    julia
    function train_model(dataloader)
    +    model = Chain(Dense(2, 32, tanh), Dense(32, 32, tanh), Dense(32, 2))
    +    ps, st = Lux.setup(Random.default_rng(), model)
    +
    +    ps_ca = ComponentArray(ps) |> gdev
    +    st = st |> gdev
    +
    +    function callback(state, l)
    +        state.iter % 25 == 1 && @printf "Iteration: %5d, Loss: %.6e\n" state.iter l
    +        return l < 1e-8 ## Terminate if loss is small
    +    end
    +
    +    smodel = StatefulLuxLayer{true}(model, nothing, st)
    +
    +    function loss_adjoint(θ, (u_batch, t_batch))
    +        t_batch = t_batch.t
    +        u0 = u_batch[:, 1]
    +        dudt(u, p, t) = smodel(u, p)
    +        prob = ODEProblem(dudt, u0, (t_batch[1], t_batch[end]), θ)
    +        pred = convert(AbstractArray, solve(prob, Tsit5(); saveat=t_batch))
    +        return MSELoss()(pred, u_batch)
    +    end
    +
    +    # Define the Optimization Function that takes in the optimization state (our parameters)
    +    # and optimization parameters (nothing in our case) and data from the dataloader and
    +    # returns the loss.
    +    opt_func = OptimizationFunction(loss_adjoint, Optimization.AutoZygote())
    +    opt_prob = OptimizationProblem(opt_func, ps_ca, dataloader)
    +
    +    epochs = 25
    +    res_adam = solve(opt_prob, Optimisers.Adam(0.001); callback, epochs)
    +
    +    # Let's finetune a bit with L-BFGS
    +    opt_prob = OptimizationProblem(opt_func, res_adam.u, (gdev(ode_data), TimeWrapper(t)))
    +    res_lbfgs = solve(opt_prob, LBFGS(); callback, maxiters=epochs)
    +
    +    # Now that we have a good fit, let's train it on the entire dataset without
    +    # Minibatching. We need to do this since ODE solves can lead to accumulated errors if
    +    # the model was trained on individual parts (without a data-shooting approach).
    +    opt_prob = remake(opt_prob; u0=res_lbfgs.u)
    +    res = solve(opt_prob, Optimisers.Adam(0.005); maxiters=500, callback)
    +
    +    return StatefulLuxLayer{true}(model, res.u, smodel.st)
    +end
    +
    +trained_model = train_model(dataloader)
    Iteration:     1, Loss: 1.893717e-01
    +Iteration:    26, Loss: 3.556251e-02
    +Iteration:    51, Loss: 1.288165e-01
    +Iteration:    76, Loss: 2.463205e-01
    +Iteration:     1, Loss: 2.282736e-01
    +Iteration:     1, Loss: 2.117264e-02
    +Iteration:    26, Loss: 3.948899e-02
    +Iteration:    51, Loss: 2.352137e-02
    +Iteration:    76, Loss: 2.201421e-02
    +Iteration:   101, Loss: 2.090701e-02
    +Iteration:   126, Loss: 1.977806e-02
    +Iteration:   151, Loss: 1.857129e-02
    +Iteration:   176, Loss: 1.735175e-02
    +Iteration:   201, Loss: 1.615999e-02
    +Iteration:   226, Loss: 1.493911e-02
    +Iteration:   251, Loss: 1.362476e-02
    +Iteration:   276, Loss: 1.221552e-02
    +Iteration:   301, Loss: 1.135817e-02
    +Iteration:   326, Loss: 1.075873e-02
    +Iteration:   351, Loss: 9.290738e-03
    +Iteration:   376, Loss: 8.201186e-03
    +Iteration:   401, Loss: 1.741432e-02
    +Iteration:   426, Loss: 7.620634e-03
    +Iteration:   451, Loss: 6.616297e-03
    +Iteration:   476, Loss: 5.912085e-03

    Plotting the results

    julia
    dudt(u, p, t) = trained_model(u, p)
    +prob = ODEProblem(dudt, gdev(u0), (tspan[1], tspan[2]), trained_model.ps)
    +sol = solve(prob, Tsit5(); saveat=t)
    +pred = convert(AbstractArray, sol) |> cdev
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1])
    +    lines!(ax, t, ode_data[1, :]; label=L"u_1(t)", color=:blue, linestyle=:dot, linewidth=4)
    +    lines!(ax, t, ode_data[2, :]; label=L"u_2(t)", color=:red, linestyle=:dot, linewidth=4)
    +    lines!(ax, t, pred[1, :]; label=L"\hat{u}_1(t)", color=:blue, linewidth=4)
    +    lines!(ax, t, pred[2, :]; label=L"\hat{u}_2(t)", color=:red, linewidth=4)
    +    axislegend(ax; position=:lt)
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.484 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/tutorials/index.html b/previews/PR1023/tutorials/index.html new file mode 100644 index 0000000000..178cc3500d --- /dev/null +++ b/previews/PR1023/tutorials/index.html @@ -0,0 +1,34 @@ + + + + + + Tutorials | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Tutorials

    Beginner Tutorials

    Intermediate Tutorials

    Advanced Tutorials

    Larger Models

    WARNING

    These models are part of the Lux examples, however, these are larger model that cannot be run on CI and aren't frequently tested. If you find a bug in one of these models, please open an issue or PR to fix it.

    Selected 3rd Party Tutorials

    WARNING

    These tutorials are developed by the community and may not be up-to-date with the latest version of Lux.jl. Please refer to the official documentation for the most up-to-date information.

    Please open an issue (ideally both at Lux.jl and at the downstream linked package) if any of them are non-functional and we will try to get them updated.

    TIP

    If you found an amazing tutorial showcasing Lux.jl online, or wrote one yourself, please open an issue or PR to add it to the list!

    + + + + \ No newline at end of file diff --git a/previews/PR1023/tutorials/intermediate/1_NeuralODE.html b/previews/PR1023/tutorials/intermediate/1_NeuralODE.html new file mode 100644 index 0000000000..e76ecc0c0a --- /dev/null +++ b/previews/PR1023/tutorials/intermediate/1_NeuralODE.html @@ -0,0 +1,305 @@ + + + + + + MNIST Classification using Neural ODEs | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    MNIST Classification using Neural ODEs

    To understand Neural ODEs, users should look up these lecture notes. We recommend users to directly use DiffEqFlux.jl, instead of implementing Neural ODEs from scratch.

    Package Imports

    julia
    using Lux, ComponentArrays, SciMLSensitivity, LuxCUDA, Optimisers, OrdinaryDiffEqTsit5,
    +      Random, Statistics, Zygote, OneHotArrays, InteractiveUtils, Printf
    +using MLDatasets: MNIST
    +using MLUtils: DataLoader, splitobs
    +
    +CUDA.allowscalar(false)

    Loading MNIST

    julia
    function loadmnist(batchsize, train_split)
    +    # Load MNIST: Only 1500 for demonstration purposes
    +    N = 1500
    +    dataset = MNIST(; split=:train)
    +    imgs = dataset.features[:, :, 1:N]
    +    labels_raw = dataset.targets[1:N]
    +
    +    # Process images into (H,W,C,BS) batches
    +    x_data = Float32.(reshape(imgs, size(imgs, 1), size(imgs, 2), 1, size(imgs, 3)))
    +    y_data = onehotbatch(labels_raw, 0:9)
    +    (x_train, y_train), (x_test, y_test) = splitobs((x_data, y_data); at=train_split)
    +
    +    return (
    +        # Use DataLoader to automatically minibatch and shuffle the data
    +        DataLoader(collect.((x_train, y_train)); batchsize, shuffle=true),
    +        # Don't shuffle the test data
    +        DataLoader(collect.((x_test, y_test)); batchsize, shuffle=false)
    +    )
    +end
    loadmnist (generic function with 1 method)

    Define the Neural ODE Layer

    First we will use the @compact macro to define the Neural ODE Layer.

    julia
    function NeuralODECompact(
    +        model::Lux.AbstractLuxLayer; solver=Tsit5(), tspan=(0.0f0, 1.0f0), kwargs...)
    +    return @compact(; model, solver, tspan, kwargs...) do x, p
    +        dudt(u, p, t) = vec(model(reshape(u, size(x)), p))
    +        # Note the `p.model` here
    +        prob = ODEProblem(ODEFunction{false}(dudt), vec(x), tspan, p.model)
    +        @return solve(prob, solver; kwargs...)
    +    end
    +end
    NeuralODECompact (generic function with 1 method)

    We recommend using the compact macro for creating custom layers. The below implementation exists mostly for historical reasons when @compact was not part of the stable API. Also, it helps users understand how the layer interface of Lux works.

    The NeuralODE is a ContainerLayer, which stores a model. The parameters and states of the NeuralODE are same as those of the underlying model.

    julia
    struct NeuralODE{M <: Lux.AbstractLuxLayer, So, T, K} <: Lux.AbstractLuxWrapperLayer{:model}
    +    model::M
    +    solver::So
    +    tspan::T
    +    kwargs::K
    +end
    +
    +function NeuralODE(
    +        model::Lux.AbstractLuxLayer; solver=Tsit5(), tspan=(0.0f0, 1.0f0), kwargs...)
    +    return NeuralODE(model, solver, tspan, kwargs)
    +end
    Main.var"##225".NeuralODE

    OrdinaryDiffEq.jl can deal with non-Vector Inputs! However, certain discrete sensitivities like ReverseDiffAdjoint can't handle non-Vector inputs. Hence, we need to convert the input and output of the ODE solver to a Vector.

    julia
    function (n::NeuralODE)(x, ps, st)
    +    function dudt(u, p, t)
    +        u_, st = n.model(reshape(u, size(x)), p, st)
    +        return vec(u_)
    +    end
    +    prob = ODEProblem{false}(ODEFunction{false}(dudt), vec(x), n.tspan, ps)
    +    return solve(prob, n.solver; n.kwargs...), st
    +end
    +
    +@views diffeqsol_to_array(l::Int, x::ODESolution) = reshape(last(x.u), (l, :))
    +@views diffeqsol_to_array(l::Int, x::AbstractMatrix) = reshape(x[:, end], (l, :))
    diffeqsol_to_array (generic function with 2 methods)

    Create and Initialize the Neural ODE Layer

    julia
    function create_model(model_fn=NeuralODE; dev=gpu_device(), use_named_tuple::Bool=false,
    +        sensealg=InterpolatingAdjoint(; autojacvec=ZygoteVJP()))
    +    # Construct the Neural ODE Model
    +    model = Chain(FlattenLayer(),
    +        Dense(784 => 20, tanh),
    +        model_fn(
    +            Chain(Dense(20 => 10, tanh), Dense(10 => 10, tanh), Dense(10 => 20, tanh));
    +            save_everystep=false, reltol=1.0f-3,
    +            abstol=1.0f-3, save_start=false, sensealg),
    +        Base.Fix1(diffeqsol_to_array, 20),
    +        Dense(20 => 10))
    +
    +    rng = Random.default_rng()
    +    Random.seed!(rng, 0)
    +
    +    ps, st = Lux.setup(rng, model)
    +    ps = (use_named_tuple ? ps : ComponentArray(ps)) |> dev
    +    st = st |> dev
    +
    +    return model, ps, st
    +end
    create_model (generic function with 2 methods)

    Define Utility Functions

    julia
    const logitcrossentropy = CrossEntropyLoss(; logits=Val(true))
    +
    +function accuracy(model, ps, st, dataloader)
    +    total_correct, total = 0, 0
    +    st = Lux.testmode(st)
    +    for (x, y) in dataloader
    +        target_class = onecold(y)
    +        predicted_class = onecold(first(model(x, ps, st)))
    +        total_correct += sum(target_class .== predicted_class)
    +        total += length(target_class)
    +    end
    +    return total_correct / total
    +end
    accuracy (generic function with 1 method)

    Training

    julia
    function train(model_function; cpu::Bool=false, kwargs...)
    +    dev = cpu ? cpu_device() : gpu_device()
    +    model, ps, st = create_model(model_function; dev, kwargs...)
    +
    +    # Training
    +    train_dataloader, test_dataloader = loadmnist(128, 0.9) |> dev
    +
    +    tstate = Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    ### Lets train the model
    +    nepochs = 9
    +    for epoch in 1:nepochs
    +        stime = time()
    +        for (x, y) in train_dataloader
    +            _, _, _, tstate = Training.single_train_step!(
    +                AutoZygote(), logitcrossentropy, (x, y), tstate)
    +        end
    +        ttime = time() - stime
    +
    +        tr_acc = accuracy(model, tstate.parameters, tstate.states, train_dataloader) * 100
    +        te_acc = accuracy(model, tstate.parameters, tstate.states, test_dataloader) * 100
    +        @printf "[%d/%d]\tTime %.4fs\tTraining Accuracy: %.5f%%\tTest \
    +                 Accuracy: %.5f%%\n" epoch nepochs ttime tr_acc te_acc
    +    end
    +end
    +
    +train(NeuralODECompact)
    [1/9]	Time 119.4158s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.4958s	Training Accuracy: 58.22222%	Test Accuracy: 57.33333%
    +[3/9]	Time 0.6961s	Training Accuracy: 67.85185%	Test Accuracy: 70.66667%
    +[4/9]	Time 0.4869s	Training Accuracy: 74.29630%	Test Accuracy: 74.66667%
    +[5/9]	Time 0.5064s	Training Accuracy: 76.29630%	Test Accuracy: 76.00000%
    +[6/9]	Time 0.7482s	Training Accuracy: 78.74074%	Test Accuracy: 80.00000%
    +[7/9]	Time 0.4736s	Training Accuracy: 82.22222%	Test Accuracy: 81.33333%
    +[8/9]	Time 0.4883s	Training Accuracy: 83.62963%	Test Accuracy: 83.33333%
    +[9/9]	Time 0.7453s	Training Accuracy: 85.18519%	Test Accuracy: 82.66667%
    julia
    train(NeuralODE)
    [1/9]	Time 36.4249s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.4793s	Training Accuracy: 57.18519%	Test Accuracy: 57.33333%
    +[3/9]	Time 0.6545s	Training Accuracy: 68.37037%	Test Accuracy: 68.00000%
    +[4/9]	Time 0.4797s	Training Accuracy: 73.77778%	Test Accuracy: 75.33333%
    +[5/9]	Time 0.4833s	Training Accuracy: 76.14815%	Test Accuracy: 77.33333%
    +[6/9]	Time 0.7233s	Training Accuracy: 79.48148%	Test Accuracy: 80.66667%
    +[7/9]	Time 0.4913s	Training Accuracy: 81.25926%	Test Accuracy: 80.66667%
    +[8/9]	Time 0.4843s	Training Accuracy: 83.40741%	Test Accuracy: 82.66667%
    +[9/9]	Time 0.7256s	Training Accuracy: 84.81481%	Test Accuracy: 82.00000%

    We can also change the sensealg and train the model! GaussAdjoint allows you to use any arbitrary parameter structure and not just a flat vector (ComponentArray).

    julia
    train(NeuralODE; sensealg=GaussAdjoint(; autojacvec=ZygoteVJP()), use_named_tuple=true)
    [1/9]	Time 42.6019s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.5487s	Training Accuracy: 57.55556%	Test Accuracy: 54.00000%
    +[3/9]	Time 0.4660s	Training Accuracy: 69.85185%	Test Accuracy: 69.33333%
    +[4/9]	Time 0.4833s	Training Accuracy: 72.51852%	Test Accuracy: 74.00000%
    +[5/9]	Time 0.4743s	Training Accuracy: 75.33333%	Test Accuracy: 76.00000%
    +[6/9]	Time 0.4944s	Training Accuracy: 78.88889%	Test Accuracy: 79.33333%
    +[7/9]	Time 0.6809s	Training Accuracy: 81.03704%	Test Accuracy: 80.00000%
    +[8/9]	Time 0.4987s	Training Accuracy: 83.77778%	Test Accuracy: 81.33333%
    +[9/9]	Time 0.5045s	Training Accuracy: 85.25926%	Test Accuracy: 82.66667%

    But remember some AD backends like ReverseDiff is not GPU compatible. For a model this size, you will notice that training time is significantly lower for training on CPU than on GPU.

    julia
    train(NeuralODE; sensealg=InterpolatingAdjoint(; autojacvec=ReverseDiffVJP()), cpu=true)
    [1/9]	Time 96.0630s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 14.0172s	Training Accuracy: 58.74074%	Test Accuracy: 56.66667%
    +[3/9]	Time 13.5410s	Training Accuracy: 69.92593%	Test Accuracy: 71.33333%
    +[4/9]	Time 13.6407s	Training Accuracy: 72.81481%	Test Accuracy: 74.00000%
    +[5/9]	Time 13.4329s	Training Accuracy: 76.37037%	Test Accuracy: 78.66667%
    +[6/9]	Time 12.0878s	Training Accuracy: 79.03704%	Test Accuracy: 80.66667%
    +[7/9]	Time 14.5981s	Training Accuracy: 81.62963%	Test Accuracy: 80.66667%
    +[8/9]	Time 13.6945s	Training Accuracy: 83.33333%	Test Accuracy: 80.00000%
    +[9/9]	Time 10.3098s	Training Accuracy: 85.40741%	Test Accuracy: 82.00000%

    For completeness, let's also test out discrete sensitivities!

    julia
    train(NeuralODE; sensealg=ReverseDiffAdjoint(), cpu=true)
    [1/9]	Time 49.7652s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 21.6687s	Training Accuracy: 58.66667%	Test Accuracy: 57.33333%
    +[3/9]	Time 21.5681s	Training Accuracy: 69.70370%	Test Accuracy: 71.33333%
    +[4/9]	Time 21.3427s	Training Accuracy: 72.74074%	Test Accuracy: 74.00000%
    +[5/9]	Time 23.9941s	Training Accuracy: 76.14815%	Test Accuracy: 78.66667%
    +[6/9]	Time 22.0233s	Training Accuracy: 79.03704%	Test Accuracy: 80.66667%
    +[7/9]	Time 22.4246s	Training Accuracy: 81.55556%	Test Accuracy: 80.66667%
    +[8/9]	Time 23.1968s	Training Accuracy: 83.40741%	Test Accuracy: 80.00000%
    +[9/9]	Time 24.0997s	Training Accuracy: 85.25926%	Test Accuracy: 81.33333%

    Alternate Implementation using Stateful Layer

    Starting v0.5.5, Lux provides a StatefulLuxLayer which can be used to avoid the Boxing of st. Using the @compact API avoids this problem entirely.

    julia
    struct StatefulNeuralODE{M <: Lux.AbstractLuxLayer, So, T, K} <:
    +       Lux.AbstractLuxWrapperLayer{:model}
    +    model::M
    +    solver::So
    +    tspan::T
    +    kwargs::K
    +end
    +
    +function StatefulNeuralODE(
    +        model::Lux.AbstractLuxLayer; solver=Tsit5(), tspan=(0.0f0, 1.0f0), kwargs...)
    +    return StatefulNeuralODE(model, solver, tspan, kwargs)
    +end
    +
    +function (n::StatefulNeuralODE)(x, ps, st)
    +    st_model = StatefulLuxLayer{true}(n.model, ps, st)
    +    dudt(u, p, t) = st_model(u, p)
    +    prob = ODEProblem{false}(ODEFunction{false}(dudt), x, n.tspan, ps)
    +    return solve(prob, n.solver; n.kwargs...), st_model.st
    +end

    Train the new Stateful Neural ODE

    julia
    train(StatefulNeuralODE)
    [1/9]	Time 38.2440s	Training Accuracy: 37.48148%	Test Accuracy: 40.00000%
    +[2/9]	Time 0.4759s	Training Accuracy: 58.22222%	Test Accuracy: 55.33333%
    +[3/9]	Time 0.4745s	Training Accuracy: 68.29630%	Test Accuracy: 68.66667%
    +[4/9]	Time 0.4670s	Training Accuracy: 73.11111%	Test Accuracy: 76.00000%
    +[5/9]	Time 0.5117s	Training Accuracy: 75.92593%	Test Accuracy: 76.66667%
    +[6/9]	Time 0.4779s	Training Accuracy: 78.96296%	Test Accuracy: 80.66667%
    +[7/9]	Time 0.4705s	Training Accuracy: 80.81481%	Test Accuracy: 81.33333%
    +[8/9]	Time 0.4590s	Training Accuracy: 83.25926%	Test Accuracy: 82.66667%
    +[9/9]	Time 0.4555s	Training Accuracy: 84.59259%	Test Accuracy: 82.00000%

    We might not see a significant difference in the training time, but let us investigate the type stabilities of the layers.

    Type Stability

    julia
    model, ps, st = create_model(NeuralODE)
    +
    +model_stateful, ps_stateful, st_stateful = create_model(StatefulNeuralODE)
    +
    +x = gpu_device()(ones(Float32, 28, 28, 1, 3));

    NeuralODE is not type stable due to the boxing of st

    julia
    @code_warntype model(x, ps, st)
    MethodInstance for (::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".NeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing})(::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}, ::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}, ::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}})
    +  from (c::Lux.Chain)(x, ps, st::NamedTuple) @ Lux /var/lib/buildkite-agent/builds/gpuci-13/julialang/lux-dot-jl/src/layers/containers.jl:480
    +Arguments
    +  c::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".NeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}
    +  x::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}
    +  ps::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}
    +  st::Core.Const((layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()), layer_4 = NamedTuple(), layer_5 = NamedTuple()))
    +Body::TUPLE{CUDA.CUARRAY{FLOAT32, 2, CUDA.DEVICEMEMORY}, NAMEDTUPLE{(:LAYER_1, :LAYER_2, :LAYER_3, :LAYER_4, :LAYER_5), <:TUPLE{@NAMEDTUPLE{}, @NAMEDTUPLE{}, ANY, @NAMEDTUPLE{}, @NAMEDTUPLE{}}}}
    +1 ─ %1 = Base.getproperty(c, :layers)::@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".NeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}
    +│   %2 = Lux.applychain(%1, x, ps, st)::TUPLE{CUDA.CUARRAY{FLOAT32, 2, CUDA.DEVICEMEMORY}, NAMEDTUPLE{(:LAYER_1, :LAYER_2, :LAYER_3, :LAYER_4, :LAYER_5), <:TUPLE{@NAMEDTUPLE{}, @NAMEDTUPLE{}, ANY, @NAMEDTUPLE{}, @NAMEDTUPLE{}}}}
    +└──      return %2

    We avoid the problem entirely by using StatefulNeuralODE

    julia
    @code_warntype model_stateful(x, ps_stateful, st_stateful)
    MethodInstance for (::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".StatefulNeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing})(::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}, ::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}, ::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}})
    +  from (c::Lux.Chain)(x, ps, st::NamedTuple) @ Lux /var/lib/buildkite-agent/builds/gpuci-13/julialang/lux-dot-jl/src/layers/containers.jl:480
    +Arguments
    +  c::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".StatefulNeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}
    +  x::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}
    +  ps::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}
    +  st::Core.Const((layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = (layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple()), layer_4 = NamedTuple(), layer_5 = NamedTuple()))
    +Body::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +1 ─ %1 = Base.getproperty(c, :layers)::@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Main.var"##225".StatefulNeuralODE{Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}, OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, Tuple{Float32, Float32}, Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}
    +│   %2 = Lux.applychain(%1, x, ps, st)::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +└──      return %2

    Note, that we still recommend using this layer internally and not exposing this as the default API to the users.

    Finally checking the compact model

    julia
    model_compact, ps_compact, st_compact = create_model(NeuralODECompact)
    +
    +@code_warntype model_compact(x, ps_compact, st_compact)
    MethodInstance for (::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.CompactLuxLayer{:₋₋₋no_special_dispatch₋₋₋, Main.var"##225".var"#2#3", Nothing, @NamedTuple{model::Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Lux.CompactMacroImpl.ValueStorage{@NamedTuple{}, @NamedTuple{solver::Returns{OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}}, tspan::Returns{Tuple{Float32, Float32}}}}, Tuple{Tuple{Symbol}, Tuple{Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing})(::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}, ::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(model = ViewAxis(1:540, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))),)), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}, ::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}})
    +  from (c::Lux.Chain)(x, ps, st::NamedTuple) @ Lux /var/lib/buildkite-agent/builds/gpuci-13/julialang/lux-dot-jl/src/layers/containers.jl:480
    +Arguments
    +  c::Lux.Chain{@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.CompactLuxLayer{:₋₋₋no_special_dispatch₋₋₋, Main.var"##225".var"#2#3", Nothing, @NamedTuple{model::Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Lux.CompactMacroImpl.ValueStorage{@NamedTuple{}, @NamedTuple{solver::Returns{OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}}, tspan::Returns{Tuple{Float32, Float32}}}}, Tuple{Tuple{Symbol}, Tuple{Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}
    +  x::CUDA.CuArray{Float32, 4, CUDA.DeviceMemory}
    +  ps::ComponentArrays.ComponentVector{Float32, CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:15700, Axis(weight = ViewAxis(1:15680, ShapedAxis((20, 784))), bias = 15681:15700)), layer_3 = ViewAxis(15701:16240, Axis(model = ViewAxis(1:540, Axis(layer_1 = ViewAxis(1:210, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)), layer_2 = ViewAxis(211:320, Axis(weight = ViewAxis(1:100, ShapedAxis((10, 10))), bias = 101:110)), layer_3 = ViewAxis(321:540, Axis(weight = ViewAxis(1:200, ShapedAxis((20, 10))), bias = 201:220)))),)), layer_4 = 16241:16240, layer_5 = ViewAxis(16241:16450, Axis(weight = ViewAxis(1:200, ShapedAxis((10, 20))), bias = 201:210)))}}}
    +  st::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}
    +Body::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +1 ─ %1 = Base.getproperty(c, :layers)::@NamedTuple{layer_1::Lux.FlattenLayer{Nothing}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.CompactLuxLayer{:₋₋₋no_special_dispatch₋₋₋, Main.var"##225".var"#2#3", Nothing, @NamedTuple{model::Lux.Chain{@NamedTuple{layer_1::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_2::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}, layer_3::Lux.Dense{typeof(tanh), Int64, Int64, Nothing, Nothing, Static.True}}, Nothing}}, Lux.CompactMacroImpl.ValueStorage{@NamedTuple{}, @NamedTuple{solver::Returns{OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}}, tspan::Returns{Tuple{Float32, Float32}}}}, Tuple{Tuple{Symbol}, Tuple{Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}}, layer_4::Lux.WrappedFunction{Base.Fix1{typeof(Main.var"##225".diffeqsol_to_array), Int64}}, layer_5::Lux.Dense{typeof(identity), Int64, Int64, Nothing, Nothing, Static.True}}
    +│   %2 = Lux.applychain(%1, x, ps, st)::Tuple{CUDA.CuArray{Float32, 2, CUDA.DeviceMemory}, @NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{model::@NamedTuple{layer_1::@NamedTuple{}, layer_2::@NamedTuple{}, layer_3::@NamedTuple{}}, solver::OrdinaryDiffEqTsit5.Tsit5{typeof(OrdinaryDiffEqCore.trivial_limiter!), typeof(OrdinaryDiffEqCore.trivial_limiter!), Static.False}, tspan::Tuple{Float32, Float32}, ₋₋₋kwargs₋₋₋::@NamedTuple{kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, @NamedTuple{save_everystep::Bool, reltol::Float32, abstol::Float32, save_start::Bool, sensealg::SciMLSensitivity.InterpolatingAdjoint{0, true, Val{:central}, SciMLSensitivity.ZygoteVJP}}}}}, layer_4::@NamedTuple{}, layer_5::@NamedTuple{}}}
    +└──      return %2

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 3.889 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/tutorials/intermediate/2_BayesianNN.html b/previews/PR1023/tutorials/intermediate/2_BayesianNN.html new file mode 100644 index 0000000000..68270158c1 --- /dev/null +++ b/previews/PR1023/tutorials/intermediate/2_BayesianNN.html @@ -0,0 +1,239 @@ + + + + + + Bayesian Neural Network | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Bayesian Neural Network

    We borrow this tutorial from the official Turing Docs. We will show how the explicit parameterization of Lux enables first-class composability with packages which expect flattened out parameter vectors.

    Note: The tutorial in the official Turing docs is now using Lux instead of Flux.

    We will use Turing.jl with Lux.jl to implement implementing a classification algorithm. Lets start by importing the relevant libraries.

    julia
    # Import libraries
    +
    +using Lux, Turing, CairoMakie, Random, Tracker, Functors, LinearAlgebra
    +
    +# Sampling progress
    +Turing.setprogress!(true);
    [ Info: [Turing]: progress logging is enabled globally
    +[ Info: [AdvancedVI]: global PROGRESS is set as true

    Generating data

    Our goal here is to use a Bayesian neural network to classify points in an artificial dataset. The code below generates data points arranged in a box-like pattern and displays a graph of the dataset we'll be working with.

    julia
    # Number of points to generate
    +N = 80
    +M = round(Int, N / 4)
    +rng = Random.default_rng()
    +Random.seed!(rng, 1234)
    +
    +# Generate artificial data
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +xt1s = Array([[x1s[i] + 0.5f0; x2s[i] + 0.5f0] for i in 1:M])
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +append!(xt1s, Array([[x1s[i] - 5.0f0; x2s[i] - 5.0f0] for i in 1:M]))
    +
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +xt0s = Array([[x1s[i] + 0.5f0; x2s[i] - 5.0f0] for i in 1:M])
    +x1s = rand(rng, Float32, M) * 4.5f0;
    +x2s = rand(rng, Float32, M) * 4.5f0;
    +append!(xt0s, Array([[x1s[i] - 5.0f0; x2s[i] + 0.5f0] for i in 1:M]))
    +
    +# Store all the data for later
    +xs = [xt1s; xt0s]
    +ts = [ones(2 * M); zeros(2 * M)]
    +
    +# Plot data points
    +
    +function plot_data()
    +    x1 = first.(xt1s)
    +    y1 = last.(xt1s)
    +    x2 = first.(xt0s)
    +    y2 = last.(xt0s)
    +
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +
    +    scatter!(ax, x1, y1; markersize=16, color=:red, strokecolor=:black, strokewidth=2)
    +    scatter!(ax, x2, y2; markersize=16, color=:blue, strokecolor=:black, strokewidth=2)
    +
    +    return fig
    +end
    +
    +plot_data()

    Building the Neural Network

    The next step is to define a feedforward neural network where we express our parameters as distributions, and not single points as with traditional neural networks. For this we will use Dense to define liner layers and compose them via Chain, both are neural network primitives from Lux. The network nn we will create will have two hidden layers with tanh activations and one output layer with sigmoid activation, as shown below.

    The nn is an instance that acts as a function and can take data, parameters and current state as inputs and output predictions. We will define distributions on the neural network parameters.

    julia
    # Construct a neural network using Lux
    +nn = Chain(Dense(2 => 3, tanh), Dense(3 => 2, tanh), Dense(2 => 1, sigmoid))
    +
    +# Initialize the model weights and state
    +ps, st = Lux.setup(rng, nn)
    +
    +Lux.parameterlength(nn) # number of parameters in NN
    20

    The probabilistic model specification below creates a parameters variable, which has IID normal variables. The parameters represents all parameters of our neural net (weights and biases).

    julia
    # Create a regularization term and a Gaussian prior variance term.
    +alpha = 0.09
    +sig = sqrt(1.0 / alpha)
    3.3333333333333335

    Construct named tuple from a sampled parameter vector. We could also use ComponentArrays here and simply broadcast to avoid doing this. But let's do it this way to avoid dependencies.

    julia
    function vector_to_parameters(ps_new::AbstractVector, ps::NamedTuple)
    +    @assert length(ps_new) == Lux.parameterlength(ps)
    +    i = 1
    +    function get_ps(x)
    +        z = reshape(view(ps_new, i:(i + length(x) - 1)), size(x))
    +        i += length(x)
    +        return z
    +    end
    +    return fmap(get_ps, ps)
    +end
    vector_to_parameters (generic function with 1 method)

    To interface with external libraries it is often desirable to use the StatefulLuxLayer to automatically handle the neural network states.

    julia
    const model = StatefulLuxLayer{true}(nn, nothing, st)
    +
    +# Specify the probabilistic model.
    +@model function bayes_nn(xs, ts)
    +    # Sample the parameters
    +    nparameters = Lux.parameterlength(nn)
    +    parameters ~ MvNormal(zeros(nparameters), Diagonal(abs2.(sig .* ones(nparameters))))
    +
    +    # Forward NN to make predictions
    +    preds = Lux.apply(model, xs, vector_to_parameters(parameters, ps))
    +
    +    # Observe each prediction.
    +    for i in eachindex(ts)
    +        ts[i] ~ Bernoulli(preds[i])
    +    end
    +end
    bayes_nn (generic function with 2 methods)

    Inference can now be performed by calling sample. We use the HMC sampler here.

    julia
    # Perform inference.
    +N = 5000
    +ch = sample(bayes_nn(reduce(hcat, xs), ts), HMC(0.05, 4; adtype=AutoTracker()), N)
    Chains MCMC chain (5000×30×1 Array{Float64, 3}):
    +
    +Iterations        = 1:1:5000
    +Number of chains  = 1
    +Samples per chain = 5000
    +Wall duration     = 21.31 seconds
    +Compute duration  = 21.31 seconds
    +parameters        = parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13], parameters[14], parameters[15], parameters[16], parameters[17], parameters[18], parameters[19], parameters[20]
    +internals         = lp, n_steps, is_accept, acceptance_rate, log_density, hamiltonian_energy, hamiltonian_energy_error, numerical_error, step_size, nom_step_size
    +
    +Summary Statistics
    +      parameters      mean       std      mcse   ess_bulk   ess_tail      rhat   ess_per_sec
    +          Symbol   Float64   Float64   Float64    Float64    Float64   Float64       Float64
    +
    +   parameters[1]    2.0965    4.4644    1.3270    12.0887    23.0787    1.3335        0.5673
    +   parameters[2]    0.0843    0.3952    0.0510    79.9413    35.2287    1.0240        3.7517
    +   parameters[3]    4.9916    1.9230    0.4456    19.3935    81.5852    1.2170        0.9102
    +   parameters[4]    0.3356    2.3096    0.6117    14.3653    24.1405    1.2067        0.6742
    +   parameters[5]    5.0569    2.3192    0.6141    15.0672    34.9402    1.1058        0.7071
    +   parameters[6]    0.7127    1.2191    0.2991    21.7200    21.7891    1.1550        1.0193
    +   parameters[7]    1.7149    3.8638    1.1143    12.4420    21.7560    1.1439        0.5839
    +   parameters[8]    0.3690    1.2835    0.2555    26.1914    29.6846    1.0246        1.2292
    +   parameters[9]   -0.4968    2.2271    0.6133    14.1406    24.5983    1.2648        0.6636
    +  parameters[10]    0.0842    2.1828    0.5840    14.0865    21.8689    1.1832        0.6611
    +  parameters[11]   -1.0288    1.5663    0.3628    18.3294    27.7789    1.0536        0.8602
    +  parameters[12]   -4.1763    1.7426    0.3705    23.0782    28.1565    1.0633        1.0831
    +  parameters[13]    3.1846    1.4791    0.3401    19.4472    53.5564    1.0444        0.9127
    +  parameters[14]    2.7199    1.9547    0.5178    14.3490    46.8984    1.3048        0.6734
    +  parameters[15]   -2.0613    1.4937    0.3727    16.3035    39.2852    1.0885        0.7651
    +  parameters[16]   -2.9853    1.4059    0.2557    31.3669    31.3956    1.0012        1.4721
    +  parameters[17]   -2.4061    2.6897    0.7370    15.6752    20.0204    1.0733        0.7356
    +  parameters[18]   -5.3040    1.1943    0.1791    44.9414    68.7121    1.0867        2.1091
    +  parameters[19]   -5.1706    2.2709    0.5991    17.6788    18.3886    1.0540        0.8297
    +  parameters[20]   -5.1303    1.3008    0.2366    30.4880    60.9517    1.0163        1.4308
    +
    +Quantiles
    +      parameters      2.5%     25.0%     50.0%     75.0%     97.5%
    +          Symbol   Float64   Float64   Float64   Float64   Float64
    +
    +   parameters[1]   -7.7024    0.5794    2.9500    5.0242    8.8277
    +   parameters[2]   -0.6189   -0.1406    0.0435    0.2877    1.0813
    +   parameters[3]    1.2261    3.6852    4.9109    6.5386    8.2717
    +   parameters[4]   -3.9045   -0.9307    0.1458    1.1265    5.7834
    +   parameters[5]    1.5809    3.2130    4.8534    6.4543   10.0149
    +   parameters[6]   -0.8100   -0.0584    0.3864    1.1121    4.4225
    +   parameters[7]   -5.8787   -0.8376    1.2050    4.7533    8.9694
    +   parameters[8]   -2.3155   -0.3960    0.2950    1.1550    2.9515
    +   parameters[9]   -5.8990   -1.7942   -0.1511    1.0876    2.9460
    +  parameters[10]   -4.7703   -1.0568    0.0534    1.4673    4.2833
    +  parameters[11]   -4.5806   -1.9640   -0.8771    0.0209    1.7384
    +  parameters[12]   -8.2243   -5.3092   -4.0546   -2.7977   -1.3694
    +  parameters[13]    0.8904    2.0618    2.9913    4.0971    6.5956
    +  parameters[14]   -0.9166    1.5821    2.5812    3.9071    6.6712
    +  parameters[15]   -4.9708   -3.1310   -2.0122   -1.0256    0.7273
    +  parameters[16]   -6.2647   -3.8094   -2.8050   -1.8812   -0.8946
    +  parameters[17]   -6.2695   -3.8672   -2.6943   -1.7352    5.5834
    +  parameters[18]   -7.6970   -6.0973   -5.2714   -4.5053   -2.9747
    +  parameters[19]   -8.3524   -6.4017   -5.5673   -4.6134    2.1958
    +  parameters[20]   -7.6214   -5.9847   -5.1652   -4.2672   -2.6349

    Now we extract the parameter samples from the sampled chain as θ (this is of size 5000 x 20 where 5000 is the number of iterations and 20 is the number of parameters). We'll use these primarily to determine how good our model's classifier is.

    julia
    # Extract all weight and bias parameters.
    +θ = MCMCChains.group(ch, :parameters).value;

    Prediction Visualization

    julia
    # A helper to run the nn through data `x` using parameters `θ`
    +nn_forward(x, θ) = model(x, vector_to_parameters(θ, ps))
    +
    +# Plot the data we have.
    +fig = plot_data()
    +
    +# Find the index that provided the highest log posterior in the chain.
    +_, i = findmax(ch[:lp])
    +
    +# Extract the max row value from i.
    +i = i.I[1]
    +
    +# Plot the posterior distribution with a contour plot
    +x1_range = collect(range(-6; stop=6, length=25))
    +x2_range = collect(range(-6; stop=6, length=25))
    +Z = [nn_forward([x1, x2], θ[i, :])[1] for x1 in x1_range, x2 in x2_range]
    +contour!(x1_range, x2_range, Z; linewidth=3, colormap=:seaborn_bright)
    +fig

    The contour plot above shows that the MAP method is not too bad at classifying our data. Now we can visualize our predictions.

    p(x~|X,α)=θp(x~|θ)p(θ|X,α)θp(θ|X,α)fθ(x~)

    The nn_predict function takes the average predicted value from a network parameterized by weights drawn from the MCMC chain.

    julia
    # Return the average predicted value across multiple weights.
    +nn_predict(x, θ, num) = mean([first(nn_forward(x, view(θ, i, :))) for i in 1:10:num])
    nn_predict (generic function with 1 method)

    Next, we use the nn_predict function to predict the value at a sample of points where the x1 and x2 coordinates range between -6 and 6. As we can see below, we still have a satisfactory fit to our data, and more importantly, we can also see where the neural network is uncertain about its predictions much easier–-those regions between cluster boundaries.

    Plot the average prediction.

    julia
    fig = plot_data()
    +
    +n_end = 1500
    +x1_range = collect(range(-6; stop=6, length=25))
    +x2_range = collect(range(-6; stop=6, length=25))
    +Z = [nn_predict([x1, x2], θ, n_end)[1] for x1 in x1_range, x2 in x2_range]
    +contour!(x1_range, x2_range, Z; linewidth=3, colormap=:seaborn_bright)
    +fig

    Suppose we are interested in how the predictive power of our Bayesian neural network evolved between samples. In that case, the following graph displays an animation of the contour plot generated from the network weights in samples 1 to 5,000.

    julia
    fig = plot_data()
    +Z = [first(nn_forward([x1, x2], θ[1, :])) for x1 in x1_range, x2 in x2_range]
    +c = contour!(x1_range, x2_range, Z; linewidth=3, colormap=:seaborn_bright)
    +record(fig, "results.gif", 1:250:size(θ, 1)) do i
    +    fig.current_axis[].title = "Iteration: $i"
    +    Z = [first(nn_forward([x1, x2], θ[i, :])) for x1 in x1_range, x2 in x2_range]
    +    c[3] = Z
    +    return fig
    +end
    "results.gif"

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 128 × AMD EPYC 7502 32-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 16 default, 0 interactive, 8 GC (on 16 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 16
    +  JULIA_DEPOT_PATH = /cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 16
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate

    This page was generated using Literate.jl.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/tutorials/intermediate/3_HyperNet.html b/previews/PR1023/tutorials/intermediate/3_HyperNet.html new file mode 100644 index 0000000000..28214b66a6 --- /dev/null +++ b/previews/PR1023/tutorials/intermediate/3_HyperNet.html @@ -0,0 +1,305 @@ + + + + + + Training a HyperNetwork on MNIST and FashionMNIST | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Training a HyperNetwork on MNIST and FashionMNIST

    Package Imports

    julia
    using Lux, ADTypes, ComponentArrays, LuxCUDA, MLDatasets, MLUtils, OneHotArrays, Optimisers,
    +      Printf, Random, Setfield, Statistics, Zygote
    +
    +CUDA.allowscalar(false)

    Loading Datasets

    julia
    function load_dataset(::Type{dset}, n_train::Int, n_eval::Int, batchsize::Int) where {dset}
    +    imgs, labels = dset(:train)[1:n_train]
    +    x_train, y_train = reshape(imgs, 28, 28, 1, n_train), onehotbatch(labels, 0:9)
    +
    +    imgs, labels = dset(:test)[1:n_eval]
    +    x_test, y_test = reshape(imgs, 28, 28, 1, n_eval), onehotbatch(labels, 0:9)
    +
    +    return (
    +        DataLoader((x_train, y_train); batchsize=min(batchsize, n_train), shuffle=true),
    +        DataLoader((x_test, y_test); batchsize=min(batchsize, n_eval), shuffle=false))
    +end
    +
    +function load_datasets(n_train=1024, n_eval=32, batchsize=256)
    +    return load_dataset.((MNIST, FashionMNIST), n_train, n_eval, batchsize)
    +end
    load_datasets (generic function with 4 methods)

    Implement a HyperNet Layer

    julia
    function HyperNet(
    +        weight_generator::Lux.AbstractLuxLayer, core_network::Lux.AbstractLuxLayer)
    +    ca_axes = Lux.initialparameters(Random.default_rng(), core_network) |>
    +              ComponentArray |>
    +              getaxes
    +    return @compact(; ca_axes, weight_generator, core_network, dispatch=:HyperNet) do (x, y)
    +        # Generate the weights
    +        ps_new = ComponentArray(vec(weight_generator(x)), ca_axes)
    +        @return core_network(y, ps_new)
    +    end
    +end
    HyperNet (generic function with 1 method)

    Defining functions on the CompactLuxLayer requires some understanding of how the layer is structured, as such we don't recommend doing it unless you are familiar with the internals. In this case, we simply write it to ignore the initialization of the core_network parameters.

    julia
    function Lux.initialparameters(rng::AbstractRNG, hn::CompactLuxLayer{:HyperNet})
    +    return (; weight_generator=Lux.initialparameters(rng, hn.layers.weight_generator),)
    +end

    Create and Initialize the HyperNet

    julia
    function create_model()
    +    # Doesn't need to be a MLP can have any Lux Layer
    +    core_network = Chain(FlattenLayer(), Dense(784, 256, relu), Dense(256, 10))
    +    weight_generator = Chain(Embedding(2 => 32), Dense(32, 64, relu),
    +        Dense(64, Lux.parameterlength(core_network)))
    +
    +    model = HyperNet(weight_generator, core_network)
    +    return model
    +end
    create_model (generic function with 1 method)

    Define Utility Functions

    julia
    const loss = CrossEntropyLoss(; logits=Val(true))
    +
    +function accuracy(model, ps, st, dataloader, data_idx)
    +    total_correct, total = 0, 0
    +    st = Lux.testmode(st)
    +    for (x, y) in dataloader
    +        target_class = onecold(y)
    +        predicted_class = onecold(first(model((data_idx, x), ps, st)))
    +        total_correct += sum(target_class .== predicted_class)
    +        total += length(target_class)
    +    end
    +    return total_correct / total
    +end
    accuracy (generic function with 1 method)

    Training

    julia
    function train()
    +    model = create_model()
    +    dataloaders = load_datasets()
    +
    +    dev = gpu_device()
    +    rng = Xoshiro(0)
    +    ps, st = Lux.setup(rng, model) |> dev
    +
    +    train_state = Training.TrainState(model, ps, st, Adam(0.001f0))
    +
    +    ### Lets train the model
    +    nepochs = 50
    +    for epoch in 1:nepochs, data_idx in 1:2
    +        train_dataloader, test_dataloader = dataloaders[data_idx] .|> dev
    +
    +        stime = time()
    +        for (x, y) in train_dataloader
    +            (_, _, _, train_state) = Training.single_train_step!(
    +                AutoZygote(), loss, ((data_idx, x), y), train_state)
    +        end
    +        ttime = time() - stime
    +
    +        train_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, train_dataloader, data_idx) * 100;
    +            digits=2)
    +        test_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, test_dataloader, data_idx) * 100;
    +            digits=2)
    +
    +        data_name = data_idx == 1 ? "MNIST" : "FashionMNIST"
    +
    +        @printf "[%3d/%3d]\t%12s\tTime %3.5fs\tTraining Accuracy: %3.2f%%\tTest \
    +                 Accuracy: %3.2f%%\n" epoch nepochs data_name ttime train_acc test_acc
    +    end
    +
    +    println()
    +
    +    test_acc_list = [0.0, 0.0]
    +    for data_idx in 1:2
    +        train_dataloader, test_dataloader = dataloaders[data_idx] .|> dev
    +        train_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, train_dataloader, data_idx) * 100;
    +            digits=2)
    +        test_acc = round(
    +            accuracy(model, train_state.parameters,
    +                train_state.states, test_dataloader, data_idx) * 100;
    +            digits=2)
    +
    +        data_name = data_idx == 1 ? "MNIST" : "FashionMNIST"
    +
    +        @printf "[FINAL]\t%12s\tTraining Accuracy: %3.2f%%\tTest Accuracy: \
    +                 %3.2f%%\n" data_name train_acc test_acc
    +        test_acc_list[data_idx] = test_acc
    +    end
    +    return test_acc_list
    +end
    +
    +test_acc_list = train()
    [  1/ 50]	       MNIST	Time 70.85048s	Training Accuracy: 61.23%	Test Accuracy: 56.25%
    +[  1/ 50]	FashionMNIST	Time 0.02819s	Training Accuracy: 43.26%	Test Accuracy: 37.50%
    +[  2/ 50]	       MNIST	Time 0.02797s	Training Accuracy: 71.19%	Test Accuracy: 68.75%
    +[  2/ 50]	FashionMNIST	Time 0.02918s	Training Accuracy: 56.25%	Test Accuracy: 46.88%
    +[  3/ 50]	       MNIST	Time 0.02907s	Training Accuracy: 79.39%	Test Accuracy: 71.88%
    +[  3/ 50]	FashionMNIST	Time 0.02807s	Training Accuracy: 59.67%	Test Accuracy: 53.12%
    +[  4/ 50]	       MNIST	Time 0.02442s	Training Accuracy: 78.71%	Test Accuracy: 68.75%
    +[  4/ 50]	FashionMNIST	Time 0.02106s	Training Accuracy: 68.36%	Test Accuracy: 65.62%
    +[  5/ 50]	       MNIST	Time 0.02221s	Training Accuracy: 83.79%	Test Accuracy: 75.00%
    +[  5/ 50]	FashionMNIST	Time 0.02173s	Training Accuracy: 71.78%	Test Accuracy: 62.50%
    +[  6/ 50]	       MNIST	Time 0.02186s	Training Accuracy: 88.67%	Test Accuracy: 75.00%
    +[  6/ 50]	FashionMNIST	Time 0.02362s	Training Accuracy: 72.95%	Test Accuracy: 56.25%
    +[  7/ 50]	       MNIST	Time 0.02382s	Training Accuracy: 90.92%	Test Accuracy: 78.12%
    +[  7/ 50]	FashionMNIST	Time 0.02322s	Training Accuracy: 80.27%	Test Accuracy: 68.75%
    +[  8/ 50]	       MNIST	Time 0.03652s	Training Accuracy: 90.82%	Test Accuracy: 78.12%
    +[  8/ 50]	FashionMNIST	Time 0.02083s	Training Accuracy: 76.46%	Test Accuracy: 68.75%
    +[  9/ 50]	       MNIST	Time 0.02124s	Training Accuracy: 94.63%	Test Accuracy: 81.25%
    +[  9/ 50]	FashionMNIST	Time 0.02080s	Training Accuracy: 74.71%	Test Accuracy: 65.62%
    +[ 10/ 50]	       MNIST	Time 0.02075s	Training Accuracy: 94.63%	Test Accuracy: 81.25%
    +[ 10/ 50]	FashionMNIST	Time 0.02080s	Training Accuracy: 77.34%	Test Accuracy: 62.50%
    +[ 11/ 50]	       MNIST	Time 0.02030s	Training Accuracy: 96.29%	Test Accuracy: 78.12%
    +[ 11/ 50]	FashionMNIST	Time 0.02048s	Training Accuracy: 82.13%	Test Accuracy: 78.12%
    +[ 12/ 50]	       MNIST	Time 0.02080s	Training Accuracy: 97.95%	Test Accuracy: 78.12%
    +[ 12/ 50]	FashionMNIST	Time 0.02626s	Training Accuracy: 81.84%	Test Accuracy: 78.12%
    +[ 13/ 50]	       MNIST	Time 0.02091s	Training Accuracy: 98.44%	Test Accuracy: 84.38%
    +[ 13/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 84.08%	Test Accuracy: 71.88%
    +[ 14/ 50]	       MNIST	Time 0.02098s	Training Accuracy: 98.93%	Test Accuracy: 81.25%
    +[ 14/ 50]	FashionMNIST	Time 0.02068s	Training Accuracy: 85.55%	Test Accuracy: 65.62%
    +[ 15/ 50]	       MNIST	Time 0.02067s	Training Accuracy: 99.22%	Test Accuracy: 84.38%
    +[ 15/ 50]	FashionMNIST	Time 0.02068s	Training Accuracy: 86.13%	Test Accuracy: 68.75%
    +[ 16/ 50]	       MNIST	Time 0.02060s	Training Accuracy: 99.51%	Test Accuracy: 81.25%
    +[ 16/ 50]	FashionMNIST	Time 0.02051s	Training Accuracy: 86.13%	Test Accuracy: 65.62%
    +[ 17/ 50]	       MNIST	Time 0.02531s	Training Accuracy: 99.61%	Test Accuracy: 81.25%
    +[ 17/ 50]	FashionMNIST	Time 0.02054s	Training Accuracy: 87.11%	Test Accuracy: 71.88%
    +[ 18/ 50]	       MNIST	Time 0.02092s	Training Accuracy: 99.80%	Test Accuracy: 81.25%
    +[ 18/ 50]	FashionMNIST	Time 0.02098s	Training Accuracy: 88.28%	Test Accuracy: 75.00%
    +[ 19/ 50]	       MNIST	Time 0.02228s	Training Accuracy: 99.80%	Test Accuracy: 81.25%
    +[ 19/ 50]	FashionMNIST	Time 0.02067s	Training Accuracy: 89.16%	Test Accuracy: 71.88%
    +[ 20/ 50]	       MNIST	Time 0.02038s	Training Accuracy: 99.90%	Test Accuracy: 81.25%
    +[ 20/ 50]	FashionMNIST	Time 0.02079s	Training Accuracy: 89.26%	Test Accuracy: 75.00%
    +[ 21/ 50]	       MNIST	Time 0.02039s	Training Accuracy: 99.90%	Test Accuracy: 81.25%
    +[ 21/ 50]	FashionMNIST	Time 0.02023s	Training Accuracy: 89.65%	Test Accuracy: 75.00%
    +[ 22/ 50]	       MNIST	Time 0.02084s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 22/ 50]	FashionMNIST	Time 0.02039s	Training Accuracy: 89.94%	Test Accuracy: 75.00%
    +[ 23/ 50]	       MNIST	Time 0.02139s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 23/ 50]	FashionMNIST	Time 0.02072s	Training Accuracy: 90.43%	Test Accuracy: 71.88%
    +[ 24/ 50]	       MNIST	Time 0.02055s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 24/ 50]	FashionMNIST	Time 0.02085s	Training Accuracy: 90.72%	Test Accuracy: 71.88%
    +[ 25/ 50]	       MNIST	Time 0.02080s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 25/ 50]	FashionMNIST	Time 0.02870s	Training Accuracy: 92.29%	Test Accuracy: 75.00%
    +[ 26/ 50]	       MNIST	Time 0.02078s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 26/ 50]	FashionMNIST	Time 0.02083s	Training Accuracy: 92.38%	Test Accuracy: 71.88%
    +[ 27/ 50]	       MNIST	Time 0.02093s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 27/ 50]	FashionMNIST	Time 0.02037s	Training Accuracy: 91.80%	Test Accuracy: 75.00%
    +[ 28/ 50]	       MNIST	Time 0.02083s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 28/ 50]	FashionMNIST	Time 0.02035s	Training Accuracy: 92.97%	Test Accuracy: 68.75%
    +[ 29/ 50]	       MNIST	Time 0.02075s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 29/ 50]	FashionMNIST	Time 0.02075s	Training Accuracy: 93.16%	Test Accuracy: 71.88%
    +[ 30/ 50]	       MNIST	Time 0.02654s	Training Accuracy: 100.00%	Test Accuracy: 81.25%
    +[ 30/ 50]	FashionMNIST	Time 0.02034s	Training Accuracy: 92.09%	Test Accuracy: 71.88%
    +[ 31/ 50]	       MNIST	Time 0.02107s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 31/ 50]	FashionMNIST	Time 0.02075s	Training Accuracy: 94.24%	Test Accuracy: 71.88%
    +[ 32/ 50]	       MNIST	Time 0.02297s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 32/ 50]	FashionMNIST	Time 0.02142s	Training Accuracy: 93.65%	Test Accuracy: 71.88%
    +[ 33/ 50]	       MNIST	Time 0.02200s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 33/ 50]	FashionMNIST	Time 0.02105s	Training Accuracy: 94.34%	Test Accuracy: 75.00%
    +[ 34/ 50]	       MNIST	Time 0.02155s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 34/ 50]	FashionMNIST	Time 0.02781s	Training Accuracy: 93.65%	Test Accuracy: 68.75%
    +[ 35/ 50]	       MNIST	Time 0.02128s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 35/ 50]	FashionMNIST	Time 0.02310s	Training Accuracy: 95.12%	Test Accuracy: 71.88%
    +[ 36/ 50]	       MNIST	Time 0.02250s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 36/ 50]	FashionMNIST	Time 0.02097s	Training Accuracy: 95.90%	Test Accuracy: 71.88%
    +[ 37/ 50]	       MNIST	Time 0.02084s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 37/ 50]	FashionMNIST	Time 0.02062s	Training Accuracy: 95.80%	Test Accuracy: 75.00%
    +[ 38/ 50]	       MNIST	Time 0.02122s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 38/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 95.70%	Test Accuracy: 71.88%
    +[ 39/ 50]	       MNIST	Time 0.01987s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 39/ 50]	FashionMNIST	Time 0.02035s	Training Accuracy: 96.88%	Test Accuracy: 71.88%
    +[ 40/ 50]	       MNIST	Time 0.02083s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 40/ 50]	FashionMNIST	Time 0.02133s	Training Accuracy: 96.68%	Test Accuracy: 71.88%
    +[ 41/ 50]	       MNIST	Time 0.02054s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 41/ 50]	FashionMNIST	Time 0.02079s	Training Accuracy: 97.07%	Test Accuracy: 71.88%
    +[ 42/ 50]	       MNIST	Time 0.02094s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 42/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 97.36%	Test Accuracy: 71.88%
    +[ 43/ 50]	       MNIST	Time 0.02632s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 43/ 50]	FashionMNIST	Time 0.02029s	Training Accuracy: 97.36%	Test Accuracy: 71.88%
    +[ 44/ 50]	       MNIST	Time 0.02053s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 44/ 50]	FashionMNIST	Time 0.02080s	Training Accuracy: 97.75%	Test Accuracy: 71.88%
    +[ 45/ 50]	       MNIST	Time 0.02082s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 45/ 50]	FashionMNIST	Time 0.02060s	Training Accuracy: 97.85%	Test Accuracy: 75.00%
    +[ 46/ 50]	       MNIST	Time 0.02029s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 46/ 50]	FashionMNIST	Time 0.02048s	Training Accuracy: 97.75%	Test Accuracy: 71.88%
    +[ 47/ 50]	       MNIST	Time 0.02093s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 47/ 50]	FashionMNIST	Time 0.02595s	Training Accuracy: 97.66%	Test Accuracy: 75.00%
    +[ 48/ 50]	       MNIST	Time 0.02109s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 48/ 50]	FashionMNIST	Time 0.02037s	Training Accuracy: 96.97%	Test Accuracy: 68.75%
    +[ 49/ 50]	       MNIST	Time 0.02034s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 49/ 50]	FashionMNIST	Time 0.02065s	Training Accuracy: 97.36%	Test Accuracy: 75.00%
    +[ 50/ 50]	       MNIST	Time 0.02088s	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[ 50/ 50]	FashionMNIST	Time 0.02084s	Training Accuracy: 97.75%	Test Accuracy: 68.75%
    +
    +[FINAL]	       MNIST	Training Accuracy: 100.00%	Test Accuracy: 84.38%
    +[FINAL]	FashionMNIST	Training Accuracy: 97.75%	Test Accuracy: 68.75%

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 2.170 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/tutorials/intermediate/4_PINN2DPDE.html b/previews/PR1023/tutorials/intermediate/4_PINN2DPDE.html new file mode 100644 index 0000000000..96fb760008 --- /dev/null +++ b/previews/PR1023/tutorials/intermediate/4_PINN2DPDE.html @@ -0,0 +1,376 @@ + + + + + + Training a PINN on 2D PDE | Lux.jl Docs + + + + + + + + + + + + + + + + + + + + + + + +
    Skip to content

    Training a PINN on 2D PDE

    In this tutorial we will go over using a PINN to solve 2D PDEs. We will be using the system from NeuralPDE Tutorials. However, we will be using our custom loss function and use nested AD capabilities of Lux.jl.

    This is a demonstration of Lux.jl. For serious usecases of PINNs, please refer to the package: NeuralPDE.jl.

    Package Imports

    julia
    using ADTypes, Lux, Optimisers, Zygote, Random, Printf, Statistics, MLUtils, OnlineStats,
    +      CairoMakie
    +using LuxCUDA
    +
    +CUDA.allowscalar(false)
    +
    +const gdev = gpu_device()
    +const cdev = cpu_device()
    (::MLDataDevices.CPUDevice) (generic function with 5 methods)

    Problem Definition

    Since Lux supports efficient nested AD upto 2nd order, we will rewrite the problem with first order derivatives, so that we can compute the gradients of the loss using 2nd order AD.

    Define the Neural Networks

    All the networks take 3 input variables and output a scalar value. Here, we will define a a wrapper over the 3 networks, so that we can train them using Training.TrainState.

    julia
    struct PINN{U, V, W} <: Lux.AbstractLuxContainerLayer{(:u, :v, :w)}
    +    u::U
    +    v::V
    +    w::W
    +end
    +
    +function create_mlp(act, hidden_dims)
    +    return Chain(
    +        Dense(3 => hidden_dims, act),
    +        Dense(hidden_dims => hidden_dims, act),
    +        Dense(hidden_dims => hidden_dims, act),
    +        Dense(hidden_dims => 1)
    +    )
    +end
    +
    +function PINN(; hidden_dims::Int=32)
    +    return PINN(
    +        create_mlp(tanh, hidden_dims),
    +        create_mlp(tanh, hidden_dims),
    +        create_mlp(tanh, hidden_dims)
    +    )
    +end
    Main.var"##225".PINN

    Define the Loss Functions

    We will define a custom loss function to compute the loss using 2nd order AD. We will use the following loss function

    julia
    @views function physics_informed_loss_function(
    +        u::StatefulLuxLayer, v::StatefulLuxLayer, w::StatefulLuxLayer, xyt::AbstractArray)
    +    ∂u_∂xyt = only(Zygote.gradient(sum  u, xyt))
    +    ∂u_∂x, ∂u_∂y, ∂u_∂t = ∂u_∂xyt[1:1, :], ∂u_∂xyt[2:2, :], ∂u_∂xyt[3:3, :]
    +    ∂v_∂x = only(Zygote.gradient(sum  v, xyt))[1:1, :]
    +    v_xyt = v(xyt)
    +    ∂w_∂y = only(Zygote.gradient(sum  w, xyt))[2:2, :]
    +    w_xyt = w(xyt)
    +    return (
    +        mean(abs2, ∂u_∂t .- ∂v_∂x .- ∂w_∂y) +
    +        mean(abs2, v_xyt .- ∂u_∂x) +
    +        mean(abs2, w_xyt .- ∂u_∂y)
    +    )
    +end
    physics_informed_loss_function (generic function with 1 method)

    Additionally, we need to compute the loss wrt the boundary conditions.

    julia
    function mse_loss_function(u::StatefulLuxLayer, target::AbstractArray, xyt::AbstractArray)
    +    return MSELoss()(u(xyt), target)
    +end
    +
    +function loss_function(model, ps, st, (xyt, target_data, xyt_bc, target_bc))
    +    u_net = StatefulLuxLayer{true}(model.u, ps.u, st.u)
    +    v_net = StatefulLuxLayer{true}(model.v, ps.v, st.v)
    +    w_net = StatefulLuxLayer{true}(model.w, ps.w, st.w)
    +    physics_loss = physics_informed_loss_function(u_net, v_net, w_net, xyt)
    +    data_loss = mse_loss_function(u_net, target_data, xyt)
    +    bc_loss = mse_loss_function(u_net, target_bc, xyt_bc)
    +    loss = physics_loss + data_loss + bc_loss
    +    return (
    +        loss,
    +        (; u=u_net.st, v=v_net.st, w=w_net.st),
    +        (; physics_loss, data_loss, bc_loss)
    +    )
    +end
    loss_function (generic function with 1 method)

    Generate the Data

    We will generate some random data to train the model on. We will take data on a square spatial and temporal domain x[0,2], y[0,2], and t[0,2]. Typically, you want to be smarter about the sampling process, but for the sake of simplicity, we will skip that.

    julia
    analytical_solution(x, y, t) = @. exp(x + y) * cos(x + y + 4t)
    +analytical_solution(xyt) = analytical_solution(xyt[1, :], xyt[2, :], xyt[3, :])
    +
    +begin
    +    grid_len = 16
    +
    +    grid = range(0.0f0, 2.0f0; length=grid_len)
    +    xyt = stack([[elem...] for elem in vec(collect(Iterators.product(grid, grid, grid)))])
    +
    +    target_data = reshape(analytical_solution(xyt), 1, :)
    +
    +    bc_len = 512
    +
    +    x = collect(range(0.0f0, 2.0f0; length=bc_len))
    +    y = collect(range(0.0f0, 2.0f0; length=bc_len))
    +    t = collect(range(0.0f0, 2.0f0; length=bc_len))
    +
    +    xyt_bc = hcat(
    +        stack((x, y, zeros(Float32, bc_len)); dims=1),
    +        stack((zeros(Float32, bc_len), y, t); dims=1),
    +        stack((ones(Float32, bc_len) .* 2, y, t); dims=1),
    +        stack((x, zeros(Float32, bc_len), t); dims=1),
    +        stack((x, ones(Float32, bc_len) .* 2, t); dims=1)
    +    )
    +    target_bc = reshape(analytical_solution(xyt_bc), 1, :)
    +
    +    min_target_bc, max_target_bc = extrema(target_bc)
    +    min_data, max_data = extrema(target_data)
    +    min_pde_val, max_pde_val = min(min_data, min_target_bc), max(max_data, max_target_bc)
    +
    +    xyt = (xyt .- minimum(xyt)) ./ (maximum(xyt) .- minimum(xyt))
    +    xyt_bc = (xyt_bc .- minimum(xyt_bc)) ./ (maximum(xyt_bc) .- minimum(xyt_bc))
    +    target_bc = (target_bc .- min_pde_val) ./ (max_pde_val - min_pde_val)
    +    target_data = (target_data .- min_pde_val) ./ (max_pde_val - min_pde_val)
    +end

    Training

    julia
    function train_model(xyt, target_data, xyt_bc, target_bc; seed::Int=0,
    +        maxiters::Int=50000, hidden_dims::Int=32)
    +    rng = Random.default_rng()
    +    Random.seed!(rng, seed)
    +
    +    pinn = PINN(; hidden_dims)
    +    ps, st = Lux.setup(rng, pinn) |> gdev
    +
    +    bc_dataloader = DataLoader((xyt_bc, target_bc); batchsize=32, shuffle=true) |> gdev
    +    pde_dataloader = DataLoader((xyt, target_data); batchsize=32, shuffle=true) |> gdev
    +
    +    train_state = Training.TrainState(pinn, ps, st, Adam(0.05f0))
    +    lr = i -> i < 5000 ? 0.05f0 : (i < 10000 ? 0.005f0 : 0.0005f0)
    +
    +    total_loss_tracker, physics_loss_tracker, data_loss_tracker, bc_loss_tracker = ntuple(
    +        _ -> Lag(Float32, 32), 4)
    +
    +    iter = 1
    +    for ((xyt_batch, target_data_batch), (xyt_bc_batch, target_bc_batch)) in zip(
    +        Iterators.cycle(pde_dataloader), Iterators.cycle(bc_dataloader))
    +        Optimisers.adjust!(train_state, lr(iter))
    +
    +        _, loss, stats, train_state = Training.single_train_step!(
    +            AutoZygote(), loss_function, (
    +                xyt_batch, target_data_batch, xyt_bc_batch, target_bc_batch),
    +            train_state)
    +
    +        fit!(total_loss_tracker, loss)
    +        fit!(physics_loss_tracker, stats.physics_loss)
    +        fit!(data_loss_tracker, stats.data_loss)
    +        fit!(bc_loss_tracker, stats.bc_loss)
    +
    +        mean_loss = mean(OnlineStats.value(total_loss_tracker))
    +        mean_physics_loss = mean(OnlineStats.value(physics_loss_tracker))
    +        mean_data_loss = mean(OnlineStats.value(data_loss_tracker))
    +        mean_bc_loss = mean(OnlineStats.value(bc_loss_tracker))
    +
    +        isnan(loss) && throw(ArgumentError("NaN Loss Detected"))
    +
    +        if iter % 500 == 1 || iter == maxiters
    +            @printf "Iteration: [%5d / %5d] \t Loss: %.9f (%.9f) \t Physics Loss: %.9f \
    +                     (%.9f) \t Data Loss: %.9f (%.9f) \t BC \
    +                     Loss: %.9f (%.9f)\n" iter maxiters loss mean_loss stats.physics_loss mean_physics_loss stats.data_loss mean_data_loss stats.bc_loss mean_bc_loss
    +        end
    +
    +        iter += 1
    +        iter  maxiters && break
    +    end
    +
    +    return StatefulLuxLayer{true}(
    +        pinn, cdev(train_state.parameters), cdev(train_state.states))
    +end
    +
    +trained_model = train_model(xyt, target_data, xyt_bc, target_bc)
    +trained_u = Lux.testmode(StatefulLuxLayer{true}(
    +    trained_model.model.u, trained_model.ps.u, trained_model.st.u))
    ┌ Warning: `Lag(T, b)` is deprecated.  Use `CircBuff(T,b,rev=true)` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +┌ Warning: `Lag(T, b)` is deprecated.  Use `CircBuff(T,b,rev=true)` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +┌ Warning: `Lag(T, b)` is deprecated.  Use `CircBuff(T,b,rev=true)` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +┌ Warning: `Lag(T, b)` is deprecated.  Use `CircBuff(T,b,rev=true)` instead.
    +│   caller = #6 at 4_PINN2DPDE.md:16 [inlined]
    +└ @ Core /var/lib/buildkite-agent/builds/gpuci-9/julialang/lux-dot-jl/docs/src/tutorials/intermediate/4_PINN2DPDE.md:16
    +Iteration: [    1 / 50000] 	 Loss: 3.159042358 (3.159042358) 	 Physics Loss: 1.982162476 (1.982162476) 	 Data Loss: 0.578374863 (0.578374863) 	 BC Loss: 0.598505080 (0.598505080)
    +Iteration: [  501 / 50000] 	 Loss: 0.040918160 (0.025583776) 	 Physics Loss: 0.000391877 (0.000269295) 	 Data Loss: 0.014243508 (0.009196416) 	 BC Loss: 0.026282774 (0.016118063)
    +Iteration: [ 1001 / 50000] 	 Loss: 0.015340659 (0.025281426) 	 Physics Loss: 0.000071670 (0.000163182) 	 Data Loss: 0.007905648 (0.010876314) 	 BC Loss: 0.007363341 (0.014241929)
    +Iteration: [ 1501 / 50000] 	 Loss: 0.019567011 (0.026170366) 	 Physics Loss: 0.001279382 (0.001009728) 	 Data Loss: 0.003071612 (0.010452257) 	 BC Loss: 0.015216017 (0.014708381)
    +Iteration: [ 2001 / 50000] 	 Loss: 0.035556547 (0.027273500) 	 Physics Loss: 0.004061943 (0.001871931) 	 Data Loss: 0.013011228 (0.010586374) 	 BC Loss: 0.018483378 (0.014815190)
    +Iteration: [ 2501 / 50000] 	 Loss: 0.011505678 (0.022150228) 	 Physics Loss: 0.002304791 (0.001940841) 	 Data Loss: 0.005615299 (0.007885863) 	 BC Loss: 0.003585588 (0.012323526)
    +Iteration: [ 3001 / 50000] 	 Loss: 0.031768262 (0.029164422) 	 Physics Loss: 0.008404830 (0.003920683) 	 Data Loss: 0.008808360 (0.010936455) 	 BC Loss: 0.014555071 (0.014307282)
    +Iteration: [ 3501 / 50000] 	 Loss: 0.017645847 (0.042499166) 	 Physics Loss: 0.001848093 (0.001690981) 	 Data Loss: 0.005461216 (0.018073166) 	 BC Loss: 0.010336538 (0.022735020)
    +Iteration: [ 4001 / 50000] 	 Loss: 0.028128654 (0.027620461) 	 Physics Loss: 0.005112350 (0.002448601) 	 Data Loss: 0.013499700 (0.011073254) 	 BC Loss: 0.009516605 (0.014098606)
    +Iteration: [ 4501 / 50000] 	 Loss: 0.014340003 (0.033320315) 	 Physics Loss: 0.001292084 (0.004329988) 	 Data Loss: 0.008556721 (0.012002973) 	 BC Loss: 0.004491198 (0.016987354)
    +Iteration: [ 5001 / 50000] 	 Loss: 0.030331207 (0.041541956) 	 Physics Loss: 0.000723805 (0.002695386) 	 Data Loss: 0.004466736 (0.016228525) 	 BC Loss: 0.025140665 (0.022618050)
    +Iteration: [ 5501 / 50000] 	 Loss: 0.022293953 (0.021166507) 	 Physics Loss: 0.000554349 (0.000707158) 	 Data Loss: 0.004542338 (0.007950513) 	 BC Loss: 0.017197266 (0.012508835)
    +Iteration: [ 6001 / 50000] 	 Loss: 0.018723227 (0.020389127) 	 Physics Loss: 0.000442930 (0.000975201) 	 Data Loss: 0.006906096 (0.007273634) 	 BC Loss: 0.011374202 (0.012140292)
    +Iteration: [ 6501 / 50000] 	 Loss: 0.028305896 (0.020493284) 	 Physics Loss: 0.000753467 (0.001849154) 	 Data Loss: 0.011062279 (0.008014920) 	 BC Loss: 0.016490150 (0.010629211)
    +Iteration: [ 7001 / 50000] 	 Loss: 0.015494239 (0.020624701) 	 Physics Loss: 0.007333768 (0.001517879) 	 Data Loss: 0.004043682 (0.008185850) 	 BC Loss: 0.004116789 (0.010920972)
    +Iteration: [ 7501 / 50000] 	 Loss: 0.019155467 (0.018008159) 	 Physics Loss: 0.002511769 (0.001448493) 	 Data Loss: 0.009514628 (0.006572613) 	 BC Loss: 0.007129070 (0.009987052)
    +Iteration: [ 8001 / 50000] 	 Loss: 0.018706074 (0.017215939) 	 Physics Loss: 0.001792779 (0.001894138) 	 Data Loss: 0.005628760 (0.005433898) 	 BC Loss: 0.011284535 (0.009887908)
    +Iteration: [ 8501 / 50000] 	 Loss: 0.017605182 (0.019859709) 	 Physics Loss: 0.002696904 (0.003125851) 	 Data Loss: 0.007372384 (0.005978104) 	 BC Loss: 0.007535893 (0.010755754)
    +Iteration: [ 9001 / 50000] 	 Loss: 0.017614847 (0.016386209) 	 Physics Loss: 0.003162773 (0.002853032) 	 Data Loss: 0.003553676 (0.004607514) 	 BC Loss: 0.010898398 (0.008925664)
    +Iteration: [ 9501 / 50000] 	 Loss: 0.008732248 (0.014530762) 	 Physics Loss: 0.001913586 (0.002123826) 	 Data Loss: 0.003329928 (0.004253434) 	 BC Loss: 0.003488734 (0.008153505)
    +Iteration: [10001 / 50000] 	 Loss: 0.017750096 (0.017799046) 	 Physics Loss: 0.003630795 (0.003061282) 	 Data Loss: 0.003031955 (0.005044522) 	 BC Loss: 0.011087346 (0.009693242)
    +Iteration: [10501 / 50000] 	 Loss: 0.007509941 (0.011342090) 	 Physics Loss: 0.001571818 (0.001135202) 	 Data Loss: 0.001611185 (0.002613829) 	 BC Loss: 0.004326937 (0.007593059)
    +Iteration: [11001 / 50000] 	 Loss: 0.022739200 (0.011915382) 	 Physics Loss: 0.000807529 (0.001103305) 	 Data Loss: 0.002606506 (0.003132161) 	 BC Loss: 0.019325165 (0.007679918)
    +Iteration: [11501 / 50000] 	 Loss: 0.019484218 (0.011457845) 	 Physics Loss: 0.001845157 (0.001325290) 	 Data Loss: 0.002358936 (0.002806861) 	 BC Loss: 0.015280124 (0.007325693)
    +Iteration: [12001 / 50000] 	 Loss: 0.019427970 (0.011598296) 	 Physics Loss: 0.004434146 (0.001386037) 	 Data Loss: 0.008772802 (0.003136263) 	 BC Loss: 0.006221022 (0.007075997)
    +Iteration: [12501 / 50000] 	 Loss: 0.012775686 (0.011906523) 	 Physics Loss: 0.001197650 (0.001402911) 	 Data Loss: 0.001059842 (0.002556076) 	 BC Loss: 0.010518193 (0.007947534)
    +Iteration: [13001 / 50000] 	 Loss: 0.006105572 (0.011037273) 	 Physics Loss: 0.000987124 (0.001454655) 	 Data Loss: 0.001305370 (0.002395016) 	 BC Loss: 0.003813077 (0.007187600)
    +Iteration: [13501 / 50000] 	 Loss: 0.010004668 (0.011247103) 	 Physics Loss: 0.001224264 (0.001615586) 	 Data Loss: 0.002474443 (0.002668936) 	 BC Loss: 0.006305961 (0.006962581)
    +Iteration: [14001 / 50000] 	 Loss: 0.009895653 (0.009313912) 	 Physics Loss: 0.001215764 (0.001694928) 	 Data Loss: 0.002037087 (0.002155375) 	 BC Loss: 0.006642802 (0.005463609)
    +Iteration: [14501 / 50000] 	 Loss: 0.014400685 (0.008724037) 	 Physics Loss: 0.001658659 (0.001564218) 	 Data Loss: 0.003658900 (0.002201537) 	 BC Loss: 0.009083126 (0.004958282)
    +Iteration: [15001 / 50000] 	 Loss: 0.007676640 (0.008405063) 	 Physics Loss: 0.001566568 (0.001608545) 	 Data Loss: 0.002262217 (0.001837625) 	 BC Loss: 0.003847855 (0.004958895)
    +Iteration: [15501 / 50000] 	 Loss: 0.004365115 (0.009256126) 	 Physics Loss: 0.001047856 (0.002247394) 	 Data Loss: 0.000648518 (0.002218451) 	 BC Loss: 0.002668741 (0.004790282)
    +Iteration: [16001 / 50000] 	 Loss: 0.004880759 (0.007501942) 	 Physics Loss: 0.001649067 (0.001671217) 	 Data Loss: 0.000296087 (0.001492234) 	 BC Loss: 0.002935605 (0.004338491)
    +Iteration: [16501 / 50000] 	 Loss: 0.008074892 (0.007220342) 	 Physics Loss: 0.001825325 (0.001970405) 	 Data Loss: 0.001302087 (0.001730468) 	 BC Loss: 0.004947479 (0.003519468)
    +Iteration: [17001 / 50000] 	 Loss: 0.005824474 (0.005835793) 	 Physics Loss: 0.002019164 (0.001728887) 	 Data Loss: 0.000624455 (0.001011056) 	 BC Loss: 0.003180855 (0.003095849)
    +Iteration: [17501 / 50000] 	 Loss: 0.006616294 (0.005807751) 	 Physics Loss: 0.002489866 (0.001884541) 	 Data Loss: 0.001154157 (0.001245214) 	 BC Loss: 0.002972272 (0.002677995)
    +Iteration: [18001 / 50000] 	 Loss: 0.004335414 (0.005200472) 	 Physics Loss: 0.001764537 (0.002015869) 	 Data Loss: 0.000705982 (0.001058994) 	 BC Loss: 0.001864895 (0.002125610)
    +Iteration: [18501 / 50000] 	 Loss: 0.004978007 (0.005351806) 	 Physics Loss: 0.002553018 (0.002129085) 	 Data Loss: 0.000752965 (0.001336156) 	 BC Loss: 0.001672024 (0.001886566)
    +Iteration: [19001 / 50000] 	 Loss: 0.004518208 (0.004657542) 	 Physics Loss: 0.001975382 (0.001959185) 	 Data Loss: 0.000239237 (0.000983244) 	 BC Loss: 0.002303589 (0.001715113)
    +Iteration: [19501 / 50000] 	 Loss: 0.006942283 (0.004119421) 	 Physics Loss: 0.004590358 (0.001714717) 	 Data Loss: 0.001148389 (0.000894285) 	 BC Loss: 0.001203537 (0.001510418)
    +Iteration: [20001 / 50000] 	 Loss: 0.008026988 (0.003463188) 	 Physics Loss: 0.005315070 (0.001485110) 	 Data Loss: 0.001919697 (0.000688489) 	 BC Loss: 0.000792221 (0.001289588)
    +Iteration: [20501 / 50000] 	 Loss: 0.004855067 (0.003504427) 	 Physics Loss: 0.001560361 (0.001747428) 	 Data Loss: 0.000460401 (0.000618138) 	 BC Loss: 0.002834306 (0.001138862)
    +Iteration: [21001 / 50000] 	 Loss: 0.002417301 (0.003299790) 	 Physics Loss: 0.000924424 (0.001513747) 	 Data Loss: 0.000300984 (0.000659882) 	 BC Loss: 0.001191893 (0.001126162)
    +Iteration: [21501 / 50000] 	 Loss: 0.003911218 (0.002670718) 	 Physics Loss: 0.002752088 (0.001218763) 	 Data Loss: 0.000835131 (0.000637475) 	 BC Loss: 0.000323999 (0.000814481)
    +Iteration: [22001 / 50000] 	 Loss: 0.002318957 (0.002511334) 	 Physics Loss: 0.001409405 (0.001309370) 	 Data Loss: 0.000344849 (0.000535839) 	 BC Loss: 0.000564703 (0.000666125)
    +Iteration: [22501 / 50000] 	 Loss: 0.001994215 (0.002343247) 	 Physics Loss: 0.000746255 (0.001113559) 	 Data Loss: 0.000431564 (0.000577084) 	 BC Loss: 0.000816396 (0.000652603)
    +Iteration: [23001 / 50000] 	 Loss: 0.002989073 (0.002301548) 	 Physics Loss: 0.001930058 (0.001243673) 	 Data Loss: 0.000805100 (0.000536315) 	 BC Loss: 0.000253915 (0.000521560)
    +Iteration: [23501 / 50000] 	 Loss: 0.002210422 (0.002371583) 	 Physics Loss: 0.001325711 (0.001179150) 	 Data Loss: 0.000160725 (0.000516864) 	 BC Loss: 0.000723986 (0.000675569)
    +Iteration: [24001 / 50000] 	 Loss: 0.002023818 (0.002276814) 	 Physics Loss: 0.000857553 (0.001135292) 	 Data Loss: 0.000525994 (0.000580056) 	 BC Loss: 0.000640270 (0.000561465)
    +Iteration: [24501 / 50000] 	 Loss: 0.002234935 (0.002236427) 	 Physics Loss: 0.001041825 (0.001241080) 	 Data Loss: 0.000286281 (0.000510494) 	 BC Loss: 0.000906830 (0.000484853)
    +Iteration: [25001 / 50000] 	 Loss: 0.001972227 (0.001982885) 	 Physics Loss: 0.000893347 (0.000971555) 	 Data Loss: 0.000666251 (0.000537486) 	 BC Loss: 0.000412629 (0.000473843)
    +Iteration: [25501 / 50000] 	 Loss: 0.001659834 (0.002081697) 	 Physics Loss: 0.001085884 (0.001258897) 	 Data Loss: 0.000359855 (0.000474958) 	 BC Loss: 0.000214095 (0.000347842)
    +Iteration: [26001 / 50000] 	 Loss: 0.002059042 (0.001770784) 	 Physics Loss: 0.001171167 (0.000890729) 	 Data Loss: 0.000426463 (0.000447986) 	 BC Loss: 0.000461412 (0.000432069)
    +Iteration: [26501 / 50000] 	 Loss: 0.002089650 (0.002068657) 	 Physics Loss: 0.001594031 (0.001356683) 	 Data Loss: 0.000330550 (0.000420685) 	 BC Loss: 0.000165069 (0.000291289)
    +Iteration: [27001 / 50000] 	 Loss: 0.001346401 (0.001879478) 	 Physics Loss: 0.000798861 (0.001050717) 	 Data Loss: 0.000333685 (0.000522715) 	 BC Loss: 0.000213855 (0.000306047)
    +Iteration: [27501 / 50000] 	 Loss: 0.001717428 (0.001494603) 	 Physics Loss: 0.000754971 (0.000796866) 	 Data Loss: 0.000408040 (0.000351864) 	 BC Loss: 0.000554417 (0.000345872)
    +Iteration: [28001 / 50000] 	 Loss: 0.001498525 (0.001789054) 	 Physics Loss: 0.000881248 (0.001008533) 	 Data Loss: 0.000310122 (0.000482373) 	 BC Loss: 0.000307154 (0.000298148)
    +Iteration: [28501 / 50000] 	 Loss: 0.001300987 (0.001541014) 	 Physics Loss: 0.000685782 (0.000873007) 	 Data Loss: 0.000372513 (0.000378884) 	 BC Loss: 0.000242692 (0.000289123)
    +Iteration: [29001 / 50000] 	 Loss: 0.001302390 (0.001531350) 	 Physics Loss: 0.000764329 (0.000809421) 	 Data Loss: 0.000326938 (0.000448536) 	 BC Loss: 0.000211123 (0.000273393)
    +Iteration: [29501 / 50000] 	 Loss: 0.001228882 (0.001639404) 	 Physics Loss: 0.000864926 (0.000892691) 	 Data Loss: 0.000257633 (0.000503808) 	 BC Loss: 0.000106323 (0.000242905)
    +Iteration: [30001 / 50000] 	 Loss: 0.001362466 (0.001636085) 	 Physics Loss: 0.000635906 (0.000994050) 	 Data Loss: 0.000649345 (0.000412151) 	 BC Loss: 0.000077215 (0.000229884)
    +Iteration: [30501 / 50000] 	 Loss: 0.000972152 (0.001479216) 	 Physics Loss: 0.000619220 (0.000883626) 	 Data Loss: 0.000230181 (0.000379169) 	 BC Loss: 0.000122752 (0.000216420)
    +Iteration: [31001 / 50000] 	 Loss: 0.005065940 (0.001380907) 	 Physics Loss: 0.004397592 (0.000831873) 	 Data Loss: 0.000477057 (0.000344165) 	 BC Loss: 0.000191290 (0.000204869)
    +Iteration: [31501 / 50000] 	 Loss: 0.001720798 (0.001439294) 	 Physics Loss: 0.001153235 (0.000778960) 	 Data Loss: 0.000366380 (0.000444564) 	 BC Loss: 0.000201183 (0.000215771)
    +Iteration: [32001 / 50000] 	 Loss: 0.001272172 (0.001182971) 	 Physics Loss: 0.000547293 (0.000645338) 	 Data Loss: 0.000612554 (0.000330688) 	 BC Loss: 0.000112325 (0.000206944)
    +Iteration: [32501 / 50000] 	 Loss: 0.001592739 (0.001303701) 	 Physics Loss: 0.001089040 (0.000732894) 	 Data Loss: 0.000368751 (0.000377450) 	 BC Loss: 0.000134948 (0.000193357)
    +Iteration: [33001 / 50000] 	 Loss: 0.001257007 (0.001731674) 	 Physics Loss: 0.000964463 (0.001143823) 	 Data Loss: 0.000217459 (0.000395994) 	 BC Loss: 0.000075086 (0.000191858)
    +Iteration: [33501 / 50000] 	 Loss: 0.001404967 (0.001307026) 	 Physics Loss: 0.000708074 (0.000685339) 	 Data Loss: 0.000530431 (0.000435325) 	 BC Loss: 0.000166462 (0.000186362)
    +Iteration: [34001 / 50000] 	 Loss: 0.000798481 (0.001060399) 	 Physics Loss: 0.000366831 (0.000566683) 	 Data Loss: 0.000218087 (0.000317301) 	 BC Loss: 0.000213564 (0.000176415)
    +Iteration: [34501 / 50000] 	 Loss: 0.001798573 (0.001364744) 	 Physics Loss: 0.001362987 (0.000847362) 	 Data Loss: 0.000308547 (0.000354412) 	 BC Loss: 0.000127040 (0.000162970)
    +Iteration: [35001 / 50000] 	 Loss: 0.000781053 (0.001014936) 	 Physics Loss: 0.000422994 (0.000539345) 	 Data Loss: 0.000270824 (0.000311768) 	 BC Loss: 0.000087234 (0.000163823)
    +Iteration: [35501 / 50000] 	 Loss: 0.001209691 (0.001329915) 	 Physics Loss: 0.000784697 (0.000694873) 	 Data Loss: 0.000264404 (0.000425117) 	 BC Loss: 0.000160591 (0.000209925)
    +Iteration: [36001 / 50000] 	 Loss: 0.001398915 (0.001136703) 	 Physics Loss: 0.000490567 (0.000583094) 	 Data Loss: 0.000744279 (0.000401171) 	 BC Loss: 0.000164069 (0.000152438)
    +Iteration: [36501 / 50000] 	 Loss: 0.000835373 (0.001367094) 	 Physics Loss: 0.000595709 (0.000792289) 	 Data Loss: 0.000132676 (0.000426714) 	 BC Loss: 0.000106987 (0.000148092)
    +Iteration: [37001 / 50000] 	 Loss: 0.000952036 (0.001044580) 	 Physics Loss: 0.000709375 (0.000580873) 	 Data Loss: 0.000161545 (0.000334467) 	 BC Loss: 0.000081115 (0.000129240)
    +Iteration: [37501 / 50000] 	 Loss: 0.000579479 (0.001085730) 	 Physics Loss: 0.000270049 (0.000599332) 	 Data Loss: 0.000242183 (0.000348117) 	 BC Loss: 0.000067247 (0.000138281)
    +Iteration: [38001 / 50000] 	 Loss: 0.001053359 (0.001110448) 	 Physics Loss: 0.000445312 (0.000595116) 	 Data Loss: 0.000482833 (0.000353724) 	 BC Loss: 0.000125214 (0.000161607)
    +Iteration: [38501 / 50000] 	 Loss: 0.000667115 (0.001049175) 	 Physics Loss: 0.000326662 (0.000543516) 	 Data Loss: 0.000173648 (0.000387762) 	 BC Loss: 0.000166804 (0.000117897)
    +Iteration: [39001 / 50000] 	 Loss: 0.000687853 (0.001085206) 	 Physics Loss: 0.000313576 (0.000590442) 	 Data Loss: 0.000321921 (0.000367264) 	 BC Loss: 0.000052356 (0.000127500)
    +Iteration: [39501 / 50000] 	 Loss: 0.000673423 (0.001160439) 	 Physics Loss: 0.000421422 (0.000714949) 	 Data Loss: 0.000192454 (0.000300986) 	 BC Loss: 0.000059547 (0.000144504)
    +Iteration: [40001 / 50000] 	 Loss: 0.000938448 (0.001243982) 	 Physics Loss: 0.000547043 (0.000710499) 	 Data Loss: 0.000287677 (0.000374305) 	 BC Loss: 0.000103729 (0.000159178)
    +Iteration: [40501 / 50000] 	 Loss: 0.001798752 (0.001093546) 	 Physics Loss: 0.000866074 (0.000650020) 	 Data Loss: 0.000780730 (0.000305183) 	 BC Loss: 0.000151947 (0.000138344)
    +Iteration: [41001 / 50000] 	 Loss: 0.001101400 (0.001448896) 	 Physics Loss: 0.000600817 (0.000901216) 	 Data Loss: 0.000405329 (0.000389668) 	 BC Loss: 0.000095254 (0.000158011)
    +Iteration: [41501 / 50000] 	 Loss: 0.000776893 (0.000824789) 	 Physics Loss: 0.000455096 (0.000410463) 	 Data Loss: 0.000206055 (0.000317277) 	 BC Loss: 0.000115742 (0.000097049)
    +Iteration: [42001 / 50000] 	 Loss: 0.001060384 (0.001240770) 	 Physics Loss: 0.000583868 (0.000778712) 	 Data Loss: 0.000378937 (0.000335865) 	 BC Loss: 0.000097578 (0.000126193)
    +Iteration: [42501 / 50000] 	 Loss: 0.000691815 (0.000944194) 	 Physics Loss: 0.000381213 (0.000516831) 	 Data Loss: 0.000162085 (0.000307154) 	 BC Loss: 0.000148517 (0.000120209)
    +Iteration: [43001 / 50000] 	 Loss: 0.000545245 (0.000868335) 	 Physics Loss: 0.000363892 (0.000449657) 	 Data Loss: 0.000124517 (0.000324281) 	 BC Loss: 0.000056836 (0.000094398)
    +Iteration: [43501 / 50000] 	 Loss: 0.001068081 (0.001141232) 	 Physics Loss: 0.000613936 (0.000622923) 	 Data Loss: 0.000369106 (0.000392804) 	 BC Loss: 0.000085040 (0.000125504)
    +Iteration: [44001 / 50000] 	 Loss: 0.001168622 (0.000963809) 	 Physics Loss: 0.000486189 (0.000540564) 	 Data Loss: 0.000549527 (0.000306839) 	 BC Loss: 0.000132906 (0.000116407)
    +Iteration: [44501 / 50000] 	 Loss: 0.000939374 (0.000756769) 	 Physics Loss: 0.000379668 (0.000386392) 	 Data Loss: 0.000454265 (0.000277635) 	 BC Loss: 0.000105440 (0.000092742)
    +Iteration: [45001 / 50000] 	 Loss: 0.001202180 (0.000892342) 	 Physics Loss: 0.000726597 (0.000506370) 	 Data Loss: 0.000367492 (0.000280093) 	 BC Loss: 0.000108091 (0.000105879)
    +Iteration: [45501 / 50000] 	 Loss: 0.000887047 (0.000908168) 	 Physics Loss: 0.000641108 (0.000560744) 	 Data Loss: 0.000148591 (0.000263541) 	 BC Loss: 0.000097348 (0.000083883)
    +Iteration: [46001 / 50000] 	 Loss: 0.000525872 (0.000734937) 	 Physics Loss: 0.000322635 (0.000362759) 	 Data Loss: 0.000158824 (0.000288360) 	 BC Loss: 0.000044412 (0.000083818)
    +Iteration: [46501 / 50000] 	 Loss: 0.000545968 (0.000907963) 	 Physics Loss: 0.000350560 (0.000489585) 	 Data Loss: 0.000136768 (0.000312205) 	 BC Loss: 0.000058640 (0.000106173)
    +Iteration: [47001 / 50000] 	 Loss: 0.000826687 (0.000924496) 	 Physics Loss: 0.000575209 (0.000511645) 	 Data Loss: 0.000205284 (0.000314716) 	 BC Loss: 0.000046194 (0.000098134)
    +Iteration: [47501 / 50000] 	 Loss: 0.000620959 (0.001185708) 	 Physics Loss: 0.000382126 (0.000788119) 	 Data Loss: 0.000148993 (0.000271556) 	 BC Loss: 0.000089840 (0.000126034)
    +Iteration: [48001 / 50000] 	 Loss: 0.000664698 (0.000798627) 	 Physics Loss: 0.000412207 (0.000461797) 	 Data Loss: 0.000182339 (0.000250679) 	 BC Loss: 0.000070152 (0.000086152)
    +Iteration: [48501 / 50000] 	 Loss: 0.000826713 (0.000925605) 	 Physics Loss: 0.000485339 (0.000512687) 	 Data Loss: 0.000170909 (0.000314013) 	 BC Loss: 0.000170466 (0.000098905)
    +Iteration: [49001 / 50000] 	 Loss: 0.000559556 (0.000846881) 	 Physics Loss: 0.000350503 (0.000421408) 	 Data Loss: 0.000165743 (0.000346362) 	 BC Loss: 0.000043311 (0.000079111)
    +Iteration: [49501 / 50000] 	 Loss: 0.000652327 (0.000740137) 	 Physics Loss: 0.000301691 (0.000376061) 	 Data Loss: 0.000195276 (0.000275985) 	 BC Loss: 0.000155360 (0.000088090)

    Visualizing the Results

    julia
    ts, xs, ys = 0.0f0:0.05f0:2.0f0, 0.0f0:0.02f0:2.0f0, 0.0f0:0.02f0:2.0f0
    +grid = stack([[elem...] for elem in vec(collect(Iterators.product(xs, ys, ts)))])
    +
    +u_real = reshape(analytical_solution(grid), length(xs), length(ys), length(ts))
    +
    +grid_normalized = (grid .- minimum(grid)) ./ (maximum(grid) .- minimum(grid))
    +u_pred = reshape(trained_u(grid_normalized), length(xs), length(ys), length(ts))
    +u_pred = u_pred .* (max_pde_val - min_pde_val) .+ min_pde_val
    +
    +begin
    +    fig = Figure()
    +    ax = CairoMakie.Axis(fig[1, 1]; xlabel="x", ylabel="y")
    +    errs = [abs.(u_pred[:, :, i] .- u_real[:, :, i]) for i in 1:length(ts)]
    +    Colorbar(fig[1, 2]; limits=extrema(stack(errs)))
    +
    +    CairoMakie.record(fig, "pinn_nested_ad.gif", 1:length(ts); framerate=10) do i
    +        ax.title = "Abs. Predictor Error | Time: $(ts[i])"
    +        err = errs[i]
    +        contour!(ax, xs, ys, err; levels=10, linewidth=2)
    +        heatmap!(ax, xs, ys, err)
    +        return fig
    +    end
    +
    +    fig
    +end

    Appendix

    julia
    using InteractiveUtils
    +InteractiveUtils.versioninfo()
    +
    +if @isdefined(MLDataDevices)
    +    if @isdefined(CUDA) && MLDataDevices.functional(CUDADevice)
    +        println()
    +        CUDA.versioninfo()
    +    end
    +
    +    if @isdefined(AMDGPU) && MLDataDevices.functional(AMDGPUDevice)
    +        println()
    +        AMDGPU.versioninfo()
    +    end
    +end
    Julia Version 1.10.6
    +Commit 67dffc4a8ae (2024-10-28 12:23 UTC)
    +Build Info:
    +  Official https://julialang.org/ release
    +Platform Info:
    +  OS: Linux (x86_64-linux-gnu)
    +  CPU: 48 × AMD EPYC 7402 24-Core Processor
    +  WORD_SIZE: 64
    +  LIBM: libopenlibm
    +  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    +Threads: 48 default, 0 interactive, 24 GC (on 2 virtual cores)
    +Environment:
    +  JULIA_CPU_THREADS = 2
    +  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/01872db4-8c79-43af-ab7d-12abac4f24f6
    +  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
    +  JULIA_PKG_SERVER = 
    +  JULIA_NUM_THREADS = 48
    +  JULIA_CUDA_HARD_MEMORY_LIMIT = 100%
    +  JULIA_PKG_PRECOMPILE_AUTO = 0
    +  JULIA_DEBUG = Literate
    +
    +CUDA runtime 12.6, artifact installation
    +CUDA driver 12.6
    +NVIDIA driver 560.35.3
    +
    +CUDA libraries: 
    +- CUBLAS: 12.6.3
    +- CURAND: 10.3.7
    +- CUFFT: 11.3.0
    +- CUSOLVER: 11.7.1
    +- CUSPARSE: 12.5.4
    +- CUPTI: 2024.3.2 (API 24.0.0)
    +- NVML: 12.0.0+560.35.3
    +
    +Julia packages: 
    +- CUDA: 5.5.2
    +- CUDA_Driver_jll: 0.10.3+0
    +- CUDA_Runtime_jll: 0.15.3+0
    +
    +Toolchain:
    +- Julia: 1.10.6
    +- LLVM: 15.0.7
    +
    +Environment:
    +- JULIA_CUDA_HARD_MEMORY_LIMIT: 100%
    +
    +1 device:
    +  0: NVIDIA A100-PCIE-40GB MIG 1g.5gb (sm_80, 4.484 GiB / 4.750 GiB available)

    This page was generated using Literate.jl.

    + + + + \ No newline at end of file diff --git a/previews/PR1023/weather-neural-ode.gif b/previews/PR1023/weather-neural-ode.gif new file mode 100644 index 0000000000..34c46737d1 Binary files /dev/null and b/previews/PR1023/weather-neural-ode.gif differ