network_impl.cpp 30.2 KB
Newer Older
1 2
/**
 * \file src/mge/network_impl.cpp
3
 * MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
4
 *
5
 * Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
6
 *
7 8 9
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 11 12 13 14 15 16 17
 */

#include "lite_build_config.h"

#if LITE_BUILD_WITH_MGE
#include "common.h"
#include "lite/network.h"
#include "memory_allocator.h"
M
Megvii Engine Team 已提交
18
#include "network_impl.h"
19
#include "parse_info/parse_info_base.h"
M
Megvii Engine Team 已提交
20
#include "parse_model/model_parser.h"
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

#include "megbrain/common.h"
#include "megbrain/comp_node.h"
#include "megbrain/comp_node_env.h"
#include "megbrain/gopt/inference.h"
#include "megbrain/graph.h"
#include "megbrain/graph/cg.h"
#include "megbrain/opr/io.h"
#include "megbrain/tensor.h"

#if MGB_OPENCL
#include "megcore_opencl.h"
#endif

#include <fstream>
#include <memory>
#include <set>

using namespace lite;
using namespace mgb;

LITE_DYN_TYPE_OBJ_FINAL_IMPL(NetworkImplDft);

void NetworkImplDft::set_config(const Config& config) {
    m_user_config = std::make_unique<Config>();
    *m_user_config = config;
    m_compnode_locator = to_compnode_locator(m_user_config->device_type);
    m_compnode_locator.device = config.device_id;
}

void NetworkImplDft::shared_weight_with(const NetworkImplBase* src_network) {
    application_config();
    const auto& src_impl = src_network->cast_final_safe<NetworkImplDft>();
M
Megvii Engine Team 已提交
54
    LITE_ASSERT(src_impl.m_loader, "Clone network must after the network is loaded.");
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
    m_load_result = src_impl.m_loader->load(m_load_config, true);

    //! flag weather the mode is cross compnode model
    cross_compnode_model_detect();

    //! update the IO of the network
    update_io();

    //! replace the IO when there is device input or output
    compile_graph();
}

void NetworkImplDft::application_config() {
    auto device_type = m_user_config->device_type;
    m_compnode_locator.type = to_compnode_locator(device_type).type;
    m_compnode_locator.device = m_user_config->device_id;
    if (m_nr_threads > 1 && device_type == LiteDeviceType::LITE_CPU) {
        m_compnode_locator.type = mgb::CompNode::DeviceType::MULTITHREAD;
        m_compnode_locator.device = m_user_config->device_id;
    }
    //! model options
#define ConfigOption(mge_name, lite_name) \
    options.mge_name = m_user_config->options.lite_name;

    auto&& options = m_load_config.comp_graph->options();
    ConfigOption(graph_opt.weight_preprocess, weight_preprocess);
    ConfigOption(graph_opt.fuse_preprocess, fuse_preprocess);
    ConfigOption(fake_next_exec, fake_next_exec);
    ConfigOption(var_sanity_check_first_run, var_sanity_check_first_run);
    m_load_config.const_var_shape = m_user_config->options.const_shape;
    ConfigOption(force_dynamic_alloc, force_dynamic_alloc);
    ConfigOption(force_output_dynamic_alloc, force_output_dynamic_alloc);
    ConfigOption(no_profiling_on_shape_change, no_profiling_on_shape_change);
M
Megvii Engine Team 已提交
88 89 90 91 92
    LITE_ASSERT(
            m_user_config->options.jit_level == 0 ||
                    (m_user_config->options.jit_level > 0 &&
                     device_type == LiteDeviceType::LITE_CUDA),
            "jit only support in cuda device.");
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
    ConfigOption(graph_opt.jit, jit_level);
    ConfigOption(comp_node_seq_record_level, comp_node_seq_record_level);
    ConfigOption(graph_opt_level, graph_opt_level);
    ConfigOption(async_exec_level, async_exec_level);

#undef ConfigOption
#define ConfigOptionLayoutTransform(name) \
    if (m_user_config->options.name) {    \
        options.graph_opt.name();         \
    }
    ConfigOptionLayoutTransform(enable_nchw44);
    ConfigOptionLayoutTransform(enable_nchw44_dot);
    ConfigOptionLayoutTransform(enable_nchw88);
    ConfigOptionLayoutTransform(enable_nhwcd4);
    ConfigOptionLayoutTransform(enable_nchw4);
    ConfigOptionLayoutTransform(enable_nchw32);
    ConfigOptionLayoutTransform(enable_nchw64);
#undef ConfigOptionLayoutTransform
    if (m_user_config->has_compression) {
        m_load_config.tensor_value_loader = decompressed_tensor_value_loader;
    }

    //! if device is LITE_NONE, the compnode information is stored in model
    if (device_type != LiteDeviceType::LITE_DEVICE_DEFAULT) {
        //! currently not set Locator type because an atlas mgb model is a
        //! cross-compnode graph
        if (device_type == LiteDeviceType::LITE_ATLAS) {
M
Megvii Engine Team 已提交
120 121 122 123 124 125 126 127
            m_load_config.comp_node_mapper = [this](mgb::CompNode::Locator& loc) {
                if (loc.type == mgb::CompNode::DeviceType::ATLAS) {
                    loc.device = m_compnode_locator.device;
                    loc.stream = m_compnode_locator.stream;
                } else if (loc.type == mgb::CompNode::DeviceType::MULTITHREAD) {
                    loc.stream = m_nr_threads;
                }
            };
128
        } else {
M
Megvii Engine Team 已提交
129 130 131
            m_load_config.comp_node_mapper = [this](mgb::CompNode::Locator& loc) {
                loc = m_compnode_locator;
            };
132 133 134 135
        }
    }
}

