Skip to content

Conversation

@li-roy
Copy link
Contributor

@li-roy li-roy commented Mar 13, 2019

Stack:
    :black_circle:  #17991 Introduce DeprecatedTypeProperties class  💚
    :white_circle:  #17601 Store ScalarType and Backend instead of Type in TensorIterator  💚
    :white_circle:  #17786 Pass ScalarType separately from Type in python constructors  💚

changes:
-Breaks bc: Tensor::type() now returns DeprecatedTypeProperties& rather than Type&.
-Added DeprecatedTypeProperties, it serves as a temporary replacement for Type as the return value of Tensor::type(). This contributes to making Type just for dispatch purposes so that we can make it dtype agnostic.
-Tensor::dispatch_type() now returns Type& like Tensor::type() used to do.
-Changed callsites of Tensor::type() appropriately.

Differential Revision: D14443117

Differential Revision: D14443117
Differential Version: 75327518
@facebook-github-bot facebook-github-bot added the oncall: jit Add this issue/PR to JIT oncall triage queue label Mar 13, 2019
royboy added 5 commits March 14, 2019 18:39
Differential Revision: D14443117
Differential Version: 75511212
Differential Revision: D14443117
Differential Version: 75608133
Differential Revision: D14443117
Differential Version: 75660088
Differential Revision: D14443117
Differential Version: 75688678
Differential Revision: D14443117
Differential Version: 77000356
@li-roy li-roy changed the title [wip] Introduce TypeProperties class Introduce TypeProperties class Mar 27, 2019
Differential Revision: D14443117
Differential Version: 77001327
@ezyang ezyang removed the oncall: jit Add this issue/PR to JIT oncall triage queue label Mar 27, 2019
@ezyang
Copy link
Contributor

ezyang commented Mar 27, 2019

Can you remind me again how we are solving the BC problem, where the return type name from type() is no longer Type but TypeProperties now?

return s;
}

