www.gusucode.com > nnet 工具箱 matlab 源码程序 > nnet/@network/sim.m
function [Y,Xf,Af,E,perf]=sim(net,varargin) %SIM Simulate a neural network. % % SIM(NET,X) takes a network NET and inputs X and returns the outputs % Y generated by the network. This syntax is equivalent to NET(X). % % [Y,Xf,Af] = <a href="matlab:doc sim">sim</a>(NET,X,Xi,Ai) takes a dynamic network NET, inputs X, % and initial input and layer delays Xi and Ai. It returns the outputs Y % and final input and layer delays states Xf and Af. % % <a href="matlab:doc sim">sim</a> arguments can have two formats: matrices, for static % problems and networks with single inputs and outputs, and cell arrays % for multiple timesteps and networks with multiple inputs and outputs. % % The matrix format is as follows: % X - RxQ matrix % Y - UxQ matrix. % Where: % Q = number of samples % R = number of elements in the network's input % U = number of elements in the network's output % % The cell array format is most general: % X - NixTS cell array, each element X{i,ts} is an RixQ matrix. % Xi - NixID cell array, each element Xi{i,k} is an RixQ matrix. % Ai - NlxLD cell array, each element Ai{i,k} is an SixQ matrix. % Y - NOxTS cell array, each element Y{i,ts} is a UixQ matrix. % Xf - NixID cell array, each element Xf{i,k} is an RixQ matrix. % Af - NlxLD cell array, each element Af{i,k} is an SixQ matrix. % Where: % TS = number of time steps % Ni = NET.<a href="matlab:doc nnproperty.net_numInputs">numInputs</a> % Nl = NET.<a href="matlab:doc nnproperty.net_numLayers">numLayers</a>, % No = NET.<a href="matlab:doc nnproperty.net_numOutputs">numOutputs</a> % ID = NET.<a href="matlab:doc nnproperty.net_numInputDelays">numInputDelays</a> % LD = NET.<a href="matlab:doc nnproperty.net_numLayerDelays">numLayerDelays</a> % Ri = NET.<a href="matlab:doc nnproperty.net_inputs">inputs</a>{i}.<a href="matlab:doc nnproperty.input_size">size</a> % Si = NET.<a href="matlab:doc nnproperty.net_layers">layers</a>{i}.<a href="matlab:doc nnproperty.layer_size">size</a> % Ui = NET.<a href="matlab:doc nnproperty.net_outputs">outputs</a>{i}.<a href="matlab:doc nnproperty.output_size">size</a> % % The columns of Xi, Xf, Ai, and Af are ordered from oldest delay % condition to most recent: % Xi{i,k} = input i at time ts=k-ID. % Xf{i,k} = input i at time ts=TS+k-ID. % Ai{i,k} = layer output i at time ts=k-LD. % Af{i,k} = layer output i at time ts=TS+k-LD. % % [Y,Pf,Af] = SIM(net,{Q TS},Pi,Ai) is used for networks % which do not have an input, such as Hopfield networks % when cell array notation is used. % % Here a static feedforward network is created, trained on some data, then % simulated using SIM and network notation. % % [x,t] = <a href="matlab:doc simplefit_dataset">simplefit_dataset</a>; % net = <a href="matlab:doc feedforwardnet">feedforwardnet</a>(10); % net = <a href="matlab:doc train">train</a>(net,x,t); % y1 = <a href="matlab:doc sim">sim</a>(net,x) % y2 = net(x) % % Here a dynamic NARX network is created, trained, and simulated on % time series data. % % [X,T] = <a href="matlab:doc simplenarx_dataset">simplenarx_dataset</a>; % net = <a href="matlab:doc narxnet">narxnet</a>(1:2,1:2,10); % <a href="matlab:doc view">view</a>(net) % [Xs,Xi,Ai,Ts] = <a href="matlab:doc preparets">preparets</a>(net,X,{},T); % net = <a href="matlab:doc train">train</a>(net,Xs,Ts,Xi,Ai); % Y1 = <a href="matlab:doc sim">sim</a>(net,Xs,Xi,Ai) % Y2 = net(Xs,Xi,Ai) % % <strong>Simulation with Parallel Computing</strong> % % Parallel Computing Toolbox allows Neural Network Toolbox to simulate % networks faster and on larger datasets than can fit on one PC. % % Here simulation automatically happens across MATLAB parallel workers. % % parpool % [X,T] = vinyl_dataset; % net = feedforwardnet(140,'trainscg'); % net = train(net,X,T,'UseParallel','yes'); % Y = net(X,'UseParallel','yes'); % % Use Composite values to distribute the data manually, and get back % the results as a Composite value. If the data is loaded as it is % distributed then while each piece of the dataset must fit in RAM, the % entire dataset is only limited by the number of workers RAM. % % Xc = Composite; % for i=1:numel(Xc) % Xc{i} = X + rand(size(X))*0.1; % (Use real data instead of random) % end % Yc = net(Xc); % Y = cat(2,Yc{:}); % % Networks can be simulated using the current GPU device, if it is % supported by the Parallel Computing Toolbox. This is efficient for % large static problems or dynamic problems with many series. % % Y = net(X,'UseGPU','yes'); % % To put the data on a GPU manually, and get the results on the GPU, % the network must be static and have a single input and output: % % Xgpu = gpuArray(X); % Ygpu = net(Xgpu); % Y = gather(Ygpu); % % To run in parallel, with workers associated with unique GPUs taking % advantage of that hardware, while the rest of the workers use CPUs: % % Y = net(X,'UseParallel','yes','UseGPU','yes'); % % Only using workers with unique GPUs may result in higher speed, as CPU % workers may not keep up. % % Y = net(X,'UseParallel','yes','UseGPU','only'); % % Use the 'ShowResources' option to verify the computing resources used. % % y = net(...,'ShowResources','yes'); % % See also INIT, REVERT, ADAPT, TRAIN % Copyright 1992-2015 The MathWorks, Inc. % CHECK AND FORMAT ARGUMENTS % -------------------------- % Network if nargin < 1, error(message('nnet:Args:NotEnough')); end if ~isa(net,'network') error('nnet:train:arguments','First argument is not a neural network.'); end net = struct(net); net.trainFcn = ''; % Disable training related setup [~,zeroDelayLoop] = nn.layer_order(net); if zeroDelayLoop, error(message('nnet:NNet:ZeroDelayLoop')); end % PICK CALCULATION MODE % Undocumented Testing API. % This API may be altered or removed at any time. % Specify calculation mode by name as last argument of train. if ~isempty(varargin) && isstruct(varargin{end}) && isfield(varargin{end},'name') calcMode = nncalc.defaultMode(net,varargin{end}); varargin(end) = []; calcMode.options = nnet.options.calc.defaults; calcMode.options.showResources = 'yes'; % Documented API % Recommended API for customers and most testing. % Use optional parameter/value pairs to pick calculation mode. else [varargin,nameValuePairs] = nnet.arguments.extractNameValuePairs(varargin); [calcMode,err] = nncalc.options2Mode(net,nameValuePairs); if ~isempty(err), error('nnet:train:arguments',err); end end problem = calcMode.netCheck(net,calcMode.hints,false,false); if ~isempty(problem), error(problem); end % Check Composite Data for consistency nargs = numel(varargin); if nargs >= 1 isComposite = isa(varargin{1},'Composite'); else isComposite = false; end for i=2:nargs if isComposite ~= isa(varargin{i},'Composite') error('nnet:sim:Composite','Data values must be all Composite or not.'); end end % Check gpuArray data for consistency isGPUArray = (nargs >= 1) && isa(varargin{1},'gpuArray'); for i=2:nargs vi = varargin{i}; if ~isempty(vi) && (isGPUArray ~= isa(vi,'gpuArray')) error('nnet:sim:Composite','Data values must be all gpuArray or not.'); end end % Fill in missing data consistent with type if isComposite emptyCell = Composite; oneCell = Composite; for i=1:numel(emptyCell) emptyCell{i} = {}; oneCell{i} = {1}; end else emptyCell = {}; oneCell = {1}; end if (nargs < 1), X = emptyCell; else X = varargin{1}; end if (nargs < 2), Xi = emptyCell; else Xi = varargin{2}; end if (nargs < 3), Ai = emptyCell; else Ai = varargin{3}; end if (nargs < 4), T = emptyCell; else T = varargin{4}; end if (nargs < 5) || isempty(varargin{5}), EW=oneCell; else EW=varargin{5}; end if isComposite for i=1:numel(X) if ~exist(X,i), X{i} = {}; end if ~exist(T,i), T{i} = {}; end if ~exist(Xi,i), Xi{i} = {}; end if ~exist(Ai,i), Ai{i} = {}; end if ~exist(EW,i), EW{i} = {1}; end end end % X a Matrix or Cell? Use to format Y later. if isComposite spmd, xMatrix = ~iscell(X); end else xMatrix = ~iscell(X); end % Convert explicit timesteps to inputs if ~isComposite && ~isGPUArray xMatrix = ~iscell(X); if (net.numInputs == 0) if xMatrix && isscalar(X) % Q X = {zeros(0,X)}; elseif ~xMatrix && isscalar(X) && isscalar(X{1}) % {TS} X = cell(1,X{1}); elseif xMatrix && (ndims(X)==2) && all(size(X)==[1 2]) % [Q TS] Q = X(1); TS = X(2); X = cell(1,TS); for i=1:TS,X{i} = zeros(1,Q); end xMatrix = false; elseif ~xMatrix && (ndims(X)==2) && all(size(X)==[1 2]) ... && isscalar(X{1}) && isscalar(X{2}) % {Q TS} Q = X{1}; TS = X{2}; X = cell(1,TS); for i=1:TS,X{i} = zeros(1,Q); end xMatrix = false; end end X = nntype.data('format',X,'Inputs'); end % NNET 5.1 Backward Compatibility if ~isComposite tMatrix = ~iscell(T); if ~isempty(T), T = nntype.data('format',T,'Targets'); end end % SIMULATE NETWORK % ---------------- % Format Data Arguments if isComposite spmd [data,err] = simData(net,X,Xi,Ai,T,EW); if ~isempty(regexp(err,'^nnet:','once')), error(message(err)), end if ~isempty(err), nnerr.throw(err), end end else [data,err] = simData(net,X,Xi,Ai,T,EW); if ~isempty(regexp(err,'^nnet:','once')), error(message(err)), end if ~isempty(err), nnerr.throw(err), end end % Setup Calculation Mode [calcLib,calcNet,net,resourceText] = nncalc_setup(calcMode,net,data); if ~isempty(resourceText) disp(' ') disp('Computing Resources:') nntext.disp(resourceText) disp(' ') end isParallel = isa(calcLib,'Composite'); doAf = (nargout == 3); doXf = (nargout >= 2); % Simulate Parallel if isParallel spmd [Y,Af] = simPerWorker(calcLib,calcNet,doAf); if isComposite if doXf, Xf = getXf(net,data); end Y = iFormatY(net,Y,xMatrix,data.Q); end if (labindex == 1), mainWorkerInd = calcLib.mainWorkerInd; end end if ~isComposite mainWorkerInd = mainWorkerInd{1}; Y = Y{mainWorkerInd}; Y = iFormatY(net,Y,xMatrix,data.Q); if doXf, Xf = getXf(net,data); end if doAf, Af = Af{mainWorkerInd}; end end % Simulate Single Process else [Y,Af] = simPerWorker(calcLib,calcNet,doAf); if doXf, Xf = getXf(net,data); end Y = iFormatY(net,Y,xMatrix,data.Q); end % NNET 5.1 Backward Compatibility if ~isComposite if nargout >= 4 E = gsubtract(data.T,Y); if (nargout>4) && (tMatrix) if (TS==0) || (net.numOutputs == 0) E = zeros(sum(nn.output_sizes),Q); else E = cell2mat(E); end end end if nargout >= 5 perf = feval(net.performFcn,net,data.T,Y,data.EW,net.performParam); end end %==================================================================== % Format Y as matrix if X was a matrix function Y = iFormatY(net,Y,xMatrix,Q) if (xMatrix) if isempty(Y) Y = zeros(sum(nn.output_sizes(net)),Q); elseif iscell(Y) if isscalar(Y) Y = Y{1}; else % Use version of cell2Mat that works with gpuArray Y = nnet.internal.array.cell2Mat(Y); end end end %==================================================================== function [Y,Af] = simPerWorker(calcLib,calcNet,doAf) ws = warning('off','parallel:gpu:kernel:NullPointer'); try if doAf [Y,Af] = calcLib.y(calcNet); else Y = calcLib.y(calcNet); Af = []; end catch me warning(ws); rethrow(me); % Ensure warning state is reverted end warning(ws); %==================================================================== function [data,err] = simData(net,X,Xi,Ai,T,EW) data = struct; err = ''; if ~isa(X,'gpuArray') [err,net,X,Xi,Ai,T,EW,Q,TS] = simDataCellOfMatrix(net,X,Xi,Ai,T,EW); if ~isempty(err), return, end data.format = 'CELLofMATRIX'; else [err] = simDataCellOfGPUArray(net,X,Xi,Ai,T,EW); if isempty(err) [err,net,X,Xi,Ai,T,EW,Q,TS] = simDataCellOfGPUArray(net,X,Xi,Ai,T,EW); data.format = 'CELLofGPU'; else [err2,net,X,Xi,Ai,T,EW,Q,TS] = simDataGPUArray(net,X,Xi,Ai,T,EW); if ~isempty(err2), return, end err = ''; data.format = 'NNDATA2GPU'; end end data.X = X; data.Xi = Xi; data.Ai = Ai; data.Q = Q; data.TS = TS; % NNET 5.1 Compatibility data.T = T; data.EW = EW; %==================================================================== function [err,net,X,Xi,Ai,T,EW,Q,TS] = simDataCellOfMatrix(net,X,Xi,Ai,T,EW) err = ''; if ~isempty(X), X = nntype.data('format',X,'Inputs'); end if ~isempty(Xi), Xi = nntype.data('format',Xi,'Input delay states'); end if ~isempty(Ai), Ai = nntype.data('format',Ai,'Layer delay states'); end % Q if ~isempty(X) && (size(X{1},2) > 0) Q = size(X{1},2); elseif ~isempty(Xi) && ~isempty(Xi{1}) Q = size(Xi{1},2); elseif ~isempty(Ai) && ~isempty(Ai{1}) Q = size(Ai{1},2); else Q = 0; end % TS if (net.numInputs == 0) && (size(X,1) == 1) && (size(X{1},1)==0) TS = size(X,2); X = cell(0,TS); elseif size(X,2) > 0 TS = size(X,2); else TS = 0; end % Array Type arrayType = nnet.internal.array.findType({X Xi Ai T}); % Input if isempty(X) || (net.numInputs == 0) X = nndata(nn.input_sizes(net),Q,TS,zeros('like',arrayType)); end err = nntype.data('check',X); if ~isempty(err), err = ['Inputs: ' err]; return; end [Xn,Xq,Xts,Xs] = nnfast.nnsize(X); if isempty(X), Xq = Q; end if (Xs == 1) && (net.numInputs ~= 1) Nn = zeros(1,net.numInputs); for i=1:net.numInputs,Nn(i) = net.inputs{i}.size; end if (Xn == sum(Nn)) X2 = cell(net.numInputs,Xts); for ts=1:Xts X2(:,ts) = mat2cell(X{1,ts},Nn,Xq); end X = X2; Xn = Nn; Xs = net.numInputs; end end if (Xs ~= net.numInputs) err = 'Number of inputs does not match net.numInputs.'; return; end % Check input sizes if ~isempty(X) for i=1:Xs if Xn(i) ~= net.inputs{i}.size istr = num2str(i); err = ['Input data sizes do not match net.inputs{' istr '}.size.']; return; end end end % Target if isempty(T) T = nndata(nn.output_sizes(net),Q,TS,nan('like',arrayType)); end err = nntype.data('check',T); if ~isempty(err), err = ['Targets: ' err]; return; end [Tn,Tq,Tts,Ts] = nnfast.nnsize(T); if ((Ts == 0) || (Tts ==0)) && (Tq == 0) Tq = Xq; end if (Tq ~= Xq) err = 'Inputs and targets have different numbers of samples.'; return end if (Tts ~= Xts) err = 'Inputs and targets have different numbers of timesteps.'; return end if (Ts == 1) && (net.numOutputs ~= 1) Nn = zeros(1,net.numOutputs); outputInd = find(net.outputConnect); for i=1:net.numOutputs,Nn(i) = net.outputs{outputInd(i)}.size; end if (Tn == sum(Nn)) T2 = cell(net.numOutputs,Xts); for ts=1:Xts T2(:,ts) = mat2cell(T{1,ts},Nn,Tq); end T = T2; Tn = Nn; Ts = net.numOutputs; end end if (Ts ~= net.numOutputs) err = 'Number of targets does not match net.numOutputs.'; return; end % Check target sizes if ~isempty(T) Tindices = find(net.outputConnect); for i=1:Ts ii = Tindices(i); if Tn(i) ~= net.outputs{ii}.size iistr = num2str(ii); err = ['Target data sizes do not match net.outputs{' iistr '}.size.']; return; end end end % Input States if isempty(Xi) Xi = nndata(nn.input_sizes(net),Q,net.numInputDelays,zeros('like',arrayType)); end err = nntype.data('check',Xi); if ~isempty(err), err = ['Input states: ' err]; return; end [Xin,Xiq,Xits,Xis] = nnfast.nnsize(Xi); if ((Xis == 0) || (Xits ==0)) && (Xiq == 0) Xiq = Xq; end if (Xiq ~= Xq) err = 'Inputs and input states have different numbers of samples.'; return end if (Xis ~= net.numInputs) err = 'Number of input states does not match net.numInputs.'; return; end if (Xits ~= net.numInputDelays) err = 'Number of input state timesteps does not match net.numInputDelays.'; return end % Check input delay sizes if (Xis > 0) && (Xits > 0) for i=1:Xis if Xin(i) ~= net.inputs{i}.size err = 'Input state sizes do not match net.inputs{:}.size.'; return; end end end % Layer States if isempty(Ai) Ai = nndata(nn.layer_sizes(net),Q,net.numLayerDelays,zeros('like',arrayType)); end err = nntype.data('check',Ai); if ~isempty(err), err = ['Layer states: ' err]; return; end [Ain,Aiq,Aits,Ais] = nnfast.nnsize(Ai); if ((Ais == 0) || (Aits ==0)) && (Aiq == 0) Aiq = Xq; end if (Aiq ~= Xq) err = 'Inputs and layer states have different numbers of samples.'; return end if (Ais ~= net.numLayers) err = 'Number of layers states does not match net.numLayers.'; return; end if (Aits ~= net.numLayerDelays) err = 'Number of layer state timesteps does not match net.numLayerDelays.'; return end % Check layer delay sizes if (Ais > 0) && (Aits > 0) for i=1:Ais if Ain(i) ~= net.layers{i}.size err = 'Layer state sizes do not match net.layers{:}.size.'; return; end end end %==================================================================== function [err,net,X,Xi,Ai,T,EW,Q,TS] = simDataCellOfGPUArray(net,X,Xi,Ai,T,EW) err = ''; if ~isempty(X), X = nntype.data('format',X,'Inputs'); end if ~isempty(Xi), Xi = nntype.data('format',Xi,'Input delay states'); end if ~isempty(Ai), Ai = nntype.data('format',Ai,'Layer delay states'); end % Q if ~isempty(X) && (size(X{1},2) > 0) Q = size(X{1},2); elseif ~isempty(Xi) && ~isempty(Xi{1}) Q = size(Xi{1},2); elseif ~isempty(Ai) && ~isempty(Ai{1}) Q = size(Ai{1},2); else Q = 0; end % TS if (net.numInputs == 0) && (size(X,1) == 1) && (size(X{1},1)==0) TS = size(X,2); X = cell(0,TS); elseif size(X,2) > 0 TS = size(X,2); else TS = 0; end % Network dimensions Ni = net.inputs{1}.size; % Expand empty values if isempty(X), X = cell(net.numInputs,0); end if isempty(Xi), Xi = cell(1,0); end if isempty(Ai), Ai = cell(net.numLayers,0); end % Check X if any(size(X) ~= [1 TS]) err = 'Incorrectly sized inputs X.'; return end for i=1:numel(X) x = X{i}; if size(x,1) ~= Ni if (Ni == 0) err = 'Network must be configured with CONFIGURE before training with gpuArray data.'; else err = 'Incorrectly sized inputs X.'; return end end if size(x,2) ~= Q err = 'Incorrectly sized inputs X.'; return end end % Check Xi if ~isempty(Xi) err = 'Incorrectly sized input states Xi.'; return end % Check Ai if ~isempty(Ai) err = 'Incorrectly sized layer states Ai.'; return end T = {}; EW = {}; %==================================================================== function [err,net,X,Xi,Ai,T,EW,Q,TS] = simDataGPUArray(net,X,Xi,Ai,T,EW) err = ''; % Infer Precision if ~isempty(X) precision = class(gather(X(1))); elseif ~isempty(Xi) precision = class(gather(Xi(1))); elseif ~isempty(Ai) precision = class(gather(Ai(1))); else precision = 'double'; end % QQ QQs = [size(X,1) size(Xi,1) size(Ai,1)]; QQs(QQs == 0) = []; QQ = max([0 QQs]); if any(QQs ~= QQ) err = 'Number of samples (rows of gpuArrays) of data arguments do not match.'; return end % Q if ~isempty(X) Qv = X; elseif ~isempty(Xi) Qv = Xi; elseif ~isempty(Ai) Qv = Ai; else Qv = []; end realRows = gather(any(isfinite(Qv),2)); Q = find(realRows,1,'last'); % Network dimensions Ni = sum(nn.input_sizes(net)); Nl = sum(nn.layer_sizes(net)); NID = net.numInputDelays; NLD = net.numLayerDelays; anyInputsZero = any(nn.input_sizes(net)==0); % Infer TS Ni_TS = size(X,2); if (Ni_TS == 0) TS = 0; elseif (Ni > 0) TS = Ni_TS / Ni; if (TS ~= floor(TS)) if anyInputsZero err = 'Input data size (gpuArray columns) does not match input sizes. Fix data or CONFIGURE network.'; else err = 'Input data size (gpuArray columns) does not match input sizes.'; end return; end else TS = 0; end % Expand empty values if isempty(X), X = gpuArray(nan(QQ,Ni*TS,precision)); end if isempty(Xi), Xi = gpuArray(nan(QQ,Ni*NID,precision)); end if isempty(Ai), Ai = gpuArray(nan(QQ,Nl*NLD,precision)); end % Check sizes if any(size(X) ~= [QQ Ni*TS]) if anyInputsZero err = 'Input data size (gpuArray columns) does not match input sizes. Fix data or CONFIGURE network.'; else err = 'Input data size (gpuArray columns) does not match input sizes.'; end return end if any(size(Xi) ~= [QQ Ni*NID]) err = 'Input state size (gpuArray columns) does not match input sizes times input delay states.'; end if any(size(Ai) ~= [QQ Nl*NLD]) err = 'Layer state size (gpuArray columns) does not match layers sizes times layer delay states.'; end T = {}; EW = {}; %==================================================================== function Xf = getXf(net,data) if ~isempty(data) Xf = cell(net.numInputs,net.numInputDelays); for ts=1:net.numInputDelays x_ts = ts+data.TS-net.numInputDelays; if (x_ts) < 1 xi_ts = x_ts + net.numInputDelays; Xf(:,ts) = data.Xi(:,xi_ts); else Xf(:,ts) = data.X(:,x_ts); end end else Xf = []; end %==================================================================== function [calcLib,calcNet,net,resourceText] = nncalc_setup(calcMode,net,data) % Setup calculation mode, net, data & hints for non-parallel calculations % Replace with call to nncalc.setup when compiler dependencies are updated % Setup Step 1: On Main Thread Only [calcMode,calcNet,calcData,calcHints,net,resourceText] = nncalc.setup1(calcMode,net,data); % Setup Step 2: On Each Worker, if using Parallel Calculation Mode if isa(calcMode,'Composite'); spmd % Finish setup for parallel mode [calcLib,calcNet] = nncalc.setup2(calcMode,net,calcData,calcHints); end else % Finish setup for MATLAB, MEX, GPU and other non-parallel modes [calcLib,calcNet] = nncalc.setup2(calcMode,calcNet,calcData,calcHints); end