M
Megvii Engine Team 已提交
136
void NetworkImplDft::set_memory_allocator(std::shared_ptr<Allocator> user_allocator) {
137 138 139 140 141 142
    auto allocator = std::make_shared<UserStaticMemAlloc>(user_allocator);
    LITE_ASSERT(m_load_config.comp_graph);
    m_load_config.comp_graph->set_device_memory_allocator(allocator);
}

//! share the runtime memory with other network, the weights is not shared
M
Megvii Engine Team 已提交
143
void NetworkImplDft::share_runtime_memory_with(Network::NetworkImplBase* network_impl) {
144 145
    LITE_ASSERT(network_impl);
    LITE_ASSERT(m_load_config.comp_graph);
M
Megvii Engine Team 已提交
146 147
    m_load_config.comp_graph->share_device_memory_with(*(
            network_impl->cast_final_safe<NetworkImplDft>().m_load_config.comp_graph));
148 149 150
}

void NetworkImplDft::set_cpu_inplace_mode() {
M
Megvii Engine Team 已提交
151 152 153
    LITE_ASSERT(
            m_user_config->device_type == LiteDeviceType::LITE_CPU,
            "cpu inplace mode is only avaliable in CPU.");
154 155 156 157 158 159 160
    m_is_cpu_inplace_mode = true;
    if (m_compnode_locator.type == mgb::CompNode::DeviceType::CPU) {
        m_compnode_locator.device = mgb::CompNode::Locator::DEVICE_CPU_DEFAULT;
    } else {
        LITE_ASSERT(
                m_compnode_locator.type == CompNode::DeviceType::MULTITHREAD,
                "cpu inplace mode is only avaliable in CPU.");
M
Megvii Engine Team 已提交
161
        m_compnode_locator.device = mgb::CompNode::Locator::DEVICE_MULTITHREAD_DEFAULT;
162 163 164 165
    }
}

void NetworkImplDft::set_cpu_threads_number(size_t nr_threads) {
M
Megvii Engine Team 已提交
166 167 168
    LITE_ASSERT(
            m_user_config->device_type == LiteDeviceType::LITE_CPU,
            "multi threads mode is only avaliable in CPU.");
169 170 171 172 173 174 175 176 177
    if (nr_threads > 1) {
        m_nr_threads = nr_threads;
        m_compnode_locator.type = mgb::CompNode::DeviceType::MULTITHREAD;
        m_compnode_locator.nr_threads = nr_threads;
    }
}

