network_impl.cpp 33.8 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
    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);
87 88 89
    ConfigOption(
            force_output_use_user_specified_memory,
            force_output_use_user_specified_memory);
90
    ConfigOption(no_profiling_on_shape_change, no_profiling_on_shape_change);
M
Megvii Engine Team 已提交
91 92 93 94 95
    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.");
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
    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 已提交
123 124 125 126 127 128 129 130
            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;
                }
            };
131
        } else {
M
Megvii Engine Team 已提交
132 133 134
            m_load_config.comp_node_mapper = [this](mgb::CompNode::Locator& loc) {
                loc = m_compnode_locator;
            };
135 136 137 138
        }
    }
}

M
Megvii Engine Team 已提交
139
void NetworkImplDft::set_memory_allocator(std::shared_ptr<Allocator> user_allocator) {
140 141 142 143 144 145
    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 已提交
146
void NetworkImplDft::share_runtime_memory_with(Network::NetworkImplBase* network_impl) {
147 148
    LITE_ASSERT(network_impl);
    LITE_ASSERT(m_load_config.comp_graph);
M
Megvii Engine Team 已提交
149 150
    m_load_config.comp_graph->share_device_memory_with(*(
            network_impl->cast_final_safe<NetworkImplDft>().m_load_config.comp_graph));
151 152 153
}

void NetworkImplDft::set_cpu_inplace_mode() {
M
Megvii Engine Team 已提交
154 155 156
    LITE_ASSERT(
            m_user_config->device_type == LiteDeviceType::LITE_CPU,
            "cpu inplace mode is only avaliable in CPU.");
157 158 159 160 161 162 163
    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 已提交
164
        m_compnode_locator.device = mgb::CompNode::Locator::DEVICE_MULTITHREAD_DEFAULT;
165 166 167 168
    }
}

void NetworkImplDft::set_cpu_threads_number(size_t nr_threads) {
M
Megvii Engine Team 已提交
169 170 171
    LITE_ASSERT(
            m_user_config->device_type == LiteDeviceType::LITE_CPU,
            "multi threads mode is only avaliable in CPU.");
172 173 174 175 176 177 178 179 180
    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 已提交
181 182 183
    LITE_ASSERT(
            m_user_config->device_type == LiteDeviceType::LITE_CPU,
            "multi threads mode is only avaliable in CPU.");
184 185 186 187 188 189 190 191
    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 已提交
192
                [thread_affinity_callback](void) { thread_affinity_callback(0); });
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    }
}

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 已提交
212 213 214 215 216
    LITE_ASSERT(!m_is_cpu_inplace_mode, "cpu inplace mode not support async mode");
    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
    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(); });
                    }
                }
            };
253 254 255 256 257 258 259
            //! if write to user-specified memory, the CallbackCaller must be nullptr.
            if (m_user_config->options.force_output_use_user_specified_memory ||
                m_user_config->options.force_output_dynamic_alloc) {
                m_output_spec.emplace_back(load_out, nullptr);
            } else {
                m_output_spec.emplace_back(load_out, std::move(cb));
            }
260
        } else {
M
Megvii Engine Team 已提交
261
            LITE_THROW(ssprintf("no output named : %s in the mode", out.name.c_str()));
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
        }
    }
}

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 已提交
277
            std::unordered_map<std::string, std::shared_ptr<mgb::DeviceTensorND>>;
278 279 280 281 282 283 284 285
    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 已提交
286
                    opr->cast_final<mgb::opr::Host2DeviceCopy>().host_data().get();
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
            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 已提交
310
    auto new_ovar = mgb::cg::replace_vars(m_load_result.output_var_list, inp_var_map);
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
    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 已提交
340
    m_nr_device_type = nr_used_device_type.size();
341 342 343 344 345 346
}

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 已提交
347 348 349 350
        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);
351 352 353 354 355 356 357 358 359 360 361 362
        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()) {
363
        set_device_id(separate_config_map["device_id"].safe_cast<int>());
364
    }
M
Megvii Engine Team 已提交
365
    if (separate_config_map.find("number_threads") != separate_config_map.end() &&
366
        separate_config_map["number_threads"].safe_cast<uint32_t>() > 1) {
367
        set_cpu_threads_number(
368
                separate_config_map["number_threads"].safe_cast<uint32_t>());
369
    }
