Skip to content

Commit

Permalink
Fix TensorList constructor from list of tensors. (NVIDIA#3626)
Browse files Browse the repository at this point in the history
Fixed issues (raising exceptions), when constructing TensorList from an empty list,
different backend tensors or different dtype tensors.

Signed-off-by: ksztenderski <ksztenderski@nvidia.com>
  • Loading branch information
ksztenderski authored and cyyever committed Jun 7, 2022
1 parent 2105147 commit 5de5e23
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 2 deletions.
27 changes: 25 additions & 2 deletions dali/python/backend_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -596,11 +596,34 @@ std::unique_ptr<Tensor<Backend> > TensorListGetItemImpl(TensorList<Backend> &t,
template <typename Backend>
std::shared_ptr<TensorList<Backend>> TensorListFromListOfTensors(py::list &list_of_tensors,
string &layout) {
if (list_of_tensors.empty()) {
throw std::runtime_error("Cannot create TensorList from an empty list.");
}

auto tl = std::make_shared<TensorList<Backend>>(list_of_tensors.size());
TensorVector<Backend> tv(list_of_tensors.size());
int expected_type = -2;

for (size_t i = 0; i < list_of_tensors.size(); ++i) {
auto &t = list_of_tensors[i].cast<Tensor<Backend>&>();
tv[i].ShareData(t);
try {
auto &t = list_of_tensors[i].cast<Tensor<Backend> &>();
DALIDataType cur_type = t.type();

if (expected_type == -2) {
expected_type = t.type();
} else if (expected_type != cur_type) {
throw py::type_error(make_string(
"Tensors cannot have different data types. Tensor at position ", i, " has type '",
cur_type, "' expected to have type '", DALIDataType(expected_type), "'."));
}

tv[i].ShareData(t);
} catch (const py::type_error &) {
throw;
} catch (const std::runtime_error &) {
throw py::type_error(make_string("Object at position ", i, " cannot be converted to Tensor",
std::is_same<Backend, GPUBackend>::value ? "GPU." : "CPU."));
}
}

cudaStream_t stream = 0;
Expand Down
26 changes: 26 additions & 0 deletions dali/test/python/test_backend_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,29 @@ def test_tl_from_list_of_tensors_different_shapes():
for arr, tensor_cpu, tensor_gpu in zip(np_arrays, tl_cpu, tl_gpu):
np.testing.assert_array_equal(arr, tensor_cpu)
np.testing.assert_array_equal(arr, tensor_gpu.as_cpu())


def test_tl_from_list_of_tensors_empty():
with assert_raises(RuntimeError, glob='Cannot create TensorList from an empty list.'):
TensorListCPU([])
with assert_raises(RuntimeError, glob='Cannot create TensorList from an empty list.'):
TensorListGPU([])


def test_tl_from_list_of_tensors_different_backends():
t1 = TensorCPU(np.zeros((1)))
t2 = TensorCPU(np.zeros((1)))._as_gpu()
with assert_raises(TypeError, glob='Object at position 1 cannot be converted to TensorCPU'):
TensorListCPU([t1, t2])
with assert_raises(TypeError, glob='Object at position 1 cannot be converted to TensorGPU'):
TensorListGPU([t2, t1])


def test_tl_from_list_of_tensors_different_dtypes():
np_types = [np.float32, np.float16, np.int16, np.int8, np.uint16, np.uint8]
for dtypes in np.random.choice(np_types, size=(3, 2), replace=False):
t1 = TensorCPU(np.zeros((1), dtype=dtypes[0]))
t2 = TensorCPU(np.zeros((1), dtype=dtypes[1]))
with assert_raises(TypeError, glob=f"Tensors cannot have different data types. Tensor at position "
"1 has type '*' expected to have type '*'."):
TensorListCPU([t1, t2])

0 comments on commit 5de5e23

Please sign in to comment.