C10_DEPRECATED_MESSAGE("passing at::Type to an AT_DISPATCH macro is deprecated, " \
Copy link
Contributor

Choose a reason for hiding this comment

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

The deprecation message isn't even accurate anymore lol


AT_CHECK(values.type().toSparse() == legacyTensorType(*this), "values type must match sparse tensor type");
AT_CHECK(values.device().type() == device().type(), "device type of values (", values.device().type(), ") must match device type of device().type()", device().type(), ")");
AT_CHECK(values.scalar_type() == typeMetaToScalarType(dtype()), "dtype of values (", values.scalar_type(), ") must match dtype of sparse tensor (", typeMetaToScalarType(dtype()), ")");
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand, why don't you just compare dtype here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because the old comparison is comparing Type, which is more than just dtype.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, and that's why you compared device(). But for the second one, why not values.dtype() == dtype()?

mult *= full_size[i];
}
auto indices_mult_cpu = indices.type().cpu()
auto indices_mult_cpu = indices.dispatch_type().cpu()
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have a non Type/TypeProperties replacement for tensorFromBlob? Could this site be replaced with it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not yet.

} else {
Type& cpudouble = tensor_.type().toBackend(Backend::CPU).toScalarType(kDouble);
Tensor tensor = tensor_.toType(cpudouble).contiguous();
Tensor tensor = tensor_.toType(Backend::CPU, kDouble).contiguous();
Copy link
Contributor

Choose a reason for hiding this comment

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

More idiomatic is tensor_.to(kCPU, kDouble)

// serves as a replacement return value for Tensor::type(). Previously,
// Tensor::type() returned Type&, but we are changing Type to not be
// dtype-specific.
class TypeProperties {
Copy link
Contributor

Choose a reason for hiding this comment

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

I can't remember, how much did we bikeshed this name :) cc @gchanan

// dtype-specific.
class TypeProperties {
public:
TypeProperties(Backend backend=Backend::Undefined, ScalarType scalar_type=ScalarType::Undefined)
Copy link
Contributor

Choose a reason for hiding this comment

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

Hot take: we shouldn't make these arguments optional. They should be mandatory, and then we should provide a default constructor that's undefined everything.

return backend_ != Backend::Undefined && scalar_type_ != ScalarType::Undefined;
}

TypeProperties& operator=(const TypeProperties& other) {
Copy link
Contributor

Choose a reason for hiding this comment

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

C++ should be able to infer this definition automatically. No need to specify it.

// Cast index to the longType matching src's backend
// This allows us to support ie indexing a cuda tensor with a cpu tensor
Tensor index = (wrapIndexOnce(indices[i], i, src.size(i)) * strides[i]).toType(longType);
Tensor index = (wrapIndexOnce(indices[i], i, src.size(i)) * strides[i]).toType(kLong);
Copy link
Contributor

Choose a reason for hiding this comment

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

just to(kLong)? :)

result.resize_({});
AT_CHECK(result.scalar_type() == self.scalar_type(),
"result dtype ", result.scalar_type(), " does not match self dtype ", self.scalar_type());
// dispatching through type ensures we don't allow mismatched types.
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment's out of date now? (Or the CHECK above is not needed?)

}
if (reduction == Reduction::Mean) {
auto target_lengths_t = at::tensor(target_lengths, res.options().device(at::Device(at::Device::Type::CPU)).dtype(kLong)).toType(res.type());
auto target_lengths_t = at::tensor(target_lengths, res.options());
Copy link
Contributor

Choose a reason for hiding this comment

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

Err... really? I'd be chuffed if this is semantics preserving, but it doesn't look obviously so to me?

Copy link
Contributor Author

@li-roy li-roy Mar 29, 2019

Choose a reason for hiding this comment

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

yeah it's good, there's a lot of instances of redundant stuff in thsi file.

}
auto* allocator = detail::getCUDAHooks().getPinnedMemoryAllocator();
auto tensor = self.type().tensorWithAllocator(self.sizes(), self.strides(), allocator);
auto tensor = self.dispatch_type().tensorWithAllocator(self.sizes(), self.strides(), allocator);
Copy link
Contributor

Choose a reason for hiding this comment

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

Another one where it would be nice to stop using the factory function on type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can't be done yet, but in the future :)

// targets [int64]: batch_size x target_length OR sum(target_lengths)
CheckedFrom c = "ctc_loss_gpu";
using target_t = typename std::conditional<target_scalar_type == kInt, int, int64_t>::type;
auto targets = targets_.toType(log_probs.type().toScalarType(target_scalar_type)); // to log_probs cuda if it isn't there already
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you sure?!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, this is the reason for the weird test I changed (that you commented on).

auto target_lengths_t = at::tensor(target_lengths, targets.options().dtype(kLong));
auto input_lengths_t = at::tensor(input_lengths, targets.options().dtype(kLong));
tg_batch_offsets = tg_batch_offsets.toType(targets.type().toScalarType(kLong));
tg_batch_offsets = tg_batch_offsets.toBackend(Backend::CUDA);
Copy link
Contributor

Choose a reason for hiding this comment

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

Just to(kCUDA) then? Or even just tg_batch_offsets.cuda()

target_lengths = [60, 25, 20]
input_lengths = [50, 50, 50]
targets = torch.randint(1, 15, (sum(target_lengths),), dtype=torch.int)
targets = torch.randint(1, 15, (sum(target_lengths),), dtype=torch.int, device='cuda')
Copy link
Contributor

Choose a reason for hiding this comment

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

Wow, how did this ever work?!

if (x_.type() != self.type()) {
throw TypeError("map2_: expected %s for argument 'x' (got %s)",
self.type().toString(), x_.type().toString());
self.type().toString().c_str(), x_.type().toString().c_str());
Copy link
Contributor

Choose a reason for hiding this comment

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

you're a lucky man, temporary lifetime extends for the entirety of the expression lol

Differential Revision: D14443117
Differential Version: 77388718
@gchanan
Copy link
Contributor

gchanan commented Mar 29, 2019

What was the resolution on the BC issue?

Perhaps if we want to do BC here, we should actually do BC? And rename the internal thing instead? (It seems correct to call the thing DeprecatedTypeProperties in code but we should alias Type to it so we don't break people, and rename the current Type to something else).

@li-roy
Copy link
Contributor Author

li-roy commented Mar 30, 2019

Will that help? It still won't return a reference.

Differential Revision: D14443117
Differential Version: 77464130
@gchanan
Copy link
Contributor

gchanan commented Apr 1, 2019

You can also make it return a reference -- that won't be that difficult, right? You just need a small registration mechanism for which we have a lot of prior art.

royboy added 2 commits April 1, 2019 12:26
Differential Revision: D14443117
Differential Version: 77644959
Differential Revision: D14443117
Differential Version: 77671735
@li-roy
Copy link
Contributor Author

li-roy commented Apr 1, 2019

Okay. I'll change it to return a reference. I'll do the renaming change in another PR because there will be a lot of changes.

@ezyang
Copy link
Contributor

ezyang commented Apr 2, 2019

New changes LGTM. Hope we can kill this soon lol.

royboy added 3 commits April 2, 2019 12:39
Differential Revision: D14443117
Differential Version: 77808612
Differential Revision: D14443117
Differential Version: 77838952
Differential Revision: D14443117
Differential Version: 78000628
@li-roy
Copy link
Contributor Author

li-roy commented Apr 3, 2019

@pytorchbot retest this please

royboy added 4 commits April 3, 2019 14:41
Differential Revision: D14443117
Differential Version: 78016243
Differential Revision: D14443117
Differential Version: 78021893
Differential Revision: D14443117
Differential Version: 78048258
Differential Revision: D14443117
Differential Version: 78065247
@facebook-github-bot
Copy link
Contributor

This pull request has been merged in c705d9e.

zdevito pushed a commit to zdevito/ATen that referenced this pull request Apr 4, 2019
Summary:
Pull Request resolved: pytorch/pytorch#17991

changes:
-Breaks bc: Tensor::type() now returns DeprecatedTypeProperties& rather than Type&.
-Added DeprecatedTypeProperties, it serves as a temporary replacement for Type as the return value of Tensor::type(). This contributes to making Type just for dispatch purposes so that we can make it dtype agnostic.
-Tensor::dispatch_type() now returns Type& like Tensor::type() used to do.
-Changed callsites of Tensor::type() appropriately.

Reviewed By: ezyang

Differential Revision: D14443117

fbshipit-source-id: 239ccb7a09626279a71d1a37f8f82e7f57bf7d9e

// This class specifies a Backend and a ScalarType. Currently, it primarily
// serves as a replacement return value for Tensor::type(). Previously,
// Tensor::type() returned Type&, but we are changing Type to not be
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 this comment is focusing on the wrong thing.

The main point is that type served as two things:

  1. our dispatch mechanism
  2. a 'user-level' API for getting backend/ScalarType and a few other ops

since we want to have freedom to change our dispatch mechanism, we want to keep these separate.

You can then add what you wrote above.

Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW, we only used it as (2) in c10d, since we care about grouping by type etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

module: bc-breaking Related to a BC-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants