Matlab Train Network
MathWorksOfficialCreated by MathWorks
- Skill
- Tool integration
- Data and AI
- BSD-2-Clause
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides guidance on using the modern MATLAB Deep Learning Toolbox APIs, specifically focusing on the dlnetwork-based workflow. It covers training, evaluation, inference, and exporting models to Simulink. The skill also includes instructions for migrating legacy code to recommended functions like trainnet and testnet, as well as techniques for diagnosing and applying dlaccelerate to optimize deep learning code execution.
What it does
- Trains neural networks using trainnet and dlnetwork.
- Migrates legacy code from functions like trainNetwork and patternnet to modern equivalents.
- Evaluates trained networks using testnet.
- Exports trained models to Simulink.
- Diagnoses and applies dlaccelerate to optimize custom training loops and functions.
- Performs inference using minibatchpredict.
When to use it
- When training or fine-tuning neural networks in MATLAB.
- When migrating legacy neural network code to modern R2024a+ APIs.
- When evaluating network performance on test data.
- When exporting trained models to Simulink.
- When optimizing the execution speed of deep learning code using dlaccelerate.
Advantages
- Provides a unified workflow for modern deep learning tasks in MATLAB.
- Simplifies the migration process from legacy or discouraged APIs.
- Offers clear decision criteria for choosing between fitcnet/fitrnet and trainnet.
- Includes structured guidance for applying dlaccelerate to improve code execution.
- Supports advanced features like custom loss functions and multi-output networks.
Usage examples
- “How do I train a classification network using the modern trainnet API?”
- The agent provides a code example using trainnet with trainingOptions, specifying the network, loss function, and data format.
- “I have code using patternnet. How do I update it?”
- The agent explains that patternnet is legacy and recommends replacing it with fitcnet for tabular data or a dlnetwork with trainnet for other data types.
- “My custom training loop is slow. How can I speed it up?”
- The agent guides the user through the dlaccelerate workflow, starting with a requirements check to determine if the function is acceleratable.
- “How do I export my trained dlnetwork to Simulink?”
- The agent provides instructions on using exportNetworkToSimulink for supported networks or the Predict block for larger or complex architectures.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/matlab/matlab-train-network/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip matlab-train-network.zip -d .agents/skills
Documentation by MathWorks
matlab-train-network
Train, evaluate, and export neural networks to Simulink in MATLAB using the
recommended dlnetwork-based API (trainnet, dlnetwork, minibatchpredict,
scores2label, testnet, imagePretrainedNetwork) or, for tabular data, the
Statistics and Machine Learning Toolbox functions fitcnet and fitrnet.
When to Use
Activate this skill when a user asks to:
Train any neural network (classifier, regression, multi-output, LSTM, CNN, etc.)
Fine-tune or use a pretrained model for transfer learning
Evaluate a trained network on test data
Run inference / predict with a trained network
Export a trained network to Simulink
Migrate existing legacy (patternnet, fitnet, narxnet, gensim) or discouraged (trainNetwork, DAGNetwork, classify) code to recommended APIs
Create a "pattern recognition network", "function fitting network", "NARX network", or any task historically associated with the Neural Network Toolbox shallow nets API
Speed up or optimize any deep learning code (even without mentioning dlaccelerate by name)
Make existing deep learning code faster using dlaccelerate
Diagnose and fix dlaccelerate issues (low HitRate, retracing, code is slower after using dlaccelerate)
Accelerate custom training (code that uses dlfeval/dlgradient)
Accelerate a function that supports dlarray input and is long running
Accelerate a custom loss function passed to trainnet (R2026a+)
When NOT to Use
Importing/exporting models (importNetworkFromPyTorch, exportONNXNetwork)
Data loading and preprocessing (imageDatastore, transforms, augmentation)
Network architecture design decisions (choosing CNN vs LSTM vs transformer)
Reinforcement learning workflows (use Reinforcement Learning Toolbox)
Object detection (use specialized detector training functions in Computer Vision Toolbox)
Decision: fitrnet/fitcnet or trainnet
Apply this check before starting any training workflow below.
| Criterion | fitcnet/fitrnet | trainnet |
|---|---|---|
| Ease of use | Simplest — one function call | Requires network definition + trainingOptions |
| Solver | L-BFGS | Adam, SGDM, RMSProp, L-BFGS, LM (R2024b+) |
| Loss functions | MSE and cross-entropy only | Any built-in or custom (pass function handle) |
| Multiple input/output branches | No | Yes |
| Custom architecture | Via Network argument (R2025a+) | Yes |
| Data type | Tabular data only (a table or a numeric matrix) | Tabular data plus everything else (sequences, images, multi-input) |
Pass tables directly to trainnet, fitcnet, and fitrnet. If inputs have
categorical columns, pass them directly — they are encoded automatically
(fitcnet/fitrnet always; trainnet/minibatchpredict/testnet from R2025a).
% Classification
mdl = fitcnet(tbl,responseName,LayerSizes=20);
[labels,score] = predict(mdl,tblTest);
L = loss(mdl,tblTest);
% Regression
mdl = fitrnet(tbl,responseName,LayerSizes=[20 20]);
Y = predict(mdl,tblTest);
L = loss(mdl,tblTest);
% Tabular data with trainnet (when fitcnet/fitrnet can't be used)
net = trainnet(tbl,net,"crossentropy",options);
accuracy = testnet(net,tblTest,"accuracy");
scores = minibatchpredict(net,tblPredictors);From R2024b,
fitrnetsupports multi-response variables.From R2025a, for custom architectures beyond
LayerSizes,Activations,LayerWeightsInitializer, andLayerBiasesInitializer, pass adlnetworkvia theNetworkname-value argument.
Conventions
Training with trainnet + dlnetwork
Data formats
trainnet expects data in specific orientations by default:
| Input layer | Expected data shape |
|---|---|
featureInputLayer(C) | observations×channels (e.g., 150×4) |
imageInputLayer([H W C]) | height×width×channels×observations (e.g., 28×28×1×5000) |
sequenceInputLayer(C) | timesteps×channels×observations, or an observations×1 cell array where each element is a timesteps×channels time series |
If your data has a different layout, use InputDataFormats and/or
TargetDataFormats in trainingOptions instead of transposing the data manually.
The format string describes your data's current layout — one letter per
dimension, not the desired layout. MATLAB handles the remapping internally.
For cell arrays, add "B" (batch) to the format string — e.g.,
InputDataFormats="CTB" for cells of C×T matrices. Do not specify these
options when data already matches the input layer's default.
What trainnet supports
Use trainnet and dlnetwork for all Deep Learning Toolbox training. This includes:
Standard classification and regression
Transfer learning
Multi-input or multi-output networks
Custom loss functions (pass a function handle to
trainnet)Custom loss function backward passes via
DifferentiableFunctionCustom metrics (string, function handle, or
deep.Metricsubclass)Custom stopping criteria via
OutputFcnintrainingOptionsCustom layers
Custom training loops (dlfeval/dlgradient/update functions) are appropriate
when the workflow requires customizations impossible via trainingOptions or
the specific workflow — multi-model adversarial training, alternating updates,
or custom weight update rules. Note that trainingOptions supports L-BFGS (R2023b+)
and Levenberg-Marquardt "lm" (R2024b+).
When a user has a working custom training loop and asks to speed it up, apply
dlaccelerate directly. Mention that their workflow may also be expressible
with trainnet (which handles acceleration internally), but do not push the
conversion — focus on accelerating the code they have.
NEVER use these legacy or discouraged APIs
If the user has existing code using these APIs, migrate it to the recommended replacement and briefly explain which APIs were replaced and what the modern equivalents are. If the user asks for a legacy or discouraged API by name, acknowledge their request and explain that the function has been replaced with a recommended alternative before providing the solution.
| Legacy or discouraged API | Recommended replacement |
|---|---|
trainNetwork | trainnet |
patternnet | fitcnet (preferred), or dlnetwork + trainnet |
fitnet | fitrnet (preferred), or dlnetwork + trainnet |
feedforwardnet | dlnetwork + trainnet |
narxnet, timedelaynet | nlarx (preferred), or dlnetwork + trainnet |
train() (shallow network object) | trainnet |
classify | minibatchpredict + scores2label |
activations | minibatchpredict(net,data,Outputs=layer) |
predictAndUpdateState, classifyAndUpdateState | [Y,state] = predict(net,X); net.State = state; |
classificationLayer | Not required — use trainnet with "crossentropy" as the loss |
regressionLayer | Not required — use trainnet with "mse" as the loss |
DAGNetwork, SeriesNetwork, layerGraph | dlnetwork — supports addLayers, connectLayers, and replaceLayer for multi-branch architectures, anything layerGraph can do, dlnetwork can do directly |
resnet18, googlenet, squeezenet, etc. (pretrained network functions that return DAGNetwork) | imagePretrainedNetwork("resnet18", ...) — returns a dlnetwork and handles head replacement automatically |
Manually converting network scores to labels (e.g., [~,idx] = max(scores)) | scores2label |
plotconfusion | confusionchart |
gensim | exportNetworkToSimulink (preferred), or Predict block |
preparets | nlarx (preferred, handles delays internally), or dlnetwork with sequenceInputLayer(C, MinLength=numDelays) + convolution1dLayer(numDelays, ..., Padding="causal") |
closeloop | forecast (preferred, with nlarx), or iterative predict loop feeding previous predictions back as input |
See references/legacy-api-redirects.md for before/after code examples.
Inference — use minibatchpredict (or predict)
If you see a for-loop calling predict or forward on batches for inference,
replace the entire loop with minibatchpredict. It handles batching, GPU
transfer, dlarray conversion, and acceleration automatically. Output format
(numeric array, table, or cell array) depends on the input type and network.
Exception: If the loop includes custom pre- or postprocessing around the
predict call that cannot be separated from it, minibatchpredict cannot
replicate the full pipeline. In that case, wrap the entire custom function
with dlaccelerate instead (see references/dlaccelerate-workflow.md).
Do not split the function into a minibatchpredict call plus separate
accelerated pre/postprocessing — a single dlaccelerate boundary around the
full function produces one unified trace.
For classification: use
minibatchpredict(orpredict) +scores2label.For regression or when you need raw scores: use
minibatchpredictorpredict.predictis for single-batch/small-batch use and accepts plain numeric arrays directly — do not wrap inputs indlarrayor callextractdataon outputs.
Evaluation — use testnet
Use
testnetto calculate post-training metrics on a test dataset instead of doing it manually.For single-output networks, use string metrics:
"accuracy","rmse".trainnetandtestnetaccept targets as a separate argument only for in-memory data (testnet(net,XTest,TTest,"accuracy")). When passing a datastore, targets must already be embedded in it (e.g., labeled imageDatastore or combined datastore with targets in a second column).For multi-output networks or advanced metric customization, see
references/metrics-guidance.md.
Transfer learning — use imagePretrainedNetwork
net = imagePretrainedNetwork("squeezenet",NumClasses=5);
options = trainingOptions("adam", ...
MaxEpochs=10, ...
MiniBatchSize=16, ...
InitialLearnRate=1e-4, ...
ValidationData=imdsVal, ...
Metrics="accuracy", ...
Plots="training-progress");
net = trainnet(augimdsTrain,net,"crossentropy",options);
% Inference — class names come from training data, not the pretrained net
classNames = categories(imdsTrain.Labels);
scores = minibatchpredict(net,imdsTest);
labels = scores2label(scores,classNames);imagePretrainedNetwork returns class names only when both NumClasses and
NumResponses are unset (pretrained mode, no transfer learning).
Workflow: Training
Check the Decision section above first — tabular data goes to fitrnet/fitcnet unless you need a non-LBFGS solver or a non-MSE/cross-entropy loss.
Standard training
% Define network
numChannels = 3;
numClasses = 5;
layers = [
sequenceInputLayer(numChannels,Normalization="zscore")
lstmLayer(100,OutputMode="last")
fullyConnectedLayer(numClasses)
softmaxLayer];
% Training options
options = trainingOptions("adam", ...
MaxEpochs=30, ...
MiniBatchSize=128, ...
ValidationData={XVal,TVal}, ...
Metrics="accuracy", ...
Plots="training-progress");
% Train
net = trainnet(XTrain,TTrain,layers,"crossentropy",options);Always normalize inputs. Set Normalization on the input layer (see example
above). For regression, also normalize targets:
R2026a+: append
inverseNormalizationLayerto the last layer and setNormalizeTargets=trueintrainingOptionsPre-R2026a: manually z-score targets before training and denormalize predictions at inference
See references/normalization.md for both workflows.
Custom loss function for multi-output
The function handle receives network outputs then targets, in order.
Pass categorical targets directly — trainnet encodes them automatically.
lossFcn = @(Y1,Y2,T1,T2) crossentropy(Y1,T1) + mse(Y2,T2);
net = trainnet(ds,net,lossFcn,options);For the full multi-output recipe (OutputNames alignment, combined datastores,
testnet evaluation), see references/multi-output-training.md.
Since the multi-output loss is a function handle, it can be accelerated using
dlaccelerate. Always inform the user that their custom loss function handle
can be accelerated with dlaccelerate for faster training — even if they did not
ask to speed up training. See references/dlaccelerate-trainnet-custom-loss.md
for the verification and production workflow.
Workflow: Simulink Export
dlnetwork(small, all layers supported): useexportNetworkToSimulinkdlnetwork(large, or has layers unsupported byexportNetworkToSimulink): use the Predict block at library pathdeeplib/Predictfitcnet/fitrnetmodels: use theClassificationNeuralNetwork PredictorRegressionNeuralNetwork Predictblocks fromstatsLibrary/
See references/simulink-export.md for details.
Workflow: Deep Learning Code Acceleration with dlaccelerate — Diagnose, Fix, or Apply
Does NOT apply to:
Simulink export
MEX/Coder compilation
fitcnet/fitrnet/nlarxworkflows
Applies when:
User has a custom training loop (
dlfeval/dlgradient)User has a function that supports dlarray input and is long running
User calls
trainnetwith a custom loss function handle (R2026a+)
Always attempt to dlaccelerate functions that:
Are long-running.
Have dlarray objects, structures of dlarray objects, or dlnetwork objects as inputs.
Only perform operations that affect the output variables. Operations that do not affect the output variables include plotting, displaying output, and writing to files.
Check references/dlaccelerate-workflow.md Step 0 to determine whether the
function is acceleratable before recommending.
Follow references/dlaccelerate-workflow.md for the full diagnostic/fix/improve
process. Entry points:
User says "make faster" or "speed up" and the code has a custom training loop: start at Step 0.
Code already uses
dlacceleratewith problems: start at Step 1 (identify antipatterns, apply fixes, verify).Custom training loop without
dlaccelerate: start at Step 0 (requirements check, wrap, verify).Any function with dlarray input that is called repeatedly: start at Step 0. This includes custom model functions used for prediction.
Custom inference function called repeatedly: same Step 0 applies.
dlaccelerateis not training-specific — any repeatedly-called dlarray function benefits. Useminibatchpredictwhen the loop only callspredictwith no custom pre- or postprocessing; usedlacceleratewhen custom operations surround the predict call.trainnet+ custom loss function handle (R2026a+): wrap the loss withdlaccelerateand pass the AcceleratedFunction to trainnet. Seereferences/dlaccelerate-trainnet-custom-loss.md.
For antipatterns that break tracing and their fixes, see
references/dlaccelerate-antipatterns.md.
dlaccelerate References
references/dlaccelerate-workflow.md— full diagnostic/fix/improve processreferences/dlaccelerate-antipatterns.md— pattern catalog with BAD/GOOD examplesreferences/dlaccelerate-custom-training-loop.md— acceleration levels, L2, clippingreferences/dlaccelerate-trainnet-custom-loss.md— trainnet + custom loss (R2026a+)references/dlaccelerate-variable-length-sequences.md— padding/bucketing strategiesreferences/dlaccelerate-custom-layers.md— Acceleratable custom layers (nnet.layer.Acceleratable)references/dlaccelerate-measure-speedup.md— benchmarking methodology
Key Functions
| Function | Purpose |
|---|---|
fitcnet | Train neural network classifier for tabular data (Statistics and Machine Learning Toolbox) |
fitrnet | Train neural network for regression on tabular data (Statistics and Machine Learning Toolbox) |
nlarx | Nonlinear ARX model for NARX / time-delay time series (System Identification Toolbox) |
trainnet | Train any dlnetwork with built-in or custom loss |
dlnetwork | Modern network object (replaces DAGNetwork/SeriesNetwork/LayerGraph) |
trainingOptions | Configure solver, epochs, validation, metrics |
minibatchpredict | Batch inference (handles batching automatically) |
scores2label | Convert score matrix to categorical labels |
testnet | Evaluate network with metrics on a dataset (handles batching automatically) |
predict | Single-batch inference on dlnetwork, ClassificationNeuralNetwork, RegressionNeuralNetwork |
imagePretrainedNetwork | Load pretrained model with automatic head replacement |
exportNetworkToSimulink | Export dlnetwork to Simulink as layer blocks |
analyzeNetwork | Inspect network: info = analyzeNetwork(net) returns layer info, parameter counts, and architecture issues |
minibatchqueue | Manage mini-batches with custom per-batch preprocessing |
dlaccelerate | Accelerate a deep learning function by tracing and caching its execution graph |
Common Mistakes
| What the agent might try | Why it's wrong | Do this instead |
|---|---|---|
predict(net,dlarray(X,"TCB")) | Unnecessary — predict on a dlnetwork accepts plain arrays | predict(net,X) |
| Manual accuracy/RMSE after training | Covered by existing functionality | testnet(net,XTest,TTest,"accuracy") |
squeezenet + layerGraph + replaceLayer | Discouraged manual layer surgery for transfer learning | imagePretrainedNetwork("squeezenet",NumClasses=N) |
| Custom training loop for multi-output | Unnecessary complexity | trainnet with function handle loss |
Transposing data to match the default layout (e.g., cellfun(@transpose,...)) | Unnecessary complexity | InputDataFormats, TargetDataFormats — arrange letters to match your data's actual dimension order |
testnet(net,ds,labels,"accuracy") | testnet does not accept separate targets with datastores | testnet(net,ds,"accuracy") |
trainnet for tabular data | Unnecessary complexity when using MSE/cross-entropy loss and LBFGS solver | fitrnet or fitcnet |
analyzeNetwork(net) without capturing output | Loses programmatic access to layer info, parameter counts, and issues | info = analyzeNetwork(net) |
Manually encoding categorical columns before passing to trainnet/fitcnet/fitrnet | Unnecessary complexity when these functions encode categorical data automatically | Pass categorical data directly |
| Manual for-loop batching for inference | Unnecessary complexity | minibatchpredict(net,X) — handles batching, GPU transfer, and acceleration automatically |
| Manual for-loop batching for custom preprocessing | Unnecessary complexity | minibatchqueue — handles batching, GPU transfer, dlarray conversion, and custom transforms |
Copyright 2026 The MathWorks, Inc.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.0 KiB
- LICENSELicence file added by AutoGineer1.4 KiB
- SKILL.md19.2 KiB
- manifest.yaml533 B
- references/dlaccelerate-antipatterns.md10.9 KiB
- references/dlaccelerate-custom-layers.md2.5 KiB
- references/dlaccelerate-custom-training-loop.md5.4 KiB
- references/dlaccelerate-measure-speedup.md2.9 KiB
- references/dlaccelerate-trainnet-custom-loss.md3.0 KiB
- references/dlaccelerate-variable-length-sequences.md3.0 KiB
- references/dlaccelerate-workflow.md11.4 KiB
- references/legacy-api-redirects.md4.0 KiB
- references/metrics-guidance.md2.1 KiB
- references/multi-output-training.md3.3 KiB
- references/normalization.md2.0 KiB
- references/simulink-export.md1.7 KiB
references/dlaccelerate-antipatterns.md
dlaccelerate Anti-Patterns Reference
Patterns that break dlaccelerate function tracing, causing re-tracing on every call and destroying cache hit rates.
Pattern 1: Data-Dependent Branches
Problem: if/switch conditions that depend on dlarray values or non-traced computations (like rand()) are evaluated only during the initial trace. The chosen branch is baked into the cached code permanently.
% BAD: condition depends on dlarray value, cached path never changes
if gradientNorm > threshold
gradients = gradients * (threshold / gradientNorm);
end
% BAD: rand() is not traced, always takes the branch from first call
if rand > 0.5
y = x * 2;
else
y = x * 3;
endFix: Replace with branch-free arithmetic:
% GOOD: no branch, works for all values
scale = min(threshold / gradientNorm, 1);
gradients = gradients * scale;
% GOOD: for the rand case, pass the decision as a non-dlarray input
% (each value gets its own cached trace, only 2 needed for boolean)
function y = myFcn(x, useDoubling)
if useDoubling
y = x * 2;
else
y = x * 3;
end
end
accFcn = dlaccelerate(@myFcn);
y = dlfeval(accFcn, x, rand > 0.5); % Two traces: one for true, one for falseSafe exception: Branching on non-dlarray constants that never change between calls is fine. Watch out for non-dlarray scalars specifically, as they are typically the inputs that appear constant but actually change between calls (iteration counters, learning rates, scheduled hyperparameters).
% SAFE: gradientThreshold and gradientClippingMethod are fixed for the entire training run. They produce one cached trace each and never retrace.
gradientThreshold = 1.0;
gradientClippingMethod = "l2norm";
accFcn = dlaccelerate(@trainStep);
for iteration = 1:numIterations
[grad, loss] = dlfeval(accFcn, net, X, T, gradientThreshold, gradientClippingMethod);
...
end
function [grad, loss] = trainStep(net, X, T, gradientThreshold, gradientClippingMethod)
[Y, state] = forward(net, X);
loss = crossentropy(Y, T);
grad = dlgradient(loss, net.Learnables);
if gradientClippingMethod == "l2norm"
grad = thresholdL2Norm(grad, gradientThreshold);
elseif gradientClippingMethod == "absolute-value"
grad = thresholdAbsoluteValue(grad, gradientThreshold);
end
end% UNSAFE: learnRate and iteration change every call. Each unique value triggers a new trace.
accFcn = dlaccelerate(@trainStep);
numIterations = 50;
for i = 1:numIterations
learnRate = baseLR * 0.5 * (1 + cos(pi * i / numIterations));
[grad, loss] = dlfeval(accFcn, net, X, T, learnRate, i);
...
end
% Fix: wrap changing inputs as dlarray before the loop
accFcn = dlaccelerate(@trainStep);
iteration = dlarray(1);
for i = 1:numIterations
learnRate = baseLR * 0.5 * (1 + cos(pi * iteration / numIterations));
[grad, loss] = dlfeval(accFcn, net, X, T, learnRate, iteration);
...
iteration = iteration + 1;
end
% Even better fix: move schedule computation inside the accelerated boundary
% Note: baseLR and numIterations are constants, safe as non-dlarray inputs.
accFcn = dlaccelerate(@trainStep);
iteration = dlarray(1);
for i = 1:numIterations
[grad, loss] = dlfeval(accFcn, net, X, T, iteration, baseLR, numIterations);
...
iteration = iteration + 1;
end
function [grad, loss] = trainStep(net, X, T, iteration, baseLR, numIterations)
learnRate = baseLR * 0.5 * (1 + cos(pi * iteration / numIterations));
...
endPattern 2: Logical Indexing — Count-Dependent Operations on Selections
Problem: Logical indexing for selection (y = X(X > 0)) produces a variable-length result whose element count varies with input values. The selection itself and value-only reductions on it (sum, max, min, .^2, dot) are traced correctly. However, numel, size, and length on a variable-length selection return the count from the first trace as a frozen constant. Functions that depend on the element count, mean, var, std, silently produce wrong results for the same reason.
% BAD: numel on selection is frozen from first trace
selected = X(X > 0);
y = sum(selected) / numel(selected); % wrong answers silently
% BAD: same issue with length or size on a selection
y = sum(X(X > 0)) / length(X(X > 0));
% BAD: mean, var, std on a selection — depend on element count
y = mean(X(X > 0)); % produces wrong answers (verify with CheckMode="tolerance")
y = var(X(X > 0));Safe patterns — value-only operations that do not depend on element count:
% SAFE: sum, max, min on selection
y = sum(X(X > 0));
y = max(X(X > 0));
% SAFE: element-wise operations on selection
y = sum(X(X > 0) .^ 2);
y = dot(X(X > 0), X(X > 0));
% SAFE: logical indexed assignment — preserves array shape
X(X >= 0) = 0;
% SAFE: cross-array logical indexed assignment — same mask applied to another array
T(Z >= 0) = 0;Key distinction: Assignment into an array (X(mask) = value, where the indexed array is on the left of =) is shape-preserving and always safe — the output array has the same shape as the input. Selection from an array (y = X(mask), where the indexed array is on the right of =) produces a variable-length result and is potentially problematic when combined with count-dependent operations.
Fix for count-dependent operations: Compute the count from the fixed-shape logical mask instead of from the variable-length selection:
% GOOD: mask-based mean — count comes from fixed-shape mask via sum
mask = X > 0;
y = sum(X .* mask, 'all') / sum(mask, 'all');
% GOOD: element-wise clipping, assuming threshold remains a constant
gradients = min(gradients, threshold);
gradients = max(gradients, -threshold);Key insight: The issue is not logical indexing itself — it is numel/size/length and functions that depend on element count (mean, var, std) applied to a variable-length selection. sum(mask, 'all') safely provides the count because the mask has fixed shape (same as the input).
Pattern 3: Random Numbers Without Tracing
Problem: rand(sz) without 'like' linkage to a dlarray is NOT traced. It produces a constant in the generated code (same random values every call).
% BAD: same random mask reused from cache every iteration
mask = rand(size(x)) > dropoutRate;Fix: Use 'like' syntax to link to a traced dlarray:
% GOOD: rand is traced because it's tied to dlarray x
mask = rand(size(x), 'like', x) > dropoutRate;Pattern 4: Side Effects
Problem: disp, fprintf, file I/O, datastore reads, plotting execute ONLY during the initial trace. On subsequent cached calls they are skipped entirely.
% BAD: only prints during initial trace, then silent forever
function [loss, grad] = modelGrad(net, X, T)
fprintf('Loss: %f\n', loss);
...
endFix: Move all side effects OUTSIDE the traced function:
% GOOD: print outside dlfeval, always executes
[loss, grad] = dlfeval(accFcn, net, X, T);
fprintf('Loss: %f\n', loss);
% Alternative (for debugging): Temporarily disable acceleration:
accFcn.Enabled = false;Pattern 5: Using extractdata Inside Traced Function
Problem: Using extractdata with a traced argument removes the value from the trace. The result becomes a constant in the cached code. Subsequent calls reuse the stale value from the first trace instead of recomputing it.
% BAD: extractdata removes loss from the trace, cached value never updates
function [loss, grad] = modelGrad(net, X, T)
Y = forward(net, X);
lossVal = extractdata(l2loss(Y, T));
...
endextractdata may also be encountered because some functions do not accept formatted dlarray data or are not compatible at all with dlarray. Code like this can train correctly without dlaccelerate (gradients still flow through other paths), but it prevents acceleration because the extracted values become stale constants in the cached trace.
Fix strategy — try in order:
First verify whether extractdata can be replaced with stripdims. Many functions that reject formatted dlarrays accept unformatted ones.
Step 1: Use stripdims — stripdims removes format labels while preserving dlaccelerate compatibility. You cannot know whether a function accepts unformatted dlarray without running it. Implement the fix using stripdims with the original functions and execute it. Only move to Step 3 if execution produces a runtime error from one of those functions not accepting the input. Do not skip this step based on assumptions about function compatibility — many functions (including awgn, fft, ifft, comm., etc) accept unformatted dlarray.
% GOOD: stripdims preserves dlaccelerate compatibility, only removes format labels
noisySignal = awgn(originalSignal, stripdims(noiseLevel));Always prefer stripdims + the original function over rewriting the math manually, because:
It preserves the original algorithm (easier for the user to verify correctness)
It is compatible with
dlacceleratetracing
Step 2: Move extractdata outside dlfeval — If the value is only needed for logging or postprocessing and does not feed back into the accelerated function:
% GOOD: extractdata only outside dlfeval
[loss, grad] = dlfeval(accFcn, net, X, T);
lossVal = extractdata(loss); % fine here, not inside the traced functionStep 3: Reformulate as a last resort — Only if Step 1 produces a runtime error (a function rejects the unformatted dlarray), reformulate that specific operation. Do not preemptively reformulate without first confirming stripdims fails.
Pattern 6: Nested Functions Accessing Enclosing Workspace
Problem: Variables from the enclosing scope are captured as constants during tracing. If those variables change between calls, the traced graph silently uses the stale values from the first trace.
% BAD: threshold captured as constant at trace time
threshold = 0.1;
accFcn = dlaccelerate(@myFunc);
function grad = myFunc(net, X, T)
...
grad = dlupdate(@(g) iClip(g, threshold), grad); % threshold frozen at 0.1
endFix: Pass all changing values as function inputs:
% GOOD: threshold is an explicit input, traced correctly
accFcn = dlaccelerate(@myFunc);
function grad = myFunc(net, X, T, threshold)
...
grad = dlupdate(@(g) iClip(g, threshold), grad);
endPattern 7: Anonymous Function Handles as Inputs
Problem: Anonymous functions recreated each call trigger a retrace because each instance is a distinct object:
isequaln(@(x)x, @(x)x) returns false.
Fix: Assign the anonymous function to a variable once to ensure identity:
% BAD: retrace every call
result = dlfeval(accFcn, net, @(y,t) crossentropy(y,t), X, T);
% GOOD: same object → cache hit
fcn = @(y,t) crossentropy(y,t);
result = dlfeval(accFcn, net, fcn, X, T);Note: Named function handles (@crossentropy) are always safe because they have stable identity.
Copyright 2026 The MathWorks, Inc.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- MathWorks
- Publisher
- MathWorks (Official)
- Source
- matlab/matlab-agentic-toolkit · skills-catalog/ai-and-statistics/matlab-train-network · commit 2a7f215
- Licence
- BSD 2-Clause License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by MathWorks or MathWorks.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-train-network.zip