Why my transfer function keep turn back in to 'logsig'? - matlab

   I try to build a basic feedforward system using patternnet command that can recognise the data from MNIST dataset. Here is my code
one = [1];
one = repelem(one,100);
%%%%%%%%%%%%%%%Create Neural network%%%%%%%%%%%%%%%%%%%%%
nn = patternnet([100 100]);
nn.numInputs = 1;
nn.inputs{1}.size = 784;
nn.layers{1}.transferFcn = 'logsig';
nn.layers{2}.transferFcn = 'logsig';
nn.layers{3}.transferFcn = 'softmax';
nn.trainFcn = 'trainscg';
net.divideParam.trainRatio = 70/100;
net.divideParam.valRatio = 15/100;
net.divideParam.testRatio = 15/100;
%%%%%%%%%%%%%%%%Dealing with data%%%%%%%%%%%%%%%%%%%%%%%%%%
mnist_in = csvread('mnist_train_100.csv');
mnist_test_in = csvread('mnist_test_10.csv');
[i,j] = size(mnist_in);
data_in = mnist_in(:,2:785);
data_in = data_in';
target_in = mnist_in(:,1);
target_in = target_in';
nn = train(nn,data_in,target_in);
   The problem is when I build this system the transfer function in output layer is set to softmax function. Somehow when I train my system the transfer function turn into 'logsig' function and it stay that way until I clear my workspace. I even try to set the transfer function of output layer in the code and program still find a way to change it to logsig. So is there anything I can do.
PS. I even try building this system using network() to make everything from scrath the program still change my tranfer function back from softmax to logsig.

As I see, there is a mistake in the divideParam parameter. You created the neural network as nn but the parameters that you changed is belong to a variable called net. Other than that, the creating neural network part is normal.
I think the problem lies in the data preparation part.
Your training target, the target_in, has the dimension of 1 x < Number of sample>. Because of that, the train function replace 'softmax' with 'logsig' to fit with the output.
The output data for softmax should be in the form of < Number of result> x < Number of sample>
For example, the output is either 1,2 or 3. Then the output array shouldn't be
[1 2 1 3 3 1 ...]
but it should be
[1 0 1 0 0 1 ...;
0 1 0 0 0 0 ...;
0 0 0 1 1 0 ...]
Hope this helps.
EDIT: To turn the single array (1 x < Number of sample>) to the multiple array (< Number of result> x < Number of sample>), the data in the single array will be map with index. For example, 11 sample in a single array:
[-1 -5.5 4 0 3.3 4 -1 0 0 0 -1]
Checking all the unique number and sort it. Now every number has its index.
[-5.5 -1 0 3.3 4] #index table
Going through the single array, for each number, place it in the right index. Basically, -1 will have index 2 so I will tick 1 in the second row at any column that -1 appear. Finally,
[ 0 1 0 0 0 0 0 0 0 0 0;
1 0 0 0 0 0 1 0 0 0 1; #there are three -1 in the single array
0 0 0 1 0 0 0 1 1 1 0;
0 0 0 0 1 0 0 0 0 0 0;
0 0 1 0 0 1 0 0 0 0 0]
Here is the code for it:
idx = sort(unique(target_in));
number_of_result = size(idx,2);
number_of_sample = size(target_in,2);
target_softmax = zeros(number_of_result,number_of_sample);
for i = 1:number_of_sample
place = find(idx == target_in(i)); % find the index of the value
target_softmax(place,i) = 1; % tick 1 at the row
end

Related

Replace repeated value based on sequence size - Matlab

