/
githubmirror
/
incubator-mxnet
Обзор
Документация
Войти
/
githubmirror
/
incubator-mxnet
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tests/cpp/operator/dnnl_test.cc
418 строк
15 KB
PiotrWolinski - Intel
[master] Remove dnnl_ops-inl.h file (#20997)
02 июн 2022, 09:40
Не верифицирован
02 июн 2022, 09:40
102388a
Код
Авторство
О чём код?
/* * 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. */ /*! * \file dnnl_test.cc * \brief test functions in dnnl. * \author Da Zheng */ #if MXNET_USE_ONEDNN == 1 #include <dnnl_types.h> #include <climits> #include <cmath> #include <set> #include "../../src/operator/nn/dnnl/dnnl_base-inl.h" #include "../include/test_dnnl.h" #include "gtest/gtest.h" #include "mxnet/imperative.h" using namespace mxnet; #if __GNUC__ >= 5 bool test_mem_align(void* mem, size_t size, size_t alignment, size_t space) { void *ret1, *ret2; size_t space1, space2; space1 = space; space2 = space; ret1 = mxnet::AlignMem(mem, size, alignment, &space1); ret2 = std::align(alignment, size, mem, space2); EXPECT_EQ(ret1, ret2); EXPECT_EQ(space1, space2); return ret1 == ret2; } #endif TEST(DNNL_UTIL_FUNC, AlignMem) { #if __GNUC__ >= 5 size_t alignment = 4096; void* mem; size_t size, space; // When mem has been aligned. mem = reinterpret_cast<void*>(0x10000); size = 1000; space = 10000; test_mem_align(mem, size, alignment, space); // When mem isn't aligned and we have enough space for alignment. mem = reinterpret_cast<void*>(0x10010); size = 1000; space = 10000; test_mem_align(mem, size, alignment, space); // When mem isn't aligned and we don't have enough memory for alignment mem = reinterpret_cast<void*>(0x10010); size = 1000; space = 1001; test_mem_align(mem, size, alignment, space); for (size_t i = 0; i < 10000; i++) { mem = reinterpret_cast<void*>(random()); size = random() % 2000; space = random() % 2000; test_mem_align(mem, size, alignment, space); } #else // std::align is not supported in GCC < 5.0, this test case will be checked // with newer version LOG(INFO) << "Skipped for GCC " << __GNUC__ << "." << __GNUC_MINOR__; #endif } static void VerifyDefMem(const dnnl::memory& mem) { dnnl::memory::desc desc = mem.get_desc(); mshadow::default_real_t* data = static_cast<mshadow::default_real_t*>(mem.get_data_handle()); size_t size = desc.get_size() / sizeof(mshadow::default_real_t); size_t num_same = 0; for (int i = 0; i < size; i++) num_same += data[i] == static_cast<mshadow::default_real_t>(i % 100 - 50); EXPECT_EQ(num_same, size); } TEST(DNNL_UTIL_FUNC, MemFormat) { // Check whether the number of format is correct. CHECK_EQ(dnnl_format_tag_last, 514); CHECK_EQ(dnnl_nchw, 5); CHECK_EQ(dnnl_oihw, 5); } static void VerifyMem(const dnnl::memory& mem) { dnnl::memory::desc desc = mem.get_desc(); dnnl::memory::dims dims(desc.data.ndims); for (size_t i = 0; i < dims.size(); i++) dims[i] = desc.data.dims[i]; dnnl::memory::desc new_desc{dims, static_cast<dnnl::memory::data_type>(desc.data.data_type), static_cast<dnnl::memory::format_tag>(GetDefaultFormat(desc))}; if (desc == new_desc) { VerifyDefMem(mem); } else { dnnl::memory* src_mem = const_cast<dnnl::memory*>(&mem); dnnl::memory new_mem(new_desc, CpuEngine::Get()->get_engine()); dnnl::stream s(CpuEngine::Get()->get_engine()); dnnl::reorder(*src_mem, new_mem).execute(s, *src_mem, new_mem); VerifyDefMem(new_mem); } } TEST(DNNL_NDArray, GetDataReorder) { TestArrayShapes tas = GetTestArrayShapes(); mxnet::ShapeVector shapes = tas.shapes; std::vector<dnnl::memory::desc> mds = tas.mds; // Reorder from the default to any other layout. for (auto s : shapes) { NDArray arr(s, Context()); InitDefaultArray(&arr); for (auto md : mds) { if (s.Size() == md.get_size() / sizeof(mshadow::default_real_t)) { const dnnl::memory* mem = arr.GetDNNLDataReorder(&md); printf("reorder from ("); for (size_t i = 0; i < s.ndim(); i++) printf("%ld, ", s[i]); printf(") to ("); for (int i = 0; i < md.data.ndims; i++) printf("%ld, ", md.data.dims[i]); printf("), format: %d\n", static_cast<int>(GetDefaultFormat(md))); DNNLStream::Get()->Submit(false); VerifyMem(*mem); DNNLStream::Get()->Cleanup(); } } } // Reorder from a special layout to another layout. for (auto s : shapes) { for (auto md : mds) { if (md.get_size() / sizeof(mshadow::default_real_t) == s.Size()) { NDArray arr(s, Context()); // There is possibility that the dimensions of an NDArray doesn't match // with the DNNL memory inside. printf("Init array ("); for (size_t i = 0; i < s.ndim(); i++) printf("%ld, ", s[i]); printf(") with oneDNN memory ("); for (int i = 0; i < md.data.ndims; i++) printf("%ld, ", md.data.dims[i]); printf("), format: %d\n", static_cast<int>(GetDefaultFormat(md))); InitDNNLArray(&arr, md); for (auto to_md : mds) { if (to_md.get_size() / sizeof(mshadow::default_real_t) == s.Size()) { const dnnl::memory* mem = arr.GetDNNLDataReorder(&to_md); printf("reorder from ("); for (size_t i = 0; i < s.ndim(); i++) printf("%ld, ", s[i]); printf("), format: %d to (", static_cast<int>(GetDefaultFormat(to_md))); for (int i = 0; i < to_md.data.ndims; i++) printf("%ld, ", to_md.data.dims[i]); printf("), format: %d\n", static_cast<int>(GetDefaultFormat(to_md))); DNNLStream::Get()->Submit(false); VerifyMem(*mem); DNNLStream::Get()->Cleanup(); } } } } } } TEST(DNNL_BASE, DNNLMemorySum) { std::vector<NDArrayAttrs> in_arrs = GetTestInputArrays(); std::vector<NDArrayAttrs> in_arrs2 = GetTestInputArrays(ArrayTypes::All, true); TestArrayShapes tas = GetTestArrayShapes(); std::vector<dnnl::memory::desc> mds = tas.mds; for (int i = 0; i < in_arrs.size(); i++) { auto in_arr = in_arrs[i]; auto in_arr2 = in_arrs2[i]; if (!SupportDNNL(in_arr.arr)) continue; if (in_arr.arr.IsDNNLData() && in_arr.arr.IsView()) { continue; } std::vector<NDArrayAttrs> out_arrs = GetTestOutputArrays(in_arr.arr.shape(), mds); for (auto& out_arr : out_arrs) { auto in_mem1 = in_arr.arr.GetDNNLData(); auto in_mem2 = in_arr2.arr.GetDNNLData(); if (out_arr.arr.IsView()) continue; auto out_mem = out_arr.arr.GetDNNLData(); PrintVerifyMsg(in_arr, in_arr); op::DNNLMemorySum(*in_mem1, *in_mem2, *out_mem); DNNLStream::Get()->Submit(); VerifySumResult({&in_arr.arr, &in_arr2.arr}, {&out_arr.arr}); } } // in place for (int i = 0; i < in_arrs.size(); i++) { auto in_arr = in_arrs[i]; auto in_arr2 = in_arrs2[i]; if (!SupportDNNL(in_arr.arr)) continue; if (in_arr.arr.IsDNNLData() && in_arr.arr.IsView()) { continue; } auto input_mem = in_arr.arr.GetDNNLData(); auto input_mem2 = in_arr2.arr.GetDNNLData(); NDArrayAttrs orig_arr(in_arr.arr.Copy(in_arr.arr.ctx()), "In Place Copy"); orig_arr.arr.WaitToRead(); PrintVerifyMsg(orig_arr, in_arr); InitDNNLArray(&orig_arr.arr, input_mem->get_desc()); orig_arr.arr.CopyFrom(*input_mem); op::DNNLMemorySum(*input_mem, *input_mem2, *input_mem); DNNLStream::Get()->Submit(); VerifySumResult({&orig_arr.arr, &in_arr2.arr}, {&in_arr.arr}); } } TEST(DNNL_BASE, CreateDNNLMem) { std::vector<NDArrayAttrs> in_arrs = GetTestInputArrays(); std::vector<NDArrayAttrs> in_arrs2 = GetTestInputArrays(ArrayTypes::All, true); TestArrayShapes tas = GetTestArrayShapes(); std::vector<dnnl::memory::desc> mds = tas.mds; DNNLStream* stream = DNNLStream::Get(); // kWriteTo for (int i = 0; i < in_arrs.size(); i++) { auto in_arr = in_arrs[i]; auto in_arr2 = in_arrs2[i]; if (!SupportDNNL(in_arr.arr)) continue; if (in_arr.arr.IsDNNLData() && in_arr.arr.IsView()) { continue; } std::vector<NDArrayAttrs> out_arrs = GetTestOutputArrays(in_arr.arr.shape(), mds); for (auto& out_arr : out_arrs) { auto in_mem = in_arr.arr.GetDNNLData(); auto in_mem2 = in_arr2.arr.GetDNNLData(); NDArray orig_output = out_arr.arr.Copy(out_arr.arr.ctx()); orig_output.WaitToRead(); PrintVerifyMsg(in_arr, out_arr); auto out_mem = out_arr.arr.GetDNNLData(); auto output_mem_t = CreateDNNLMem(out_arr.arr, out_mem->get_desc(), kWriteTo); op::DNNLMemorySum(*in_mem, *in_mem2, *output_mem_t.second); CommitOutput(out_arr.arr, output_mem_t); stream->Submit(); VerifySumResult({&in_arr.arr, &in_arr2.arr}, {&out_arr.arr}); } } // kWriteInPlace for (int i = 0; i < in_arrs.size(); i++) { auto in_arr = in_arrs[i]; auto in_arr2 = in_arrs2[i]; if (!SupportDNNL(in_arr.arr)) continue; if (in_arr.arr.IsDNNLData() && in_arr.arr.IsView()) { continue; } auto input_mem = in_arr.arr.GetDNNLData(); auto input_mem2 = in_arr2.arr.GetDNNLData(); NDArrayAttrs orig_arr(in_arr.arr.Copy(in_arr.arr.ctx()), "In Place Copy"); orig_arr.arr.WaitToRead(); PrintVerifyMsg(orig_arr, in_arr); InitDNNLArray(&orig_arr.arr, input_mem->get_desc()); orig_arr.arr.CopyFrom(*input_mem); auto output_mem_t = CreateDNNLMem(in_arr.arr, input_mem->get_desc(), kWriteInplace, &in_arr.arr); op::DNNLMemorySum(*input_mem, *input_mem2, *output_mem_t.second); CommitOutput(in_arr.arr, output_mem_t); stream->Submit(); VerifySumResult({&orig_arr.arr, &in_arr2.arr}, {&in_arr.arr}); } // kAddTo for (int i = 0; i < in_arrs.size(); i++) { auto in_arr = in_arrs[i]; auto in_arr2 = in_arrs2[i]; if (!SupportDNNL(in_arr.arr)) continue; if (in_arr.arr.IsDNNLData() && in_arr.arr.IsView()) { continue; } std::vector<NDArrayAttrs> out_arrs = GetTestOutputArrays(in_arr.arr.shape(), mds); for (auto& out_arr : out_arrs) { auto in_mem = in_arr.arr.GetDNNLData(); auto in_mem2 = in_arr2.arr.GetDNNLData(); NDArray orig_output = out_arr.arr.Copy(out_arr.arr.ctx()); orig_output.WaitToRead(); PrintVerifyMsg(in_arr, out_arr); auto out_mem = out_arr.arr.GetDNNLData(); auto output_mem_t = CreateDNNLMem(out_arr.arr, out_mem->get_desc(), kAddTo); op::DNNLMemorySum(*in_mem, *in_mem2, *output_mem_t.second); CommitOutput(out_arr.arr, output_mem_t); stream->Submit(); VerifyAddRequest( {&in_arr.arr, &in_arr2.arr}, {&orig_output}, {&out_arr.arr}, VerifySumResult); } } // kNullOp for (int i = 0; i < in_arrs.size(); i++) { auto in_arr = in_arrs[i]; auto in_arr2 = in_arrs2[i]; if (!SupportDNNL(in_arr.arr)) continue; if (in_arr.arr.IsDNNLData() && in_arr.arr.IsView()) { continue; } auto input_mem = in_arr.arr.GetDNNLData(); auto input_mem2 = in_arr2.arr.GetDNNLData(); NDArrayAttrs orig_arr(in_arr.arr.Copy(in_arr.arr.ctx()), "In Place Copy"); orig_arr.arr.WaitToRead(); PrintVerifyMsg(orig_arr, in_arr); InitDNNLArray(&orig_arr.arr, input_mem->get_desc()); orig_arr.arr.CopyFrom(*input_mem); auto output_mem_t = CreateDNNLMem(in_arr.arr, input_mem->get_desc(), kNullOp); op::DNNLMemorySum(*input_mem, *input_mem2, *output_mem_t.second); CommitOutput(in_arr.arr, output_mem_t); stream->Submit(); // original and input should be the same since noop VerifyCopyResult({&orig_arr.arr}, {&in_arr.arr}); } } TEST(DNNL_NDArray, GetTestInputArraysConcat) { auto in_arrs = GetTestInputArrays(); for (int dim = 0; dim < 5; dim++) { for (int num_inputs = 2; num_inputs < 5; num_inputs++) { std::vector<float> scale_vector(dim + 1); for (size_t i = 0; i < dim + 1; ++i) scale_vector[i] = 1; scale_vector[dim] = num_inputs; std::vector<NDArrayAttrs> expanded_arrs = GetTestInputArrays(ArrayTypes::All, false, scale_vector); int i = 0; for (auto& arr : in_arrs) { if (dim >= arr.arr.shape().ndim()) continue; auto ex_arr = expanded_arrs[i]; PrintVerifyMsg(arr, ex_arr); EXPECT_EQ(arr.arr.shape().Size() * num_inputs, ex_arr.arr.shape().Size()); EXPECT_EQ(arr.arr.shape()[dim] * num_inputs, ex_arr.arr.shape()[dim]); i++; } } } } TEST(DNNL_NDArray, GetTestOutputArraysConcat) { auto shapes_pds = GetTestArrayShapes(); std::vector<mxnet::TShape> shapes = shapes_pds.shapes; std::vector<dnnl::memory::desc> mds = shapes_pds.mds; for (auto& shape : shapes) { for (int dim = 0; dim < 5; dim++) { for (int num_inputs = 2; num_inputs < 5; num_inputs++) { if (shape.ndim() <= dim) continue; std::cout << "Extending " << shape << " dim " << dim << " and " << num_inputs << "num_inputs\n"; std::vector<float> scale_vector(shape.ndim()); for (int i = 0; i < shape.ndim(); i++) scale_vector[i] = 1; scale_vector[dim] = num_inputs; auto output_arrs = GetTestOutputArrays(shape, mds, scale_vector); for (auto& out_arr : output_arrs) { auto out_shape = out_arr.arr.shape(); EXPECT_EQ(shape.Size() * num_inputs, out_arr.arr.shape().Size()); EXPECT_EQ(shape[dim] * num_inputs, out_arr.arr.shape()[dim]); } } } } } TEST(DNNL_NDArray, CopyFrom) { TestArrayShapes tas = GetTestArrayShapes(); std::vector<dnnl::memory::desc> mds = tas.mds; std::vector<NDArrayAttrs> in_arrs = GetTestInputArrays(); for (auto& in_arr : in_arrs) { if (in_arr.arr.IsDNNLData() && in_arr.arr.IsView()) continue; std::vector<NDArrayAttrs> out_arrs = GetTestOutputArrays(in_arr.arr.shape(), mds); for (auto& out_arr : out_arrs) { const dnnl::memory* mem = in_arr.arr.GetDNNLData(); out_arr.arr.CopyFrom(*mem); DNNLStream::Get()->Submit(); std::vector<NDArray*> inputs(1); inputs[0] = &in_arr.arr; VerifyCopyResult(inputs, {&out_arr.arr}); } } } #endif // MXNET_USE_ONEDNN == 1