Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions extension/tensor/tensor_ptr_maker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ bool extract_scalar(executorch::aten::Scalar scalar, INT_T* out_val) {

template <
typename FLOAT_T,
typename std::enable_if<std::is_floating_point<FLOAT_T>::value, bool>::
type = true>
typename std::enable_if<
std::is_floating_point_v<FLOAT_T> ||
std::is_same_v<FLOAT_T, executorch::aten::BFloat16> ||
std::is_same_v<FLOAT_T, executorch::aten::Half>,
bool>::type = true>
bool extract_scalar(executorch::aten::Scalar scalar, FLOAT_T* out_val) {
double val;
if (scalar.isFloatingPoint()) {
Expand All @@ -59,7 +62,7 @@ template <
typename std::enable_if<std::is_same<BOOL_T, bool>::value, bool>::type =
true>
bool extract_scalar(executorch::aten::Scalar scalar, BOOL_T* out_val) {
if (scalar.isIntegral(false)) {
if (scalar.isIntegral(/*includeBool=*/false)) {
*out_val = static_cast<bool>(scalar.to<int64_t>());
return true;
}
Expand All @@ -86,7 +89,7 @@ TensorPtr random_strided(
empty_strided(std::move(sizes), std::move(strides), type, dynamism);
std::default_random_engine gen{std::random_device{}()};

ET_SWITCH_REALB_TYPES(type, nullptr, "random_strided", CTYPE, [&] {
ET_SWITCH_REALHBBF16_TYPES(type, nullptr, "random_strided", CTYPE, [&] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the problem is here -- there are presumably fp32 values that, while not 1.0f, convert to bfloat16 as 1.0 thanks to round-to-nearest-even.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I think both rand_strided and randint_strided (the two functions that use a uniform distribution on a half-open interval) need special handling not to generate the excluded endpoint of their interval. PyTorch's implementation seems to suggest this is a bit of a pain: https://github.com/pytorch/pytorch/blob/dcac3c3e06556bc0e729dd1fa75f4f1e81caa356/aten/src/ATen/native/DistributionTemplates.h#L30

Technically, code sharing support landed today, so we could refactor update_to and update_from out of this header and share them...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hope #8340 should be enough to fix the flakiness.

std::generate_n(tensor->mutable_data_ptr<CTYPE>(), tensor->numel(), [&]() {
return static_cast<CTYPE>(distribution(gen));
});
Expand Down Expand Up @@ -121,7 +124,7 @@ TensorPtr full_strided(
executorch::aten::TensorShapeDynamism dynamism) {
auto tensor =
empty_strided(std::move(sizes), std::move(strides), type, dynamism);
ET_SWITCH_REALB_TYPES(type, nullptr, "full_strided", CTYPE, [&] {
ET_SWITCH_REALHBBF16_TYPES(type, nullptr, "full_strided", CTYPE, [&] {
CTYPE value;
ET_EXTRACT_SCALAR(fill_value, value);
std::fill(
Expand Down
44 changes: 44 additions & 0 deletions extension/tensor/test/tensor_ptr_maker_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,20 @@ TEST_F(TensorPtrMakerTest, CreateFull) {
EXPECT_EQ(tensor4->size(1), 5);
EXPECT_EQ(tensor4->scalar_type(), executorch::aten::ScalarType::Double);
EXPECT_EQ(tensor4->const_data_ptr<double>()[0], 11);

auto tensor5 = full({4, 5}, 13, executorch::aten::ScalarType::Half);
EXPECT_EQ(tensor5->dim(), 2);
EXPECT_EQ(tensor5->size(0), 4);
EXPECT_EQ(tensor5->size(1), 5);
EXPECT_EQ(tensor5->scalar_type(), executorch::aten::ScalarType::Half);
EXPECT_EQ(tensor5->const_data_ptr<executorch::aten::Half>()[0], 13);

auto tensor6 = full({4, 5}, 15, executorch::aten::ScalarType::BFloat16);
EXPECT_EQ(tensor6->dim(), 2);
EXPECT_EQ(tensor6->size(0), 4);
EXPECT_EQ(tensor6->size(1), 5);
EXPECT_EQ(tensor6->scalar_type(), executorch::aten::ScalarType::BFloat16);
EXPECT_EQ(tensor6->const_data_ptr<executorch::aten::BFloat16>()[0], 15);
}

TEST_F(TensorPtrMakerTest, CreateScalar) {
Expand Down Expand Up @@ -363,6 +377,36 @@ TEST_F(TensorPtrMakerTest, CreateRandTensorWithDoubleType) {
}
}

TEST_F(TensorPtrMakerTest, CreateRandTensorWithHalfType) {
auto tensor = rand({4, 5}, executorch::aten::ScalarType::Half);

EXPECT_EQ(tensor->dim(), 2);
EXPECT_EQ(tensor->size(0), 4);
EXPECT_EQ(tensor->size(1), 5);
EXPECT_EQ(tensor->scalar_type(), executorch::aten::ScalarType::Half);

for (auto i = 0; i < tensor->numel(); ++i) {
auto val = tensor->const_data_ptr<executorch::aten::Half>()[i];
EXPECT_GE(val, 0.0);
EXPECT_LT(val, 1.0);
}
}

TEST_F(TensorPtrMakerTest, CreateRandTensorWithBFloatType) {
auto tensor = rand({4, 5}, executorch::aten::ScalarType::BFloat16);

EXPECT_EQ(tensor->dim(), 2);
EXPECT_EQ(tensor->size(0), 4);
EXPECT_EQ(tensor->size(1), 5);
EXPECT_EQ(tensor->scalar_type(), executorch::aten::ScalarType::BFloat16);

for (auto i = 0; i < tensor->numel(); ++i) {
auto val = tensor->const_data_ptr<executorch::aten::BFloat16>()[i];
EXPECT_GE(val, 0.0);
EXPECT_LT(val, 1.0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused. doesn't rand generate normally distributed numbers? the mean is set to 0 and stddev is 1, and the normal distribution can certainly include numbers 1 or more standard deviations away from the mean.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess what you described is PyTorch's randn()?
Pretty confusing naming though, I agree.

Copy link
Contributor

@swolchok swolchok Feb 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to mention that I brought this up because this test is flaking; val is sometimes 1.0

Copy link
Contributor

@swolchok swolchok Feb 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess what you described is PyTorch's randn()?

you're right: I misread earlier. however, the test is still flaking. see inline code comment

}
}

TEST_F(TensorPtrMakerTest, CreateRandnTensor) {
auto tensor = randn({100, 100});

Expand Down
Loading