Files
2025-12-19 23:03:40 +02:00

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