I have a 2D matrix composed of ones and zeros.
mat = [0 0 0 0 1 1 1 0 0
1 1 1 1 1 0 0 1 0
0 0 1 0 1 1 0 0 1];
I need to find all consecutive repetitions of ones in each row and replace all ones with zeros only when the sequence size is smaller than 5 (5 consecutive ones):
mat = [0 0 0 0 0 0 0 0 0
1 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0];
Any suggestion on how to approach this problem would be very welcome.
You can use diff to find the start and end points of the runs of 1, and some logic based on that to zero out the runs which are too short. Please see the below code with associated comments
% Input matrix of 0s and 1s
mat = [0 0 0 0 1 1 1 0 0
1 1 1 1 1 0 0 1 0
0 0 1 0 1 1 0 0 1];
% Minimum run length of 1s to keep
N = 5;
% Get the start and end points of the runs of 1. Add in values from the
% original matrix to ensure that start and end points are always paired
d = [mat(:,1),diff(mat,1,2),-mat(:,end)];
% Find those start and end points. Use the transpose during the find to
% flip rows/cols and search row-wise relative to input matrix.
[cs,r] = find(d.'>0.5); % Start points
[ce,~] = find(d.'<-0.5); % End points
c = [cs, ce]; % Column number array for start/end
idx = diff(c,1,2) < N; % From column number, check run length vs N
% Loop over the runs which didn't satisfy the threshold and zero them
for ii = find(idx.')
mat(r(ii),c(ii,1):c(ii,2)-1) = 0;
end
If you want to throw legibility out of the window, this can be condensed for a slightly faster and denser version, based on the exact same logic:
[c,r] = find([mat(:,1),diff(mat,1,2),-mat(:,end)].'); % find run start/end points
for ii = 1:2:numel(c) % Loop over runs
if c(ii+1)-c(ii) < N % Check if run exceeds threshold length
mat(r(ii),c(ii):c(ii+1)-1) = 0; % Zero the run if not
end
end
The vectorized solution by #Wolfie is nice and concise, but a bit hard to understand and far from the wording of the problem. Here is a direct translation of the problem using loops. It has the advantage of being easier to understand and is slightly faster with less memory allocations, which means it will work for huge inputs.
[m,n] = size(mat);
for i = 1:m
j = 1;
while j <= n
seqSum = 1;
if mat(i,j) == 1
for k = j+1:n
if mat(i,k) == 1
seqSum = seqSum + 1;
else
break
end
end
if seqSum < 5
mat(i,j:j+seqSum-1) = 0;
end
end
j = j + seqSum;
end
end

Create Vector Ranges From Variables

I have two vectors that hold the "start" and "end" locations (as logicals) that I wish to combine as to create a third vector, Final:
Starts = [0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0];
Ends = [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0];
With the Final Vector looking like this:
Final = [0 0 0 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0];
Currently, I can accomplish this using a for loop as follows:
Start_Locations = find(Starts);
End_Locations = find(Ends);
Final = zeros(20,1);
for x=1:length(Start_Locations)
Final(Start_Locations(x):End_Locations(x),1) = 1;
end
I was wondering if there's a way to accomplish the same exact thing without a for loop. For example, I could accomplish what I outlined above with the following "hard-coded" statement:
Final([4:8,11:19],1) = 1;
Specifically, is there a way to combine the Start_Locations and End_Locations vectors in a way such that I could have a single statement like:
Final(Combined_Start_and_End_Locations,1) = 1;
to accomplish what I did with the for loop above? I'm trying to learn to avoid for loops as much as I can and would really appreciate any solution that creates the Final vector as described above without resorting to a loop.
Problems like this can often be solved using either diff or cumsum. They are essentially discrete derivative and integration functions.
For your problem I believe that
Final = cumsum([Starts 0]-[0 Ends]);
Final = Final(1:end-1);
achieves the desired result.

How to replace non-zero elements randomly with zero?

I have a matrix including 1 and 0 elements like below which is used as a network adjacency matrix.
A =
0 1 1 1
1 1 0 1
1 1 0 1
1 1 1 0
I want to simulate an attack on the network, so I must replace some specific percent of 1 elements randomly with 0. How can I do this in MATLAB?
I know how to replace a percentage of elements randomly with zeros, but I must be sure that the element that is replaced randomly, is one of the 1 elements of matrix not zeros.
If you want to change each 1 with a certain probability:
p = 0.1%; % desired probability of change
A_ones = find(A); % linear index of ones in A
A_ones_change = A_ones(rand(size(A_ones))<=p); % entries to be changed
A(A_ones_change) = 0; % apply changes in those entries
If you want to randomly change a fixed fraction of the 1 entries:
f = 0.1; % desired fraction
A_ones = find(A);
n = round(f*length(A_ones));
A_ones_change = randsample(A_ones,n);
A(A_ones_change) = 0;
Note that in this case the resulting fraction may be different to that intended, because of the need to round to an integer number of entries.
#horchler's point is a good one. However, if we keep it simple, then you can just multiple your input matrix to a mask matrix.
>> a1=randint(5,5,[0 1]) #before replacing 1->0
a1 =
1 1 1 0 1
0 1 1 1 0
0 1 0 0 1
0 0 1 0 1
1 0 1 0 1
>> a2=random('unif',0,1,5,5) #Assuming frequency distribution is uniform ('unif')
a2 =
0.7889 0.3200 0.2679 0.8392 0.6299
0.4387 0.9601 0.4399 0.6288 0.3705
0.4983 0.7266 0.9334 0.1338 0.5751
0.2140 0.4120 0.6833 0.2071 0.4514
0.6435 0.7446 0.2126 0.6072 0.0439
>> a1.*(a2>0.1) #And the replacement prob. is 0.1
ans =
1 1 1 0 1
0 1 1 1 0
0 1 0 0 1
0 0 1 0 1
1 0 1 0 0
And other trick can be added to the mask matrix (a2). Such as a different freq. distribution, or a structure (e.g. once a cell is replaced, the adjacent cells become less likely to be replaced and so on.)
Cheers.
The function find is your friend:
indices = find(A);
This will return an array of the indices of 1 elements in your matrix A and you can use your method of replacing a percent of elements with zero on a subset of this array. Then,
A(subsetIndices) = 0;
will replace the remaining indices of A with zero.

Effiicient ways to count a streak of consecutive integers in MATLAB

Say I have a vector containing only logical values, such as
V = [1 0 1 0 1 1 1 1 0 0]
I would like to write a function in MATLAB which returns a 'streak' vector S for V, where S(i) represents the number of consecutive 1s in V up to but not including V(i). For the example above, the streak vector would be
S = [0 1 0 1 0 1 2 3 4 0]
Given that I have to do this for a very large matrix, I would very much appreciate any solution that is vectorized / efficient.
This should do the trick:
S = zeros(size(V));
for i=2:length(V)
if(V(i-1)==1)
S(i) = 1 + S(i-1);
end
end
The complexity is only O(n), which I guess should be good enough.
For your sample input:
V = [1 0 1 0 1 1 1 1 0 0];
S = zeros(size(V));
for i=2:length(V)
if(V(i-1)==1)
S(i) = 1 + S(i-1);
end
end
display(V);
display(S);
The result would be:
V =
1 0 1 0 1 1 1 1 0 0
S =
0 1 0 1 0 1 2 3 4 0
You could also do it completely vectorized with a couple intermediate steps:
V = [1 0 1 0 1 1 1 1 0 0];
Sall = cumsum(V);
stopidx = find(diff(V)==-1)+1;
V2=V;
V2(stopidx) = -Sall(stopidx)+[0 Sall(stopidx(1:end-1))];
S2 = cumsum(V2);
S = [0 S2(1:end-1)];
Afaik the only thing that can take a while is the find call; you can't use logical indexing everywhere and bypass the find call, because you need the absolute indices.
It's outside the box - but have you considered using text functions? Since strings are just vectors for Matlab it should be easy to use them.
Regexp contains some nice functions for finding repeated values.

MATLAB: Reset Vector at Index

Consider the following vectors:
>> signals
signals =
1
1
1
1
0
0
0
0
1
1
1
1
0
0
0
0
>>exits
exits =
2
10
What I need to do is set the 1s to 0s in the signal matrix from each value in exits until the value in signals changes. For example, where exits=2, I would set the 1s to 0s in the signal vector at indicies 2, 3, and 4.
What I have done so far is to identify where the values change in the signal vector so that I can identify the start and stop index. For example:
>> find(diff(signals)~=0)
ans =
4
8
12
By doing this, I know I have to set the 1s to 0s from exits=2 to signals=4 and exits=10 to signals=12. I am stuck however in figuring out how to do this with no loops.
I realize this may be a bit vague, so here is a simpler example:
>> signals
signals =
1
1
1
1
1
0
0
0
1
1
1
>> exit
exit =
3
>> rst=exit:find(diff(signals)~=0)
rst =
3 4 5
signals =
1
1
0
0
0
0
0
0
1
1
1
I am basically trying to generalize this simple example to cases where there are multiple exit values and multiple different sequences of signals.
Looping is most certainly going to be the simpler and more readable solution. The way to make this without loops is to reconstruct the signals-array, keeping starts and throwing away redundant exits.
signals = [
1
1
1
1
1
0
0
0
1
1
1];
exit = 3;
startEnd = diff([0;signals]);
%# add the new exit
startEnd(exit) = -1;
%# remove redundant "exits"
startEndIdx = find(startEnd);
deltaEvent = diff([0;startEnd(startEndIdx)]);
deltaIsZero = deltaEvent == 0; %# these are the bad exits
startEnd(startEndIdx(deltaIsZero)) = 0;
%# now we can reconstruct the signals vector
signals = cumsum(startEnd)
signals =
1
1
0
0
0
0
0
0
1
1
1