blob: 1fe01e538d4b3b890607ab857a9cbd3d5a84e149 [file]
/*
* 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 params.cc
* \brief VM parameter dictionary serialization.
*/
#include <tvm/ffi/container/map.h>
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ffi/string.h>
#include <tvm/runtime/tensor.h>
#include <tvm/support/bytes_io.h>
#include <tvm/support/io.h>
#include <cstdio>
#include <cstring>
#include <string>
#include <utility>
#include <vector>
namespace tvm {
namespace runtime {
namespace vm {
namespace {
constexpr uint64_t kTVMTensorListMagic = 0xF7E58D4F05049CB7;
struct SimpleBinaryFileStream : public support::Stream {
public:
using Stream::Read;
using Stream::Write;
SimpleBinaryFileStream(const std::string& path, std::string mode) {
const char* fname = path.c_str();
TVM_FFI_ICHECK(mode == "wb" || mode == "rb") << "Only allowed modes are 'wb' and 'rb'";
read_ = mode == "rb";
fp_ = std::fopen(fname, mode.c_str());
TVM_FFI_ICHECK(fp_ != nullptr) << "Unable to open file " << path;
}
virtual ~SimpleBinaryFileStream(void) { this->Close(); }
virtual size_t Read(void* ptr, size_t size) {
TVM_FFI_ICHECK(read_) << "File opened in write-mode, cannot read.";
TVM_FFI_ICHECK(fp_ != nullptr) << "File is closed";
return std::fread(ptr, 1, size, fp_);
}
virtual size_t Write(const void* ptr, size_t size) {
TVM_FFI_ICHECK(!read_) << "File opened in read-mode, cannot write.";
TVM_FFI_ICHECK(fp_ != nullptr) << "File is closed";
size_t nwrite = std::fwrite(ptr, 1, size, fp_);
int err = std::ferror(fp_);
TVM_FFI_ICHECK_EQ(err, 0) << "SimpleBinaryFileStream.Write incomplete: " << std::strerror(err);
return nwrite;
}
inline void Close(void) {
if (fp_ != nullptr) {
std::fclose(fp_);
fp_ = nullptr;
}
}
private:
std::FILE* fp_ = nullptr;
bool read_;
}; // class SimpleBinaryFileStream
} // namespace
ffi::Map<ffi::String, ffi::Tensor> LoadParams(support::Stream* strm) {
ffi::Map<ffi::String, ffi::Tensor> params;
uint64_t header, reserved;
TVM_FFI_ICHECK(strm->Read(&header)) << "Invalid parameters file format";
TVM_FFI_ICHECK(header == kTVMTensorListMagic) << "Invalid parameters file format";
TVM_FFI_ICHECK(strm->Read(&reserved)) << "Invalid parameters file format";
std::vector<std::string> names;
TVM_FFI_ICHECK(strm->Read(&names)) << "Invalid parameters file format";
uint64_t sz;
strm->Read(&sz);
size_t size = static_cast<size_t>(sz);
TVM_FFI_ICHECK(size == names.size()) << "Invalid parameters file format";
for (size_t i = 0; i < size; ++i) {
// The data_entry is allocated on device, Tensor.load always load the array into CPU.
ffi::Tensor temp = LoadTensor(strm);
params.Set(names[i], temp);
}
return params;
}
ffi::Map<ffi::String, ffi::Tensor> LoadParams(const std::string& param_blob) {
support::BytesInStream strm(param_blob);
return LoadParams(&strm);
}
void SaveParams(support::Stream* strm, const ffi::Map<ffi::String, ffi::Tensor>& params) {
for (const auto& entry : params) {
TVM_FFI_ICHECK(entry.second.defined());
}
std::vector<std::string> names;
std::vector<const DLTensor*> arrays;
for (auto& p : params) {
names.push_back(p.first);
arrays.push_back(p.second.GetDLTensorPtr());
}
uint64_t header = kTVMTensorListMagic, reserved = 0;
strm->Write(header);
strm->Write(reserved);
strm->Write(names);
{
uint64_t sz = static_cast<uint64_t>(arrays.size());
strm->Write(sz);
for (size_t i = 0; i < sz; ++i) {
tvm::runtime::SaveTensor(arrays[i], strm);
}
}
}
std::string SaveParams(const ffi::Map<ffi::String, ffi::Tensor>& params) {
std::string result;
support::BytesOutStream strm(&result);
SaveParams(&strm, params);
return result;
}
TVM_FFI_STATIC_INIT_BLOCK() {
namespace refl = tvm::ffi::reflection;
refl::GlobalDef()
.def("vm.SaveParams",
[](const ffi::Map<ffi::String, ffi::Tensor>& params) {
std::string s = ::tvm::runtime::vm::SaveParams(params);
return ffi::Bytes(std::move(s));
})
.def("vm.SaveParamsToFile",
[](const ffi::Map<ffi::String, ffi::Tensor>& params, const ffi::String& path) {
for (const auto& entry : params) {
TVM_FFI_ICHECK(entry.second.defined());
}
SimpleBinaryFileStream strm(path, "wb");
SaveParams(&strm, params);
})
.def("vm.LoadParams", [](const ffi::Bytes& s) { return ::tvm::runtime::vm::LoadParams(s); })
.def("vm.LoadParamsFromFile", [](const ffi::String& path) {
SimpleBinaryFileStream strm(path, "rb");
return LoadParams(&strm);
});
}
} // namespace vm
} // namespace runtime
} // namespace tvm