3 #include <ATen/core/ivalue.h> 4 #include <ATen/core/jit_type.h> 5 #include <ATen/core/stack.h> 6 #include <torch/csrc/Device.h> 7 #include <torch/csrc/jit/operator.h> 8 #include <torch/csrc/jit/script/module.h> 9 #include <torch/csrc/utils/auto_gil.h> 10 #include <torch/csrc/utils/pybind.h> 11 #include <torch/csrc/utils/six.h> 13 #include <ATen/core/function_schema.h> 14 #include <c10/util/Exception.h> 25 #define VISIBILITY_HIDDEN 27 #define VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) 34 using ::c10::Argument;
35 using ::c10::FunctionSchema;
42 inline void findErrorInKwargs(
const FunctionSchema& schema, py::kwargs kwargs) {
43 const auto& arguments = schema.arguments();
46 for (
const auto& kwarg : kwargs) {
47 const auto key = py::cast<std::string>(kwarg.first);
51 [&key](
const Argument& argument) {
52 return argument.name() == key;
54 throw std::runtime_error(c10::str(
55 "Unknown keyword argument '",
65 for (
const auto& argument : arguments) {
66 if (kwargs.contains(argument.name().c_str())) {
67 AT_ASSERT(!argument.default_value());
68 throw std::runtime_error(c10::str(
71 "' specified both as positional and ",
72 "keyword argument. Schema: ",
79 inline IValue toIValue(py::handle input) {
80 if (THPVariable_Check(input.ptr())) {
81 auto ten = py::cast<at::Tensor>(input);
82 if (ten.is_sparse()) {
83 AT_ERROR(
"sparse tensors not supported");
86 }
else if (six::isTuple(input)) {
87 py::tuple input_tuple = py::cast<py::tuple>(input);
89 s.reserve(input_tuple.size());
90 for (py::handle elem : input_tuple) {
91 s.push_back(toIValue(elem));
93 return Tuple::create(s);
96 "Only tensors and (possibly nested) tuples of tensors are supported " 97 "as inputs or outputs of traced functions");
101 inline Stack toStack(
const py::tuple& inputs) {
102 return toIValue(inputs).toTuple()->elements();
105 inline IValue toIValue(
110 inline IValue createGenericList(py::handle obj,
const TypePtr& elem_type) {
111 std::vector<IValue> elems;
112 for (
auto elem : obj) {
113 elems.push_back(toIValue(elem, elem_type));
115 return List<IValue>::create(std::move(elems));
118 inline IValue createGenericDict(
120 const TypePtr& key_type,
121 const TypePtr& value_type) {
122 at::ivalue::UnorderedMap elems;
123 elems.reserve(py::len(obj));
124 for (
auto key : obj) {
125 elems.insert(std::make_pair(
126 toIValue(key, key_type), toIValue(obj[key], value_type)));
128 return at::ivalue::GenericDict::create(std::move(elems));
131 inline IValue toIValue(
135 switch (type->kind()) {
136 case TypeKind::TensorType:
137 case TypeKind::AutogradZeroTensorType:
138 case TypeKind::DimensionedTensorType:
139 case TypeKind::CompleteTensorType: {
140 auto var = py::cast<autograd::Variable>(obj);
141 if (var.is_sparse()) {
142 AT_ERROR(
"sparse tensors not supported");
146 case TypeKind::FloatType:
147 return py::cast<double>(obj);
148 case TypeKind::IntType:
149 return py::cast<int64_t>(obj);
150 case TypeKind::NoneType:
152 throw py::cast_error();
155 case TypeKind::BoolType:
156 return py::cast<bool>(obj);
157 case TypeKind::TupleType: {
158 if (!PyTuple_Check(obj.ptr()))
159 throw py::cast_error();
161 py::tuple tuple = py::cast<py::tuple>(obj);
162 size_t tuple_size = tuple.size();
163 const auto& elem_types = type->cast<TupleType>()->elements();
164 if (elem_types.size() != tuple_size) {
165 throw py::cast_error();
167 std::vector<IValue> values;
168 values.reserve(tuple_size);
169 for (
size_t i = 0; i < tuple_size; ++i) {
170 values.push_back(toIValue(tuple[i], elem_types[i]));
172 return Tuple::create(std::move(values));
174 case TypeKind::StringType:
175 return ConstantString::create(py::cast<std::string>(obj));
176 case TypeKind::DeviceObjType: {
177 auto device =
reinterpret_cast<THPDevice*
>(obj.ptr());
178 return device->device;
180 case TypeKind::ListType: {
181 const auto& elem_type = type->expect<ListType>()->getElementType();
182 switch (elem_type->kind()) {
184 case TypeKind::IntType:
185 if (!N || !py::isinstance<py::int_>(obj)) {
186 return py::cast<std::vector<int64_t>>(obj);
188 double value = py::cast<int64_t>(obj);
189 std::vector<double> repeated(*N, value);
192 case TypeKind::FloatType:
193 if (!N || !py::isinstance<py::float_>(obj)) {
194 return py::cast<std::vector<double>>(obj);
196 double value = py::cast<double>(obj);
197 std::vector<double> repeated(*N, value);
200 case TypeKind::DimensionedTensorType:
201 case TypeKind::TensorType:
202 return py::cast<std::vector<at::Tensor>>(obj);
204 return createGenericList(obj, elem_type);
207 case TypeKind::DictType: {
208 const auto& dict_type = type->expect<DictType>();
209 return createGenericDict(
210 obj, dict_type->getKeyType(), dict_type->getValueType());
212 case TypeKind::OptionalType: {
214 if (obj == Py_None) {
219 return toIValue(obj, type->expect<OptionalType>()->getElementType());
221 case TypeKind::NumberType:
222 case TypeKind::GeneratorType:
223 case TypeKind::VarType:
224 case TypeKind::FutureType:
225 case TypeKind::ClassType:
229 "Missing cases in toIValue for type: ",
231 "! File a bug report.");
234 inline IValue argumentToIValue(
235 const FunctionSchema& schema,
236 size_t argumentPosition,
238 const auto& argument = schema.arguments().at(argumentPosition);
240 return toIValue(
object, argument.type(), argument.N());
241 }
catch (
const py::cast_error& error) {
242 throw std::runtime_error(c10::str(
244 "() expected value of type ",
245 argument.type()->str(),
250 ", but instead got value of type ",
251 py::str(
object.get_type().attr(
"__name__")),
260 inline IValue returnToIValue(
const TypePtr& type, py::handle
object) {
262 return toIValue(
object, type);
263 }
catch (
const py::cast_error& error) {
264 throw std::runtime_error(c10::str(
265 " expected value of type ",
267 " for return value but instead got value of type ",
268 py::str(
object.get_type().attr(
"__name__")),
275 inline py::object toPyObject(IValue&& ivalue) {
276 if (ivalue.isNone()) {
278 }
else if (ivalue.isTensor()) {
279 auto tensor = std::move(ivalue).toTensor();
280 if (tensor.is_sparse()) {
281 AT_ERROR(
"sparse tensors not supported");
283 return py::cast(autograd::Variable(std::move(tensor)));
284 }
else if (ivalue.isDouble()) {
285 return py::cast(ivalue.toDouble());
286 }
else if (ivalue.isInt()) {
287 return py::cast(ivalue.toInt());
288 }
else if (ivalue.isBool()) {
289 return py::cast(ivalue.toBool());
290 }
else if (ivalue.isString()) {
291 return py::cast(ivalue.toStringRef());
292 }
else if (ivalue.isIntList()) {
293 return py::cast(ivalue.toIntListRef());
294 }
else if (ivalue.isDoubleList()) {
295 return py::cast(ivalue.toDoubleListRef());
296 }
else if (ivalue.isBoolList()) {
297 return py::cast(ivalue.toBoolListRef());
298 }
else if (ivalue.isTensorList()) {
299 return py::cast(ivalue.toTensorListRef());
300 }
else if (ivalue.isGenericList()) {
301 auto list = ivalue.toGenericList();
302 const auto& elements = list->elements();
303 py::list t{elements.size()};
304 for (
size_t i = 0; i < elements.size(); ++i) {
305 t[i] = toPyObject(IValue{elements[i]});
308 }
else if (ivalue.isTuple()) {
309 auto tuple = ivalue.toTuple();
310 const auto& elements = tuple->elements();
311 py::tuple t{elements.size()};
312 for (
size_t i = 0; i < elements.size(); ++i) {
313 t[i] = toPyObject(IValue{elements[i]});
316 }
else if (ivalue.isDevice()) {
317 return py::cast<py::object>(THPDevice_New(ivalue.toDevice()));
318 }
else if (ivalue.isGenericDict()) {
319 auto dict = ivalue.toGenericDict();
320 const auto& elements = dict->elements();
322 for (
auto pair : elements) {
323 py_dict[toPyObject(IValue{pair.first})] = toPyObject(IValue{pair.second});
325 return std::move(py_dict);
327 AT_ERROR(
"Missing cases in 'toPyObject'! File a bug report.");
333 : tup(std::move(tup_)), b(0), e(tup.size()) {}
334 tuple_slice(py::tuple tup_, int64_t b_)
335 : tup(std::move(tup_)), b(b_), e(tup.size()) {}
336 tuple_slice(py::tuple tup_, int64_t b_, int64_t e_)
337 : tup(std::move(tup_)), b(b_), e(e_) {}
338 py::detail::tuple_iterator begin()
const {
339 return {tup,
static_cast<pybind11::ssize_t
>(b)};
341 py::detail::tuple_iterator end()
const {
342 return {tup,
static_cast<pybind11::ssize_t
>(e)};
344 size_t size()
const {
347 py::detail::tuple_accessor operator[](
size_t index)
const {
348 return {tup,
static_cast<size_t>(b + index)};
357 inline Stack createStackForSchema(
360 const py::kwargs& kwargs = py::kwargs()) {
361 if (args.size() + kwargs.size() > schema.arguments().size()) {
362 throw std::runtime_error(c10::str(
364 "() expected at most ",
365 schema.arguments().size(),
366 " argument(s) but received ",
367 args.size() + kwargs.size(),
368 " argument(s). Declaration: ",
372 stack.reserve(schema.arguments().size());
375 for (
size_t i = 0; i < args.size(); ++i) {
377 push(stack, argumentToIValue(schema, i, args[i]));
383 size_t consumed_kwargs = 0;
384 for (
size_t i = args.size(); i < schema.arguments().size(); ++i) {
385 const auto& arg = schema.arguments()[i];
386 if (kwargs.contains(arg.name().c_str())) {
387 push(stack, argumentToIValue(schema, i, kwargs[arg.name().c_str()]));
388 consumed_kwargs += 1;
389 }
else if (arg.default_value()) {
390 push(stack, *arg.default_value());
392 throw std::runtime_error(c10::str(
394 "() is missing value for argument '",
401 if (consumed_kwargs != kwargs.size()) {
402 detail::findErrorInKwargs(schema, kwargs);
408 inline py::object createPyObjectForStack(Stack&& stack) {
415 if (stack.size() == 1) {
416 return toPyObject(std::move(stack[0]));
420 py::tuple return_values(stack.size());
421 for (
size_t ret = 0; ret < return_values.size(); ++ret) {
422 return_values[ret] = toPyObject(std::move(stack[ret]));
425 return std::move(return_values);
429 inline Stack evilDeprecatedBadCreateStackDoNotUse(
430 const py::tuple& tuple,
432 size_t reserve_extra_space = 0) {
433 if (tuple.size() != inputs.
size()) {
435 "expected " + std::to_string(inputs.
size()) +
" inputs, but got " +
436 std::to_string(tuple.size()));
439 result.reserve(tuple.size() + reserve_extra_space);
440 for (
size_t i = 0; i < inputs.
size(); ++i) {
441 result.push_back(toIValue(std::move(tuple[i]), inputs[i]->type()));
446 inline py::object invokeScriptMethodFromPython(
450 auto stack = createStackForSchema(
451 method.getSchema(), std::move(args), std::move(kwargs));
456 return toPyObject(std::move(stack.back()));
459 inline py::object invokeOperatorFromPython(
465 createStackForSchema(op.schema(), std::move(args), std::move(kwargs));
468 op.getOperation()(stack);
470 return createPyObjectForStack(std::move(stack));
constexpr size_t size() const
size - Get the array size.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...