void NetworkImplDft::set_runtime_thread_affinity(
        const ThreadAffinityCallback& thread_affinity_callback) {
M
Megvii Engine Team 已提交
178 179 180
    LITE_ASSERT(
            m_user_config->device_type == LiteDeviceType::LITE_CPU,
            "multi threads mode is only avaliable in CPU.");
181 182 183 184 185 186 187 188
    mgb::CompNode::Locator loc;
    m_load_config.comp_node_mapper(loc);
    auto cn = mgb::CompNode::load(loc);
    if (m_nr_threads > 1) {
        mgb::CompNodeEnv::from_comp_node(cn).cpu_env().set_affinity(
                thread_affinity_callback);
    } else {
        mgb::CompNodeEnv::from_comp_node(cn).cpu_env().dispatch(
M
Megvii Engine Team 已提交
189
                [thread_affinity_callback](void) { thread_affinity_callback(0); });
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
    }
}

void NetworkImplDft::set_device_id(int device_id) {
    m_compnode_locator.device = device_id;
    m_user_config->device_id = device_id;
}

void NetworkImplDft::set_stream_id(int stream_id) {
    m_compnode_locator.stream = stream_id;
}

void NetworkImplDft::use_tensorrt() {
    auto&& options = m_load_config.comp_graph->options();
    options.graph_opt.tensorrt = true;
}

//! set the callback in async model
void NetworkImplDft::set_async_callback(const AsyncCallback& callback) {
M
Megvii Engine Team 已提交
209
    LITE_ASSERT(!m_is_cpu_inplace_mode, "cpu inplace mode not support async mode");
210 211 212
    LITE_ASSERT(
            m_user_config->options.comp_node_seq_record_level == 0,
            "record mode not support async mode");
M
Megvii Engine Team 已提交
213 214 215 216
    LITE_ASSERT(
            m_user_config->device_type == LiteDeviceType::LITE_CPU ||
                    m_user_config->device_type == LiteDeviceType::LITE_CUDA,
            "Now only cpu and cuda>10.0 support async mode");
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
    m_async = true;
    m_async_callback = std::move(callback);
}

void NetworkImplDft::make_output_spec() {
    m_output_spec.clear();
    for (auto&& out : m_network_io->outputs) {
        if (m_load_result.output_var_map.count(out.name)) {
            auto&& load_out = m_load_result.output_var_map[out.name];
            auto cb = [&out, this](const mgb::DeviceTensorND& dv) mutable {
                mgb::CompNode comp_node = dv.comp_node();
                if (out.io_type == LiteIOType::LITE_IO_SHAPE) {
                    auto mgb_layout = dv.layout();
                    out.lite_tensor->set_layout(to_lite_layout(mgb_layout));
                } else {
                    TensorHelper::implement(out.lite_tensor)
                            ->cast_final_safe<TensorImplDft>()
                            .copy_from_mge_tensor(dv);
                    out.lite_tensor->update_from_implement();
                }
                if (m_async) {
                    out.have_sync = true;
                    bool need_exec_cb = true;
                    for (auto&& j : m_network_io->outputs) {
                        if (!j.have_sync) {
                            need_exec_cb = false;
                        }
                    }
                    if (need_exec_cb) {
                        for (auto&& j : m_network_io->outputs) {
                            j.have_sync = false;
                        }
                        comp_node.add_callback([this]() { finish(); });
                    }
                }
            };
            m_output_spec.emplace_back(load_out, std::move(cb));
        } else {
M
Megvii Engine Team 已提交
255
            LITE_THROW(ssprintf("no output named : %s in the mode", out.name.c_str()));
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
        }
    }
}

