如何使用 Eigen 提高我的表现? (包括示例代码)
How can I increase my performance with Eigen? (sample code included)
我的矩阵数学在以下函数中是否有任何效率过低的地方?我在 visual studio 中启用了优化,并且正在以 64 位发布模式构建。我正在通过这里 (750X350) 提供相当大的矩阵,但我的表现似乎很慢 none-the-less。
void NeuralNetwork::backward(Eigen::MatrixXf back, float learningRate)
{
std::vector<Eigen::MatrixXf> dedw;
std::vector<Eigen::MatrixXf> delta;
int nLayers = layers.size();
int dIt = 0;
for (int i = nLayers -1;i > 0; i=i-1)
{
Eigen::MatrixXf deltai;
logger->LogVerbose("--------","Back", i,"---------");
if (i == (nLayers - 1))
{
deltai.noalias() = back.cwiseProduct(dSigmoid(X[i]));
delta.push_back(deltai);
dIt++;
}
else
{
logger->LogVerbose("W", i);
deltai.noalias() = (W[i].transpose() * delta[dIt - 1]).cwiseProduct(dSigmoid(X[i]));
delta.push_back(deltai);
dIt++;
}
Eigen::MatrixXf dedwi;
dedwi.noalias() = delta[dIt - 1] * X[i - 1].transpose();
dedw.push_back(dedwi);
logger->LogVerbose("dedw", dIt - 1, dedw[dIt - 1]);
Eigen::MatrixXf WiNew;
WiNew.noalias() = W[i - 1] - learningRate * dedw[dIt - 1];
W[i-1] = WiNew;
logger->LogVerbose("W", i - 1);
logger->LogVerbose(W[i - 1]);
Eigen::MatrixXf BiNew;
BiNew.noalias() = B[i - 1] - learningRate * delta[dIt - 1];
B[i-1] = BiNew;
logger->LogVerbose("B", i - 1);
logger->LogVerbose(B[i - 1]);
}
}
避免在性能敏感的代码中进行内存密集型操作。
- 永远不要按值传递 "big arguments"。
例如
void NeuralNetwork::backward(Eigen::MatrixXf back, float learningRate)
应该是
void NeuralNetwork::backward(const Eigen::MatrixXf& back, float learningRate)
这避免了在函数中一次又一次地复制构造参数。
- 避免在函数内部复制。您将临时的
delta
和 dedw
向量矩阵推入。你可能想像这样移动它们:delta.push_back(std::move(deltai));
- 重用分配的内存。您或许可以重复使用
delta
和 dedw
工作空间向量。即使尽量减少不必要的分配-释放。如果您不需要上次调用中的元素 - 只需清除它们即可。
这些是首先要做的事情。最后 -- 个人资料!
我会用perf record
来分析程序中的瓶颈。挤出更多性能的最佳方法是解决最大的瓶颈。此时你不知道你最大的瓶颈在哪里。所以个人资料,个人资料,个人资料。
我的矩阵数学在以下函数中是否有任何效率过低的地方?我在 visual studio 中启用了优化,并且正在以 64 位发布模式构建。我正在通过这里 (750X350) 提供相当大的矩阵,但我的表现似乎很慢 none-the-less。
void NeuralNetwork::backward(Eigen::MatrixXf back, float learningRate)
{
std::vector<Eigen::MatrixXf> dedw;
std::vector<Eigen::MatrixXf> delta;
int nLayers = layers.size();
int dIt = 0;
for (int i = nLayers -1;i > 0; i=i-1)
{
Eigen::MatrixXf deltai;
logger->LogVerbose("--------","Back", i,"---------");
if (i == (nLayers - 1))
{
deltai.noalias() = back.cwiseProduct(dSigmoid(X[i]));
delta.push_back(deltai);
dIt++;
}
else
{
logger->LogVerbose("W", i);
deltai.noalias() = (W[i].transpose() * delta[dIt - 1]).cwiseProduct(dSigmoid(X[i]));
delta.push_back(deltai);
dIt++;
}
Eigen::MatrixXf dedwi;
dedwi.noalias() = delta[dIt - 1] * X[i - 1].transpose();
dedw.push_back(dedwi);
logger->LogVerbose("dedw", dIt - 1, dedw[dIt - 1]);
Eigen::MatrixXf WiNew;
WiNew.noalias() = W[i - 1] - learningRate * dedw[dIt - 1];
W[i-1] = WiNew;
logger->LogVerbose("W", i - 1);
logger->LogVerbose(W[i - 1]);
Eigen::MatrixXf BiNew;
BiNew.noalias() = B[i - 1] - learningRate * delta[dIt - 1];
B[i-1] = BiNew;
logger->LogVerbose("B", i - 1);
logger->LogVerbose(B[i - 1]);
}
}
避免在性能敏感的代码中进行内存密集型操作。
- 永远不要按值传递 "big arguments"。
例如
void NeuralNetwork::backward(Eigen::MatrixXf back, float learningRate)
应该是
void NeuralNetwork::backward(const Eigen::MatrixXf& back, float learningRate)
这避免了在函数中一次又一次地复制构造参数。
- 避免在函数内部复制。您将临时的
delta
和dedw
向量矩阵推入。你可能想像这样移动它们:delta.push_back(std::move(deltai));
- 重用分配的内存。您或许可以重复使用
delta
和dedw
工作空间向量。即使尽量减少不必要的分配-释放。如果您不需要上次调用中的元素 - 只需清除它们即可。
这些是首先要做的事情。最后 -- 个人资料!
我会用perf record
来分析程序中的瓶颈。挤出更多性能的最佳方法是解决最大的瓶颈。此时你不知道你最大的瓶颈在哪里。所以个人资料,个人资料,个人资料。