M
Megvii Engine Team 已提交
370
    if (separate_config_map.find("enable_inplace_model") != separate_config_map.end() &&
371
        separate_config_map["enable_inplace_model"].safe_cast<bool>()) {
372 373 374
        set_cpu_inplace_mode();
    }
    if (separate_config_map.find("use_tensorrt") != separate_config_map.end() &&
375
        separate_config_map["use_tensorrt"].safe_cast<bool>()) {
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 420 421 422 423 424 425
        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 已提交
426
        LITE_ASSERT(m_async_callback, "The callback func must set when async mode.");
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
        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);
    }
}

453
void NetworkImplDft::try_infer_tensor_layout(std::shared_ptr<Tensor> tensor, Var var) {
454 455
    if (var.node()->capable_shape_infer()) {
        auto&& static_infer_mgr = m_load_config.comp_graph->static_infer_manager();
456 457 458 459 460 461
        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");
462 463 464 465
            LITE_ASSERT(
                    !m_user_config->options.force_output_use_user_specified_memory,
                    "force_output_use_user_specified_memory can't be used when output "
                    "shape can't be derived.");
466 467
            return;
        }
468
        Layout layout = to_lite_layout(TensorLayout{*shape, var.dtype()});
469 470 471 472
        tensor->set_layout(layout);
    }
}

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
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 已提交
493
                if (in_tensor_iter.first == config_in.name && !config_in.is_host) {
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
                    //! 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 已提交
522 523
                    config_in.lite_tensor =
                            std::make_shared<Tensor>(device_id, stream_id, device_type);
524 525 526
                    config_in.lite_tensor->set_layout(
                            to_lite_layout(in_tensor_iter.second->layout()));
                }
527 528 529 530
                TensorHelper::implement(config_in.lite_tensor)
                        ->cast_final_safe<TensorImplDft>()
                        .m_record_reset =
                        m_user_config->options.comp_node_seq_record_level > 0;
531
                if (config_in.config_layout.ndim &&
M
Megvii Engine Team 已提交
532
                    !(config_in.config_layout == config_in.lite_tensor->get_layout())) {
533 534 535 536 537 538 539
                    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 已提交
540 541
            io_in.lite_tensor =
                    std::make_shared<Tensor>(device_id, stream_id, device_type, true);
542 543 544
            TensorHelper::implement(io_in.lite_tensor)
                    ->cast_final_safe<TensorImplDft>()
                    .m_host_tensor = in_tensor_iter.second;
545 546 547 548
            TensorHelper::implement(io_in.lite_tensor)
                    ->cast_final_safe<TensorImplDft>()
                    .m_record_reset =
                    m_user_config->options.comp_node_seq_record_level > 0;
549 550 551 552 553
            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 已提交
554
    for (auto it = m_network_io->inputs.begin(); it != m_network_io->inputs.end();) {
555
        if (it->lite_tensor == nullptr) {
M
Megvii Engine Team 已提交
556
            LITE_LOG("%s is not the network input, ignore it.", it->name.c_str());
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
            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 已提交
576 577
        if (std::find_if(
                    m_load_result.output_var_list.begin(),
578
                    m_load_result.output_var_list.end(), [out_it](const SymbolVar var) {
M
Megvii Engine Team 已提交
579 580 581
                        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());
582 583 584 585 586 587 588
            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 已提交
589 590 591
        LITE_ASSERT(
                m_network_io->outputs.size() > 0,
                "compute configured output only with no configure output.");
592 593 594 595 596 597 598
        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 已提交
599 600
                out_it->lite_tensor =
                        std::make_shared<Tensor>(device_id, stream_id, device_type);
601
            }
602
            SymbolVar var;
603 604 605 606 607 608 609
            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);
610
            output_tensor_copy_optimize(var, out_it->lite_tensor);
611 612 613 614
            TensorHelper::implement(out_it->lite_tensor)
                    ->cast_final_safe<TensorImplDft>()
                    .m_record_reset =
                    m_user_config->options.comp_node_seq_record_level > 0;
615 616 617 618
        }
        //! user not set, use default output
    } else {
        for (auto&& out : m_load_result.output_var_list) {
619
            std::shared_ptr<Tensor> lite_tensor = nullptr;
M
Megvii Engine Team 已提交
620 621 622
            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(); });
623 624 625 626 627
            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 已提交
628 629
                    it->lite_tensor =
                            std::make_shared<Tensor>(device_id, stream_id, device_type);
630
                }
631
                try_infer_tensor_layout(it->lite_tensor, out);
632
                lite_tensor = it->lite_tensor;
633 634 635 636 637 638
            } 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});
639
                try_infer_tensor_layout(output.lite_tensor, out);
640
                lite_tensor = output.lite_tensor;
