You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
8.9 KiB
266 lines
8.9 KiB
/* Copyright (c) 2016 Baidu, Inc. All Rights Reserve.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License. */
|
|
|
|
#undef PADDLE_DISABLE_TIMER
|
|
#include <paddle/utils/PythonUtil.h>
|
|
#include <cstdlib>
|
|
#include <algorithm>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "paddle/trainer/Trainer.h"
|
|
#include "paddle/utils/Stat.h"
|
|
#include "TestUtil.h"
|
|
|
|
using namespace paddle; // NOLINT
|
|
using namespace std; // NOLINT
|
|
|
|
P_DECLARE_int32(gpu_id);
|
|
P_DECLARE_double(checkgrad_eps);
|
|
P_DEFINE_bool(use_label, true, "input label or sequence label");
|
|
P_DEFINE_bool(static_para, false, "static parameter");
|
|
|
|
struct DataIn {
|
|
std::vector<Argument> inArgs;
|
|
std::vector<MatrixPtr> outGrads;
|
|
std::vector<VectorPtr> paraValues;
|
|
};
|
|
|
|
struct DataOut {
|
|
std::vector<MatrixPtr> outValues;
|
|
std::vector<VectorPtr> paraGrads;
|
|
};
|
|
|
|
void initArgument(DataIn& data, const std::string& configPath,
|
|
bool useGpu = FLAGS_use_gpu) {
|
|
TrainerConfigHelper config(configPath);
|
|
size_t batchSize = config.getOptConfig().batch_size();
|
|
|
|
for (const auto& layer_name : config.getModelConfig().input_layer_names()) {
|
|
auto layer_config = std::find_if(config.getModelConfig().layers().begin(),
|
|
config.getModelConfig().layers().end(),
|
|
[=](const LayerConfig& layer_config) {
|
|
return layer_config.name() == layer_name;
|
|
});
|
|
CHECK(layer_config != config.getModelConfig().layers().end());
|
|
|
|
size_t layerSize = layer_config->size();
|
|
Argument arg;
|
|
arg.value = Matrix::create(batchSize, layerSize, false, useGpu);
|
|
arg.grad = Matrix::create(batchSize, layerSize, false, useGpu);
|
|
arg.value->randomizeUniform();
|
|
arg.value->add(-0.5);
|
|
arg.value->sigmoid(*arg.value);
|
|
arg.grad->zeroMem();
|
|
if (FLAGS_use_label) {
|
|
arg.ids = VectorT<int>::create(batchSize, useGpu);
|
|
arg.ids->rand(layerSize);
|
|
}
|
|
generateSequenceStartPositions(batchSize, arg.sequenceStartPositions);
|
|
data.inArgs.push_back(arg);
|
|
}
|
|
|
|
for (const auto& layer_name : config.getModelConfig().output_layer_names()) {
|
|
auto layer_config = std::find_if(config.getModelConfig().layers().begin(),
|
|
config.getModelConfig().layers().end(),
|
|
[=](const LayerConfig& layer_config) {
|
|
return layer_config.name() == layer_name;
|
|
});
|
|
CHECK(layer_config != config.getModelConfig().layers().end());
|
|
|
|
size_t layerSize = layer_config->size();
|
|
MatrixPtr grad = Matrix::create(batchSize, layerSize, false, useGpu);
|
|
grad->randomizeUniform();
|
|
data.outGrads.push_back(grad);
|
|
}
|
|
|
|
for (const auto& para_config : config.getModelConfig().parameters()) {
|
|
VectorPtr value = Vector::create(para_config.size(), useGpu);
|
|
value->randnorm(0, 2);
|
|
data.paraValues.push_back(value);
|
|
}
|
|
}
|
|
|
|
void calcGradient(DataIn& in, DataOut& out, const std::string& configPath) {
|
|
*ThreadLocalRand::getSeed() = 0;
|
|
srand(0);
|
|
|
|
Trainer trainer;
|
|
auto config = std::make_shared<TrainerConfigHelper>(configPath);
|
|
trainer.init(config, false);
|
|
|
|
std::vector<ParameterPtr> parameters;
|
|
vector<Argument> outArgs;
|
|
|
|
auto gradientMachine = trainer.getGradientMachine();
|
|
parameters = gradientMachine->getParameters();
|
|
if (FLAGS_static_para) {
|
|
for (size_t i = 0; i < parameters.size(); i++) {
|
|
parameters[i]->getBuf(PARAMETER_VALUE)->one();
|
|
}
|
|
} else {
|
|
for (size_t i = 0; i < in.paraValues.size(); i++) {
|
|
parameters[i]->getBuf(PARAMETER_VALUE)->copyFrom(*in.paraValues[i]);
|
|
}
|
|
}
|
|
gradientMachine->start(trainer.getConfig(), nullptr);
|
|
gradientMachine->forward(in.inArgs, &outArgs, PASS_TRAIN);
|
|
for (size_t i = 0; i < in.outGrads.size(); i++) {
|
|
// If the all the layers in the config have no parameters, also
|
|
// not set NeedGradient(), the outArgs[i] will be nullptr.
|
|
outArgs[i].grad->copyFrom(*in.outGrads[i]);
|
|
}
|
|
gradientMachine->backward();
|
|
for (size_t i = 0; i < in.outGrads.size(); i++) {
|
|
MatrixPtr value =
|
|
Matrix::create(outArgs[i].value->getHeight(),
|
|
outArgs[i].value->getWidth(), false, false);
|
|
value->copyFrom(*outArgs[i].value);
|
|
out.outValues.push_back(value);
|
|
}
|
|
for (size_t i = 0; i < in.paraValues.size(); i++) {
|
|
VectorPtr grad = Vector::create(
|
|
parameters[i]->getBuf(PARAMETER_GRADIENT)->getSize(), false);
|
|
grad->copyFrom(*parameters[i]->getBuf(PARAMETER_GRADIENT));
|
|
out.paraGrads.push_back(grad);
|
|
}
|
|
|
|
for (int i = 0; i < 20; i++) {
|
|
REGISTER_TIMER("forward");
|
|
gradientMachine->forward(in.inArgs, &outArgs, PASS_TRAIN);
|
|
}
|
|
for (int i = 0; i < 20; i++) {
|
|
REGISTER_TIMER("backward");
|
|
gradientMachine->backward();
|
|
}
|
|
|
|
gradientMachine->finish();
|
|
}
|
|
|
|
void checkBuffer(real* A, const char* desA, real* B, const char* desB,
|
|
size_t len, size_t width = 1) {
|
|
int nNum = 0;
|
|
for (size_t i = 0; i < len; ++i) {
|
|
real diff = fabs(A[i] - B[i]);
|
|
if (diff > 0.0f &&
|
|
diff / std::max(fabs(A[i]), fabs(B[i])) > FLAGS_checkgrad_eps) {
|
|
nNum++;
|
|
LOG(INFO) << "Row: " << i / width << ", " << desA << " : " << A[i]
|
|
<< " " << desB << " : " << B[i];
|
|
}
|
|
}
|
|
EXPECT_EQ(0, nNum);
|
|
}
|
|
|
|
void compareGradient(DataOut& outA, DataOut& outB) {
|
|
LOG(INFO) << "------------------------------"
|
|
<< " Check Network Output "
|
|
<< "------------------------------";
|
|
for (size_t i = 0; i < outA.outValues.size(); ++i) {
|
|
LOG(INFO) << "OUTPUT VALUE: " << i;
|
|
checkBuffer(outA.outValues[i]->getData(), "network A output",
|
|
outB.outValues[i]->getData(), "network B output",
|
|
outA.outValues[i]->getElementCnt(),
|
|
outA.outValues[i]->getWidth());
|
|
}
|
|
|
|
if (!FLAGS_static_para) {
|
|
LOG(INFO) << "------------------------------"
|
|
<< " Check Parameters "
|
|
<< "------------------------------";
|
|
for (size_t i = 0; i < outA.paraGrads.size(); ++i) {
|
|
LOG(INFO) << "PARAMETER GRADIENT: " << i;
|
|
checkBuffer(outA.paraGrads[i]->getData(), "Network A",
|
|
outB.paraGrads[i]->getData(), "Network B",
|
|
outA.paraGrads[i]->getSize());
|
|
}
|
|
}
|
|
}
|
|
|
|
void compareNetwork(const std::string& config_file_a,
|
|
const std::string& config_file_b) {
|
|
DataIn in;
|
|
initArgument(in, config_file_a);
|
|
|
|
DataOut dataA;
|
|
calcGradient(in, dataA, config_file_a);
|
|
LOG(INFO) << "forwardBackward of Network A is finished";
|
|
globalStat.printSegTimerStatus();
|
|
globalStat.reset();
|
|
LOG(INFO) << "\n\n";
|
|
|
|
DataOut dataB;
|
|
calcGradient(in, dataB, config_file_b);
|
|
LOG(INFO) << "forwardBackward of the Network B is finished";
|
|
globalStat.printSegTimerStatus();
|
|
globalStat.reset();
|
|
LOG(INFO) << "\n\n";
|
|
|
|
compareGradient(dataA, dataB);
|
|
}
|
|
|
|
TEST(Compare, concat_dotmul) {
|
|
std::string config_file_a = "./gserver/tests/concat_dotmul_a.conf";
|
|
std::string config_file_b = "./gserver/tests/concat_dotmul_b.conf";
|
|
compareNetwork(config_file_a, config_file_b);
|
|
}
|
|
|
|
TEST(Compare, concat_fullmatrix) {
|
|
std::string config_file_a = "./gserver/tests/concat_fullmatrix_a.conf";
|
|
std::string config_file_b = "./gserver/tests/concat_fullmatrix_b.conf";
|
|
compareNetwork(config_file_a, config_file_b);
|
|
}
|
|
|
|
TEST(Compare, concat_table) {
|
|
std::string config_file_a = "./gserver/tests/concat_table_a.conf";
|
|
std::string config_file_b = "./gserver/tests/concat_table_b.conf";
|
|
compareNetwork(config_file_a, config_file_b);
|
|
}
|
|
|
|
#ifndef PADDLE_ONLY_CPU
|
|
TEST(Compare, img_pool) {
|
|
std::string config_file_a = "./gserver/tests/img_pool_a.conf";
|
|
std::string config_file_b = "./gserver/tests/img_pool_b.conf";
|
|
bool useGpu = FLAGS_use_gpu;
|
|
FLAGS_use_gpu = true;
|
|
compareNetwork(config_file_a, config_file_b);
|
|
FLAGS_use_gpu = useGpu;
|
|
}
|
|
|
|
TEST(Compare, img_conv) {
|
|
std::string config_file_a = "./gserver/tests/img_conv_a.conf";
|
|
std::string config_file_b = "./gserver/tests/img_conv_b.conf";
|
|
bool useGpu = FLAGS_use_gpu;
|
|
FLAGS_use_gpu = true;
|
|
compareNetwork(config_file_a, config_file_b);
|
|
FLAGS_use_gpu = useGpu;
|
|
}
|
|
#endif
|
|
|
|
|
|
P_DEFINE_string(config_file_a, "", "config of one network to compare");
|
|
P_DEFINE_string(config_file_b, "", "config of another network to compare");
|
|
TEST(Compare, network) {
|
|
if (FLAGS_config_file_a != "" && FLAGS_config_file_b != "") {
|
|
compareNetwork(FLAGS_config_file_a, FLAGS_config_file_b);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
testing::InitGoogleTest(&argc, argv);
|
|
paddle::initMain(argc, argv);
|
|
initPython(argc, argv);
|
|
int ret = RUN_ALL_TESTS();
|
|
return ret;
|
|
}
|