serialize.cpp 5.92 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*******************************************************************************
* Copyright 2017-2018 Intel Corporation
*
* 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.
*******************************************************************************/
Robert Kimball's avatar
Robert Kimball committed
16

Robert Kimball's avatar
Robert Kimball committed
17 18 19
#include <fstream>
#include <sstream>

Robert Kimball's avatar
Robert Kimball committed
20
#include "gtest/gtest.h"
Robert Kimball's avatar
Robert Kimball committed
21

22
#include "ngraph/file_util.hpp"
Robert Kimball's avatar
Robert Kimball committed
23 24 25
#include "ngraph/ngraph.hpp"
#include "ngraph/serializer.hpp"
#include "ngraph/util.hpp"
26
#include "nlohmann/json.hpp"
27
#include "util/test_tools.hpp"
Robert Kimball's avatar
Robert Kimball committed
28 29 30

using namespace std;
using namespace ngraph;
31
using json = nlohmann::json;
Robert Kimball's avatar
Robert Kimball committed
32

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
template <typename T>
T get_or_default(nlohmann::json& j, const std::string& key, const T& default_value)
{
    T rc;
    try
    {
        rc = j.at(key).get<T>();
    }
    catch (...)
    {
        rc = default_value;
    }
    return rc;
}

48
#if defined(NGRAPH_INTERPRETER_ENABLE)
Robert Kimball's avatar
Robert Kimball committed
49 50 51
TEST(serialize, main)
{
    // First create "f(A,B,C) = (A+B)*C".
52
    Shape shape{2, 2};
53 54 55
    auto A = make_shared<op::Parameter>(element::f32, shape);
    auto B = make_shared<op::Parameter>(element::f32, shape);
    auto C = make_shared<op::Parameter>(element::f32, shape);
56
    auto f = make_shared<Function>((A + B) * C, op::ParameterVector{A, B, C}, "f");
Robert Kimball's avatar
Robert Kimball committed
57 58

    // Now make "g(X,Y,Z) = f(X,Y,Z) + f(X,Y,Z)"
59 60 61
    auto X = make_shared<op::Parameter>(element::f32, shape);
    auto Y = make_shared<op::Parameter>(element::f32, shape);
    auto Z = make_shared<op::Parameter>(element::f32, shape);
62 63 64
    auto g = make_shared<Function>(make_shared<op::FunctionCall>(f, NodeVector{X, Y, Z}) +
                                       make_shared<op::FunctionCall>(f, NodeVector{X, Y, Z}),
                                   op::ParameterVector{X, Y, Z},
Robert Kimball's avatar
Robert Kimball committed
65 66 67
                                   "g");

    // Now make "h(X,Y,Z) = g(X,Y,Z) + g(X,Y,Z)"
68 69 70
    auto X1 = make_shared<op::Parameter>(element::f32, shape);
    auto Y1 = make_shared<op::Parameter>(element::f32, shape);
    auto Z1 = make_shared<op::Parameter>(element::f32, shape);
71 72 73
    auto h = make_shared<Function>(make_shared<op::FunctionCall>(g, NodeVector{X1, Y1, Z1}) +
                                       make_shared<op::FunctionCall>(g, NodeVector{X1, Y1, Z1}),
                                   op::ParameterVector{X1, Y1, Z1},
Robert Kimball's avatar
Robert Kimball committed
74 75
                                   "h");

76
    string js = serialize(h, 4);
Robert Kimball's avatar
Robert Kimball committed
77 78

    {
79 80
        ofstream out("serialize_function.js");
        out << js;
Robert Kimball's avatar
Robert Kimball committed
81 82 83 84 85
    }

    istringstream in(js);
    shared_ptr<Function> sfunc = deserialize(in);

86
    // Now call h on some test vectors.
87
    auto backend = runtime::Backend::create("INTERPRETER");
Robert Kimball's avatar
Robert Kimball committed
88

89
    auto x = backend->create_tensor(element::f32, shape);
Robert Kimball's avatar
Robert Kimball committed
90
    copy_data(x, vector<float>{1, 2, 3, 4});
91
    auto y = backend->create_tensor(element::f32, shape);
Robert Kimball's avatar
Robert Kimball committed
92
    copy_data(y, vector<float>{5, 6, 7, 8});
93
    auto z = backend->create_tensor(element::f32, shape);
Robert Kimball's avatar
Robert Kimball committed
94
    copy_data(z, vector<float>{9, 10, 11, 12});
95
    auto result = backend->create_tensor(element::f32, shape);
Robert Kimball's avatar
Robert Kimball committed
96

97
    backend->call_with_validate(sfunc, {result}, {x, y, z});
98
    EXPECT_EQ((vector<float>{216, 320, 440, 576}), read_vector<float>(result));
Robert Kimball's avatar
Robert Kimball committed
99

100
    backend->call_with_validate(sfunc, {result}, {y, x, z});
101
    EXPECT_EQ((vector<float>{216, 320, 440, 576}), read_vector<float>(result));
Robert Kimball's avatar
Robert Kimball committed
102

103
    backend->call_with_validate(sfunc, {result}, {x, z, y});
104
    EXPECT_EQ((vector<float>{200, 288, 392, 512}), read_vector<float>(result));
Robert Kimball's avatar
Robert Kimball committed
105
}
106
#endif
107 108 109