void NetworkImplDft::replace_dev_input_pass() {
    mgb::CompNode::Locator locator;
    m_load_config.comp_node_mapper(locator);
    //! CPU is not need use device input
    if (locator.type == mgb::CompNode::DeviceType::CPU) {
        return;
    }
    //! repalce the H2D with VolatileSharedDeviceTensor, and keep the dev tensor
    //! in m_network_io.input, user can directly change the dev tensor
    //! storage through m_network_io.input.lite_tensor->reset() befor forward
    using DeviceTensorMap =
M
Megvii Engine Team 已提交
271
            std::unordered_map<std::string, std::shared_ptr<mgb::DeviceTensorND>>;
272 273 274 275 276 277 278 279
    DeviceTensorMap name2dev_tensor;

    mgb::ThinHashMap<mgb::HostTensorND*, mgb::SymbolVar> host_val2var;

    //! construct host_val2var that maps from host tensor to corresponding var
    auto on_opr = [&](mgb::cg::OperatorNodeBase* opr) {
        if (opr->same_type<mgb::opr::Host2DeviceCopy>()) {
            mgb::HostTensorND* tensor =
M
Megvii Engine Team 已提交
280
                    opr->cast_final<mgb::opr::Host2DeviceCopy>().host_data().get();
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
            host_val2var[tensor] = opr->output(0);
        }
    };
    mgb::cg::DepOprIter dep_iter{on_opr};
    for (auto i : m_load_result.output_var_list) {
        dep_iter.add(i.node()->owner_opr());
    }

    mgb::ThinHashMap<mgb::SymbolVar, mgb::SymbolVar> inp_var_map, out_var_map;

    mgb::SmallVector<std::string> to_clear;
    for (auto&& config_in : m_network_io->inputs) {
        if (!config_in.is_host) {
            auto host_val = m_load_result.tensor_map[config_in.name];
            auto dev_val = TensorHelper::implement(config_in.lite_tensor)
                                   ->cast_final_safe<TensorImplDft>()
                                   .m_dev_tensor;
            auto dev_var = mgb::opr::VolatileSharedDeviceTensor::make(
                    *m_load_result.graph, dev_val, {config_in.name});
            inp_var_map[host_val2var.at(host_val.get())] = dev_var;
            name2dev_tensor[config_in.name] = dev_val;
        }
    }
M
Megvii Engine Team 已提交
304
    auto new_ovar = mgb::cg::replace_vars(m_load_result.output_var_list, inp_var_map);
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
    for (size_t i = 0; i < new_ovar.size(); ++i) {
        out_var_map[m_load_result.output_var_list[i]] = new_ovar[i];
    }
    for (auto&& i : m_load_result.output_var_map) {
        i.second = out_var_map.at(i.second);
    }
    for (auto&& i : m_load_result.output_var_map_id) {
        i.second = out_var_map.at(i.second);
    }
    for (size_t i = 0; i < m_load_result.output_var_list.size(); i++) {
        new_ovar[i].rename(m_load_result.output_var_list[i].node()->name());
    }
    m_load_result.output_var_list = std::move(new_ovar);
}

void NetworkImplDft::cross_compnode_model_detect() {
    mgb::ThinHashSet<LiteDeviceType> nr_used_device_type;
    auto on_opr = [&](mgb::cg::OperatorNodeBase* opr) {
        for (auto j : opr->output()) {
            if (j->comp_node() != mgb::CompNode::default_cpu()) {
                nr_used_device_type.insert(
                        get_device_from_locator(j->comp_node().locator()));
            }
        }
    };
    mgb::cg::DepOprIter dep_iter{on_opr};
    for (auto i : m_load_result.output_var_list) {
        dep_iter.add(i.node()->owner_opr());
    }
M
Megvii Engine Team 已提交
334
    m_nr_device_type = nr_used_device_type.size();
335 336 337 338 339 340
}

void NetworkImplDft::load_model(
        std::shared_ptr<void> model_mem, size_t size,
        std::unordered_map<std::string, LiteAny> separate_config_map) {
    if (!m_loader) {
M
Megvii Engine Team 已提交
341 342 343 344
        m_input_file =
                mgb::serialization::InputFile::make_mem_proxy(model_mem, size, false);
        auto format = mgb::serialization::GraphLoader::identify_graph_dump_format(
                *m_input_file);
345 346 347 348 349 350 351 352 353 354 355 356
        if (!format.valid()) {
            LITE_THROW("invalid model format");
        }
        m_loader = mgb::serialization::GraphLoader::make(
                std::move(m_input_file), format.val());
    }

    //! applay the user configration to mge model
    application_config();

    //! config some flag get from json config file
    if (separate_config_map.find("device_id") != separate_config_map.end()) {
357
        set_device_id(separate_config_map["device_id"].safe_cast<int>());
358
    }
M
Megvii Engine Team 已提交
359
    if (separate_config_map.find("number_threads") != separate_config_map.end() &&
360
        separate_config_map["number_threads"].safe_cast<uint32_t>() > 1) {
361
        set_cpu_threads_number(
362
                separate_config_map["number_threads"].safe_cast<uint32_t>());
363
    }
M
Megvii Engine Team 已提交
364
    if (separate_config_map.find("enable_inplace_model") != separate_config_map.end() &&
365
        separate_config_map["enable_inplace_model"].safe_cast<bool>()) {
366 367 368
        set_cpu_inplace_mode();
    }
    if (separate_config_map.find("use_tensorrt") != separate_config_map.end() &&
369
        separate_config_map["use_tensorrt"].safe_cast<bool>()) {
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
        use_tensorrt();
    }

    m_load_result = m_loader->load(m_load_config, true);

    cross_compnode_model_detect();

    //! update the IO of the network
    update_io();

    //! replace the IO when there is device input or output
    compile_graph();
}

