Neural Network Primitives (BNNS)
AppleAccelerate wraps the current, non-deprecated slice of Apple's BNNS (Basic Neural Network Subroutines) library — 61 of the ~136 BNNS* C entry points. The bulk of the remainder are APIs Apple deprecated in macOS 15 / iOS 18: the classic filter/layer construction API and the deprecated classic + DirectApply tensor kernels (BNNSMatMul, BNNSTile, BNNSGather/BNNSScatter, the clip / norm family, BNNSOptimizerStep, …). Those are intentionally not wrapped — target the BNNS Graph API instead. The wrappers are Float32-centric, matching BNNS's native precision for inference. Numerically verified helpers (transpose, copy, reductions, top-k, random generation, nearest neighbors) are cross-checked here against plain-Julia references; the remaining thin wrappers expose the rest of the current surface with exact FFI signatures for callers who need them.
These functions are not exported. Access them via the AppleAccelerate. prefix (e.g. AppleAccelerate.bnns_reduce).
Apple deprecated the classic BNNS filter/layer API and much of the classic tensor/DirectApply surface (macOS 15 / iOS 18) in favour of the newer BNNS Graph API (BNNSGraph). This package does not wrap any of those deprecated entry points; use the Graph API for that functionality. The "What's left to the raw layer" section below lists the full excluded set.
Descriptors
BNNSArray builds a GC-safe BNNSNDArrayDescriptor view of a dense, contiguous Julia array. Internally the N-D op wrappers map a column-major Julia Array onto a BNNSDataLayout{N}DLastMajor descriptor with explicit strides, so BNNS axis k corresponds to Julia dimension k+1 (axis 0 is the contiguous/fastest axis).
AppleAccelerate.BNNSArray — Type
BNNSArray(A::AbstractArray)A GC-safe BNNSNDArrayDescriptor view of a Julia array A, suitable for passing to BNNS routines via Ref. The wrapper keeps a reference to the backing array so it is not collected while the descriptor is alive; pass the underlying descriptor with Base.cconvert/Ref only inside a GC.@preserve block guarding A.
BNNS descriptors are layout aware. Julia stores arrays in column-major order, so this constructor reports the array using a column-major-friendly BNNS layout:
- 1D
Vector->BNNSDataLayoutVector - 2D
Matrix->BNNSDataLayoutColumnMajorMatrix(BNNSsize = (rows, cols)).
Only Float32 (and Int32) dense, contiguous arrays are supported here; other element types or strided/transposed arrays should use the raw LibAccelerate layer directly.
Tensor manipulation
Stateless tensor ops that remain current, cross-validated against permutedims and plain copies.
| Function | Meaning |
|---|---|
bnns_transpose | swap two axes |
bnns_copy! | copy with BNNS layout rules |
M = Float32[1 2 3; 4 5 6]
@assert AppleAccelerate.bnns_transpose(M, 1, 2) == permutedims(M, (2, 1))
@assert AppleAccelerate.bnns_copy!(zeros(Float32, 2, 3), M) == MAppleAccelerate.bnns_transpose — Function
bnns_transpose(A::Array, dim0, dim1) -> ArraySwap Julia dimensions dim0 and dim1 of A (1-based) via BNNSTranspose, equivalent to a permutedims that exchanges those two axes.
AppleAccelerate.bnns_copy! — Function
bnns_copy!(dest::Array, src::Array) -> destCopy (with BNNS's broadcasting / layout conversion rules) src into dest via BNNSCopy. For equal shapes this is a plain element copy.
Reductions
AppleAccelerate.bnns_reduce — Function
bnns_reduce(func::Symbol, input::Array{Float32}; dim=1) -> Array{Float32}Reduce input along Julia dimension dim with func (:sum, :mean, :max, :min, :sumsquare, :l1, :l2, :product, :logsumexp) via BNNSDirectApplyReduction. The reduced axis collapses to length 1.
DirectApply kernels
Fused kernels that run without an explicit filter handle.
AppleAccelerate.bnns_topk — Function
bnns_topk(input::Array{Float32}, K; dim=1) -> (values, indices)Top-K values and their 0-based indices along Julia dimension dim via BNNSDirectApplyTopK. values is Float32, indices is Int32. Comparable to sort-based partialsortperm per slice.
AppleAccelerate.bnns_in_topk — Function
bnns_in_topk(input::Array{Float32}, targets::Array{Int32}, K; dim=1) -> Array{Bool}For each batch column, test whether the targets class index is among the top-K scores of input along Julia dimension dim (BNNSDirectApplyInTopK).
Utility queries
AppleAccelerate.bnns_layout_rank — Function
bnns_layout_rank(layout::BNNSDataLayout) -> IntRank (number of dimensions) encoded by a BNNSDataLayout constant, via BNNSDataLayoutGetRank.
AppleAccelerate.bnns_data_size — Function
bnns_data_size(A::Array) -> IntNumber of bytes of tensor data described by A (BNNSNDArrayGetDataSize).
AppleAccelerate.bnns_tensor_allocation_size — Function
bnns_tensor_allocation_size(A::Array) -> IntBytes required to allocate a BNNSTensor describing A (BNNSTensorGetAllocationSize). Uses the modern BNNSTensor struct (rank + shape/stride), distinct from the legacy BNNSNDArrayDescriptor.
Random number generation
BNNSRandomGenerator is an AES-CTR generator with an optional seed; the fill functions populate arrays in place and the state can be snapshot and restored for reproducibility.
AppleAccelerate.BNNSRandomGenerator — Type
BNNSRandomGenerator([seed]) -> BNNSRandomGeneratorA BNNS random number generator handle (AES-CTR method). Construct with an optional 64-bit seed for reproducibility (BNNSCreateRandomGeneratorWithSeed, or BNNSCreateRandomGenerator when omitted). The handle is destroyed automatically by a finalizer (BNNSDestroyRandomGenerator).
Use with bnns_random_fill_uniform!, bnns_random_fill_normal!, bnns_random_fill_uniform_int!, bnns_random_fill_categorical! and the bnns_random_state/bnns_random_state! round-trip.
AppleAccelerate.bnns_random_fill_uniform! — Function
bnns_random_fill_uniform!(g::BNNSRandomGenerator, A::Array{Float32}, lo=0f0, hi=1f0) -> AFill A with i.i.d. uniform samples on [lo, hi) (BNNSRandomFillUniformFloat).
AppleAccelerate.bnns_random_fill_uniform_int! — Function
bnns_random_fill_uniform_int!(g::BNNSRandomGenerator, A::Array{Int32}, lo, hi) -> AFill integer array A with i.i.d. uniform samples on the half-open range [lo, hi) (BNNSRandomFillUniformInt).
AppleAccelerate.bnns_random_fill_normal! — Function
bnns_random_fill_normal!(g::BNNSRandomGenerator, A::Array{Float32}, mean=0f0, stddev=1f0) -> AFill A with i.i.d. Gaussian samples (BNNSRandomFillNormalFloat).
AppleAccelerate.bnns_random_fill_categorical! — Function
bnns_random_fill_categorical!(g::BNNSRandomGenerator, out::Array{Float32}, probs::Vector{Float32}; log_probs=false) -> outDraw categorical samples (0-based category indices, stored as Float32) into out using per-category weights probs (BNNSRandomFillCategoricalFloat). Pass log_probs=true if probs holds log probabilities.
AppleAccelerate.bnns_random_state — Function
bnns_random_state(g::BNNSRandomGenerator) -> Vector{UInt8}Snapshot the generator's internal state (BNNSRandomGeneratorStateSize + BNNSRandomGeneratorGetState). Restore it with bnns_random_state!.
AppleAccelerate.bnns_random_state! — Function
bnns_random_state!(g::BNNSRandomGenerator, state::Vector{UInt8}) -> gRestore a generator state captured by bnns_random_state (BNNSRandomGeneratorSetState).
Nearest neighbors
AppleAccelerate.BNNSNearestNeighbors — Type
BNNSNearestNeighbors(max_samples, n_features, n_neighbors; T=Float32) -> BNNSNearestNeighborsA brute-force k-nearest-neighbours index (BNNSCreateNearestNeighbors) holding up to max_samples reference points of dimension n_features, answering n_neighbors-NN queries. Destroyed automatically (BNNSDestroyNearestNeighbors).
Add reference points with bnns_knn_load! and query with bnns_knn_query.
AppleAccelerate.bnns_knn_load! — Function
bnns_knn_load!(knn::BNNSNearestNeighbors, data::Matrix{Float32}) -> IntAppend reference samples to the index (BNNSNearestNeighborsLoad). data is n_features × n_new_samples (each column is one sample, matching BNNS's feature-major layout). Returns the number of samples loaded.
AppleAccelerate.bnns_knn_query — Function
bnns_knn_query(knn::BNNSNearestNeighbors, sample_number) -> (indices, distances)Return the n_neighbors nearest reference points to the (0-based) loaded sample sample_number (BNNSNearestNeighborsGetInfo): their 0-based indices (Vector{Int32}) and Float32 distances.
BNNS Graph API
The modern, non-deprecated pipeline: build compile options, compile a serialized graph package into a BNNSGraph, make an executable BNNSGraphContext, then introspect and execute. Compiling requires an on-disk graph package (there is no in-memory graph builder in this API).
AppleAccelerate.BNNSGraphCompileOptions — Type
BNNSGraphCompileOptions(; single_thread=nothing, generate_debug_info=nothing,
optimization=nothing, log_mask=nothing,
output_path=nothing, output_fd=nothing) -> BNNSGraphCompileOptionsOptions controlling BNNSGraphCompileFromFile, backed by BNNSGraphCompileOptionsMakeDefault and destroyed by a finalizer (BNNSGraphCompileOptionsDestroy). Any keyword left nothing keeps the BNNS default. optimization is :performance or :ir_size. Individual fields can also be read/written with the accessor functions below.
AppleAccelerate.BNNSGraph — Type
BNNSGraph(filename; func=nothing, options=BNNSGraphCompileOptions()) -> BNNSGraphCompile a serialized BNNS graph package at filename (optionally selecting a named func inside it) into an executable graph via BNNSGraphCompileFromFile. The returned handle feeds BNNSGraphContext and the graph-introspection helpers.
AppleAccelerate.BNNSGraphContext — Type
BNNSGraphContext(g::BNNSGraph) -> BNNSGraphContextAn executable context for a compiled BNNSGraph (BNNSGraphContextMake), destroyed by a finalizer (BNNSGraphContextDestroy). Feed it to bnns_graph_execute!.
AppleAccelerate.bnns_graph_execute! — Function
bnns_graph_execute!(c, arguments::Vector{bnns_graph_argument_t}; func=nothing, workspace=UInt8[]) -> cExecute func with the supplied argument buffers (BNNSGraphContextExecute). Size workspace from bnns_graph_context_workspace_size.
AppleAccelerate.bnns_graph_context_workspace_size — Function
Workspace size (bytes) required to execute func (BNNSGraphContextGetWorkspaceSize).
The compile-options accessors (bnns_compile_options_set_single_thread!, …_set_optimization!, …_set_output_path!, and their getters) and the graph introspection helpers (bnns_graph_input_count, bnns_graph_argument_names, bnns_graph_argument_intents, …) round out the family.
What's left to the raw layer
Everything not wrapped above is reachable through the raw AppleAccelerate.LibAccelerate layer. It falls into three groups:
- Deprecated classic tensor / DirectApply kernels (macOS 15 / iOS 18) —
BNNSMatMul, the activation-filter path,BNNSTile/BNNSTileBackward,BNNSCompareTensor,BNNSBandPart,BNNSGather/BNNSScatter(and their ND forms),BNNSShuffle, the clip family (BNNSClipByValue/…ByNorm/…ByGlobalNorm),BNNSComputeNorm,BNNSOptimizerStep, and theBNNSDirectApply{ActivationBatch,BroadcastMatMul,Quantizer}kernels. Superseded by the BNNS Graph API; intentionally not given an idiomatic wrapper. - The deprecated classic filter/layer API — the
BNNSFilterCreate*/BNNSFilterCreateLayer*constructors and their*FilterApply*/BNNSFusedFilterApply*execute paths (including the two-input / fused / loss / normalization / pooling / permute batch variants). - Exotic, training-only entry points that need training caches or opaque multi-kilobyte parameter blocks that cannot be validated generically: multi-head attention (
BNNSApplyMultiheadAttentionand its backward), the LSTM training-cache path (BNNSComputeLSTMTrainingCacheCapacity,BNNSDirectApplyLSTMBatchTrainingCaching/…Backward),BNNSComputeNormBackward, image crop/resize (BNNSCropResize/BNNSCropResizeBackward), and the fully-connected sparsification helpers (BNNSNDArrayFullyConnectedSparsifySparse{COO,CSR}).