|
|
/*
|
||
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||
|
|
* or more contributor license agreements. See the NOTICE file
|
||
|
|
* distributed with this work for additional information
|
||
|
|
* regarding copyright ownership. The ASF licenses this file
|
||
|
|
* to you 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.
|
||
|
|
*/
|
||
|
|
#include "mxnet/c_api.h" // MXGetGPUCount()
|
||
|
|
#include "mxnet-cpp/MxNetCpp.h"
|
||
|
|
|
||
|
|
using namespace mxnet::cpp;
|
||
|
|
|
||
|
|
static bool test_single_key(const Context &context, const std::string &context_str) {
|
||
|
|
std::string key = "singlekeytest-" + context_str;
|
||
|
|
|
||
|
|
NDArray result(Shape(4), context);
|
||
|
|
NDArray result_cpu;
|
||
|
|
|
||
|
|
// initialize data
|
||
|
|
NDArray data_cpu({0.f, 233.f, -0.12f, 9.f}, Shape(4), Context::cpu());
|
||
|
|
NDArray data = data_cpu.Copy(context);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
KVStore::Init(key, data);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
// retrieve result
|
||
|
|
KVStore::Pull(key, &result);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
result_cpu = result.Copy(Context::cpu());
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
// compare
|
||
|
|
for (size_t j=0; j < result_cpu.Size(); j++) {
|
||
|
|
if (result_cpu.GetData()[j] != data_cpu.GetData()[j]) {
|
||
|
|
LG << "Error: wrong initialized data in singlekeytest-" << context_str
|
||
|
|
<< ", expect " << data_cpu.GetData()[j]
|
||
|
|
<< " got " << result_cpu.GetData()[j];
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// push gradient
|
||
|
|
NDArray grad_cpu({0.1f, -2.f, -4.4f, 0.f}, Shape(4), Context::cpu());
|
||
|
|
NDArray grad = grad_cpu.Copy(context);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
KVStore::Push(key, grad);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
// retrieve result
|
||
|
|
KVStore::Pull(key, &result);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
result_cpu = result.Copy(Context::cpu());
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
// compare
|
||
|
|
for (size_t j=0; j < result_cpu.Size(); j++) {
|
||
|
|
if (result_cpu.GetData()[j] != grad_cpu.GetData()[j]) {
|
||
|
|
LG << "Error: wrong gradient data in singlekeytest-" << context_str
|
||
|
|
<< ", expect " << grad_cpu.GetData()[j]
|
||
|
|
<< " got " << result_cpu.GetData()[j];
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool test_multiple_key(const Context &context, const std::string &context_str) {
|
||
|
|
std::vector<std::string> keys(2);
|
||
|
|
keys[0] = "multikeytest-0-" + context_str;
|
||
|
|
keys[1] = "multikeytest-1-" + context_str;
|
||
|
|
|
||
|
|
std::vector<NDArray> results(2);
|
||
|
|
results[0] = NDArray(Shape(4), context);
|
||
|
|
results[1] = NDArray(Shape(4), context);
|
||
|
|
std::vector<NDArray> results_cpu(2);
|
||
|
|
|
||
|
|
// initialize data
|
||
|
|
std::vector<NDArray> data_cpu(2);
|
||
|
|
data_cpu[0] = NDArray({0.f, 2.f, -3.12f, 4.f}, Shape(4), Context::cpu());
|
||
|
|
data_cpu[1] = NDArray({0.8f, -2.f, 6.6f, 77.f}, Shape(4), Context::cpu());
|
||
|
|
std::vector<NDArray> data(2);
|
||
|
|
data[0] = data_cpu[0].Copy(context);
|
||
|
|
data[1] = data_cpu[1].Copy(context);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
KVStore::Init(keys, data);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
// retrieve result
|
||
|
|
KVStore::Pull(keys, &results);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
results_cpu[0] = results[0].Copy(Context::cpu());
|
||
|
|
results_cpu[1] = results[1].Copy(Context::cpu());
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
// compare
|
||
|
|
for (size_t i=0; i < results_cpu.size(); i++) {
|
||
|
|
for (size_t j=0; j < results_cpu[i].Size(); j++) {
|
||
|
|
if (results_cpu[i].GetData()[j] != data_cpu[i].GetData()[j]) {
|
||
|
|
LG << "Error: wrong initialized data in multikeytest-" << context_str
|
||
|
|
<< ", expect " << data_cpu[i].GetData()[j]
|
||
|
|
<< " got " << results_cpu[i].GetData()[j];
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// push gradient, reduce for the second
|
||
|
|
std::vector<std::string> push_keys(3);
|
||
|
|
push_keys[0] = "multikeytest-0-" + context_str;
|
||
|
|
push_keys[1] = "multikeytest-1-" + context_str;
|
||
|
|
push_keys[2] = "multikeytest-1-" + context_str;
|
||
|
|
|
||
|
|
std::vector<NDArray> grads_cpu(3);
|
||
|
|
grads_cpu[0] = NDArray({0.2f, -0.3f, -1.1f, 0.0f}, Shape(4), Context::cpu());
|
||
|
|
grads_cpu[1] = NDArray({2.f, 4.f, -4.f, -5.f}, Shape(4), Context::cpu());
|
||
|
|
grads_cpu[2] = NDArray({-3.f, -0.2f, 12.f, -9.f}, Shape(4), Context::cpu());
|
||
|
|
std::vector<NDArray> grads(3);
|
||
|
|
grads[0] = grads_cpu[0].Copy(context);
|
||
|
|
grads[1] = grads_cpu[1].Copy(context);
|
||
|
|
grads[2] = grads_cpu[2].Copy(context);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
KVStore::Push(push_keys, grads);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
// retrieve result
|
||
|
|
KVStore::Pull(keys, &results);
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
results_cpu[0] = results[0].Copy(Context::cpu());
|
||
|
|
results_cpu[1] = results[1].Copy(Context::cpu());
|
||
|
|
NDArray::WaitAll();
|
||
|
|
|
||
|
|
// compare the first
|
||
|
|
for (size_t j=0; j < results_cpu[0].Size(); j++) {
|
||
|
|
if (results_cpu[0].GetData()[j] != grads_cpu[0].GetData()[j]) {
|
||
|
|
LG << "Error: wrong gradient data in multikeytest-" << context_str
|
||
|
|
<< ", expect " << grads_cpu[0].GetData()[j]
|
||
|
|
<< " got " << results_cpu[0].GetData()[j];
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// compare the second
|
||
|
|
for (size_t j=0; j < results_cpu[1].Size(); j++) {
|
||
|
|
if (results_cpu[1].GetData()[j] != (grads_cpu[1].GetData()[j] + grads_cpu[2].GetData()[j])) {
|
||
|
|
LG << "Error: wrong reduced gradient data in multikeytest-" << context_str
|
||
|
|
<< ", expect " << (grads_cpu[1].GetData()[j] + grads_cpu[2].GetData()[j])
|
||
|
|
<< " got " << results_cpu[1].GetData()[j];
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(int argc, char** argv) {
|
||
|
|
KVStore::SetType("local");
|
||
|
|
|
||
|
|
bool success1 = test_single_key(Context::cpu(), "cpu");
|
||
|
|
bool success2 = test_multiple_key(Context::cpu(), "cpu");
|
||
|
|
|
||
|
|
bool success3 = true;
|
||
|
|
bool success4 = true;
|
||
|
|
|
||
|
|
int gpu_count = 0;
|
||
|
|
if (MXGetGPUCount(&gpu_count) != 0) {
|
||
|
|
LG << "Error: MXGetGPUCount";
|
||
|
|
|
||
|
|
MXNotifyShutdown();
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (gpu_count > 0) {
|
||
|
|
success3 = test_single_key(Context::gpu(), "gpu");
|
||
|
|
success4 = test_multiple_key(Context::gpu(), "gpu");
|
||
|
|
}
|
||
|
|
|
||
|
|
int ret = (success1 && success2 && success3 && success4) ? 0 : 1;
|
||
|
|
|
||
|
|
MXNotifyShutdown();
|
||
|
|
return ret;
|
||
|
|
}
|