182 lines
5.3 KiB
C++
182 lines
5.3 KiB
C++
// Copyright 2018 Intel Corporation
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
#include "tensor.h"
|
|
#include "engine.h"
|
|
#include <fstream>
|
|
|
|
OIDN_NAMESPACE_BEGIN
|
|
|
|
std::ostream& operator <<(std::ostream& sm, const TensorDims& dims)
|
|
{
|
|
sm << "[";
|
|
for (size_t i = 0; i < dims.size(); ++i)
|
|
{
|
|
if (i > 0)
|
|
sm << ", ";
|
|
sm << dims[i];
|
|
}
|
|
sm << "]";
|
|
return sm;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
// Tensor
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
Tensor::Tensor(const TensorDesc& desc)
|
|
: TensorDesc(desc)
|
|
{
|
|
if (!desc.isValid())
|
|
throw std::invalid_argument("invalid tensor descriptor");
|
|
}
|
|
|
|
Tensor::Tensor(const Ref<Buffer>& buffer, const TensorDesc& desc, size_t byteOffset)
|
|
: Memory(buffer, byteOffset),
|
|
TensorDesc(desc)
|
|
{
|
|
if (!desc.isValid())
|
|
throw std::invalid_argument("invalid tensor descriptor");
|
|
}
|
|
|
|
Ref<Tensor> Tensor::toDevice(Engine* engine, Storage storage)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
#if 0
|
|
uint32_t Tensor::getHash() const
|
|
{
|
|
std::vector<uint8_t> hostBytes;
|
|
const uint8_t* bytes;
|
|
|
|
if (buffer && buffer->getStorage() == Storage::Device)
|
|
{
|
|
// Copy the tensor to the host
|
|
hostBytes.resize(getByteSize());
|
|
getBuffer()->getEngine()->usmCopy(hostBytes.data(), getPtr(), getByteSize());
|
|
bytes = hostBytes.data();
|
|
}
|
|
else
|
|
{
|
|
bytes = static_cast<const uint8_t*>(getPtr());
|
|
}
|
|
|
|
const size_t numBytes = getByteSize();
|
|
uint32_t hash = 0x811c9dc5;
|
|
for (size_t i = 0; i < numBytes; ++i)
|
|
{
|
|
hash ^= bytes[i];
|
|
hash *= 0x1000193;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
void Tensor::dump(const std::string& filenamePrefix)
|
|
{
|
|
if (dataType == DataType::Float32 && layout == TensorLayout::chw)
|
|
dumpImpl<float, TensorLayout::chw>(filenamePrefix);
|
|
else if (dataType == DataType::Float32 && layout == TensorLayout::Chw8c)
|
|
dumpImpl<float, TensorLayout::Chw8c>(filenamePrefix);
|
|
else if (dataType == DataType::Float32 && layout == TensorLayout::Chw16c)
|
|
dumpImpl<float, TensorLayout::Chw16c>(filenamePrefix);
|
|
else if (dataType == DataType::Float16 && layout == TensorLayout::chw)
|
|
dumpImpl<half, TensorLayout::chw>(filenamePrefix);
|
|
else if (dataType == DataType::Float16 && layout == TensorLayout::Chw16c)
|
|
dumpImpl<half, TensorLayout::Chw16c>(filenamePrefix);
|
|
else if (dataType == DataType::Float16 && layout == TensorLayout::hwc)
|
|
dumpImpl<half, TensorLayout::hwc>(filenamePrefix);
|
|
else
|
|
throw std::runtime_error("tensor dump not implemented");
|
|
}
|
|
|
|
template<typename T, TensorLayout accessorLayout>
|
|
void Tensor::dumpImpl(const std::string& filenamePrefix)
|
|
{
|
|
if (buffer && buffer->getStorage() == Storage::Device)
|
|
throw std::runtime_error("tensor dump not implemented for device storage");
|
|
|
|
TensorAccessor3D<T, accessorLayout> acc = *this;
|
|
|
|
for (int c = 0; c < acc.C; ++c)
|
|
{
|
|
// Open the file
|
|
const std::string filename = filenamePrefix + toString(c) + ".pfm";
|
|
std::ofstream file(filename, std::ios::binary);
|
|
if (file.fail())
|
|
throw std::runtime_error("cannot open image file: " + std::string(filename));
|
|
|
|
// Write the header
|
|
file << "Pf" << std::endl;
|
|
file << acc.W << " " << acc.H << std::endl;
|
|
file << "-1.0" << std::endl;
|
|
|
|
// Write the pixels
|
|
for (int h = acc.H-1; h >= 0; --h)
|
|
{
|
|
for (int w = 0; w < acc.W; ++w)
|
|
{
|
|
const float x = acc(c, h, w);
|
|
file.write((char*)&x, sizeof(float));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
// HostTensor
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
HostTensor::HostTensor(const TensorDesc& desc)
|
|
: Tensor(desc),
|
|
ptr(alignedMalloc(getByteSize())),
|
|
shared(false) {}
|
|
|
|
HostTensor::HostTensor(const TensorDesc& desc, void* data)
|
|
: Tensor(desc),
|
|
ptr(data),
|
|
shared(true) {}
|
|
|
|
HostTensor::~HostTensor()
|
|
{
|
|
if (!shared)
|
|
alignedFree(ptr);
|
|
}
|
|
|
|
Ref<Tensor> HostTensor::toDevice(Engine* engine, Storage storage)
|
|
{
|
|
const size_t byteSize = getByteSize();
|
|
auto bufferCopy = engine->newBuffer(byteSize, storage);
|
|
bufferCopy->write(0, byteSize, getPtr());
|
|
return engine->newTensor(bufferCopy, getDesc());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
// DeviceTensor
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
DeviceTensor::DeviceTensor(Engine* engine, const TensorDesc& desc, Storage storage)
|
|
: Tensor(desc)
|
|
{
|
|
buffer = engine->newBuffer(getByteSize(), storage);
|
|
ptr = buffer->getPtr();
|
|
}
|
|
|
|
DeviceTensor::DeviceTensor(const Ref<Buffer>& buffer, const TensorDesc& desc, size_t byteOffset)
|
|
: Tensor(buffer, desc, byteOffset)
|
|
{
|
|
if (byteOffset + getByteSize() > buffer->getByteSize())
|
|
throw Exception(Error::InvalidArgument, "buffer region is out of bounds");
|
|
|
|
ptr = static_cast<char*>(buffer->getPtr()) + byteOffset;
|
|
}
|
|
|
|
void DeviceTensor::postRealloc()
|
|
{
|
|
if (buffer)
|
|
ptr = static_cast<char*>(buffer->getPtr()) + byteOffset;
|
|
}
|
|
|
|
OIDN_NAMESPACE_END
|