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)...