using JacobMult option for N-dimensional fit

조회 수: 2 (최근 30일)
sarah goldberg
sarah goldberg 2019년 5월 14일
편집: sarah goldberg 2019년 5월 14일
Hi,
This question references the approach described in
I am trying to fit N generalized Gaussian fits using lsqcurevefit with the JacobMult option. The Jacobian multiply option is currently not working.
Here k is the number of 1D fits with n points and p parameters, N=n x k, P=p x k. Jacobian size is indeed (N x P) - I checked the output of lsqcurvefit (with opts instead of optsJm).
I'm running into the following issue with the Jacobian multiply function (myJ): the size of the input vector Y is either (Nx1) or (Px1) or (Px2). How is this possible?
Code below. I am simply looking at
size(Y)
Thanks,
Sarah
clear all; close all; fclose all; clc;
%s=rng('shuffle');
rng(828016308,'twister');
global history;
history=[];
% plot
doPlot=false; %true;
num_plot=4; % how many fits to plot
% fit params
alg='trust-region-reflective' ; % 'trust-region-reflective' or 'levenberg-marquardt'
displaySetting='off'; % 'iter', 'off', 'final', etc.
maxIter=1e5;
maxFunEvals=1e5;
tolfun=1e-6;
% options
opts = optimoptions('lsqcurvefit','MaxIter',maxIter,'MaxFunEvals',maxFunEvals,'OutputFcn', @myoutput,'display',displaySetting,'Algorithm',alg,'tolfun',tolfun);
optsJ = optimoptions('lsqcurvefit','MaxIter',maxIter,'MaxFunEvals',maxFunEvals,'OutputFcn', @myoutput,'display',displaySetting,'Algorithm',alg,'tolfun',tolfun,'Jacobian','on');
optsJm = optimoptions('lsqcurvefit','MaxIter',maxIter,'MaxFunEvals',maxFunEvals,'OutputFcn', @myoutput,'display',displaySetting,'Algorithm',alg,'tolfun',tolfun,'SpecifyObjectiveGradient',true,'JacobianMultiplyFcn',@(Jinfo,Y,flag,xdata)myJ(Jinfo,Y,flag));
% THE MODEL. generate function handles for evaluating f (f_func) and its partial derivatives (dfdp_func).
[f_func,dfdp_func,num_params]=sym_model_derivatives();
% 2D model parameter values
num_g=2; % number of gaussians
npoints=[3,5]; % image size [r,c]=[y,x], ROI intentionally not symmetric for debugging
min_width=1; % so we don't have sigma==0
a0=30;
a_std=1;
mu_std=0.1;
sigma0=[2,1]; % be careful, do not make these too small!
sigma_std=0.1;
theta=0*(pi/180); % in radians
theta_std=10*(pi/180);
bg=10;
bg_std=5;
mu0=npoints/2; % place gaussians roughly at center
im=zeros(npoints);
% generate data: num_g images of size(im)
ims=zeros(num_g,size(im,1),size(im,2)); % image set size
mus=mu0'*ones(1,num_g) + mu_std*randn(2,num_g); % 1 per dimension
sigmas=sigma0'*ones(1,num_g) + sigma_std*randn(2,num_g); % 1 per dimension
as=a0 + a_std*randn(1,num_g); % 1 per gaussian
sigmas(sigmas<0.1)=min_width; % to avoid division by 0
thetas=theta+theta_std*randn(1,num_g);
bgs=bg+bg_std*randn(1,num_g);
[X,Y]=meshgrid(1:size(im,2),1:size(im,1)); % x-y coordinates
x_ind=X(:); % x, column vector
y_ind=Y(:); % y, column vector
for mm=1:num_g
% parameter order: %Amplitude % Row (y) % Col (x) % Theta -3* 3* % Sigma_row (y) % Sigma_col (x) % Background
c0s(mm,:)=[as(mm) mus(2,mm) mus(1,mm) thetas(mm) sigmas(2,mm) sigmas(1,mm) bgs(mm)];
ims(mm,:)=model_func(c0s(mm,:),x_ind,y_ind,f_func); % 1D vector per 2D plot
end
% guesses
guesses=zeros(num_g,num_params);
% parameter order: %Amplitude % Row % Col % Theta -3* 3* % Sigma_row % Sigma_col % Background
for mm=1:num_g
[maxval,~]=max(ims(mm,:));
tmp_im=reshape(ims(mm,:)',size(im,1),size(im,2));
[xpos,ypos]=find(tmp_im==maxval);
[~,half_x]=min(abs(tmp_im(ypos,:) - maxval/2));
[~,half_y]=min(abs(tmp_im(:,xpos) - maxval/2));
guesses(mm,:)=[maxval xpos ypos 0 (abs(half_x(1)-xpos)+min_width) (abs(half_y(1)-ypos)+min_width) 0]; % adding something small to avoid 0
end
%% N x 2D + Jacobian multiply
history=[];
results_ND_J=zeros(num_g,num_params);
fprintf(1,['\n']);
tic
f_ND = @(c,xdata)model_func_ND_Jm(c,xdata,ydata,f_func,dfdp_func); % need to pass args x_ind, y_ind, etc. to model_func
[results_ND_Jm,resnormN_Jm,residualN_Jm,exitflagN_Jm,outputN_Jm,lambdaN_Jm,jacobianN_Jm]=lsqcurvefit(f_ND,guesses_ND,xdata,im_data,[],[],optsJm); % each row is 1 object
toc
fprintf(1,['Nx2D + Jacobian multiply\n']);
resnormN_Jm
historyNm=history;
exitflagN_Jm
return
%% %%%%%% functions %%%%%%%%%%%%%%%%%%%
% model:
% f = Amplitude*.*exp(- ( A*(x-Col).^2 + 2*B*(x-Col).*(y-Row) + C*(y-Row).^2 ) ) + Background
% A = cos(Theta)^2/(2*Sigma_col) + sin(Theta)^2/(2*Sigma_row)
% B = sin(2*Theta) * (1/Sigma_row^2 - 1/Sigma_col^2)/4;
% C = sin(Theta)^2/(2*Sigma_col) + cos(Theta)^2/(2*Sigma_row);
% parameter order: %Amplitude % Row % Col % Theta -3* 3* % Sigma_row % Sigma_col % Background
function [f_func,df,num_params]=sym_model_derivatives()
num_params=7;
p=sym('p',[1 num_params]);
syms f x y A B C tmp_df;
% model definition HERE
A=cos(p(4))^2/(2*p(6)^2) + sin(p(4))^2/(2*p(5)^2);
B=sin(2*p(4)) * (1/p(5)^2 - 1/p(6)^2)/4;
C=sin(p(4))^2/(2*p(6)^2) + cos(p(4))^2/(2*p(5)^2);
f = p(1)*exp(- ( A*(x-p(3))^2 + 2*B*(x-p(3))*(y-p(2)) + C*(y-p(2))^2 ) ) + p(7);
% end of model definition
vars=[p x y];
for ii=1:length(p)
tmp_df=diff(f,p(ii));
% convert dfdp to matlab function
df{ii}=matlabFunction(tmp_df,'vars',vars);
end
% convert f to matlab function
f_func=matlabFunction(f,'vars',vars);
end
% 2D model - used to generate data
function [f]=model_func(p,x,y,f_func)
p_list=num2cell(p); % to avoid p(1),p(2),...,p(n) argument passing
f=f_func(p_list{:},x,y);
end
% Nx2D + Jacobian multiply
function [f,Jinfo] = model_func_ND_Jm(c,xdata,ydata,f_func,dfdp_func)
global G_df_func G_P G_n G_k G_xd G_yd; % needed for jacobian multiply function
G_n=size(xdata,2); % number of data points
G_k=size(xdata,1); % number of fits
f = zeros(G_k, G_n);
for ff=1:G_k
xp=xdata(ff,:); % points for this fit (n)
yp=ydata(ff,:);
cp=c(ff,:); % params for this fit (m)
cp_list=num2cell(cp);
% f
f(ff,:)=f_func(cp_list{:},xp,yp);
end
% update globals
G_P=c; % parameters
G_p=numel(dfdp_func);% number of parameters per fit
G_xd=xdata; % indices
G_yd=ydata;
G_df_func=dfdp_func; % partial derivative function handles
% Jinfo sparse matrix for preconditioning, required even when jacobian
% multiply is used. size should equal the size of the jacobian.
Jinfo = spalloc(G_n*G_k, G_p*G_k, G_n*G_k*G_p); % all zeros
end
% compute Jacobian multiply functions.
% note: Jacobian C is sparse. the only nonzero elements are
% derivatives of points xi belonging to fit j
% with respect to their own fitting parameters. there positions within the
% jacobian can be viewed by looking at the jacobian generated in model_func_ND_J
% using the command full(J).
function w = myJ(Jinfo,Y,flag)
size(Y) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global G_df_func G_P G_n G_k G_xd G_yd;
P=G_P;
n=G_n;
k=G_k;
xd=G_xd;
yd=G_yd;
df_func=G_df_func;
if flag > 0
w = Jpositive(Y, df_func,P,n,k,xd,yd);
elseif flag < 0
w = Jnegative(Y, df_func,P,n,k,xd,yd);
else
w1= Jpositive(Y, df_func,P,n,k,xd,yd);
w = Jnegative(w1,df_func,P,n,k,xd,yd);
end
function a = Jpositive(q,df_func,P,n,k,xd,yd)
% Calculate C*q (dimensions NxP, Px1 => Nx1)
a = zeros(n*k,1);
for ff=1:k % loop over fits, calculate n sums for each fit
xp=xd(ff,:); % points for this fit (n)
yp=yd(ff,:);
p=P(ff,:); % params for this fit (m)
qp=q(ff:k:end); % values of q for this fit (m)
sump=zeros(1,n);
for pp=1:numel(df_func)
df=df_func{pp}; % 1 of m function handles
p_list=num2cell(p);
dfp=df(p_list{:},xp,yp); % n partial derivatives (may have 1 value if derivative is a const)
sump=sump+qp(pp)*dfp; % add n terms for each of m params
end
a(ff:k:end)=sump'; % n terms
end
end
function a = Jnegative(q,df_func,P,n,k,xd,yd)
% Calculate C'*q (dimensions PxN, Nx1 => Px1)
a = zeros(prod(size(P)),1); % Px1
for ff=1:k % loop over fits, calculate 3 sums for 3 fit parameters
xp=xd(ff,:); % points for this fit (n)
yp=yd(ff,:);
p=P(ff,:); % params for this fit (m)
qp=q(ff:k:end); % part of input vector q that contributes for this fit (n)
for pp=1:numel(df_func)
df=df_func{pp}; % 1 of m function handles
p_list=num2cell(p);
dfp=df(p_list{:},xp,yp); % n partial derivatives
a(ff+(pp-1)*k)=sum(qp'.*dfp);
end
end
end
end
% append history if state=='iter', useful for checking convergence
function stop = myoutput(x,optimvalues,state)
global history;
stop = false;
if isequal(state,'iter')
history = [history; x];
end
end

답변 (0개)

카테고리

Help CenterFile Exchange에서 Fit Postprocessing에 대해 자세히 알아보기

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by