Skip to content
Closed
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
1 change: 1 addition & 0 deletions aten/src/ATen/Declarations.cwrap
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@
[[
name: _th_nonzero
cname: nonzero
cpu_half: True
cpu_bool: True
cuda_bool: True
variants:
Expand Down
3 changes: 0 additions & 3 deletions aten/src/ATen/gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,6 @@ def legacy_iterate_types():
for scalar_type in (scalar_types + quantized_scalar_types):
if density == 'Mkldnn' and (backend != 'CPU' or scalar_type[0] != 'Float'):
continue
if density == 'Sparse' and scalar_type[0] == 'Half':
# THS does not do half type yet.
continue
else:
yield (backend, density, scalar_type)
for backend in quantized_backends:
Expand Down
2 changes: 2 additions & 0 deletions aten/src/ATen/native/native_functions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2523,12 +2523,14 @@
variants: function, method

- func: to_sparse(Tensor self, int sparse_dim) -> Tensor
cpu_half: True
variants: method
dispatch:
CPU: dense_to_sparse
CUDA: dense_to_sparse

- func: to_sparse(Tensor self) -> Tensor
cpu_half: True
variants: method
dispatch:
CPU: dense_to_sparse
Expand Down
3 changes: 3 additions & 0 deletions aten/src/ATen/native/sparse/SparseTensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,9 @@ SparseTensor dense_to_sparse(const Tensor& self, int64_t sparse_dim){
// NB: Dropped the resizeNd variants

Tensor sparse_to_dense(const SparseTensor& self) {
if(self.scalar_type() == ScalarType::Half && self.options().device().is_cpu()) {
AT_ERROR("to_dense() not supported for float16 on CPU");
}
Tensor dst = at::zeros(self.sizes(), self.options().layout(kStrided));
return dst.add_(self);
}
Expand Down
3 changes: 3 additions & 0 deletions aten/src/TH/THTensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
#include <TH/generic/THTensorMath.h>
#include <TH/THGenerateBoolType.h>

#include <TH/generic/THTensorMath.h>
#include <TH/THGenerateHalfType.h>

/* fill and zero*/
#include <TH/generic/THTensorFill.h>
#include <TH/THGenerateAllTypes.h>
Expand Down
3 changes: 3 additions & 0 deletions aten/src/TH/THTensorEvenMoreMath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@

#include <TH/generic/THTensorEvenMoreMath.cpp>
#include <TH/THGenerateBoolType.h>

#include <TH/generic/THTensorEvenMoreMath.cpp>
#include <TH/THGenerateHalfType.h>
11 changes: 8 additions & 3 deletions aten/src/TH/generic/THTensorEvenMoreMath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ void THTensor_(nonzero)(THLongTensor *subscript, THTensor *tensor)
int64_t *subscript_data;
int64_t i = 0;
#ifdef TH_REAL_IS_HALF
#define IS_NONZERO(val) ((val.x & 0x7fff) != 0)
#define IS_NONZERO(val) (c10::Half(0)!=val)
#else
#define IS_NONZERO(val) ((val)!=0)
#endif
Expand Down Expand Up @@ -65,8 +65,12 @@ void THTensor_(nonzero)(THLongTensor *subscript, THTensor *tensor)
);
delete [] sizes;
delete [] idx;

#undef IS_NONZERO
}

#if !defined(TH_REAL_IS_HALF) /* non half only part */

accreal THTensor_(sumall)(THTensor *tensor)
{
accreal sum = 0;
Expand All @@ -86,8 +90,7 @@ accreal THTensor_(sumall)(THTensor *tensor)
}
return sum;
}

#if !defined(TH_REAL_IS_BOOL) /* non bool only part */
#if !defined(TH_REAL_IS_BOOL)

