The BetaML.Nn Module
BetaML.Nn — Module
BetaML.Nn moduleImplement the functionality required to define an artificial Neural Network, train it with data, forecast data and assess its performance.
Common types of layers and optimisation algorithms are already provided, but you can define your own by subclassing respectively the AbstractLayer and OptimisationAlgorithm abstract types.
The module provides the following types or functions. Use ?[type or function] to access their full signature and detailed documentation:
Model definition:
DenseLayer: Classical feed-forward layer with user-defined activation functionDenseNoBiasLayer: Classical layer without the bias parameterVectorFunctionLayer: Layer whose activation function runs over the ensemble of its nodes rather than on each one individually. No learnable weights on input, optional learnable weights as parameters of the activation function.ScalarFunctionLayer: Layer whose activation function runs over each node individually, like a classicDenseLayer, but with no learnable weights on input and optional learnable weights as parameters of the activation function.ReplicatorLayer: Alias for aScalarFunctionLayerwith no learnable parameters and identity as activation functionReshaperLayer: Reshape the output of a layer (or the input data) to the shape needed for the next onePoolingLayer: In the middle betweenVectorFunctionLayerandScalarFunctionLayer, it applies a function to the set of nodes defined in a sliding kernel. Weightless.ConvLayer: A generic N+1 (channels) dimensional convolutional layerGroupedLayer: To stack several layers into a single layer, e.g. for multi-branches networksNeuralNetworkEstimator: Build the chained network and define a cost function
Each layer can use a default activation function, one of the functions provided in the Utils module (relu, tanh, softmax,...) or one provided by you. BetaML will try to recognise if it is a "known" function for which it sets the exact derivatives, otherwise you can normally provide the layer with it. If the derivative of the activation function is not provided (either manually or automatically), AD will be used and training may be slower, although this difference tends to vanish with bigger datasets.
You can alternatively implement your own layer by defining a new type as subtype of the abstract type AbstractLayer. Each user-implemented layer must define the following methods:
- A suitable constructor
forward(layer,x)backward(layer,x,next_gradient)get_params(layer)get_gradient(layer,x,next_gradient)set_params!(layer,w)size(layer)
The first three functions work on a single record. Training and prediction internally work on whole batches of records, calling the batched versions forward_batch(layer,X), backward_batch(layer,X,next_gradient) and get_gradient_batch(layer,X,next_gradient), whose default implementations simply loop over the records of the batch. Implement the batched versions instead of (or in addition to) the single-record ones to speed up your layer, as all the default layers do.
Running on GPUs
Neural networks can be trained and used on GPUs of any vendor (NVIDIA, AMD, Apple, Intel). Just load the package of your GPU vendor (e.g. using CUDA, using AMDGPU, using Metal or using oneAPI) and either:
- pass your data already on the GPU (e.g.
fit!(m,cu(X),cu(Y))): with the default optiondevice=:autothe network is trained where the data is, and the results are returned there; - or keep your data on the CPU and use the option
device=:gpuofNeuralNetworkEstimator: each batch is moved to the GPU for the computation, while the results are returned on the CPU.
On GPUs, unless the data is already there with a different floating point type, the computations are performed in Float32. To run your own layers on GPUs, their forward_batch, backward_batch and get_gradient_batch functions must use array-level operations (and not loops over the individual elements of the arrays) and BetaML must be able to rebuild the layer with its arrays moved to the GPU. This is automatic if the layer has a constructor taking all its fields in order (like the default one), otherwise define Adapt.adapt_structure(to,layer::MyLayer) (see the Adapt.jl package).
Most default layers run entirely on GPUs. The exceptions, that still work with data on GPUs but compute record by record on the CPU, are:
VectorFunctionLayerwith functions other thansoftmax, unless the function can work on a whole batch and the layer is created withbatched=true;PoolingLayerwith functions other thanmaximumandmean.
In particular, for pooling on GPUs use PoolingLayer with f=maximum or f=mean (e.g. PoolingLayer(nₗ,k,1,stride=1,padding=0,f=mean) is the equivalent of pool1d(x,k,f=mean)), or a VectorFunctionLayer with batched=true and a pooling function working on whole batches with array slices (see the documentation of VectorFunctionLayer).
Model fitting:
fit!(nn,X,Y): fitting functionfitting_info(nn): Default callback function during fittingSGD: The classical optimisation algorithmADAM: A faster moment-based optimisation algorithm
To define your own optimisation algorithm define a subtype of OptimisationAlgorithm and implement the function single_update!(θ,▽;opt_alg) and optionally init_optalg!(⋅) specific for it.
Model predictions and assessment:
predict(nn)orpredict(nn,X): Return the output given the data
While high-level functions operating on the dataset expect it to be in the standard format (nrecords × ndimensions matrices) it is customary to represent the chain of a neural network as a flow of column vectors, so all low-level operations (operating on a single datapoint) expect both the input and the output as a column vector.
Module Index
BetaML.Nn.ReplicatorLayerBetaML.Nn.backwardBetaML.Nn.backward_batchBetaML.Nn.fitting_infoBetaML.Nn.forwardBetaML.Nn.forward_batchBetaML.Nn.forward_batchBetaML.Nn.forward_batchBetaML.Nn.get_gradientBetaML.Nn.get_gradientBetaML.Nn.get_gradient_batchBetaML.Nn.get_paramsBetaML.Nn.get_paramsBetaML.Nn.init_optalg!BetaML.Nn.init_optalg!BetaML.Nn.preprocess!BetaML.Nn.set_params!BetaML.Nn.set_params!BetaML.Nn.single_update!BetaML.Nn.ADAMBetaML.Nn.ConvLayerBetaML.Nn.ConvLayerBetaML.Nn.ConvLayerBetaML.Nn.DenseLayerBetaML.Nn.DenseLayerBetaML.Nn.DenseNoBiasLayerBetaML.Nn.DenseNoBiasLayerBetaML.Nn.GroupedLayerBetaML.Nn.GroupedLayerBetaML.Nn.LearnableBetaML.Nn.NeuralNetworkE_hpBetaML.Nn.NeuralNetworkE_optionsBetaML.Nn.NeuralNetworkEstimatorBetaML.Nn.PoolingLayerBetaML.Nn.PoolingLayerBetaML.Nn.PoolingLayerBetaML.Nn.ReshaperLayerBetaML.Nn.ReshaperLayerBetaML.Nn.SGDBetaML.Nn.ScalarFunctionLayerBetaML.Nn.ScalarFunctionLayerBetaML.Nn.VectorFunctionLayerBetaML.Nn.VectorFunctionLayer
Detailed API
BetaML.Nn.ADAM — Type
ADAM(;η, λ, β₁, β₂, ϵ)The ADAM algorithm, an adaptive moment estimation optimiser.
Fields:
η: Learning rate (stepsize, α in the paper), as a function of the current epoch [def: t -> 0.001 (i.e. fixed)]λ: Multiplicative constant to the learning rate [def: 1]β₁: Exponential decay rate for the first moment estimate [range: ∈ [0,1], def: 0.9]β₂: Exponential decay rate for the second moment estimate [range: ∈ [0,1], def: 0.999]ϵ: Epsilon value to avoid division by zero [def: 10^-8]
BetaML.Nn.ConvLayer — Type
struct ConvLayer{ND, NDPLUS1, NDPLUS2, TF<:Function, TDF<:Union{Nothing, Function}, WET<:Number, WT<:AbstractArray{WET<:Number, NDPLUS2}, BT<:AbstractArray{WET<:Number, 1}} <: AbstractLayerA generic N+1 (channels) dimensional convolutional layer
EXPERIMENTAL: Still too slow for practical applications
This convolutional layer has two constructors, one with the form ConvLayer(input_size,kernel_size,nchannels_in,nchannels_out), and an alternative one as ConvLayer(input_size_with_channel,kernel_size,nchannels_out). If the input is a vector, use a ReshaperLayer in front.
Fields:
input_size::StaticArraysCore.SVector{NDPLUS1, Int64} where NDPLUS1: Input size (including nchannel_in as last dimension)output_size::StaticArraysCore.SVector{NDPLUS1, Int64} where NDPLUS1: Output size (including nchannel_out as last dimension)weight::AbstractArray{WET, NDPLUS2} where {NDPLUS2, WET<:Number}: Weight tensor (aka "filter" or "kernel") with respect to the input from previous layer or data (kernelsize array augmented by the nchannelsin and nchannels_out dimensions)usebias::Bool: Whether to use (and learn) a bias weight [def: true]bias::AbstractVector{WET} where WET<:Number: Bias (nchannels_out array)padding_start::StaticArraysCore.SVector{ND, Int64} where ND: Padding (initial)padding_end::StaticArraysCore.SVector{ND, Int64} where ND: Padding (ending)stride::StaticArraysCore.SVector{ND, Int64} where ND: Stridendims::Int64: Number of dimensions (excluding input and output channels)f::Function: Activation functiondf::Union{Nothing, Function}: Derivative of the activation function
BetaML.Nn.ConvLayer — Method
ConvLayer(
input_size,
kernel_size,
nchannels_in,
nchannels_out;
stride,
rng,
padding,
kernel_eltype,
kernel_init,
usebias,
bias_init,
f,
df
) -> ConvLayer{_A, _B, _C, typeof(identity), _D, Float64, _E, _F} where {_A, _B, _C, _D<:Union{Nothing, Function}, _E<:AbstractArray{Float64, _C}, _F<:AbstractVector{Float64}}
Instantiate a new nD-dimensional, possibly multichannel ConvolutionalLayer
The input data is either a column vector (in which case it is reshaped) or an array of input_size augmented by the n_channels dimension, the output size depends on the input_size, kernel_size, padding and striding but always has nchannels_out as its last dimension.
Positional arguments:
input_size: Shape of the input layer (integer for 1D convolution, tuple otherwise). Do not consider the channels number here.kernel_size: Size of the kernel (aka filter or learnable weights) (integer for 1D or hypercube kernels or nD-sized tuple for asymmetric kernels). Do not consider the channels number here.nchannels_in: Number of channels in inputnchannels_out: Number of channels in output
Keyword arguments:
stride: "Steps" to move the convolution with across the various tensor dimensions [def:ones]padding: Integer or 2-element tuple of tuples of the starting and ending padding across the various dimensions [def:nothing, i.e. set the padding required to keep the same dimensions in output (with stride==1)]f: Activation function [def:identity]df: Derivative of the activation function [default: try to match a known function, AD otherwise. Usenothingto force AD]kernel_eltype: Kernel eltype [def:Float64]kernel_init: Initial weights with respect to the input [default: Xavier initialisation]. If explicitly provided, it should be a multidimensional array ofkernel_sizeaugmented bynchannels_inandnchannels_outdimensionsbias_init: Initial weights with respect to the bias [default: Xavier initialisation]. If given it should be anchannels_outvector of scalars.rng: Random Number Generator (seeFIXEDSEED) [default:Random.GLOBAL_RNG]
Notes:
- Xavier initialization is sampled from a
Uniformdistribution between⨦ sqrt(6/(prod(input_size)*nchannels_in)) - to retrieve the output size of the layer, use
size(ConvLayer[2]). The output size on each dimension d (except the last one that is given bynchannels_out) is given by the following formula (ceiled):output_size[d] = 1 + (input_size[d]+2*padding[d]-kernel_size[d])/stride[d] - with strides higher than 1, the automatic padding is set to keep outsize = insize/stride
BetaML.Nn.ConvLayer — Method
ConvLayer(
input_size_with_channel,
kernel_size,
nchannels_out;
stride,
rng,
padding,
kernel_eltype,
kernel_init,
usebias,
bias_init,
f,
df
) -> Union{ConvLayer{_A, _B, _C, typeof(identity), _D, _E, _F, _G} where {_E<:Number, _F<:AbstractArray{_E, _C}, _G<:AbstractVector{_E}}, ConvLayer{_A, _B, _C, typeof(identity), _D, WET, _F} where {WET<:Number, _F<:AbstractArray{WET, _C}}} where {_A, _B, _C, _D<:Union{Nothing, Function}}
Alternative constructor for a ConvLayer where the number of channels in input is specified as a further dimension in the input size instead of as a separate parameter, so as to use size(previous_layer)[2] if one wishes.
For arguments and default values see the documentation of the main constructor.
BetaML.Nn.DenseLayer — Type
struct DenseLayer{TF<:Function, TDF<:Union{Nothing, Function}, WET<:Number, WT<:AbstractArray{WET<:Number, 2}, BT<:AbstractArray{WET<:Number, 1}} <: AbstractLayerRepresentation of a layer in the network
Fields:
w: Weights matrix with respect to the input from previous layer or data (n x n pr. layer)wb: Biases (n)f: Activation functiondf: Derivative of the activation function
BetaML.Nn.DenseLayer — Method
DenseLayer(
nₗ,
n;
rng,
w_eltype,
w,
wb,
f,
df
) -> DenseLayer{typeof(identity), _A, Float64, _B, _C} where {_A<:Union{Nothing, Function}, _B<:AbstractMatrix{Float64}, _C<:AbstractVector{Float64}}
Instantiate a new DenseLayer
Positional arguments:
nₗ: Number of nodes of the previous layern: Number of nodes
Keyword arguments:
w_eltype: Eltype of the weights [def:Float64]w: Initial weights with respect to input [default: Xavier initialisation, dims = (n,nₗ)]wb: Initial weights with respect to bias [default: Xavier initialisation, dims = (n)]f: Activation function [def:identity]df: Derivative of the activation function [default: try to match with well-known derivatives, resort to AD iffis unknown]rng: Random Number Generator (seeFIXEDSEED) [default:Random.GLOBAL_RNG]
Notes:
- Xavier initialization =
rand(Uniform(-sqrt(6)/sqrt(nₗ+n),sqrt(6)/sqrt(nₗ+n)) - Specify
df=nothingto explicitly use AD
BetaML.Nn.DenseNoBiasLayer — Type
struct DenseNoBiasLayer{TF<:Function, TDF<:Union{Nothing, Function}, WET<:Number, WT<:AbstractArray{WET<:Number, 2}} <: AbstractLayerRepresentation of a layer without bias in the network
Fields:
w: Weights matrix with respect to the input from previous layer or data (n x n pr. layer)f: Activation functiondf: Derivative of the activation function
BetaML.Nn.DenseNoBiasLayer — Method
DenseNoBiasLayer(
nₗ,
n;
rng,
w_eltype,
w,
f,
df
) -> DenseNoBiasLayer{typeof(identity), _A, Float64, _B} where {_A<:Union{Nothing, Function}, _B<:AbstractMatrix{Float64}}
Instantiate a new DenseNoBiasLayer
Positional arguments:
nₗ: Number of nodes of the previous layern: Number of nodes
Keyword arguments:
w_eltype: Eltype of the weights [def:Float64]w: Initial weights with respect to input [default: Xavier initialisation, dims = (n,nₗ)]f: Activation function [def:identity]df: Derivative of the activation function [default: try to match with well-known derivatives, resort to AD iffis unknown]rng: Random Number Generator (seeFIXEDSEED) [default:Random.GLOBAL_RNG]
Notes:
- Xavier initialization =
rand(Uniform(-sqrt(6)/sqrt(nₗ+n),sqrt(6)/sqrt(nₗ+n))
BetaML.Nn.GroupedLayer — Type
struct GroupedLayer <: AbstractLayerRepresentation of a "group" of layers, each of which operates on different inputs (features), acting as a single layer in the network.
Fields:
layers: The individual layers that compose this grouped layer
BetaML.Nn.GroupedLayer — Method
GroupedLayer(layers) -> GroupedLayer
Instantiate a new GroupedLayer, a layer made up of several other layers stacked together in order to cover all the data dimensions but without connecting all the inputs to all the outputs like a single DenseLayer would do.
Positional arguments:
layers: The individual layers that compose this grouped layer
Notes:
- can be used to create composable neural networks with multiple branches
- tested only with 1 dimensional layers. For convolutional networks use ReshaperLayers before and/or after.
BetaML.Nn.Learnable — Type
Learnable(data)
Structure representing the learnable parameters of a layer or its gradient.
The learnable parameters of a layer are given in the form of a N-tuple of arrays of any dimension (e.g. we can have a layer with the first parameter being a matrix, and the second one being a vector). The arrays can be stored on any device (CPU or GPU). We wrap the tuple in its own structure a bit for some efficiency gain, but above all to define standard mathematical operations on the gradients without doing "type piracy" with respect to Base tuples.
Operations with a scalar convert the scalar to the element type of the arrays, so that e.g. Float32 parameters stay Float32.
BetaML.Nn.NeuralNetworkE_hp — Type
**`
mutable struct NeuralNetworkE_hp <: BetaMLHyperParametersSet`**
Hyperparameters for the Feedforward neural network model
Parameters:
layers: Array of layer objects [def:nothing, i.e. basic network]. Seesubtypes(BetaML.AbstractLayer)for supported layersloss: Loss (cost) function [def:squared_cost] It must always assume y and ŷ as (n x d) matrices, possibly usingdropdimsinside, and return the loss summed over the n records. Write it with array-level operations (e.g. broadcasting) for it to work also on GPUs.
dloss: Derivative of the loss function [def:dsquared_costifloss==squared_cost,nothingotherwise, i.e. use the derivative of the squared cost or autodiff]epochs: Number of epochs, i.e. passages through the whole training sample [def:200]batch_size: Size of each individual batch [def:16]opt_alg: The optimisation algorithm to update the gradient at each batch [def:ADAM()]shuffle: Whether to randomly shuffle the data at each iteration (epoch) [def:true]tunemethod: The method - and its parameters - to employ for hyperparameters autotuning. SeeSuccessiveHalvingSearchfor the default method. To implement automatic hyperparameter tuning during the (first)fit!call simply setautotune=trueand optionally change the defaulttunemethodoptions (including the parameter ranges, the resources to employ and the loss function to adopt).
To know the available layers, type subtypes(AbstractLayer) and then type ?LayerName for information on how to use each layer.
BetaML.Nn.NeuralNetworkE_options — Type
NeuralNetworkE_options
A struct defining the options used by the Feedforward neural network model
Parameters:
cache: Cache the results of the fitting stage, so as to allow predict(mod) [default:true]. Set it tofalseto save memory for large data.descr: An optional title and/or description for this modelverbosity: The verbosity level to be used in training or prediction (seeVerbosity) [default:STD]cb: A callback function to provide information during training [def:fitting_info]autotune: Option for hyper-parameters autotuning [def:false, i.e. no autotuning performed]. If activated, autotuning is performed on the firstfit!()call. Control auto-tuning through the optiontunemethod(see the model hyper-parameters)onfail: The strategy to apply in case of failure during the fitting (loss not decreasing) [def: "tryagain"]. The default is to try again with a new random initialization of the weights and the batch ("tryagain"). Other valid values are "continue", "stop" and "error". The first ignores the issue, the second one stops the training (but without generating an error) and the last one stops the fitting and generates an error.
fail_epoch_ref: The epoch to use as initial comparison to check for the onfail strategy [def:2]
fail_epoch: The epoch at which to try the onfail strategy [def:5]
fail_threshold: The (relative) threshold to use for the onfail strategy [def:0.01]. If the loss doesn't decrease by at least this value, the onfail strategy is applied. Note that this is computed in relation to the loss on the second epoch, so it is not an absolute value.
fail_attempts: The maximum number of attempts to use for the tryagain strategy [def:10]
rng: Random Number Generator (seeFIXEDSEED) [default:Random.GLOBAL_RNG]device: The device where to train the network and compute the predictions [def::auto]. Options are::auto: use the device where the training data is (e.g. the GPU ifXis a GPU array);:cpu: use the CPU;:gpu: use the GPU of the backend package loaded (e.g.using CUDA,using AMDGPU,using Metalorusing oneAPI), moving each batch of data there if it is on the CPU;- a device object of the MLDataDevices.jl package (e.g.
CUDADevice()), to choose a specific GPU backend.
Predictions are always returned on the device of the input data. On GPUs the network parameters are converted to
Float32(unless the data is already on the GPU with a different floating point type). Models saved withmodel_savewhile on a GPU have their parameters saved on the CPU. Withdevice=:auto, they are moved back to the same kind of GPU when used for predictions, if its package is loaded (otherwise they stay on the CPU).
BetaML.Nn.NeuralNetworkEstimator — Type
NeuralNetworkEstimator
A "feedforward" (but also multi-branch) neural network (supervised).
For the parameters see NeuralNetworkE_hp and for the training options NeuralNetworkE_options (we have a few more options for this specific estimator, in particular the device where to run the computation, e.g. :cpu or :gpu).
Notes:
- data must be numerical
- the label can be a n-records vector or a n-records by n-dimensions matrix, but the result is always a matrix.
- For one-dimension regressions drop the unnecessary dimension with
dropdims(ŷ,dims=2) - For classification tasks the columns should normally be interpreted as the probabilities for each category
- For one-dimension regressions drop the unnecessary dimension with
Examples:
- Classification...
julia> using BetaML
julia> X = [1.8 2.5; 0.5 20.5; 0.6 18; 0.7 22.8; 0.4 31; 1.7 3.7];
julia> y = ["a","b","b","b","b","a"];
julia> ohmod = OneHotEncoder()
A OneHotEncoder BetaMLModel (unfitted)
julia> y_oh = fit!(ohmod,y)
6×2 Matrix{Bool}:
1 0
0 1
0 1
0 1
0 1
1 0
julia> layers = [DenseLayer(2,6),DenseLayer(6,2),VectorFunctionLayer(2,f=softmax)];
julia> m = NeuralNetworkEstimator(layers=layers,opt_alg=ADAM(),epochs=300,verbosity=LOW)
NeuralNetworkEstimator - A Feed-forward neural network (unfitted)
julia> ŷ_prob = fit!(m,X,y_oh)
***
*** Training for 300 epochs with algorithm ADAM.
Training.. avg ϵ on (Epoch 1 Batch 1): 0.4116936481380642
Training of 300 epochs completed. Final epoch error: 0.44308719831108734.
6×2 Matrix{Float64}:
0.853198 0.146802
0.0513715 0.948629
0.0894273 0.910573
0.0367079 0.963292
0.00548038 0.99452
0.808334 0.191666
julia> ŷ = inverse_predict(ohmod,ŷ_prob)
6-element Vector{String}:
"a"
"b"
"b"
"b"
"b"
"a"- Regression...
julia> using BetaML
julia> X = [1.8 2.5; 0.5 20.5; 0.6 18; 0.7 22.8; 0.4 31; 1.7 3.7];
julia> y = 2 .* X[:,1] .- X[:,2] .+ 3;
julia> layers = [DenseLayer(2,6),DenseLayer(6,6),DenseLayer(6,1)];
julia> m = NeuralNetworkEstimator(layers=layers,opt_alg=ADAM(),epochs=3000,verbosity=LOW)
NeuralNetworkEstimator - A Feed-forward neural network (unfitted)
julia> ŷ = fit!(m,X,y);
***
*** Training for 3000 epochs with algorithm ADAM.
Training.. avg ϵ on (Epoch 1 Batch 1): 33.30063874270561
Training of 3000 epochs completed. Final epoch error: 34.61265465430473.
julia> hcat(y,ŷ)
6×2 Matrix{Float64}:
4.1 4.11015
-16.5 -16.5329
-13.8 -13.8381
-18.4 -18.3876
-27.2 -27.1667
2.7 2.70542BetaML.Nn.PoolingLayer — Type
struct PoolingLayer{ND, NDPLUS1, NDPLUS2, TF<:Function, TDF<:Union{Nothing, Function}, WET<:Number} <: AbstractLayerRepresentation of a pooling layer in the network (weightless)
EXPERIMENTAL: Still too slow for practical applications
In the middle between VectorFunctionLayer and ScalarFunctionLayer, it applies a function to the set of nodes defined in a sliding kernel.
Fields:
input_size::StaticArraysCore.SVector{NDPLUS1, Int64} where NDPLUS1: Input size (including nchannel_in as last dimension)output_size::StaticArraysCore.SVector{NDPLUS1, Int64} where NDPLUS1: Output size (including nchannel_out as last dimension)kernel_size::StaticArraysCore.SVector{NDPLUS2, Int64} where NDPLUS2: kernelsize augmented by the nchannelsin and nchannels_out dimensionspadding_start::StaticArraysCore.SVector{ND, Int64} where ND: Padding (initial)padding_end::StaticArraysCore.SVector{ND, Int64} where ND: Padding (ending)stride::StaticArraysCore.SVector{ND, Int64} where ND: Stridendims::Int64: Number of dimensions (excluding input and output channels)f::Function: Activation functiondf::Union{Nothing, Function}: Derivative of the activation function
BetaML.Nn.PoolingLayer — Method
PoolingLayer(
input_size,
kernel_size,
nchannels_in;
stride,
kernel_eltype,
padding,
f,
df
) -> PoolingLayer{_A, _B, _C, typeof(maximum), _D, Float64} where {_A, _B, _C, _D<:Union{Nothing, Function}}
Instantiate a new nD-dimensional, possibly multichannel PoolingLayer
The input data is either a column vector (in which case it is reshaped) or an array of input_size augmented by the n_channels dimension, the output size depends on the input_size, kernel_size, padding and striding but always has nchannels_out as its last dimension.
Positional arguments:
input_size: Shape of the input layer (integer for 1D convolution, tuple otherwise). Do not consider the channels number here.kernel_size: Size of the kernel (aka filter) (integer for 1D or hypercube kernels or nD-sized tuple for asymmetric kernels). Do not consider the channels number here.nchannels_in: Number of channels in input
Keyword arguments:
kernel_eltype: Kernel eltype [def:Float64]stride: "Steps" to move the convolution with across the various tensor dimensions [def:kernel_size, i.e. each X contributes to a single y]padding: Integer or 2-element tuple of tuples of the starting and ending padding across the various dimensions [def:nothing, i.e. set the padding required to keep outsize = insize / stride ]f: Activation function. It should have a vector as input and produce a scalar as output [def:maximum]df: Derivative (gradient) of the activation function for the various inputs. [default:nothing(i.e. use AD)]kernel_eltype: Eltype of the output when the input is not made of floating point numbers [def:Float64]
Notes:
- to retrieve the output size of the layer, use
size(PoolLayer[2]). The output size on each dimension d (except the last one that is given bynchannels_out) is given by the following formula (ceiled):output_size[d] = 1 + (input_size[d]+2*padding[d]-kernel_size[d])/stride[d] - on GPUs only
f=maximumandf=meanare supported (their derivatives are computed directly within the GPU kernel), while other functions work only on the CPU. For other pooling functions on GPUs, use aVectorFunctionLayerwithbatched=true(see its documentation) - a 1-dimensional pooling of
nₗnodes over windows ofknodes moving one node at a time, as done bypool1d, is obtained withPoolingLayer(nₗ,k,1,stride=1,padding=0,f=f). The output has a further singleton "channel" dimension (size(layer) == ((nₗ,1),(nₗ-k+1,1))), that the following dense layers simply ignore - differently from a ConvLayer, the pooling always applies on a single channel level, so that the output always has the same number of channels as the input. If you want to reduce the channels number either use a
ConvLayerwith the desired number of channels in output or use aReshaperLayerto add a 1-element further dimension that will be treated as "channel" and choose the desired stride for the last pooling dimension (the one that was originally the channel dimension)
BetaML.Nn.PoolingLayer — Method
PoolingLayer(
input_size_with_channel,
kernel_size;
stride,
padding,
f,
kernel_eltype,
df
) -> PoolingLayer{_A, _B, _C, typeof(maximum)} where {_A, _B, _C}
Alternative constructor for a PoolingLayer where the number of channels in input is specified as a further dimension in the input size instead of as a separate parameter, so as to use size(previous_layer)[2] if one wishes.
For arguments and default values see the documentation of the main constructor.
BetaML.Nn.ReshaperLayer — Type
ReshaperLayer(input_size) -> ReshaperLayer
ReshaperLayer(input_size, output_size) -> ReshaperLayer
Instantiate a new ReshaperLayer
Positional arguments:
input_size: Shape of the input layer (tuple).output_size: Shape of the output layer (tuple) [def:prod([input_size...]), i.e. reshape to a vector of appropriate length].
BetaML.Nn.ReshaperLayer — Type
struct ReshaperLayer{NDIN, NDOUT} <: AbstractLayerRepresentation of a "reshaper" (weightless) layer in the network
Reshape the output of a layer (or the input data) to the shape needed for the next one.
Fields:
input_size::StaticArraysCore.SVector{NDIN, Int64} where NDIN: Input sizeoutput_size::StaticArraysCore.SVector{NDOUT, Int64} where NDOUT: Output size
BetaML.Nn.SGD — Type
SGD(;η=t -> 1/(1+t), λ=2)Stochastic Gradient Descent algorithm
Fields:
η: Learning rate, as a function of the current epoch [def: t -> 1/(1+t)]λ: Multiplicative constant to the learning rate [def: 2]
BetaML.Nn.ScalarFunctionLayer — Type
struct ScalarFunctionLayer{N, TF<:Function, TDFX<:Union{Nothing, Function}, TDFW<:Union{Nothing, Function}, WET<:Number, WT<:AbstractArray{WET<:Number, N}} <: AbstractLayerRepresentation of a ScalarFunction layer in the network. ScalarFunctionLayer applies the activation function directly to the output of the previous layer (i.e., without passing through a weight matrix), node by node, optionally using a learnable weight as second argument: yᵢ = f(xᵢ) or yᵢ = f(xᵢ,wᵢ). The learnable weights can be either one per node, or a single one shared by all nodes. Differently from VectorFunctionLayer, the function is applied scalarwise to each node.
The number of nodes in input must be set to the same as in the previous layer
Fields:
w: Weights (parameter) vector passed as second argument to the activation function (if not empty), either with one element per node or a single elementn: Number of nodes in output (≡ number of nodes in input )f: Activation function (scalar)dfx: Derivative of the activation function with respect to the layer input of the node (x)dfw: Derivative of the activation function with respect to the learnable weight of the node (w)
Notes:
- The output
sizeof this layer is the same as that of the previous layer.
BetaML.Nn.ScalarFunctionLayer — Method
ScalarFunctionLayer(
nₗ;
rng,
wsize,
w_eltype,
w,
f,
dfx,
dfw
) -> ScalarFunctionLayer{_A, typeof(softmax), _B, Nothing, Float64, _C} where {_A, _B<:Union{Nothing, Function}, _C<:AbstractArray{Float64, _A}}
Instantiate a new ScalarFunctionLayer
Positional arguments:
nₗ: Number of nodes (must be the same as in the previous layer)
Keyword arguments:
wsize: The size of the learnable weights, either[nₗ](one weight per node) or[1](a single weight shared by all nodes) [def: empty array, i.e. no learnable weights]w_eltype: Eltype of the weights [def:Float64]w: Initial weights [default: Xavier initialisation, dims =wsize]f: Activation function. Without learnable weights it is called asf(xᵢ), with learnable weights asf(xᵢ,wᵢ)[def:softmax]dfx: Derivative of the activation function with respect to the data:dfx(xᵢ)ordfx(xᵢ,wᵢ)[default: try to match with well-known derivatives, resort to AD iffis unknown]dfw: Derivative of the activation function with respect to the learnable weight:dfw(xᵢ,wᵢ)[default:nothing(i.e. use AD)]rng: Random Number Generator (seeFIXEDSEED) [default:Random.GLOBAL_RNG]
Notes:
- The derivatives, if provided, are scalar functions (of the scalar input and, if any, of the scalar weight of the node)
- With a single shared weight,
wᵢis the same for all nodes - Xavier initialization =
rand(Uniform(-sqrt(6)/sqrt(sum(wsize...)),sqrt(6)/sqrt(sum(wsize...))))
BetaML.Nn.VectorFunctionLayer — Type
struct VectorFunctionLayer{N, TF<:Function, TDFX<:Union{Nothing, Function}, TDFW<:Union{Nothing, Function}, WET<:Number, WT<:AbstractArray{WET<:Number, N}} <: AbstractLayerRepresentation of a VectorFunction layer in the network. Vector function layer expects a vector activation function, i.e. a function taking the whole output of the previous layer as input rather than working on a single node as "normal" activation functions would do. Useful for example with the SoftMax function in classification or with the pool1D function to implement a "pool" layer in 1 dimension. By default it is weightless, i.e. it doesn't apply any transformation to the output coming from the previous layer except the activation function. However, by passing the parameter wsize (a tuple or array - tested only 1D) you can pass the learnable parameter to the activation function too. It is your responsibility to be sure the activation function accepts only X or also this learnable array (as second argument). The number of nodes in input must be set to the same as in the previous layer (and if you are using this for classification, to the number of classes, i.e. the previous layer must be set equal to the number of classes in the predictions).
Fields:
w: Weights (parameter) array passed as second argument to the activation function (if not empty)nₗ: Number of nodes in input (i.e. length of previous layer)n: Number of nodes in output (automatically inferred in the constructor)f: Activation function (vector)dfx: Derivative of the (vector) activation function with respect to the layer inputs (x)dfw: Derivative of the (vector) activation function with respect to the optional learnable weights (w)
Notes:
- The output
sizeof this layer is given by the size of the output function,
which is not necessarily the same as that of the previous layer.
BetaML.Nn.VectorFunctionLayer — Method
VectorFunctionLayer(
nₗ;
rng,
wsize,
w_eltype,
w,
f,
dfx,
dfw,
batched,
dummyDataToTestOutputSize
) -> VectorFunctionLayer{_A, typeof(softmax), _B, Nothing, Float64, _C} where {_A, _B<:Union{Nothing, Function}, _C<:AbstractArray{Float64, _A}}
Instantiate a new VectorFunctionLayer
Positional arguments:
nₗ: Number of nodes (must be the same as in the previous layer)
Keyword arguments:
wsize: A tuple or array specifying the size (number of elements) of the learnable parameter [def: empty array]w_eltype: Eltype of the weights [def:Float64]w: Initial weights with respect to input [default: Xavier initialisation, dims = (nₗ,n)]f: Activation function [def:softmax]dfx: Derivative of the activation function with respect to the data
[default: try to match with well-known derivatives, resort to AD if f is unknown]
dfw: Derivative of the activation function with respect to the learnable parameter [default:nothing(i.e. use AD)]batched: Whetherfcan be applied directly to a whole batch of records, i.e. to a (nₗ × n records) matrix, returning the (n × n records) matrix of the outputs of each record (e.g.f = X -> X ./ sum(X,dims=1)) [def:false, i.e.fis applied record by record]dummyDataToTestOutputSize: Dummy data to test the output size [def:
ones(nₗ)]
rng: Random Number Generator (seeFIXEDSEED) [default:Random.GLOBAL_RNG]
Notes:
- If the derivative is provided, it should return the gradient as a (n,n) matrix (i.e. the Jacobian) and it is computed record by record. Otherwise the derivatives are computed by AD (with Zygote), on the whole batch if
batched=true - With
batched=true(and no derivative provided) the layer is computed with array-level operations on the whole batch, so it is much faster and it can run on GPUs (iffis written with array-level operations, e.g. broadcasting, sums and array slices, and not with loops over the individual elements). Otherwise the computation is performed record by record on the CPU (except forsoftmax, that is always computed on the whole batch) - Pooling functions with a sliding window can be written for whole batches using array slices, e.g. a root-mean-square pooling over windows of
knodes:VectorFunctionLayer(nₗ,f=X -> sqrt.(sum(X[i:end-k+i,:].^2 for i in 1:k) ./ k),batched=true). Formaximumandmeanpooling use insteadPoolingLayer - To avoid recomputing the activation function just to determine its output size, we compute the output size once here in the layer constructor by calling the activation function with
dummyDataToTestOutputSize. Feel free to change it if it doesn't match with the activation function you are setting - Xavier initialization =
rand(Uniform(-sqrt(6)/sqrt(sum(wsize...)),sqrt(6)/sqrt(sum(wsize...))))
BetaML.Nn.ReplicatorLayer — Method
ReplicatorLayer(
n
) -> ScalarFunctionLayer{_A, typeof(identity), _B, Nothing, Float64, _C} where {_A, _B<:Union{Nothing, Function}, _C<:AbstractArray{Float64, _A}}
Create a weightless layer whose output is equal to the input.
Fields:
n: Number of nodes in output (≡ number of nodes in input )
Notes:
- The output
sizeof this layer is the same as that of the previous layer. - This is just an alias for a
ScalarFunctionLayerwith no weights and identity function.
BetaML.Nn.backward — Method
backward(layer,x,next_gradient)Compute backpropagation for this layer with respect to its inputs
Parameters:
layer: Worker layerx: Input to the layernext_gradient: Derivative of the overall loss with respect to the input of the next layer (output of this layer)
Return:
- The evaluated gradient of the loss with respect to this layer's inputs
Notes:
- For layers implementing
backward_batchthis is computed by calling it on a batch with a single record
BetaML.Nn.backward_batch — Method
backward_batch(layer,X,next_gradient)Compute backpropagation for this layer with respect to its inputs for a whole batch of records
Parameters:
layer: Worker layerX: Input to the layer, with the records along the last dimensionnext_gradient: Derivative of the overall loss with respect to the input of the next layer (output of this layer), with the records along the last dimension
Return:
- The evaluated gradient of the loss with respect to this layer's inputs, with the records along the last dimension
Notes:
- The default implementation calls
backward(layer,x,next_gradient)for each record. Implement this function directly with array-level operations to speed up your layer.
BetaML.Nn.fitting_info — Method
fittinginfo(nn,xbatch,ybatch,x,y;n,nbatches,epochs,epochsran,verbosity,nepoch,n_batch)
Default callback function to display information during training, depending on the verbosity level
Parameters:
nn: Worker networkxbatch: Batch input to the network (batch_size,din)ybatch: Batch label input (batch_size,dout)x: Full input to the network (n_records,din)y: Full label input (n_records,dout)n: Size of the full training setn_batches: Number of batches per epochepochs: Number of epochs defined for the trainingepochs_ran: Number of epochs already run in previous training sessionsverbosity: Verbosity level defined for the training (NONE,LOW,STD,HIGH,FULL)n_epoch: Counter of the current epochn_batch: Counter of the current batch
#Notes:
- Reporting of the error (loss of the network) is expensive. Use
verbosity=NONEfor better performance
BetaML.Nn.forward — Method
forward(layer,x)Predict the output of the layer given the input
Parameters:
layer: Worker layerx: Input to the layer
Return:
- An Array{T,1} of the prediction (even for a scalar)
Notes:
- For layers implementing
forward_batchthis is computed by calling it on a batch with a single record
BetaML.Nn.forward_batch — Method
forward_batch(layer,X)Predict the output of the layer for a whole batch of records
Parameters:
layer: Worker layerX: Input to the layer, with the records along the last dimension (i.e. an array whose size is the input size of the layer augmented by the number of records)
Return:
- The output of the layer, again with the records along the last dimension
Notes:
- The default implementation calls
forward(layer,x)for each record. Implement this function directly with array-level operations to speed up your layer.
BetaML.Nn.forward_batch — Method
forward_batch(layer::ConvLayer, X) -> Any
Compute forward pass of a ConvLayer for a batch of records (on the last dimension)
BetaML.Nn.forward_batch — Method
forward_batch(layer::PoolingLayer{ND}, X) -> AbstractArray
Compute forward pass of a PoolingLayer for a batch of records (on the last dimension)
BetaML.Nn.get_gradient — Method
get_gradient(layer,x,next_gradient)Compute backpropagation for this layer with respect to the layer weights
Parameters:
layer: Worker layerx: Input to the layernext_gradient: Derivative of the overall loss with respect to the input of the next layer (output of this layer)
Return:
- The evaluated gradient of the loss with respect to this layer's trainable parameters as a tuple of matrices. It is up to you to decide how to organise this tuple, as long as you are consistent with the
get_params()andset_params()functions. Note that starting from BetaML 0.2.2 this tuple needs to be wrapped in itsLearnabletype.
Notes:
- For layers implementing
get_gradient_batchthis is computed by calling it on a batch with a single record
BetaML.Nn.get_gradient — Method
get_gradient(nn,x,y)
Low level function that retrieves the current gradient of the weights (i.e. derivative of the cost with respect to the weights) for a single record. Unexported in BetaML >= v0.9
Parameters:
nn: Worker networkx: Input to the network (d,1)y: Label input (d,1)
#Notes:
- The output is a vector of tuples of each layer's input weights and bias weights
BetaML.Nn.get_gradient_batch — Method
get_gradient_batch(layer,X,next_gradient)Compute backpropagation for this layer with respect to the layer weights for a whole batch of records
Parameters:
layer: Worker layerX: Input to the layer, with the records along the last dimensionnext_gradient: Derivative of the overall loss with respect to the input of the next layer (output of this layer), with the records along the last dimension
Return:
- The sum over the records of the batch of the gradients of the loss with respect to this layer's trainable parameters, wrapped in a
Learnableobject
Notes:
- The default implementation sums
get_gradient(layer,x,next_gradient)over the records. Implement this function directly with array-level operations to speed up your layer.
BetaML.Nn.get_params — Method
get_params(layer)Get the current value of the layer's trainable parameters
Parameters:
layer: Worker layer
Return:
- The current value of the layer's trainable parameters as a tuple of matrices. It is up to you to decide how to organise this tuple, as long as you are consistent with the
get_gradient()andset_params()functions. Note that starting from BetaML 0.2.2 this tuple needs to be wrapped in itsLearnabletype.
BetaML.Nn.get_params — Method
get_params(nn)
Retrieve current weights
Parameters:
nn: Worker network
Notes:
- The output is a vector of tuples of each layer's input weights and bias weights
BetaML.Nn.init_optalg! — Method
init_optalg!(opt_alg::ADAM;θ,batch_size,x,y,rng)Initialize the ADAM algorithm with the parameters m and v as zeros and check parameter bounds
BetaML.Nn.init_optalg! — Method
initoptalg!(optalg;θ,batch_size,x,y)
Initialize the optimisation algorithm
Parameters:
opt_alg: The Optimisation algorithm to useθ: Current parametersbatch_size: The size of the batchx: The training (input) datay: The training "labels" to matchrng: Random Number Generator (seeFIXEDSEED) [default:Random.GLOBAL_RNG]
Notes:
- Only a few optimizers need this function and consequently override it. By default it does nothing, so if you want to write your own optimizer and don't need to initialise it, you don't have to override this method
BetaML.Nn.preprocess! — Method
preprocess!(layer::AbstractLayer)
Preprocess the layer with information known at layer creation (i.e. no data info used)
This function is used for some layers to cache some computation that doesn't require the data and it is called at the beginning of fit!.
Notes:
- as it doesn't depend on data, it is not reset by
reset!
BetaML.Nn.set_params! — Method
set_params!(layer,w)Set the trainable parameters of the layer with the given values
Parameters:
layer: Worker layerw: The new parameters to set (Learnable)
Notes:
- The format of the tuple wrapped by Learnable must be consistent with those of the
get_params()andget_gradient()functions.
BetaML.Nn.set_params! — Method
set_params!(nn,w)
Update weights of the network
Parameters:
nn: Worker networkw: The new weights to set
BetaML.Nn.single_update! — Method
singleupdate!(θ,▽;nepoch,nbatch,nbatches,xbatch,ybatch,opt_alg)
Perform the parameters update based on the average batch gradient.
Parameters:
θ: Current parameters▽: Average gradient of the batchn_epoch: Count of current epochn_batch: Count of current batchn_batches: Number of batches per epochxbatch: Data associated to the current batchybatch: Labels associated to the current batchopt_alg: The Optimisation algorithm to use for the update
Notes:
- This function is overridden so that each optimisation algorithm implements its
own version
- Most parameters are not used by any optimisation algorithm. They are provided
to support the largest possible class of optimisation algorithms
- Some optimisation algorithms may change their internal structure in this function