641
            }
642
            output_tensor_copy_optimize(out, lite_tensor);
643 644 645 646
            TensorHelper::implement(lite_tensor)
                    ->cast_final_safe<TensorImplDft>()
                    .m_record_reset =
                    m_user_config->options.comp_node_seq_record_level > 0;
647 648 649 650
        }
    }
}

651 652 653 654 655 656 657 658
void NetworkImplDft::output_tensor_copy_optimize(
        Var var, std::shared_ptr<Tensor> tensor) {
    LITE_ASSERT(
            !(m_user_config->options.force_output_use_user_specified_memory &&
              m_user_config->options.force_output_dynamic_alloc),
            "Can't set force_output_use_user_specified_memory and "
            "force_output_dynamic_alloc at the same time.");
    if (m_user_config->options.force_output_use_user_specified_memory) {
659
        bool in_record = m_user_config->options.comp_node_seq_record_level > 0;
660 661
        TensorHelper::implement(tensor)
                ->cast_final_safe<TensorImplDft>()
662
                .set_reset_callback([var, in_record](TensorImplDft* dft_tensor) {
663 664 665 666
                    dft_tensor->device_share_host_memory();
                    auto dv = dft_tensor->dev_tensor().get();
                    dv->comp_node(var.node()->comp_node(), true);
                    var.node()->init_mem_plan(dv);
667 668 669 670 671 672
                    if (in_record) {
                        auto&& device_tensor = var.node()->mutable_dev_tensor();
                        device_tensor.only_reset_raw_storage(dv->storage());
                    } else {
                        var.node()->reset_dev_tensor_from_tensor(*dv);
                    }
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
                });
    }
    if (m_user_config->options.force_output_dynamic_alloc) {
        TensorHelper::implement(tensor)
                ->cast_final_safe<TensorImplDft>()
                .set_get_memory_callback([var](TensorImplDft* dft_tensor) {
                    if (dft_tensor->is_host()) {
                        auto host_tensor = dft_tensor->m_host_tensor;
                        *host_tensor =
                                HostTensorND::make_proxy(var.node()->dev_tensor());
                    } else {
                        auto dev_tensor = dft_tensor->m_dev_tensor;
                        *dev_tensor = var.node()->dev_tensor();
                    }
                });
    }
}

M
Megvii Engine Team 已提交
691 692 693
std::shared_ptr<Tensor> NetworkImplDft::get_io_tensor(
        std::string io_name, LiteTensorPhase phase) {
    if (phase == LiteTensorPhase::LITE_INPUT || phase == LiteTensorPhase::LITE_IO) {
694 695 696 697 698 699
        for (auto&& config_in : m_network_io->inputs) {
            if (io_name == config_in.name) {
                return config_in.lite_tensor;
            }
        }
    }
M
Megvii Engine Team 已提交
700
    if (phase == LiteTensorPhase::LITE_OUTPUT || phase == LiteTensorPhase::LITE_IO) {
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
        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 已提交
726 727 728
void NetworkImplDft::set_network_algo_policy(
        LiteAlgoSelectStrategy strategy, uint32_t shared_batch_size,
        bool binary_equal_between_batch) {
729 730
    using S = megdnn::param::ExecutionPolicy::Strategy;
    auto dst_strategy = static_cast<S>(0);
M
Megvii Engine Team 已提交
731
    if (static_cast<uint32_t>(strategy) & LiteAlgoSelectStrategy::LITE_ALGO_HEURISTIC) {
732 733
        dst_strategy = dst_strategy | S::HEURISTIC;
    }
M
Megvii Engine Team 已提交
734
    if (static_cast<uint32_t>(strategy) & LiteAlgoSelectStrategy::LITE_ALGO_PROFILE) {
735 736 737 738 739 740
        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 已提交
741
    if (static_cast<uint32_t>(strategy) & LiteAlgoSelectStrategy::LITE_ALGO_OPTIMIZED) {
742 743 744 745
        dst_strategy = dst_strategy | S::OPTIMIZED;
    }
    m_execution_policy = dst_strategy;

M
Megvii Engine Team 已提交
746
    auto&& fast_run_config = m_load_config.comp_graph->options().fast_run_config;
747 748 749 750 751 752 753 754 755 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 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
    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 已提交
823
    m_profiler = std::make_unique<mgb::GraphProfiler>(m_load_config.comp_graph.get());
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
    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
}
851 852 853 854 855 856 857

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
858
#endif
859 860
    LITE_MARK_USED_VAR(log_dir);
}
861

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