test_tools.hpp 7.25 KB
Newer Older
1
//*****************************************************************************
2
// Copyright 2017-2019 Intel Corporation
3 4 5 6 7 8 9 10 11 12 13 14 15
//
// 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.
//*****************************************************************************
16

17
#pragma once
18

19
#include <exception>
20
#include <fstream>
21 22
#include <iomanip>
#include <iostream>
23
#include <list>
Robert Kimball's avatar
Robert Kimball committed
24
#include <memory>
25
#include <random>
26
#include <vector>
27

Scott Cyphers's avatar
Scott Cyphers committed
28
#include "ngraph/descriptor/layout/tensor_layout.hpp"
29
#include "ngraph/file_util.hpp"
30
#include "ngraph/log.hpp"
31
#include "ngraph/runtime/backend.hpp"
32
#include "ngraph/runtime/tensor.hpp"
33
#include "ngraph/serializer.hpp"
34

35
namespace ngraph
36
{
37
    class Node;
38
    class Function;
39
}
40

41
bool validate_list(const std::list<std::shared_ptr<ngraph::Node>>& nodes);
42
std::shared_ptr<ngraph::Function> make_test_graph();
43
std::shared_ptr<ngraph::Function> make_function_from_file(const std::string& file_name);
44 45

template <typename T>
46
void copy_data(std::shared_ptr<ngraph::runtime::Tensor> tv, const std::vector<T>& data)
47 48 49 50
{
    size_t data_size = data.size() * sizeof(T);
    tv->write(data.data(), 0, data_size);
}
51 52

template <typename T>
53
std::vector<T> read_vector(std::shared_ptr<ngraph::runtime::Tensor> tv)
54
{
Scott Cyphers's avatar
Scott Cyphers committed
55
    if (ngraph::element::from<T>() != tv->get_tensor_layout()->get_element_type())
56
    {
57
        throw std::invalid_argument("read_vector type must match Tensor type");
58 59 60 61 62 63 64 65
    }
    size_t element_count = ngraph::shape_size(tv->get_shape());
    size_t size = element_count * sizeof(T);
    std::vector<T> rc(element_count);
    tv->read(rc.data(), 0, size);
    return rc;
}

66
std::vector<float> read_float_vector(std::shared_ptr<ngraph::runtime::Tensor> tv);
67

68
template <typename T>
69
void write_vector(std::shared_ptr<ngraph::runtime::Tensor> tv, const std::vector<T>& values)
70 71 72
{
    tv->write(values.data(), 0, values.size() * sizeof(T));
}
73

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
template <typename T>
std::vector<std::shared_ptr<T>> get_ops_of_type(std::shared_ptr<ngraph::Function> f)
{
    std::vector<std::shared_ptr<T>> ops;
    for (auto op : f->get_ops())
    {
        if (auto cop = std::dynamic_pointer_cast<T>(op))
        {
            ops.push_back(cop);
        }
    }

    return ops;
}

89 90 91 92 93 94 95 96 97 98 99 100 101 102
template <typename T>
size_t count_ops_of_type(std::shared_ptr<ngraph::Function> f)
{
    size_t count = 0;
    for (auto op : f->get_ops())
    {
        if (std::dynamic_pointer_cast<T>(op))
        {
            count++;
        }
    }

    return count;
}
103

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
template <typename T>
void init_int_tv(ngraph::runtime::Tensor* tv, std::default_random_engine& engine, T min, T max)
{
    size_t size = tv->get_element_count();
    std::uniform_int_distribution<T> dist(min, max);
    std::vector<T> vec(size);
    for (T& element : vec)
    {
        element = dist(engine);
    }
    tv->write(vec.data(), 0, vec.size() * sizeof(T));
}

template <typename T>
void init_real_tv(ngraph::runtime::Tensor* tv, std::default_random_engine& engine, T min, T max)
{
    size_t size = tv->get_element_count();
    std::uniform_real_distribution<T> dist(min, max);
    std::vector<T> vec(size);
    for (T& element : vec)
    {
        element = dist(engine);
    }
    tv->write(vec.data(), 0, vec.size() * sizeof(T));
}

void random_init(ngraph::runtime::Tensor* tv, std::default_random_engine& engine);