void NetworkImplDft::compile_graph() {
    modify_exection_policy();
    replace_dev_input_pass();
    make_output_spec();
    m_execute_func = m_load_result.graph_compile(m_output_spec);
}

void NetworkImplDft::start() const {
    if (m_start_callback) {
        std::unordered_map<std::string, std::pair<IO, std::shared_ptr<Tensor>>>
                input_io_map;
        for (auto&& io_inner : m_network_io->inputs) {
            input_io_map[io_inner.name] = {
                    IO{io_inner.name, io_inner.is_host, io_inner.io_type,
                       io_inner.config_layout},
                    io_inner.lite_tensor};
        }
        m_start_callback(input_io_map);
    }
}

void NetworkImplDft::forward() {
    start();
    LITE_ASSERT(m_execute_func, "forward must be called after network loaded.");
    m_execute_func->execute();
}

void NetworkImplDft::wait() {
    if (!m_async) {
        m_execute_func->wait();
    }
    finish();
}

void NetworkImplDft::finish() const {
    if (m_async) {
M
Megvii Engine Team 已提交
420
        LITE_ASSERT(m_async_callback, "The callback func must set when async mode.");
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
        m_async_callback();
    }
    if (m_finish_callback) {
        std::unordered_map<std::string, std::pair<IO, std::shared_ptr<Tensor>>>
                output_io_map;
        for (auto&& io_inner : m_network_io->outputs) {
            output_io_map[io_inner.name] = {
                    IO{io_inner.name, io_inner.is_host, io_inner.io_type,
                       io_inner.config_layout},
                    io_inner.lite_tensor};
        }
        m_finish_callback(output_io_map);
    }
    output_plugin_result();
}

void NetworkImplDft::set_io(const NetworkIO& network_io) {
    m_network_io = std::make_unique<NetworkIOInner>();
    for (auto&& in : network_io.inputs) {
        m_network_io->inputs.emplace_back(in);
    }
    for (auto&& out : network_io.outputs) {
        m_network_io->outputs.emplace_back(out);
    }
}

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
void NetworkImplDft::try_infer_tensor_layout(
        std::shared_ptr<Tensor> tensor, mgb::cg::SymbolVar var) {
    auto&& static_infer_mgr = m_load_config.comp_graph->static_infer_manager();
    auto infer_trait = var.node()->get_static_infer_trait();
    if (std::get<0>(infer_trait)) {
        auto shape = static_infer_mgr.infer_shape_fallible(var.node());
        if (!shape) {
            LITE_WARN(
                    "Lite infer output shape failed, maybe the model is "
                    "dynamic "
                    "shape.\n");
            return;
        }
        Layout layout = to_lite_layout(mgb::TensorLayout{*shape, var.dtype()});
        tensor->set_layout(layout);
    }
}

465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
void NetworkImplDft::update_io() {
    update_input();
    update_output();
}