void THTensor_(maskedFill)(THTensor *tensor, THByteTensor *mask, scalar_t value)
{
Expand Down Expand Up @@ -1031,4 +1034,6 @@ void THTensor_(bitand)(THTensor *r_, THTensor *t, scalar_t value)

#endif

#endif

#endif /* TH_GENERIC_FILE */
3 changes: 3 additions & 0 deletions aten/src/TH/generic/THTensorMath.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

TH_API void THTensor_(nonzero)(THLongTensor *subscript, THTensor *tensor);

#ifndef TH_REAL_IS_HALF

TH_API void THTensor_(ltValue)(THByteTensor *r_, THTensor* t, scalar_t value);
TH_API void THTensor_(leValue)(THByteTensor *r_, THTensor* t, scalar_t value);
TH_API void THTensor_(gtValue)(THByteTensor *r_, THTensor* t, scalar_t value);
Expand Down Expand Up @@ -183,3 +185,4 @@ TH_API void THTensor_(dirichlet_grad)(THTensor *self, THTensor *x, THTensor *alp

#endif
#endif
#endif
80 changes: 60 additions & 20 deletions test/test_nn.py
Original file line number Diff line number Diff line change
Expand Up @@ -2070,24 +2070,61 @@ def test_embedding_dense_grad(self):
def test_embedding_dense_grad_cuda(self):
self._test_embedding_dense_grad("cuda")

def test_move_sparse_half_embedding(self):
embedding = nn.Embedding(10, 3, sparse=True)
self.assertEqual(embedding.weight.device.type, 'cpu')
self.assertEqual(embedding.weight.dtype, torch.float64)
embedding.to(torch.float16)
self.assertEqual(embedding.weight.dtype, torch.float16)
self.assertEqual(embedding.embedding_dim, 3)
self.assertEqual(embedding.num_embeddings, 10)

if torch.cuda.is_available():
embedding.to('cuda')
self.assertEqual(embedding.weight.device.type, 'cuda')
embedding.to('cpu')
self.assertEqual(embedding.weight.device.type, 'cpu')

def test_embedding_sparse_backward(self):
self._test_embedding_backward()

@unittest.skipIf(not TEST_CUDA, "CUDA unavailable")
def test_embedding_sparse_half_backward(self):
# same as test_embedding_sparse_backward above but testing half types in
# cuda. cpu sum not supported for half types.
self._test_embedding_backward('cuda', torch.float16)

def _test_embedding_backward(self, device='cpu', dtype=torch.float64):
embedding = nn.Embedding(10, 3, sparse=True)
tensor = torch.tensor([[7, 1, 3]])
ones = torch.tensor(1.).expand(3, 3)
tensorTwice = tensor.repeat(1, 2)
onesTwice = torch.cat((ones, ones))

embedding = embedding.to(dtype=dtype).to(device)
tensor = tensor.to(device)
ones = ones.to(device)
tensorTwice = tensorTwice.to(device)
onesTwice = onesTwice.to(device)

embedding.zero_grad()
embedding(torch.LongTensor([7, 1, 3])).sum().backward()
self.assertEqual(embedding.weight.grad._indices(), torch.LongTensor([[7, 1, 3]]))
self.assertEqual(embedding.weight.grad._values(), torch.tensor(1.).expand(3, 3))
embedding(tensor[0]).sum().backward()
self.assertEqual(embedding.weight.grad._indices(), tensor)
self.assertEqual(embedding.weight.grad._values(), ones)

embedding.zero_grad()
embedding(torch.LongTensor([7, 1, 3])).sum().backward()
embedding(torch.LongTensor([7, 1, 3])).sum().backward()
self.assertEqual(embedding.weight.grad._indices(), torch.LongTensor([[7, 1, 3, 7, 1, 3]]))
self.assertEqual(embedding.weight.grad._values(), torch.tensor(1.).expand(6, 3))
embedding(tensor[0]).sum().backward()
embedding(tensor[0]).sum().backward()
self.assertEqual(embedding.weight.grad._indices(), tensorTwice)
self.assertEqual(embedding.weight.grad._values(), onesTwice)

embedding.zero_grad()
embedding(torch.LongTensor([7, 1, 3])).sum().backward()
embedding(torch.LongTensor([8, 1, 3])).sum().backward()
self.assertEqual(embedding.weight.grad._indices(), torch.LongTensor([[7, 1, 3, 8, 1, 3]]))
self.assertEqual(embedding.weight.grad._values(), torch.tensor(1.).expand(6, 3))
embedding(tensor[0]).sum().backward()
tensor[0, 0] = 8
embedding(tensor[0]).sum().backward()
tensorTwice[0, 3] = 8
self.assertEqual(embedding.weight.grad._indices(), tensorTwice)
self.assertEqual(embedding.weight.grad._values(), onesTwice)

def test_embedding_padding_idx(self):
embedding = nn.Embedding(10, 20, padding_idx=0)
Expand Down Expand Up @@ -2377,6 +2414,7 @@ def _test_EmbeddingBag_vs_Embedding(self, N, D, B, L, max_norm=None,
needed_prec = dtype2prec[dtype] * 2
else:
needed_prec = backward_prec

self.assertEqual(es_weight_grad, e.weight.grad, needed_prec)

if test_per_sample_weights and trainable_per_sample_weights:
Expand Down Expand Up @@ -2564,12 +2602,13 @@ def test_contig_wrong_stride_cudnn(self):

def test_embedding_bag(self):
for dtype in [torch.double, torch.float]:
# TODO: figure out why backward on float breaks
test_backward = dtype is not torch.float
self._test_EmbeddingBag(False, 'sum', False, test_backward=test_backward, dtype=dtype)
self._test_EmbeddingBag(False, 'mean', False, test_backward=test_backward, dtype=dtype)
self._test_EmbeddingBag(False, 'max', False, test_backward=test_backward, dtype=dtype)
self._test_EmbeddingBag(False, 'sum', False, dtype=dtype)
self._test_EmbeddingBag(False, 'mean', False, dtype=dtype)
self._test_EmbeddingBag(False, 'max', False, dtype=dtype)

# TODO: figure out why precision on sparse embeddings isn't the
# same as for dense.
test_backward = dtype is not torch.float
self._test_EmbeddingBag(False, 'sum', True, test_backward=test_backward, dtype=dtype)
self._test_EmbeddingBag(False, 'mean', True, test_backward=test_backward, dtype=dtype)

Expand Down Expand Up @@ -2733,10 +2772,11 @@ def test_embedding_bag_cuda(self, dtype=torch.float):
self._test_EmbeddingBag(True, 'sum', False, dtype)
self._test_EmbeddingBag(True, 'mean', False, dtype)
self._test_EmbeddingBag(True, 'max', False, dtype)
if dtype != torch.half:
# torch.cuda.sparse.HalfTensor is not enabled.
self._test_EmbeddingBag(True, 'sum', True, dtype)
self._test_EmbeddingBag(True, 'mean', True, dtype)

# see 'todo' in test_embedding_bag.
test_backward = dtype is not torch.float16
self._test_EmbeddingBag(True, 'sum', True, dtype, test_backward=test_backward)
self._test_EmbeddingBag(True, 'mean', True, dtype, test_backward=test_backward)

def test_fractional_max_pool2d(self):
x = torch.randn(1, 2, 7, 7, requires_grad=True)
Expand Down
Loading