Can I code a deep learning layer without a backward function? - matlab

I want to create a layer that make two copies of the previous layer (input layer), here is my code:
classdef CopyLayer < nnet.layer.Layer
methods
function layer = CopyLayer(numOutputs,name)
% Set number of inputs.
layer.NumOutputs = numOutputs;
% Set layer name.
layer.Name = name;
% Set layer description.
layer.Description = "Make " + numOutputs + ...
" copies of the input layer";
end
function [varargout] = predict(X)
% Layer forward function for prediction goes here.
numOutputs = layer.NumOutputs;
[h,w,c] = size(X);
Z = zeros(h,w,c,numOutputs);
for i= 1 : numOutputs
Z(:,:,:,i) = X;
end
varargout = Z;
end
% function [] = backward()
% end
end
end
and when I try to create the layer by:
layer = CopyLayer(2,'copy');
the following error appears:
Abstract classes cannot be instantiated. Class 'CopyLayer' inherits
abstract methods or properties but does not implement them.
See the list of methods and properties that 'CopyLayer' must implement
if you do not intend the class to be abstract.
Error in SplitLayer (line 1)
layer = CopyLayer(2,'copy');
and I think it's because of the no existing of backward function. Is that correct? How can I resolve this error?

The error message is clear -- if you're used to reading error messages, and you're familiar with abstract classes.
A class is abstract if it contains elements that are not yet defined in a manner one could instantiate. They are intended particularly to be templates that the user can fill out to have the desired implementation details. nn.layer.layer is one such abstract class.
When you instantiate an abstract class, but fail to define every template element, then the result is another abstract class -- just with fewer "template" elements. That is what you've done: CopyLayer does not implement backward, so it's still abstract. When you instantiate with layer = CopyLayer(2,'copy'), you still have open elements, so you cannot make a concrete object from the class. Hence the error message.
You can work around this in a couple of ways:
Implement your own layer class, one that doesn't even mention a back-prop function. You'll have extra connection work to do, since you give up your inheritance from nn.layer.
Implement backward, but leave the body non-functional (empty). This will satisfy the compiler, and give you a very boring (but fast) back-prop stage.

thanks to Mr #Prune
the code after correction becomes as follow:
classdef CopyLayer < nnet.layer.Layer
properties
% (Optional) Layer properties.
NumOutputs
end
methods
function layer = CopyLayer(numOutputs,name)
% Set number of inputs.
layer.NumOutputs = numOutputs;
% Set layer name.
layer.Name = name;
% Set layer description.
layer.Description = "Make " + numOutputs + ...
" copies of the input layer";
end
function varargout = predict(layer,X)
numOutputs = layer.NumOutputs;
[h,w,c] = size(X);
Z = zeros(h,w,c,numOutputs);
for i= 1 : numOutputs
Z(:,:,:,i) = X;
end
varargout = Z;
end
function [dLdX] = backward(~,~,~,~,~)
end
end
end

Related

Subclass constructor refuses to accept any name-value arguments