void NetworkImplDft::update_input() {
    auto device_type = m_user_config->device_type;
    auto device_id = m_compnode_locator.device;
    auto stream_id = m_compnode_locator.stream;
    //! if cpu all input and output are host
    if (device_type == LiteDeviceType::LITE_CPU) {
        for (auto&& in : m_network_io->inputs) {
            in.is_host = true;
        }
    }
    //! if cross compnode model, modify the device input if it is not valid
    if (m_nr_device_type > 1) {
        for (auto&& in_tensor_iter : m_load_result.tensor_map) {
            for (auto&& config_in : m_network_io->inputs) {
                //! if tensor is set to device input
M
Megvii Engine Team 已提交
485
                if (in_tensor_iter.first == config_in.name && !config_in.is_host) {
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
                    //! if the origin compnode of the tensor is not the device,
                    //! set the input to host
                    if (get_device_from_locator(
                                in_tensor_iter.second->comp_node().locator()) ==
                        LiteDeviceType::LITE_CPU) {
                        config_in.is_host = true;
                        LITE_WARN(
                                "The input tensor %s of the cross device model "
                                "should not from device.",
                                config_in.name.c_str());
                    }
                }
            }
        }
    }
    for (auto&& in_tensor_iter : m_load_result.tensor_map) {
        bool found = false;
        for (auto&& config_in : m_network_io->inputs) {
            if (in_tensor_iter.first == config_in.name) {
                found = true;
                if (config_in.is_host) {
                    config_in.lite_tensor = std::make_shared<Tensor>(
                            device_id, stream_id, device_type, true);
                    TensorHelper::implement(config_in.lite_tensor)
                            ->cast_final_safe<TensorImplDft>()
                            .m_host_tensor = in_tensor_iter.second;
                    config_in.lite_tensor->update_from_implement();
                } else {
M
Megvii Engine Team 已提交
514 515
                    config_in.lite_tensor =
                            std::make_shared<Tensor>(device_id, stream_id, device_type);
516 517 518 519
                    config_in.lite_tensor->set_layout(
                            to_lite_layout(in_tensor_iter.second->layout()));
                }
                if (config_in.config_layout.ndim &&
M
Megvii Engine Team 已提交
520
                    !(config_in.config_layout == config_in.lite_tensor->get_layout())) {
521 522 523 524 525 526 527
                    config_in.lite_tensor->set_layout(config_in.config_layout);
                }
            }
        }
        if (!found) {
            IOInner io_in;
            io_in.name = in_tensor_iter.first;
M
Megvii Engine Team 已提交
528 529
            io_in.lite_tensor =
                    std::make_shared<Tensor>(device_id, stream_id, device_type, true);
530 531 532 533 534 535 536 537
            TensorHelper::implement(io_in.lite_tensor)
                    ->cast_final_safe<TensorImplDft>()
                    .m_host_tensor = in_tensor_iter.second;
            io_in.lite_tensor->update_from_implement();
            m_network_io->inputs.push_back(io_in);
        }
    }
    //! delete the IO that is not the network
M
Megvii Engine Team 已提交
538
    for (auto it = m_network_io->inputs.begin(); it != m_network_io->inputs.end();) {
539
        if (it->lite_tensor == nullptr) {
M
Megvii Engine Team 已提交
540
            LITE_LOG("%s is not the network input, ignore it.", it->name.c_str());
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
            it = m_network_io->inputs.erase(it);
        } else {
            it++;
        }
    }
}

void NetworkImplDft::update_output() {
    auto device_type = m_user_config->device_type;
    auto device_id = m_compnode_locator.device;
    auto stream_id = m_compnode_locator.stream;
    if (device_type == LiteDeviceType::LITE_CPU) {
        for (auto&& out : m_network_io->outputs) {
            out.is_host = true;
        }
    }
    //! delete the output that is not the network
    for (auto out_it = m_network_io->outputs.begin();
         out_it != m_network_io->outputs.end();) {
M
Megvii Engine Team 已提交
560 561 562 563 564 565 566
        if (std::find_if(
                    m_load_result.output_var_list.begin(),
                    m_load_result.output_var_list.end(),
                    [out_it](const mgb::SymbolVar var) {
                        return var.node()->name() == out_it->name;
                    }) == m_load_result.output_var_list.end()) {
            LITE_LOG("%s is not the network output, ignore it.", out_it->name.c_str());
567 568 569 570 571 572 573
            out_it = m_network_io->outputs.erase(out_it);
        } else {
            out_it++;
        }
    }
    //! user config the output tensor, so only compute the config output
    if (m_compute_configured_output_only) {
M
Megvii Engine Team 已提交
574 575 576
        LITE_ASSERT(
                m_network_io->outputs.size() > 0,
                "compute configured output only with no configure output.");
577 578 579 580 581 582 583
        for (auto out_it = m_network_io->outputs.begin();
             out_it != m_network_io->outputs.end(); out_it++) {
            //! use pinned memory to copy form device
            if (out_it->is_host) {
                out_it->lite_tensor = std::make_shared<Tensor>(
                        device_id, stream_id, device_type, true);
            } else {
M
Megvii Engine Team 已提交
584 585
                out_it->lite_tensor =
                        std::make_shared<Tensor>(device_id, stream_id, device_type);
586
            }
587 588 589 590 591 592 593 594
            mgb::SymbolVar var;
            for (auto&& out_var : m_load_result.output_var_list) {
                if (out_var.node()->name() == out_it->name) {
                    var = out_var;
                    break;
                }
            }
            try_infer_tensor_layout(out_it->lite_tensor, var);
595 596 597 598
        }
        //! user not set, use default output
    } else {
        for (auto&& out : m_load_result.output_var_list) {
M
Megvii Engine Team 已提交
599 600 601
            auto it = std::find_if(
                    m_network_io->outputs.begin(), m_network_io->outputs.end(),
                    [&out](const IOInner io) { return io.name == out.node()->name(); });
602 603 604 605 606
            if (it != m_network_io->outputs.end()) {
                if (it->is_host) {
                    it->lite_tensor = std::make_shared<Tensor>(
                            device_id, stream_id, device_type, true);
                } else {
M
Megvii Engine Team 已提交
607 608
                    it->lite_tensor =
                            std::make_shared<Tensor>(device_id, stream_id, device_type);
609
                }
610
                try_infer_tensor_layout(it->lite_tensor, out);
611 612 613 614 615 616
            } else {
                IOInner output;
                output.name = out.node()->name();
                output.lite_tensor = std::make_shared<Tensor>(
                        device_id, stream_id, device_type, true);
                m_network_io->outputs.push_back({output});
617
                try_infer_tensor_layout(output.lite_tensor, out);
618 619 620 621 622
            }
        }
    }
}

