Merge pull request #20450 from JulieBar:lstm_inside
Support non-zero hidden state for LSTM * fully support non-zero hidden state for LSTM * check dims of hidden state for LSTM * fix failed test Test_Model.TextRecognition * add new tests for LSTM w/ non-zero hidden params Co-authored-by: Julie Bareeva <julia.bareeva@xperience.ai>
This commit is contained in:
@@ -434,7 +434,7 @@ class Layer_LSTM_Test : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
int numInp, numOut;
|
||||
Mat Wh, Wx, b;
|
||||
Mat Wh, Wx, b, h, c;
|
||||
Ptr<LSTMLayer> layer;
|
||||
std::vector<Mat> inputs, outputs;
|
||||
|
||||
@@ -449,12 +449,17 @@ public:
|
||||
Wh = Mat::ones(4 * numOut, numOut, CV_32F);
|
||||
Wx = Mat::ones(4 * numOut, numInp, CV_32F);
|
||||
b = Mat::ones(4 * numOut, 1, CV_32F);
|
||||
h = Mat::ones(4, numOut, CV_32F);
|
||||
c = Mat::ones(4, numOut, CV_32F);
|
||||
|
||||
LayerParams lp;
|
||||
lp.blobs.resize(3);
|
||||
lp.blobs.resize(5);
|
||||
lp.blobs[0] = Wh;
|
||||
lp.blobs[1] = Wx;
|
||||
lp.blobs[2] = b;
|
||||
lp.blobs[3] = h;
|
||||
lp.blobs[4] = c;
|
||||
|
||||
lp.set<bool>("produce_cell_output", produceCellOutput);
|
||||
lp.set<bool>("use_timestamp_dim", useTimestampDim);
|
||||
|
||||
@@ -502,10 +507,12 @@ TEST_F(Layer_LSTM_Test, get_set_test)
|
||||
TEST(Layer_LSTM_Test_Accuracy_with_, CaffeRecurrent)
|
||||
{
|
||||
LayerParams lp;
|
||||
lp.blobs.resize(3);
|
||||
lp.blobs.resize(5);
|
||||
lp.blobs[0] = blobFromNPY(_tf("lstm.prototxt.w_2.npy")); // Wh
|
||||
lp.blobs[1] = blobFromNPY(_tf("lstm.prototxt.w_0.npy")); // Wx
|
||||
lp.blobs[2] = blobFromNPY(_tf("lstm.prototxt.w_1.npy")); // bias
|
||||
lp.blobs[3] = Mat::zeros(2, 17, CV_32F); // h_0
|
||||
lp.blobs[4] = Mat::zeros(2, 17, CV_32F); // c_0
|
||||
Ptr<LSTMLayer> layer = LSTMLayer::create(lp);
|
||||
|
||||
Mat inp = blobFromNPY(_tf("recurrent.input.npy"));
|
||||
@@ -516,6 +523,68 @@ TEST(Layer_LSTM_Test_Accuracy_with_, CaffeRecurrent)
|
||||
normAssert(h_t_reference, outputs[0]);
|
||||
}
|
||||
|
||||
TEST(Layer_LSTM_Test_Accuracy_with_, HiddenParams)
|
||||
{
|
||||
Mat Wx = blobFromNPY(_tf("lstm.hidden.W.npy"));
|
||||
Mat Wh = blobFromNPY(_tf("lstm.hidden.R.npy"));
|
||||
Mat b = blobFromNPY(_tf("lstm.hidden.B.npy"));
|
||||
Mat h0 = blobFromNPY(_tf("lstm.hidden.h0.npy"));
|
||||
Mat c0 = blobFromNPY(_tf("lstm.hidden.c0.npy"));
|
||||
|
||||
const int numHidden = 3;
|
||||
const int numDirs = Wx.size[0];
|
||||
const int numFeatures = Wx.size[2];
|
||||
|
||||
b = b.reshape(1, b.size[0]);
|
||||
Mat bx = b.colRange(0, b.cols / 2);
|
||||
Mat bh = b.colRange(b.cols / 2, b.cols);
|
||||
b = bx + bh;
|
||||
|
||||
// IFGO->IGFO
|
||||
for (int k = 0; k < numDirs; ++k)
|
||||
{
|
||||
float* WxData = Wx.ptr<float>(k);
|
||||
float* WhData = Wh.ptr<float>(k);
|
||||
float* biasData = b.ptr<float>(k);
|
||||
for (int j = 0; j < numHidden; ++j)
|
||||
{
|
||||
for (int i = 0; i < numFeatures; ++i)
|
||||
{
|
||||
std::swap(WxData[(numHidden + j) * numFeatures + i],
|
||||
WxData[(numHidden * 2 + j) * numFeatures + i]);
|
||||
}
|
||||
for (int i = 0; i < numHidden; ++i)
|
||||
{
|
||||
std::swap(WhData[(numHidden + j) * numHidden + i],
|
||||
WhData[(numHidden * 2 + j) * numHidden + i]);
|
||||
}
|
||||
std::swap(biasData[numHidden + j], biasData[numHidden * 2 + j]);
|
||||
}
|
||||
}
|
||||
|
||||
Wx = Wx.reshape(1, Wx.size[0] * Wx.size[1]);
|
||||
Wh = Wh.reshape(1, Wh.size[0] * Wh.size[1]);
|
||||
h0 = h0.reshape(1, h0.size[0] * h0.size[1]);
|
||||
c0 = c0.reshape(1, c0.size[0] * c0.size[1]);
|
||||
|
||||
LayerParams lstmParams;
|
||||
lstmParams.blobs.resize(5);
|
||||
lstmParams.blobs[0] = Wh;
|
||||
lstmParams.blobs[1] = Wx;
|
||||
lstmParams.blobs[2] = b;
|
||||
lstmParams.blobs[3] = h0;
|
||||
lstmParams.blobs[4] = c0;
|
||||
lstmParams.set("bidirectional", false);
|
||||
Ptr<LSTMLayer> layer = LSTMLayer::create(lstmParams);
|
||||
|
||||
Mat inp = blobFromNPY(_tf("lstm.hidden.input.npy"));
|
||||
std::vector<Mat> inputs(1, inp), outputs;
|
||||
runLayer(layer, inputs, outputs);
|
||||
|
||||
Mat h_t_reference = blobFromNPY(_tf("lstm.hidden.output.npy"));
|
||||
normAssert(h_t_reference, outputs[0]);
|
||||
}
|
||||
|
||||
TEST(Layer_RNN_Test_Accuracy_with_, CaffeRecurrent)
|
||||
{
|
||||
Ptr<RNNLayer> layer = RNNLayer::create(LayerParams());
|
||||
@@ -560,6 +629,9 @@ TEST(Layer_LSTM_Test_Accuracy_, Reverse)
|
||||
bias.at<float>(2, 0) = 1e10f; // Output gate - always output everything
|
||||
bias.at<float>(3, 0) = 0.f; // Update signal
|
||||
|
||||
cv::Mat hInternal = cv::Mat::zeros(1, 1, CV_32FC1);
|
||||
cv::Mat cInternal = cv::Mat::zeros(1, 1, CV_32FC1);
|
||||
|
||||
LayerParams lp;
|
||||
lp.set("reverse", true);
|
||||
lp.set("use_timestamp_dim", true);
|
||||
@@ -567,6 +639,8 @@ TEST(Layer_LSTM_Test_Accuracy_, Reverse)
|
||||
lp.blobs.push_back(Wh);
|
||||
lp.blobs.push_back(Wx);
|
||||
lp.blobs.push_back(bias);
|
||||
lp.blobs.push_back(hInternal);
|
||||
lp.blobs.push_back(cInternal);
|
||||
|
||||
cv::Ptr<cv::dnn::LSTMLayer> layer = LSTMLayer::create(lp);
|
||||
std::vector<cv::Mat> outputs;
|
||||
|
||||
Reference in New Issue
Block a user