计算具有大量变量的符号函数的 argmin

Computing argmin of a symbolic function with a lot of variables

我有一个大小为 3065x57 的数据矩阵 X 和一个大小为 3065x1 的列矩阵 y,我想计算 argmin 定义的函数 sum在下面的代码中。

我尝试了下面的编码,fminsearch 等等,但是 none 有效。 另一个问题是我有 57 个符号变量,因此 MATLAB 计算非常慢。

如何加快计算速度?

function [] = argmin(X,y)
w = transpose(sym('w', [1 57]));
sum = 0;
for i=1:3065
    sum = sum + log(1+exp(transpose(w)*transpose(X(i,:)))) -...
        y(i,1)*transpose(w)*transpose(X(i,:));
end
F = matlabFunction(sum);
argmin = fsolve(F,zeros(1,57))
end

编辑:我尝试了以下方法:

fun = @(w)log(1+exp(transpose([w(1);w(2);w(3);w(4);w(5);w(6);w(7);w(8);w(9);w(10)])*...
    [1;1;1;1;1;1;1;1;1;1]))-...
    transpose([w(1);w(2);w(3);w(4);w(5);w(6);w(7);w(8);w(9);w(10)])*...
    [1;1;1;1;1;1;1;1;1;1]

x0 = [1,1,1,1,1,1,1,1,1,1];
x = fminsearch(fun,x0)

但是,我无法执行 for 循环。

当使用 fminsearchfmincon 之类的东西时,您不必在使用它的意义上使用匿名函数。您可以创建自己的函数并将其变成匿名函数。

此外,您的最小化变量不必是符号。正如评论中所说,这对于您的问题来说非常缓慢且不必要。

代码:

function sum = argmin_fun(x,y,w)

sum = 0;

for ii = 1:3065
    sum = sum + log(1 + exp(w'*x(ii,:)')) - y(ii)*w'*x(ii,:)';
end

return

然后您可以从您的脚本中调用

x = randn(3065,57);
y = randn(3065,1);
fun = @(w) argmin_fun(x,y,w);
x0 = ones(57,1);
minimized_vals = fminsearch(fun,x0);

一些注意事项:

考虑使用一个选项变量,这样你就可以设置选项参数,比如你希望优化它的程度、最大迭代次数,以及其他参数,你可以这样设置。

opts1 = optimset('Display','iter','MaxIter',100);
minimized_vals = fminsearch(fun,x0,opts1);

如果您有优化工具箱,请考虑使用 fmincon 或其他优化器之一,fminsearch 适用于具有 1-10 个变量的问题,但对于大规模问题而言准确性要低得多。使用 fmincon 您还可以为最小值和最大值设置边界约束。 fminsearch 有变通办法,但实施起来并不容易。

在性能方面,fminsearch的误差函数实现了9637.23的误差值,而fmincon在没有添加任何约束的情况下实现了1945.63的误差值。

[minimized_vals,error_val] = fmincon(fun,x0,[],[]);

如果我遗漏了什么,请告诉我,我会修改我的答案。

如果要去除循环,可以使用矩阵运算:

 a = transpose(w)*transpose(X);

a 是一个大小为 1 x 3065 的向量(因为 w' 是 1 x 57 而 X' 是 57 x 3065)。 现在你可以像下面这样进行第二个操作:

b = transpose(y).*a

因此,sum 将是:

totalSum =  sum(log(1+exp(a)) - b);

你应该考虑到 sum 是 Matlab 中的一个函数,最好更改 sum 变量的名称tosum`。

总而言之,我们可以删除循环并用以下内容替换循环:

a = transpose(w)*transpose(X); % w: 57 x 1, X:3065 x 57
b = b = transpose(y).*a; % y: 3065 x 1, a: 1 x 3065
totalSum =  sum(log(1+exp(a)) - b);

它可能比您为第一个解决方案编写的速度更快。