M
Megvii Engine Team 已提交
623 624 625
std::shared_ptr<Tensor> NetworkImplDft::get_io_tensor(
        std::string io_name, LiteTensorPhase phase) {
    if (phase == LiteTensorPhase::LITE_INPUT || phase == LiteTensorPhase::LITE_IO) {
626 627 628 629 630 631
        for (auto&& config_in : m_network_io->inputs) {
            if (io_name == config_in.name) {
                return config_in.lite_tensor;
            }
        }
    }
M
Megvii Engine Team 已提交
632
    if (phase == LiteTensorPhase::LITE_OUTPUT || phase == LiteTensorPhase::LITE_IO) {
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
        for (auto&& config_out : m_network_io->outputs) {
            if (io_name == config_out.name) {
                config_out.lite_tensor->update_from_implement();
                return config_out.lite_tensor;
            }
        }
    }
    LITE_THROW(mgb::ssprintf(
            "tensor name must be %s input tensor name or the registered "
            "output tensor name if NetworkIO is set, if NetworkIO is not set, "
            "the output tensor is all the network output tensor, or the output "
            "tensor is only the registered tensor.",
            io_name.c_str()));
    return nullptr;
}

std::shared_ptr<Tensor> NetworkImplDft::get_input_tensor(size_t index) {
    return get_io_tensor(get_input_name(index));
}

std::shared_ptr<Tensor> NetworkImplDft::get_output_tensor(size_t index) {
    return get_io_tensor(get_output_name(index));
}

//! set opr algorithm selection strategy in the network
M
Megvii Engine Team 已提交
658 659 660
void NetworkImplDft::set_network_algo_policy(
        LiteAlgoSelectStrategy strategy, uint32_t shared_batch_size,
        bool binary_equal_between_batch) {
661 662
    using S = megdnn::param::ExecutionPolicy::Strategy;
    auto dst_strategy = static_cast<S>(0);
M
Megvii Engine Team 已提交
663
    if (static_cast<uint32_t>(strategy) & LiteAlgoSelectStrategy::LITE_ALGO_HEURISTIC) {
664 665
        dst_strategy = dst_strategy | S::HEURISTIC;
    }
M
Megvii Engine Team 已提交
666
    if (static_cast<uint32_t>(strategy) & LiteAlgoSelectStrategy::LITE_ALGO_PROFILE) {
667 668 669 670 671 672
        dst_strategy = dst_strategy | S::PROFILE;
    }
    if (static_cast<uint32_t>(strategy) &
        LiteAlgoSelectStrategy::LITE_ALGO_REPRODUCIBLE) {
        dst_strategy = dst_strategy | S::REPRODUCIBLE;
    }
M
Megvii Engine Team 已提交
673
    if (static_cast<uint32_t>(strategy) & LiteAlgoSelectStrategy::LITE_ALGO_OPTIMIZED) {
674 675 676 677
        dst_strategy = dst_strategy | S::OPTIMIZED;
    }
    m_execution_policy = dst_strategy;

M
Megvii Engine Team 已提交
678
    auto&& fast_run_config = m_load_config.comp_graph->options().fast_run_config;
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
    fast_run_config.binary_equal_between_batch = binary_equal_between_batch;
    fast_run_config.shared_batch_size = shared_batch_size;

    if (m_execute_func) {
        LITE_WARN(
                "set_network_algo_policy maybe cause error after loaded "
                "network!!!!");
        modify_exection_policy();
    }
}