TL;DR
I am having an issue with the arguments functionality, wherein a subclass fails to instantiate if any name-value argument pairs are passed to it.
(Class definitions are given at the end.)
The arguments functionality, introduced in R2019b, brings great promise in terms of simplifying argument validation and removing boilerplate code from functions [1]. However, upon trying to implement name-value (NV) arguments taken from public class properties, I got the following error:
Invalid argument list. Check for wrong number of positional arguments or placement of positional arguments after
name-value pairs. Also, check for name-value pairs with invalid names or not specified in pairs.
before any subclass code is even executed. This message is confusing, because tab-completion appears to work as expected for NV pairs:
Moreover, if no arguments are passed at all, everything works fine:
>> FluidLayer()
ans =
FluidLayer with properties:
prop1: NaN
prop2: NaN
vs.
>> FluidLayer('prop1',1)
Error using FluidLayer
Invalid argument list. ...
Questions:
Why am I getting an error? I don't think I'm using the arguments mechanism in some unintended or undocumented way, so I'm doubly puzzled about what I might be doing wrong (assuming this is not a bug).
What can be done to resolve this, other than abandoning the whole arguments approach (I would like to keep argument name suggestions)? I have considered transitioning to varargin and/or using the functionSignatures.json approach - but these require significantly more work.
classdef Layer < handle & matlab.mixin.Heterogeneous
properties (GetAccess = public, SetAccess = protected)
prop1(1,1) double {mustBeNonempty} = NaN
prop2(1,1) double {mustBeNonempty} = NaN
end % properties
methods (Access = protected)
function layerObj = Layer(props)
% A protected/private constructor means this class cannot be instantiated
% externally, but only through a subclass.
arguments
props.?Layer
end
% Copy field contents into object properties
fn = fieldnames(props);
for idxF = 1:numel(fn)
layerObj.(fn{idxF}) = props.(fn{idxF});
end
end % constructor
end % methods
end
classdef FluidLayer < Layer
properties (GetAccess = public, SetAccess = protected)
% Subclass-specific properties
end % properties
methods
function layerObj = FluidLayer(props)
arguments
props.?FluidLayer
end
% Create superclass:
propsKV = namedargs2cell(props);
layerObj = layerObj#Layer(propsKV{:});
% Custom modifications:
end % constructor
end % methods
end
I have been able to simplify your example to this:
classdef Layer
properties (GetAccess = public, SetAccess = protected)
prop1
prop2
end % properties
methods
function layerObj = Layer(props)
arguments
props.?Layer
end
disp(props)
end % constructor
end % methods
end
Now Layer('prop1',1) throws an error as you describe.
Thus, it has nothing to do with subclassing or inheritance.
However, if we remove the SetAccess = protected restriction (leaving the properties with public get and set access), then it all works as you expected.
I don't know why restricting set access would limit this use case, as it has nothing to do with writing those properties, and a class method should have set access anyway. My guess is that this is a bug.
The documentation of R2020a states that the structName.?ClassName syntax can only be used with "settable properties defined by a class (that is, all properties with public SetAccess)". Thus, using it with protected properties is explicitly unsupported.
As such, if we want to use the "automatic" arguments validation mechanism, we have no choice but to set the SetAccess to public. However, this solution exposes the object properties to unwanted external changes, and so a workaround is suggested based on several principles:
properties now have public SetAccess, as required by the documentation.
Custom setters are added that perform access validation based on dbstack and meta.class comparison.
New Layer.m (notice the 2 new methods blocks):
classdef Layer < handle & matlab.mixin.Heterogeneous
properties (GetAccess = public, SetAccess = public)
prop1(1,1) double {mustBeNonempty} = NaN
prop2(1,1) double {mustBeNonempty} = NaN
end % properties
%% Constructor
methods (Access = protected)
function layerObj = Layer(props)
% A protected/private constructor means this class cannot be instantiated
% externally, but only through a subclass.
arguments
props.?Layer
end
% Copy field contents into object properties
fn = fieldnames(props);
for idxF = 1:numel(fn)
layerObj.(fn{idxF}) = props.(fn{idxF});
end
end % constructor
end % protected methods
%% Setters & Getters
methods
function set.prop1(obj, val)
if Layer.getCallerMetaclass() <= ?Layer
obj.prop1 = val;
else
Layer.throwUnprotectedAccess();
end
end
function set.prop2(obj, val)
if Layer.getCallerMetaclass() <= ?Layer
obj.prop2 = val;
else
Layer.throwUnprotectedAccess();
end
end
end % no-attribute methods
%% Pseudo-protected implementation
methods (Access = protected, Static = true)
function throwUnprotectedAccess()
stack = dbstack(1);
[~,setterName,~] = fileparts(stack(1).name);
throw(MException('Layer:unprotectedPropertyAccess',...
['Unable to set "', stack(1).name(numel(setterName)+2:end),...
'", as it is a protected property!']));
end
function mc = getCallerMetaclass()
stack = dbstack(2, '-completenames');
if isempty(stack)
mc = ?meta.class;
else
[~,className,~] = fileparts(stack(1).file);
mc = meta.class.fromName(className);
end
end
end % protected static methods
end % classdef
New FluidLayer.m (the foo method was added):
classdef FluidLayer < Layer
properties (GetAccess = public, SetAccess = protected)
% Subclass-specific properties
end % properties
methods
%% Constructor
function layerObj = FluidLayer(props)
arguments
props.?Layer
end
% Create superclass:
propsKV = namedargs2cell(props);
layerObj = layerObj#Layer(propsKV{:});
end % constructor
function obj = foo(obj)
obj.prop1 = obj.prop1 + 1;
end
end % methods
end % classdef
Here's a demonstration of how it works:
>> fl = FluidLayer('prop1', 2, 'prop2', 1)
fl =
FluidLayer with properties:
prop1: 2
prop2: 1
>> fl.prop1 = 5; % attempting to set property directly (unintended)
Error using Layer/throwUnprotectedAccess (line 51)
Unable to set "prop1", as it is a protected property!
Error in Layer/set.prop1 (line 32)
Layer.throwUnprotectedAccess();
>> fl.foo() % attempting to set property through method (intended)
ans =
FluidLayer with properties:
prop1: 3
prop2: 1
>>
In conclusion: it is possible to overcome the SetAccess = public limitation using setter methods, but convoluted modifications to class code are required.
Practical Notes:
The getCallerMetaclass is limited in that it doesn't correctly identify packages - resulting in potentially empty metaclass objects. So keep in mind that this function should be modified if that is the case.
dbstack is called multiple times, although it is not necessary (it can be called once in the setter and the result can then be passed around).
The setter code for different properties is 5-lines long and mostly replicated (with the exception of the property name) - this can be improved by grabbing the property name through dbstack.

