Matlab:parfor 循环和元胞数组不起作用

Matlab: parfor loop and cell arrays not working

我收到以下错误:“parfor 中的变量 X_bs 不能 classified" 当尝试 运行 以下 parfor 循环时:

  y = zeros(1000,1)
        parfor bb = 1:1000
            rng(bb)
            % deleted line: X_bs{8} = [];
            for ii = 1:8
                ind = ceil(N(ii)*rand(N(ii),1));
                X_bs{ii} = X{ii}(ind,:);
            end 

           y(bb) = another_function(X_bs)

        end

X 是一个 1x8 元胞数组,每个元胞包含一个 N(ii)x4 矩阵(N(ii) 变化)。该代码对 X 的行重新采样并创建一个名为 X_bs 的元胞数组。我通过一个函数传递 X_bs,该函数输出我感兴趣的变量 y(bb)

为什么会出现此错误?我该如何解决这个问题?

这是一个例子:

 X{1} = [1 ; 2 ; 3]
 X{2} = [4 ; 5 ; 6; 7]
 N(1) = 3 % size of X{1}
 N(2) = 4 % size of X{2}
    parfor bb=1:10
        rng(bb)
        for ii = 1:2
            X_bs{ii} = zeros(N(ii),1);
            ind = ceil(N(ii)*rand(N(ii),1));
            X_bs{ii} = X{ii}(ind,:);
        end
        % Output is a function of X_bs.  For illustration, say it is the sum
        y(bb) = sum(X_bs{1}) + sum(X_bs{2});
    end

以上代码得到与之前相同的错误:"The variable X_bs in a parfor cannot be classified"。这是一个更简单的版本,它可以工作并且不使用单元格结构:

X = [1 ; 2 ; 3]
N = 3; %size of X
parfor bb=1:10
    rng(bb)
    X_bs = zeros(N,1);
    ind = ceil(N*rand(N,1));
    X_bs= X(ind,:);
    y(bb) = sum(X_bs) 
end

问题(我认为)在于重写单元格结构。也许 parfor 将单元结构视为切片变量而不是临时变量。有什么想法吗?

更新:Adriaan 建议随机向量 ind 和细胞结构 X_bs{ii} 存在问题。这是一个更简单的示例,它没有调用随机向量 ind 并且仍然有相同的错误:

X{1} = [1 ; 2 ; 3]
 X{2} = [4 ; 5 ; 6; 7]
 N(1) = 3 % size of X{1}
 N(2) = 4 % size of X{2}
    parfor bb=1:10
        for ii = 1:2
            X_bs{ii} = X{ii};
        end
        % Output is a function of X_bs.  For illustration, say it is the sum
        y(bb) = sum(X_bs{1}) + sum(X_bs{2});
    end

因此,我相当确定 MatLab 不会将单元格结构 X_bs{ii} 视为临时变量。

在线创建问题:

ind = ceil(N(ii)*rand(N(ii),1));

并在此处显示:

X_bs{ii} = X{ii}(ind,:);

在执行 parfor 之前,ind 的大小对于 MATLAB 来说是 "unknown",因此不能 运行。 parfor 不是 运行 的连续顺序,因此预先指定所有必需的大小至关重要。也许您可以在调用 y(bb) 之前使用 clear X_bs 来规避此问题,这会将它们从内存中删除并确保包含的矩阵与您分配的上一次迭代的矩阵大小不同。

另一方面,如果这不能解决问题,则您不能将其并行化,因为您每次都使用随机大小的矩阵。对此进行扩展:rand(N(ii)) 可以产生相当大范围的数字。无论该范围如何,重要的事实是该范围是 不确定的 ,这意味着您无法在执行之前知道它会是什么。即使这通常没有问题,因为单元将存储任何旧矩阵大小,parfor 环境 需要 事先知道所有大小,以优化内存和 CPU 分配工作给工人之前的用法。

如果可能:获取最大值 ind 可以获得并初始化临时变量中所需的矩阵为最大允许大小,并且仅访问已使用的条目。

一个解决方案(感谢 Andriaan 的评论)是将生成 X_bs 的 forloop 放在嵌套函数 randomize_X 中。有关工作示例的解决方案,请参见下文:

X{1} = [1 ; 2 ; 3]
X{2} = [4 ; 5 ; 6; 7]
N(1) = 3 % size of X{1}
N(2) = 4 % size of X{2}
parfor bb=1:10
    [X_bs] = randomize_X(X,N)
    % Output is a function of X_bs.  For illustration, say it is the sum
    y(bb) = sum(X_bs{1}) + sum(X_bs{2});
end

哪里

function [X_bs] = randomize_X(X,N)
  for ii = 1:2
      X_bs{ii} = zeros(N(ii),1);
      ind = ceil(N(ii)*rand(N(ii),1));
      X_bs{ii} = X{ii}(ind,:);
  end
end

我相当确定 parfor 循环将单元格结构视为切片变量,因此需要事先指定并且不能在 parfor 循环中被覆盖。为了解决这个问题,一个简单的技巧是将单元结构的计算发送到另一个函数。 parfoor循环与优化工具箱CVX有类似的问题。可以使用相同的技巧 - 在 parfor.

的子例程中调用 CVX