void NetworkImplDft::modify_exection_policy() {
    mgb::SymbolVarArray vars;
    for (auto i : m_output_spec) {
        vars.push_back(i.first);
    }
    if (static_cast<uint32_t>(m_execution_policy) != 0)
        mgb::gopt::modify_opr_algo_strategy_inplace(vars, m_execution_policy);
}

//! set opr algorithm selection strategy in the network
void NetworkImplDft::set_network_algo_workspace_limit(size_t workspace_limit) {
    mgb::SymbolVarArray vars;
    for (auto i : m_output_spec) {
        vars.push_back(i.first);
    }
    mgb::gopt::set_opr_algo_workspace_limit_inplace(vars, workspace_limit);
}

//! get the input tensor name in the order of graph
std::vector<const char*> NetworkImplDft::get_all_output_name() const {
    std::vector<const char*> output_names;
    for (auto& output : m_network_io->outputs) {
        output_names.push_back(output.name.c_str());
    }
    return output_names;
}

//! get the input tensor name in the order of graph
std::vector<const char*> NetworkImplDft::get_all_input_name() const {
    std::vector<const char*> input_names;
    for (auto& input : m_load_result.tensor_map) {
        input_names.push_back(input.first.c_str());
    }
    return input_names;
}

//! get the output tensor name in the order of graph
const char* NetworkImplDft::get_output_name(size_t index) const {
    LITE_ASSERT(
            index < m_load_result.output_var_list.size(),
            "The output tensor index is large than the total outputs number.");
    return m_load_result.output_var_list[index].node()->name().c_str();
}

//! get the input tensor name in the order of graph
const char* NetworkImplDft::get_input_name(size_t index) const {
    LITE_ASSERT(
            index < m_load_result.tensor_map.size(),
            "The input tensor index is large than the total inputs number.");
    size_t i = 0;
    for (auto& input : m_load_result.tensor_map) {
        if (i == index) {
            return input.first.c_str();
        }
        i++;
    }
    LITE_THROW(ssprintf("no input tensor of index %zu.", index));
}

//! Plugin part
void NetworkImplDft::enable_profile_performance(std::string profile_json_file) {
#if MGB_ENABLE_JSON
#if MGB_OPENCL
    mgb::CompNode::enable_opencl_profile(true);
#endif
M
Megvii Engine Team 已提交
755
    m_profiler = std::make_unique<mgb::GraphProfiler>(m_load_config.comp_graph.get());
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
    m_profiler_output_file = profile_json_file;
#else
    LITE_MARK_USED_VAR(profile_json_file);
    LITE_THROW("JSON is disable at compile time.");
#endif
}

void NetworkImplDft::enable_io_txt_dump(std::string io_txt_out_file) {
    auto iodump = std::make_unique<mgb::TextOprIODump>(
            m_load_config.comp_graph.get(), io_txt_out_file.c_str());
    iodump->print_addr(false);
    m_iodump = std::move(iodump);
}

void NetworkImplDft::enable_io_bin_dump(std::string io_bin_out_dir) {
    m_iodump = std::make_unique<mgb::BinaryOprIODump>(
            m_load_config.comp_graph.get(), io_bin_out_dir.c_str());
}

void inline NetworkImplDft::output_plugin_result() const {
#if MGB_ENABLE_JSON
    if (m_profiler && m_execute_func) {
        m_profiler->to_json_full(m_execute_func.get())
                ->writeto_fpath(m_profiler_output_file);
    }
#endif
}
783 784 785 786 787 788 789

void NetworkImplDft::get_static_memory_alloc_info(const std::string& log_dir) const {
#ifndef __IN_TEE_ENV__
#if MGB_ENABLE_JSON
    m_execute_func->get_static_memory_alloc_info(log_dir);
    return;
#endif
790
#endif
791 792
    LITE_MARK_USED_VAR(log_dir);
}
793

794
#endif
795
// vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}