From 9b87db80e0992c99b52166b560ed23670af720ef Mon Sep 17 00:00:00 2001 From: Terry Heo <terryheo@google.com> Date: Thu, 3 Dec 2020 17:19:02 -0800 Subject: [PATCH] tflite: Prevent from reallocation of persistent tensors After ResetAllocationsAfter() is called, CalculateAllocations() could be called again for nodes which have persistent temporary tensors. The logic should prevent from reallocation of these tensors since they're not going to be initialized again. This issue could be reproduced easily with hybrid quantized models since some hybrid kernels are using persistent temporary tensors. This PR resolves GitHub issue #44520. PiperOrigin-RevId: 345569003 Change-Id: I1b9777b33a664ebd0f09df8d3236c7ece0118b1a --- tensorflow/lite/arena_planner.cc | 4 +++- tensorflow/lite/arena_planner_test.cc | 34 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tensorflow/lite/arena_planner.cc b/tensorflow/lite/arena_planner.cc index b134a5de044..8b8913d7322 100644 --- a/tensorflow/lite/arena_planner.cc +++ b/tensorflow/lite/arena_planner.cc @@ -323,7 +323,9 @@ TfLiteStatus ArenaPlanner::CalculateAllocations(int first_node, int last_node) { tensor_index, alloc_node_[tensor_index], dealloc_node_[tensor_index], &allocs_[tensor_index])); } - if (tensor.allocation_type == kTfLiteArenaRwPersistent) { + // Check allocs_[].size to prevent from reallocation of persistent tensors. + if (tensor.allocation_type == kTfLiteArenaRwPersistent && + allocs_[tensor_index].size == 0) { TF_LITE_ENSURE_STATUS(persistent_arena_.Allocate( context_, tensor_alignment_, tensor.bytes, tensor_index, /*first_node=*/alloc_node_[tensor_index], diff --git a/tensorflow/lite/arena_planner_test.cc b/tensorflow/lite/arena_planner_test.cc index 47ecc68cf40..ca2127d8333 100644 --- a/tensorflow/lite/arena_planner_test.cc +++ b/tensorflow/lite/arena_planner_test.cc @@ -356,6 +356,40 @@ TEST_F(ArenaPlannerTest, SimpleGraphWithResetAllocationsAfter) { EXPECT_TRUE(IsUnallocated(5)); } +TEST_F(ArenaPlannerTest, SimpleGraphWithPersistentResetAllocationsAfter) { + TestGraph graph({0, 1}, + { + /* in, out, tmp */ + {{0, 1}, {2}, {}}, // First op + {{2, 0}, {4}, {5}}, // Second op, with temporary + {{4}, {3}, {}} // Third op + }, + {3}); + // Make the tensor #5 persistent. + (*graph.tensors())[5].allocation_type = kTfLiteArenaRwPersistent; + SetGraph(&graph); + Execute(0, 10); + + // Save the pointer of the persistent temporary tensor #5. + void* tensor5_ptr = (*graph.tensors())[5].data.raw; + + // Reset allocations after the first node + ResetAllocationsAfter(0); + + EXPECT_FALSE(IsUnallocated(0)); + EXPECT_FALSE(IsUnallocated(1)); + EXPECT_FALSE(IsUnallocated(2)); + EXPECT_TRUE(IsUnallocated(3)); + EXPECT_TRUE(IsUnallocated(4)); + EXPECT_FALSE(IsUnallocated(5)); + + // Second run + Execute(0, 10); + + // Check if the persistent pointer isn't changed. + EXPECT_TRUE(tensor5_ptr == (*graph.tensors())[5].data.raw); +} + TEST_F(ArenaPlannerTest, SimpleGraphWithOptionals) { TestGraph graph({0, -1, 1}, {