CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
506 lines
15 KiB
C++
506 lines
15 KiB
C++
/*******************************************************************************
|
|
*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2017 Advanced Micro Devices, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*******************************************************************************/
|
|
#ifndef GUARD_TENSOR_HOLDER_HPP
|
|
#define GUARD_TENSOR_HOLDER_HPP
|
|
|
|
#include "network_data.hpp"
|
|
#include <miopen/ford.hpp>
|
|
#include <miopen/tensor.hpp>
|
|
#include <miopen/functional.hpp>
|
|
#include <miopen/type_name.hpp>
|
|
#include <miopen/each_args.hpp>
|
|
#include <miopen/bfloat16.hpp>
|
|
#include "../driver/random.hpp"
|
|
|
|
#include "serialize.hpp"
|
|
|
|
#include <half/half.hpp>
|
|
using half = half_float::half;
|
|
using hip_bfloat16 = bfloat16;
|
|
#include "../../src/kernels/hip_float8.hpp"
|
|
using float8_fnuz = miopen_f8::hip_f8<miopen_f8::hip_f8_type::fp8>;
|
|
using bfloat8_fnuz = miopen_f8::hip_f8<miopen_f8::hip_f8_type::bf8>;
|
|
|
|
#include <iomanip>
|
|
#include <fstream>
|
|
|
|
template <class F>
|
|
void visit_tensor_size(std::size_t n, F f)
|
|
{
|
|
switch(n)
|
|
{
|
|
case 0: {
|
|
f(std::integral_constant<std::size_t, 0>{});
|
|
break;
|
|
}
|
|
case 1: {
|
|
f(std::integral_constant<std::size_t, 1>{});
|
|
break;
|
|
}
|
|
case 2: {
|
|
f(std::integral_constant<std::size_t, 2>{});
|
|
break;
|
|
}
|
|
case 3: {
|
|
f(std::integral_constant<std::size_t, 3>{});
|
|
break;
|
|
}
|
|
case 4: {
|
|
f(std::integral_constant<std::size_t, 4>{});
|
|
break;
|
|
}
|
|
case 5: {
|
|
f(std::integral_constant<std::size_t, 5>{});
|
|
break;
|
|
}
|
|
default: throw std::runtime_error("Unknown tensor size");
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
struct miopen_type;
|
|
|
|
template <>
|
|
struct miopen_type<float> : std::integral_constant<miopenDataType_t, miopenFloat>
|
|
{
|
|
};
|
|
|
|
template <>
|
|
struct miopen_type<double> : std::integral_constant<miopenDataType_t, miopenDouble>
|
|
{
|
|
};
|
|
|
|
template <>
|
|
struct miopen_type<half_float::half> : std::integral_constant<miopenDataType_t, miopenHalf>
|
|
{
|
|
};
|
|
template <>
|
|
struct miopen_type<bfloat16> : std::integral_constant<miopenDataType_t, miopenBFloat16>
|
|
{
|
|
};
|
|
|
|
template <>
|
|
struct miopen_type<int8_t> : std::integral_constant<miopenDataType_t, miopenInt8>
|
|
{
|
|
};
|
|
|
|
template <>
|
|
struct miopen_type<int> : std::integral_constant<miopenDataType_t, miopenInt32>
|
|
{
|
|
};
|
|
|
|
template <>
|
|
struct miopen_type<int64_t> : std::integral_constant<miopenDataType_t, miopenInt64>
|
|
{
|
|
};
|
|
|
|
template <>
|
|
struct miopen_type<float8_fnuz> : std::integral_constant<miopenDataType_t, miopenFloat8_fnuz>
|
|
{
|
|
};
|
|
|
|
template <>
|
|
struct miopen_type<bfloat8_fnuz> : std::integral_constant<miopenDataType_t, miopenBFloat8_fnuz>
|
|
{
|
|
};
|
|
|
|
template <>
|
|
struct miopen_type<uint8_t> : std::integral_constant<miopenDataType_t, miopenInt8>
|
|
{
|
|
};
|
|
|
|
template <>
|
|
struct miopen_type<uint16_t> : std::integral_constant<miopenDataType_t, miopenHalf>
|
|
{
|
|
};
|
|
|
|
template <>
|
|
struct miopen_type<uint64_t> : std::integral_constant<miopenDataType_t, miopenInt64>
|
|
{
|
|
};
|
|
|
|
template <class T>
|
|
struct tensor
|
|
{
|
|
using value_type = T;
|
|
miopen::TensorDescriptor desc;
|
|
std::vector<T> data;
|
|
|
|
#if defined(__clang__) || defined(__GNUG__)
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
#endif
|
|
|
|
tensor() : desc(miopen_type<T>{}) {}
|
|
|
|
#if defined(__clang__) || defined(__GNUG__)
|
|
#pragma GCC diagnostic pop
|
|
#endif
|
|
|
|
template <class X>
|
|
tensor(const std::vector<X>& dims) : desc(miopen_type<T>{}, dims), data(desc.GetElementSpace())
|
|
{
|
|
}
|
|
|
|
template <class X>
|
|
tensor(const std::vector<X>& dims, const std::vector<X>& strides)
|
|
: desc(miopen_type<T>{}, dims, strides), data(desc.GetElementSpace())
|
|
{
|
|
assert(dims.size() == strides.size());
|
|
}
|
|
|
|
template <class X>
|
|
tensor(miopenTensorLayout_t layout, const std::vector<X>& dims)
|
|
: desc(miopen_type<T>{}, layout, dims), data(desc.GetElementSpace())
|
|
{
|
|
}
|
|
|
|
template <class X>
|
|
tensor(miopenTensorLayout_t layout, const std::vector<X>& dims, const std::vector<X>& strides)
|
|
: desc(miopen_type<T>{}, layout, dims, strides), data(desc.GetElementSpace())
|
|
{
|
|
assert(dims.size() == strides.size());
|
|
}
|
|
|
|
tensor(std::size_t n, std::size_t c, std::size_t h, std::size_t w)
|
|
: desc(miopen_type<T>{}, {n, c, h, w}), data(n * c * h * w)
|
|
{
|
|
}
|
|
|
|
tensor(miopenTensorLayout_t layout, std::size_t n, std::size_t c, std::size_t h, std::size_t w)
|
|
: desc(miopen_type<T>{}, layout, {n, c, h, w}), data(desc.GetElementSpace())
|
|
{
|
|
}
|
|
|
|
tensor(std::size_t n, std::size_t c, std::size_t d, std::size_t h, std::size_t w)
|
|
: desc(miopen_type<T>{}, {n, c, d, h, w}), data(n * c * d * h * w)
|
|
{
|
|
}
|
|
|
|
tensor(std::size_t n) : desc(miopen_type<T>{}, {n}), data(n) {}
|
|
|
|
tensor(miopen::TensorDescriptor rhs) : desc(std::move(rhs))
|
|
{
|
|
assert(desc.GetType() == miopen_type<T>{}
|
|
/// In the driver, T is input tensor type, but output tensor holders
|
|
/// are instantiatied with T as well. This leads to false assertion
|
|
/// failures when T is INT8 because output type is different.
|
|
/// \todo Get rid of this hack when the driver is improved:
|
|
|| (miopen_type<T>{} == miopenInt8 && desc.GetType() == miopenInt32));
|
|
data.resize(desc.GetElementSpace());
|
|
}
|
|
|
|
size_t GetDataByteSize() const { return GetSize() * sizeof(T); }
|
|
|
|
size_t GetSize() const { return desc.GetElementSpace(); }
|
|
|
|
template <class G>
|
|
tensor& generate(G g) &
|
|
{
|
|
if(this->desc.GetVectorLength() > 1)
|
|
this->generate_vect_impl(g);
|
|
else
|
|
this->generate_impl(g);
|
|
return *this;
|
|
}
|
|
|
|
template <class G>
|
|
tensor&& generate(G g) &&
|
|
{
|
|
if(this->desc.GetVectorLength() > 1)
|
|
this->generate_vect_impl(g);
|
|
else
|
|
this->generate_impl(g);
|
|
return std::move(*this);
|
|
}
|
|
|
|
template <class G>
|
|
void generate_impl(G g)
|
|
{
|
|
auto seed = std::accumulate(desc.GetLengths().begin(),
|
|
desc.GetLengths().end(),
|
|
std::size_t{521288629},
|
|
[](auto x, auto y) {
|
|
x ^= x << 1U;
|
|
return x ^ y;
|
|
});
|
|
seed ^= data.size();
|
|
seed ^= desc.GetLengths().size();
|
|
prng::reset_seed(seed);
|
|
auto iterator = data.begin();
|
|
auto assign = [&](T x) {
|
|
*iterator = x;
|
|
++iterator;
|
|
};
|
|
this->for_each(
|
|
miopen::compose(miopen::compose(assign, miopen::cast_to<T>()), std::move(g)));
|
|
}
|
|
|
|
template <class G>
|
|
void generate_vect_impl(G g)
|
|
{
|
|
auto seed = std::accumulate(desc.GetLengths().begin(),
|
|
desc.GetLengths().end(),
|
|
std::size_t{521288629},
|
|
[](auto x, auto y) {
|
|
x ^= x << 1U;
|
|
return x ^ y;
|
|
});
|
|
seed ^= data.size();
|
|
seed ^= desc.GetLengths().size();
|
|
prng::reset_seed(seed);
|
|
auto iterator = data.begin();
|
|
auto vectorLength = desc.GetVectorLength();
|
|
auto assign = [&](T x) {
|
|
assert(iterator < data.end());
|
|
// for debugging
|
|
for(auto i = 0; i < vectorLength; i++)
|
|
{
|
|
*(iterator + i) = x;
|
|
}
|
|
iterator += vectorLength;
|
|
};
|
|
this->for_each(
|
|
miopen::compose(miopen::compose(assign, miopen::cast_to<T>()), std::move(g)));
|
|
}
|
|
|
|
template <class Loop, class F>
|
|
struct for_each_unpacked
|
|
{
|
|
Loop loop;
|
|
F f;
|
|
template <class... Ts>
|
|
auto operator()(Ts... xs) const -> decltype(f(xs...), void())
|
|
{
|
|
loop(xs...)(std::move(f));
|
|
}
|
|
|
|
struct any
|
|
{
|
|
any() {}
|
|
template <class X>
|
|
any(X)
|
|
{
|
|
}
|
|
};
|
|
|
|
[[noreturn]] void operator()(any = {},
|
|
any = {},
|
|
any = {},
|
|
any = {},
|
|
any = {},
|
|
any = {},
|
|
any = {},
|
|
any = {},
|
|
any = {}) const
|
|
{
|
|
throw std::runtime_error(
|
|
"Arguments to for_each do not match tensor size or the function " +
|
|
miopen::get_type_name<F>() + " can not be called.");
|
|
}
|
|
};
|
|
|
|
struct for_each_handler
|
|
{
|
|
template <class Self, class Loop, class F, class Size>
|
|
void operator()(Self* self, Loop loop, F f, Size size) const
|
|
{
|
|
auto dims = miopen::tien<size>(self->desc.GetLengths());
|
|
miopen::unpack(for_each_unpacked<Loop, F>{loop, std::move(f)}, dims);
|
|
}
|
|
};
|
|
|
|
template <class F>
|
|
void for_each(F f) const
|
|
{
|
|
visit_tensor_size(
|
|
desc.GetLengths().size(),
|
|
std::bind(for_each_handler{}, this, miopen::ford, std::move(f), std::placeholders::_1));
|
|
}
|
|
|
|
template <class F>
|
|
void par_for_each(F f) const
|
|
{
|
|
visit_tensor_size(
|
|
desc.GetLengths().size(),
|
|
std::bind(
|
|
for_each_handler{}, this, miopen::par_ford, std::move(f), std::placeholders::_1));
|
|
}
|
|
|
|
template <class... Ts>
|
|
T& operator()(Ts... xs)
|
|
{
|
|
assert(this->desc.GetIndex(xs...) < data.size());
|
|
return this->data[this->desc.GetIndex(xs...)];
|
|
}
|
|
|
|
template <class... Ts>
|
|
const T& operator()(Ts... xs) const
|
|
{
|
|
assert(this->desc.GetIndex(xs...) < data.size());
|
|
return this->data[this->desc.GetIndex(xs...)];
|
|
}
|
|
|
|
template <class Integer, Integer N>
|
|
const T& operator()(const std::array<Integer, N>& multi_id) const
|
|
{
|
|
auto f = [&](auto... is) { return this->desc.GetIndex(is...); };
|
|
assert(miopen::unpack(f, multi_id) < data.size());
|
|
return this->data[miopen::unpack(f, multi_id)];
|
|
}
|
|
|
|
T& operator[](std::size_t i) { return data.at(i); }
|
|
|
|
const T& operator[](std::size_t i) const { return data.at(i); }
|
|
|
|
typename std::vector<T>::iterator begin() { return data.begin(); }
|
|
|
|
typename std::vector<T>::iterator end() { return data.end(); }
|
|
|
|
typename std::vector<T>::const_iterator begin() const { return data.begin(); }
|
|
|
|
typename std::vector<T>::const_iterator end() const { return data.end(); }
|
|
|
|
friend std::ostream& operator<<(std::ostream& stream, const tensor& t)
|
|
{
|
|
return stream << t.desc;
|
|
}
|
|
|
|
template <size_t N, typename Stream>
|
|
void dump_inner(size_t dim, std::array<size_t, N>& coord, Stream& stream) const
|
|
{
|
|
const auto lengths = this->desc.GetLengths();
|
|
if(lengths.size() == 0)
|
|
{
|
|
// 0D special case: Just print the one value that we have and return.
|
|
stream << (*this)(coord);
|
|
}
|
|
else if(dim + 1 == lengths.size())
|
|
{
|
|
// 1D special case: dump everything on one line
|
|
for(size_t i = 0; i < lengths[dim]; ++i)
|
|
{
|
|
if(i != 0)
|
|
stream << ' ';
|
|
|
|
coord[dim] = i;
|
|
stream << std::setw(4) << (*this)(coord);
|
|
}
|
|
|
|
stream << '\n';
|
|
}
|
|
else
|
|
{
|
|
if(dim + 2 == lengths.size())
|
|
{
|
|
// 2D special case: Also print which 2D slice we are currently printing
|
|
// Note: this is not needed for higher dimensions, as they will also pass
|
|
// through this branch.
|
|
stream << "slice [";
|
|
for(size_t i = 0; i < dim; ++i)
|
|
{
|
|
stream << coord[i] << ", ";
|
|
}
|
|
stream << ":, :]\n";
|
|
}
|
|
|
|
for(size_t i = 0; i < lengths[dim]; ++i)
|
|
{
|
|
coord[dim] = i;
|
|
this->dump_inner<N>(dim + 1, coord, stream);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Stream = decltype(std::cout)>
|
|
void dump(const char* name, Stream& stream = std::cout) const
|
|
{
|
|
const auto n = this->desc.GetLengths().size();
|
|
stream << "==== " << name << ": " << *this << n << '\n';
|
|
stream.fill(' ');
|
|
|
|
const auto flags = stream.flags();
|
|
|
|
visit_tensor_size(n, [&](const auto size) {
|
|
constexpr size_t N = decltype(size)::value;
|
|
std::array<size_t, N> coord;
|
|
this->dump_inner<N>(0, coord, stream);
|
|
});
|
|
|
|
stream.flags(flags);
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
void serialize(std::istream& s, tensor<T>& x)
|
|
{
|
|
std::vector<std::size_t> lens;
|
|
serialize(s, lens);
|
|
std::vector<std::size_t> strides;
|
|
serialize(s, strides);
|
|
x.desc = miopen::TensorDescriptor{miopen_type<T>{}, lens, strides};
|
|
serialize(s, x.data);
|
|
}
|
|
|
|
template <class T>
|
|
void serialize(std::ostream& s, const tensor<T>& x)
|
|
{
|
|
const auto& lens = x.desc.GetLengths();
|
|
const auto& strides = x.desc.GetStrides();
|
|
serialize(s, lens);
|
|
serialize(s, strides);
|
|
serialize(s, x.data);
|
|
}
|
|
|
|
struct tensor_generate
|
|
{
|
|
template <class Tensor, class G>
|
|
Tensor&& operator()(Tensor&& t, G g) const
|
|
{
|
|
return std::forward<Tensor>(t.generate(g));
|
|
}
|
|
};
|
|
|
|
struct tensor_elem_gen_integer
|
|
{
|
|
uint64_t max_value = 17;
|
|
|
|
template <class... Ts>
|
|
double operator()(Ts... Xs) const
|
|
{
|
|
static_assert(sizeof...(Ts) < 6,
|
|
"Dimensions in tensor_elem_gen_integer must be less than 6.");
|
|
assert(max_value > 0);
|
|
std::array<uint64_t, sizeof...(Ts)> left = {{Xs...}};
|
|
std::array<uint64_t, 5> right = {{613, 547, 701, 877, 1049}};
|
|
uint64_t dot =
|
|
std::inner_product(left.begin(), left.end(), right.begin(), static_cast<uint64_t>(173));
|
|
return static_cast<double>(dot % max_value);
|
|
}
|
|
};
|
|
|
|
#endif
|