TEST(serialize, existing_models)
{
110 111 112 113
    vector<string> models = {"mxnet/mnist_mlp_forward.json",
                             "mxnet/10_bucket_LSTM.json",
                             "mxnet/LSTM_backward.json",
                             "mxnet/LSTM_forward.json"};
114 115 116 117 118

    for (const string& model : models)
    {
        const string json_path = file_util::path_join(SERIALIZED_ZOO, model);
        const string json_string = file_util::read_file_to_string(json_path);
119
        shared_ptr<Function> f = ngraph::deserialize(json_string);
120 121
    }
}
122

123 124 125 126 127 128 129 130 131 132 133 134
TEST(serialize, default_value)
{
    json j = {{"test1", 1}, {"test2", 2}};

    int x1 = j.at("test1").get<int>();
    EXPECT_EQ(x1, 1);
    int x2 = get_or_default<int>(j, "test2", 0);
    EXPECT_EQ(x2, 2);
    int x3 = get_or_default<int>(j, "test3", 3);
    EXPECT_EQ(x3, 3);
}

135 136 137 138 139 140 141 142 143 144
TEST(serialize, constant)
{
    const string tmp_file = "serialize_constant.cpio";
    Shape shape{2, 2, 2};
    auto A = op::Constant::create(element::f32, shape, {1, 2, 3, 4, 5, 6, 7, 8});
    auto f = make_shared<Function>(A, op::ParameterVector{});

    EXPECT_EQ((vector<float>{1, 2, 3, 4, 5, 6, 7, 8}), A->get_vector<float>());
    serialize(tmp_file, f);
    auto g = deserialize(tmp_file);
145
    ASSERT_NE(g, nullptr);
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
    file_util::remove_file(tmp_file);
    bool found = false;
    for (shared_ptr<Node> node : g->get_ops())
    {
        shared_ptr<op::Constant> c = dynamic_pointer_cast<op::Constant>(node);
        if (c)
        {
            found = true;
            EXPECT_EQ((vector<float>{1, 2, 3, 4, 5, 6, 7, 8}), c->get_vector<float>());
            break;
        }
    }
    EXPECT_TRUE(found);
}

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
TEST(benchmark, serialize)
{
    stopwatch timer;
    string model = "mxnet/LSTM_backward.json";

    const string json_path = file_util::path_join(SERIALIZED_ZOO, model);
    timer.start();
    const string json_string = file_util::read_file_to_string(json_path);
    timer.stop();
    cout << "file read took " << timer.get_milliseconds() << "ms\n";
    timer.start();
    shared_ptr<Function> f = ngraph::deserialize(json_string);
    timer.stop();
    cout << "deserialize took " << timer.get_milliseconds() << "ms\n";
}