Passing additional iteration-dependent inputs to ode45

I'm trying to solve differential equation using the ode45 function. Consider the following code,
[t1,X2] = ode45(#(t,x)fun(t,x,C1,C2,C3,C4),t0,X01);
where parameters C1, C2, C3 and C4 are column vectors, which should be available to the function that ode45 is referring to (fun.m). I want the values to change after every iteration, so for example, at the beginning the entry of C1 I want in is C1(1), in the next iteration it's C1(2), etc.
How can I implement that?
You may have noticed that the official docs are not too helpful in this scenario (as they pretty much force you to use global variables - which is doable, but discouraged). Instead, I'll show you how this can be done with classes and function handles. Consider the following:
classdef SimpleQueue < handle
%SIMPLEQUEUE A simple FIFO data structure.
properties (Access = private)
data
position
end
methods (Access = public)
function obj = SimpleQueue(inputData)
%SIMPLEQUEUE Construct an instance of this class
obj.data = inputData;
rewind(obj);
end % constructor
function out = pop(obj, howMany)
%POP return the next howMany elements.
if nargin < 2
howMany = 1; % default amount of values to return
end
finalPosition = obj.position + howMany;
if finalPosition > numel(obj.data)
error('Too many elements requested!');
end
out = obj.data(obj.position + 1 : obj.position + howMany);
obj.position = finalPosition;
end % pop
function [] = rewind(obj)
%REWIND restarts the element tracking
% Subsequent calls to pop() shall return elements from the beginning.
obj.position = 0;
end % rewind
end % methods
end % classdef
How to use this? Simple:
C1q = SimpleQueue(C1);
C2q = SimpleQueue(C2);
C3q = SimpleQueue(C3);
C4q = SimpleQueue(C4);
[t1,X2] = ode45(#(t,x)fun(t,x,#C1q.pop,#C2q.pop,#C3q.pop,#C4q.pop),t0,X01);
As you can see, inside fun we use C1q() instead of C1.

Efficient way of passing data between MATLAB functions

I am solving a very large optimization problem. The objective function and constraint function needs numerous data. Currently I am passing the data as a structure to them.
myFS(X, Dat, g_Index, f_Index) % Dat is a structure which includes many variables
Do you think it's an efficient way to reduce the elapsed time?
What better alternatives do exist?
Is this what the given answer, regarding to class definition, means?
%% First we define the class in a separate file:
classdef myDataStructure < handle
properties
NRES;
NOBJ;
NVAR;
end
methods
function obj = myDataStructure()
end
end
end
%% In another file where the main program is, we initialize the class.
Dat = myDataStructure();
%% Initialize
Dat.NRES = 1;
Dat.NOBJ = 1;
Dat.NVAR = 1;
[myF, Dat_updated] = BBB(Dat);
%% Here we define the function and use the class
function [f, CalssDat] = BBB(CalssDat)
x = CalssDat.NRES;
y = CalssDat.NOBJ;
z = CalssDat.NVAR;
f = x + y + z;
CalssDat.NOBJ = 2;
end
As far as I know, MATLAB does not actually copy the content of the data you pass to a function until the point when you modify it in the function itself - in which case it makes a local copy and that takes some CPU time.
Therefore, as long as Dat doesn't change inside myFS(), what you are doing now does not add any CPU overhead. In case you do change the values of Dat inside myFS() and want to return it, I can think of two ways to optimise it:
You can declare myFS() as: function [Dat, anythingElse] = myFs(X,Dat,g_Index, f_Index), which should prevent matlab from making a local copy.
Another approach is to use a class that derives from handle and have Dat be a member of that. This way, whenever you pass the object containing Dat, you only pass the object handle and not a copy of the object itself.
Example of the second approach:
classdef myDataStructure < handle
properties
p1FromDat;
p2FromDat;
% .
% .
% .
pNFromDat;
end
methods
function obj = myDataStructure()
% Add initialization code here if you want. Otherwise p1FromDat
% ... pNFromDat are accessible from outside
end
end
end
Than, in your code:
Dat = myDataStructure();
Dat.p1FromDat = 1;
Dat.p2FromDat = 1;
And in your myFs() you use Dat exactly the same way as you used before.
Because myDataStructure derives from handle, the data inside will not be copied when you pass Dat around.
Do be careful with this, because when you change Dat in myFS(), the values will be changed outside the scope of myFS() as well.

creating rational class constructor in matlab

suppose we have following class,i want to declare rational number class in matlab,i am beginner of object oriented programming in matlab languages and i want to learn basics
classdef ratnum %rational number class
properties (Access=protected)
n %numerator
d %denomerator
end
methods
function r=ratnum(numerator,denomenator)
r.n=numerator;
r.d=denomenator;
end
end
end
how can i create constructor with specific values in matlab main part?should i use name of class ?thanks in advance
To instantiate an object of this class you can use: num1 = ratnum(2,3)
Since MATLAB doesn't have method overloading that is based on the amount of passed inputs, you could use nargin to select the correct scenario, as follows:
classdef ratnum %rational number class
properties (Access=protected)
n %//numerator
d %//denominator
end
methods
function r = ratnum(numerator,denominator)
switch nargin
case 2
r.n=numerator;
r.d=denominator;
case 0
%//whatever you want the defaults to be
end
end
end
end
A simple debug trick is to do num1_str=struct(num1) which allows you to see the contents of the object. However, you should create some public methods to get the values (instead of turning the object to a struct every time).
To overload the default summation of MATLAB you need to understand that whenever you write a+b it is automatically translated into plus(a,b). When defining custom classes with custom summation you should make a folder that has the name #classname (in your case #ratnum) and in it:
ratnum.m: the class definition file (which is the code you wrote)
a file named plus.m which looks something like:
.
function sum = plus(ratnum1,ratnum2)
ratnum1 = ratnum(ratnum1);
ratnum2 = ratnum(ratnum2);
sum = (...
ratnum1.r*ratnum2.d + ...
ratnum2.r*ratnum1.d )/ ...
(ratnum1.d * ratnum2.d);
end
Then, when you use + to add ratnums it will use the correct plus function.
Here's some helpful reading: MATLAB Documntation: Implementing Operators for Your Class
To call class methods, even from within other class methods, you must always write the class name first: ratnum.sum(ratnum1). Here's an example:
classdef ratnum %rational number class
properties (Access=public)
n %//numerator
d %//denominator
end
methods (Access = public)
function r = ratnum(numerator,denominator)
switch nargin
case 2
r.n=numerator;
r.d=denominator;
case 0
%whatever you want the defaults to be
end
end
end
methods (Access = public, Static)
function out = sum(ratnum)
out = ratnum.n + ratnum.d;
end
end
end
then:
>> a = ratnum(1,1)
a =
ratnum with properties:
n: 1
d: 1
>> ratnum.sum(a)
ans =
2
If you want to overload constructor with many different forms you'll have to initialize missing parameters with default value (or use varargin for more complex overloads):
function [r] = ratnum(num, den, varargin)
% Showing initializing missing parameters
if (nargin < 2), den = 42; end
if (nargin < 1), num = 7; end
% Showing working with varargin
if (nargin == 3)
...
elseif((nargin > 1) && (ischar(varargin{1}))
...
else
...
end
end
If you want to create named initializers for clarification of their meaning, you'll have to do it with Static methods:
methods (Static)
function [r] = TwoThird()
r = ratnum(2, 3);
end
function [r] = Half()
r = ratnum(1, 2);
end
end
Which can be used like this:
dummy = ratnum.Half(); % Ratio is 1/2
dummy = ratnum.TwoThird(); % Ratio is 2/3
dummy = ratnum(42, 666); % Ratio can be any custom one

Matlab - Manipulating datasets within subclass methods

I am having some difficulty designing a subclass of dataset in Matlab (R2010b). I am experienced programming Matlab, but new to using its OOP features. My constructor seems to be fine, but when I try to build some methods that access data in the dataset, I can't seem to get it to work. Here is an example:
classdef mydataset < dataset
properties
end
methods
function [obj] = mydataset(obs,array)
% obs is N x 1 cell array of strings
% array is N x 2 double array
obj = obj#dataset({array,'Field1','Field2'},'ObsNames',obs)
end
function [val] = computeValue(obj)
col = obj.Field1;
% I get an error above regardless of how I try to access the dataset.
% e.g. col = double(obj(obs,'Field1')) also does not work.
% Some more code using col to determine val
end
end
end
In my method computeValue, I am trying to access the data in the dataset using dataset syntax, i.e. on the command line I could access Field1 using ".". It complains there is no method, property, or field Field1 for class mydataset. If I try the alternate syntax
col = double(obj(:,'Field1'));
it complains about the size of obj, e.g. "Index exceeds matrix dimensions".
I found a workaround using subsref:
methods
function [val] = computeValue(obj)
s.type = '.';
s.subs = 'Field1';
col = subsref(obj,s);
% Some more code using col to determine val
end
end
Although the workaround works, it is not very convenient and largely defeats the purpose of wanting a subclass of dataset. Is there some attribute or something simple I am missing?
Thank you very much.
Eric
Can you post the complete code of your class. I suppose you didn't declare your property "factor" and try to access it.
Your class should look like this :
classdef MyClass
properties
factor;
end
methods
function obj = MyClass(factor)
% The constructor set the property factor
obj.factor = factor;
end
function val = computeValue(obj)
col = obj.factor;
% ...
end
end
end