tsocha's avatar
tsocha committed
132 133 134 135 136
template <typename T>
std::vector<std::shared_ptr<ngraph::runtime::Tensor>>
    prepare_and_run(const std::shared_ptr<ngraph::Function>& function,
                    std::vector<std::vector<T>> args,
                    const std::string& backend_id)
137
{
138
    auto backend = ngraph::runtime::Backend::create(backend_id);
139

140
    auto parms = function->get_parameters();
141 142 143 144 145 146

    if (parms.size() != args.size())
    {
        throw ngraph::ngraph_error("number of parameters and arguments don't match");
    }

147
    std::vector<std::shared_ptr<ngraph::runtime::Tensor>> arg_tensors(args.size());
148 149 150 151 152 153 154
    for (size_t i = 0; i < args.size(); i++)
    {
        auto t = backend->create_tensor(parms.at(i)->get_element_type(), parms.at(i)->get_shape());
        copy_data(t, args.at(i));
        arg_tensors.at(i) = t;
    }

155
    auto results = function->get_results();
156
    std::vector<std::shared_ptr<ngraph::runtime::Tensor>> result_tensors(results.size());
157 158 159 160 161 162 163

    for (size_t i = 0; i < results.size(); i++)
    {
        result_tensors.at(i) =
            backend->create_tensor(results.at(i)->get_element_type(), results.at(i)->get_shape());
    }

164
    auto handle = backend->compile(function);
165
    handle->call_with_validate(result_tensors, arg_tensors);
tsocha's avatar
tsocha committed
166 167 168 169 170 171 172 173 174 175
    return result_tensors;
}

template <typename T, typename T1 = T>
std::vector<std::vector<T1>> execute(const std::shared_ptr<ngraph::Function>& function,
                                     std::vector<std::vector<T>> args,
                                     const std::string& backend_id)
{
    std::vector<std::shared_ptr<ngraph::runtime::Tensor>> result_tensors =
        prepare_and_run(function, args, backend_id);
176

tsocha's avatar
tsocha committed
177
    std::vector<std::vector<T1>> result_vectors;
178 179
    for (auto rt : result_tensors)
    {
tsocha's avatar
tsocha committed
180
        result_vectors.push_back(read_vector<T1>(rt));
181 182 183
    }
    return result_vectors;
}
184 185

template <typename T>
186 187
std::string
    get_results_str(std::vector<T>& ref_data, std::vector<T>& actual_data, size_t max_results = 16)
188
{
189
    std::stringstream ss;
190
    size_t num_results = std::min(static_cast<size_t>(max_results), ref_data.size());
191
    ss << "First " << num_results << " results";
192 193
    for (size_t i = 0; i < num_results; ++i)
    {
194 195 196
        ss << "\n"
           << std::setw(4) << i << " ref: " << std::setw(16) << std::left << ref_data[i]
           << "  actual: " << std::setw(16) << std::left << actual_data[i];
197
    }
198 199 200
    ss << "\n";

    return ss.str();
201 202 203
}

template <>
204 205 206
std::string get_results_str(std::vector<char>& ref_data,
                            std::vector<char>& actual_data,
                            size_t max_results);
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238

/// \brief      Reads a binary file to a vector.
///
/// \param[in]  path  The path where the file is located.
///
/// \tparam     T     The type we want to interpret as the elements in binary file.
///
/// \return     Return vector of data read from input binary file.
///
template <typename T>
std::vector<T> read_binary_file(const std::string& path)
{
    std::vector<T> file_content;
    std::ifstream inputs_fs{path, std::ios::in | std::ios::binary};
    if (!inputs_fs)
    {
        throw std::runtime_error("Failed to open the file: " + path);
    }

    inputs_fs.seekg(0, std::ios::end);
    auto size = inputs_fs.tellg();
    inputs_fs.seekg(0, std::ios::beg);
    if (size % sizeof(T) != 0)
    {
        throw std::runtime_error(
            "Error reading binary file content: Input file size (in bytes) "
            "is not a multiple of requested data type size.");
    }
    file_content.resize(size / sizeof(T));
    inputs_fs.read(reinterpret_cast<char*>(file_content.data()), size);
    return file_content;
}