prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  RuntimeError: Unsupported op descriptor: thnn_batch_norm_forward-5-eps-momentum-training. File a bug report.
  I started getting this with the latest code while using JIT:
  
  RuntimeError: Unsupported op descriptor: thnn_batch_norm_forward-5-eps-momentum-training. File a bug report.
  
  It did not happen 7 days ago and still does not happen if I roll back pytorch to the version I had 7 days ago.  Do you need any simplified test case to fix it?
    
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `tools/jit/gen_jit_dispatch.py`
  Content:
  ```
  1 import os
  2 import argparse
  3 from itertools import count
  4 from ..autograd.utils import CodeTemplate, write
  5 from ..autograd.gen_autograd import load_aten_declarations
  6 
  7 template_path = os.path.join(os.path.dirname(__file__), 'templates')
  8 
  9 ATEN_DISPATCH_H = CodeTemplate.from_file(template_path + '/aten_dispatch.h')
  10 ATEN_DISPATCH_CPP = CodeTemplate.from_file(template_path + '/aten_dispatch.cpp')
  11 
  12 ATTR_METHOD_MAP = {
  13     'int64_t': 'i',
  14     'IntList': 'is',
  15     'Scalar': 't',
  16     'bool': 'i',
  17     'double': 'f',
  18     'std::array<bool,2>': 'is',
  19     'std::array<bool,3>': 'is',
  20 }
  21 
  22 TYPE_CASTS = {
  23     'std::array<bool,2>': 'as_bool_array<2>',
  24     'std::array<bool,3>': 'as_bool_array<3>',
  25     'Scalar': 'Scalar',
  26     'IntList': 'std::vector<int64_t>',
  27 }
  28 
  29 ATTR_ASSIGNMENT = CodeTemplate("""\
  30 auto ${name} = ${type_cast}(node->${method}(stringToSymbol("${name}")));\
  31 """)
  32 
  33 CALL_NAMESPACE = CodeTemplate("at::${name}(${args})")
  34 CALL_METHOD = CodeTemplate("TensorTemporary(inputs[0]).value().${name}(${args})")
  35 
  36 CONSTRUCTOR = CodeTemplate("""\
  37 {"${descriptor}", [](Node *node) {
  38   ${assignments}
  39   return TensorOp([=](const list_of_retainable & inputs,
  40                       list_of_retainable & outputs) {
  41     autograd::profiler::RecordFunction record("${name}");
  42     AutoGPU device_guard(deviceForInputs(inputs));
  43     pack_list(outputs, ${call});
  44   }, "${name}", ${num_inputs});
  45 }},
  46 """)
  47 
  48 
  49 def is_jit_op(decl):
  50     return (not decl['api_name'].endswith('_') and
  51             not decl['name'].endswith('_out') and
  52             not decl['name'].endswith('_forward') and
  53             not any(arg['simple_type'] == 'Generator' for arg in decl['arguments']) and
  54             not any(arg['simple_type'] == 'SparseTensor' for arg in decl['arguments']) and
  55             not any(arg['simple_type'] == 'Storage' for arg in decl['arguments']) and
  56             any(arg['simple_type'] in {'Tensor', 'TensorList'} for arg in decl['arguments']) and
  57             'Tensor' in decl['return_type'])
  58 
  59 
  60 def gen_jit_dispatch(declarations, out):
  61     aten_decls = load_aten_declarations(declarations)
  62     jit_decls = [d for d in aten_decls if is_jit_op(d)]
  63 
  64     def is_tensor_arg(arg):
  65         return arg['simple_type'] in {'Tensor', 'TensorList'}
  66 
  67     ops = {}
  68     for decl in jit_decls:
  69         arguments = decl['arguments']
  70         name = decl['name']
  71         scalar_args = [arg for arg in arguments if not is_tensor_arg(arg)]
  72         has_tensorlist = any(arg['simple_type'] == 'TensorList' for arg in arguments)
  73 
  74         # Descriptor is a unique identified for a particular overload of an op
  75         attr_names = sorted([arg['name'] for arg in scalar_args])
  76         num_inputs = len(arguments) - len(scalar_args) if not has_tensorlist else "*"
  77         descriptor = '-'.join([decl['name'], str(num_inputs)] + attr_names)
  78 
  79         # All scalar args need to be assigned, so they can be captured by a lambda
  80         assignments = [ATTR_ASSIGNMENT.substitute(type=arg['simple_type'],
  81                                                   type_cast=TYPE_CASTS.get(arg['simple_type'], arg['simple_type']),
  82                                                   name=arg['name'],
  83                                                   method=ATTR_METHOD_MAP[arg['simple_type']])
  84                        for arg in scalar_args]
  85 
  86         # Generate the actuall ATen call. This gets a bit tricky because of
  87         # TensorList arguments, and functions that are only available as methods.
  88         if 'namespace' in decl['method_of']:
  89             if has_tensorlist:
  90                 if sum(map(is_tensor_arg, arguments)) != 1:
  91                     # TODO: support this
  92                     continue
  93                 args = ['TensorTemporaryList(inputs)' if is_tensor_arg(arg) else arg['name']
  94                         for arg in arguments]
  95             else:
  96                 tensor_id = iter(count(start=0))
  97                 args = ['TensorTemporary(inputs[{}]).value()'.format(
  98                     next(tensor_id)) if is_tensor_arg(arg) else arg['name']
  99                     for arg in arguments]
  100             call = CALL_NAMESPACE.substitute(name=name, args=args)
  101         else:
  102             tensor_id = iter(count(start=1))
  103             args = ['TensorTemporary(inputs[{}]).value()'.format(next(tensor_id)) if is_tensor_arg(arg) else arg['name']
  104                     for arg in arguments[1:]]
  105             call = CALL_METHOD.substitute(name=name, args=args)
  106 
  107         constructor = CONSTRUCTOR.substitute(descriptor=descriptor, name=name, call=call,
  108                                              assignments=assignments,
  109                                              # num_inputs is only used in AutogradClosure, which
  110                                              # is going to be removed soon anyway. There's no good value
  111                                              # we can provide for cat.
  112                                              num_inputs=num_inputs if num_inputs != "*" else 0)
  113         assert descriptor not in ops, descriptor
  114         ops[descriptor] = constructor
  115 
  116     # Sort the generated snippets to ensure that the generation is deterministic
  117     env = {'constructors': sorted(list(ops.values()))}
  118     write(out, 'aten_dispatch.h', ATEN_DISPATCH_H, env)
  119     write(out, 'aten_dispatch.cpp', ATEN_DISPATCH_CPP, env)
  120 
  121 
  122 def main():
  123     parser = argparse.ArgumentParser(
  124         description='Generate JIT op dispatch')
  125     parser.add_argument('declarations', metavar='DECL',
  126                         help='path to Declarations.yaml')
  127     parser.add_argument('out', metavar='OUT',
  128                         help='path to output directory')
  129     args = parser.parse_args()
  130     gen_jit_dispatch(args.declarations, args.out)
  131 
  132 
  133 if __name__ == '__main__':
  134     main()
  135
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/tools/jit/gen_jit_dispatch.py b/tools/jit/gen_jit_dispatch.py
  --- a/tools/jit/gen_jit_dispatch.py
  +++ b/tools/jit/gen_jit_dispatch.py
  @@ -49,7 +49,6 @@
   def is_jit_op(decl):
       return (not decl['api_name'].endswith('_') and
               not decl['name'].endswith('_out') and
  -            not decl['name'].endswith('_forward') and
               not any(arg['simple_type'] == 'Generator' for arg in decl['arguments']) and
               not any(arg['simple_type'] == 'SparseTensor' for arg in decl['arguments']) and
               not any(arg['simple_type'] == 'Storage' for arg in decl['arguments']) and
  
verification_info: {"golden_diff": "diff --git a/tools/jit/gen_jit_dispatch.py b/tools/jit/gen_jit_dispatch.py\n--- a/tools/jit/gen_jit_dispatch.py\n+++ b/tools/jit/gen_jit_dispatch.py\n@@ -49,7 +49,6 @@\n def is_jit_op(decl):\n     return (not decl['api_name'].endswith('_') and\n             not decl['name'].endswith('_out') and\n-            not decl['name'].endswith('_forward') and\n             not any(arg['simple_type'] == 'Generator' for arg in decl['arguments']) and\n             not any(arg['simple_type'] == 'SparseTensor' for arg in decl['arguments']) and\n             not any(arg['simple_type'] == 'Storage' for arg in decl['arguments']) and\n", "issue": "RuntimeError: Unsupported op descriptor: thnn_batch_norm_forward-5-eps-momentum-training. File a bug report.\nI started getting this with the latest code while using JIT:\r\n\r\nRuntimeError: Unsupported op descriptor: thnn_batch_norm_forward-5-eps-momentum-training. File a bug report.\r\n\r\nIt did not happen 7 days ago and still does not happen if I roll back pytorch to the version I had 7 days ago.  Do you need any simplified test case to fix it?\r\n  \n", "before_files": [{"content": "import os\nimport argparse\nfrom itertools import count\nfrom ..autograd.utils import CodeTemplate, write\nfrom ..autograd.gen_autograd import load_aten_declarations\n\ntemplate_path = os.path.join(os.path.dirname(__file__), 'templates')\n\nATEN_DISPATCH_H = CodeTemplate.from_file(template_path + '/aten_dispatch.h')\nATEN_DISPATCH_CPP = CodeTemplate.from_file(template_path + '/aten_dispatch.cpp')\n\nATTR_METHOD_MAP = {\n    'int64_t': 'i',\n    'IntList': 'is',\n    'Scalar': 't',\n    'bool': 'i',\n    'double': 'f',\n    'std::array<bool,2>': 'is',\n    'std::array<bool,3>': 'is',\n}\n\nTYPE_CASTS = {\n    'std::array<bool,2>': 'as_bool_array<2>',\n    'std::array<bool,3>': 'as_bool_array<3>',\n    'Scalar': 'Scalar',\n    'IntList': 'std::vector<int64_t>',\n}\n\nATTR_ASSIGNMENT = CodeTemplate(\"\"\"\\\nauto ${name} = ${type_cast}(node->${method}(stringToSymbol(\"${name}\")));\\\n\"\"\")\n\nCALL_NAMESPACE = CodeTemplate(\"at::${name}(${args})\")\nCALL_METHOD = CodeTemplate(\"TensorTemporary(inputs[0]).value().${name}(${args})\")\n\nCONSTRUCTOR = CodeTemplate(\"\"\"\\\n{\"${descriptor}\", [](Node *node) {\n  ${assignments}\n  return TensorOp([=](const list_of_retainable & inputs,\n                      list_of_retainable & outputs) {\n    autograd::profiler::RecordFunction record(\"${name}\");\n    AutoGPU device_guard(deviceForInputs(inputs));\n    pack_list(outputs, ${call});\n  }, \"${name}\", ${num_inputs});\n}},\n\"\"\")\n\n\ndef is_jit_op(decl):\n    return (not decl['api_name'].endswith('_') and\n            not decl['name'].endswith('_out') and\n            not decl['name'].endswith('_forward') and\n            not any(arg['simple_type'] == 'Generator' for arg in decl['arguments']) and\n            not any(arg['simple_type'] == 'SparseTensor' for arg in decl['arguments']) and\n            not any(arg['simple_type'] == 'Storage' for arg in decl['arguments']) and\n            any(arg['simple_type'] in {'Tensor', 'TensorList'} for arg in decl['arguments']) and\n            'Tensor' in decl['return_type'])\n\n\ndef gen_jit_dispatch(declarations, out):\n    aten_decls = load_aten_declarations(declarations)\n    jit_decls = [d for d in aten_decls if is_jit_op(d)]\n\n    def is_tensor_arg(arg):\n        return arg['simple_type'] in {'Tensor', 'TensorList'}\n\n    ops = {}\n    for decl in jit_decls:\n        arguments = decl['arguments']\n        name = decl['name']\n        scalar_args = [arg for arg in arguments if not is_tensor_arg(arg)]\n        has_tensorlist = any(arg['simple_type'] == 'TensorList' for arg in arguments)\n\n        # Descriptor is a unique identified for a particular overload of an op\n        attr_names = sorted([arg['name'] for arg in scalar_args])\n        num_inputs = len(arguments) - len(scalar_args) if not has_tensorlist else \"*\"\n        descriptor = '-'.join([decl['name'], str(num_inputs)] + attr_names)\n\n        # All scalar args need to be assigned, so they can be captured by a lambda\n        assignments = [ATTR_ASSIGNMENT.substitute(type=arg['simple_type'],\n                                                  type_cast=TYPE_CASTS.get(arg['simple_type'], arg['simple_type']),\n                                                  name=arg['name'],\n                                                  method=ATTR_METHOD_MAP[arg['simple_type']])\n                       for arg in scalar_args]\n\n        # Generate the actuall ATen call. This gets a bit tricky because of\n        # TensorList arguments, and functions that are only available as methods.\n        if 'namespace' in decl['method_of']:\n            if has_tensorlist:\n                if sum(map(is_tensor_arg, arguments)) != 1:\n                    # TODO: support this\n                    continue\n                args = ['TensorTemporaryList(inputs)' if is_tensor_arg(arg) else arg['name']\n                        for arg in arguments]\n            else:\n                tensor_id = iter(count(start=0))\n                args = ['TensorTemporary(inputs[{}]).value()'.format(\n                    next(tensor_id)) if is_tensor_arg(arg) else arg['name']\n                    for arg in arguments]\n            call = CALL_NAMESPACE.substitute(name=name, args=args)\n        else:\n            tensor_id = iter(count(start=1))\n            args = ['TensorTemporary(inputs[{}]).value()'.format(next(tensor_id)) if is_tensor_arg(arg) else arg['name']\n                    for arg in arguments[1:]]\n            call = CALL_METHOD.substitute(name=name, args=args)\n\n        constructor = CONSTRUCTOR.substitute(descriptor=descriptor, name=name, call=call,\n                                             assignments=assignments,\n                                             # num_inputs is only used in AutogradClosure, which\n                                             # is going to be removed soon anyway. There's no good value\n                                             # we can provide for cat.\n                                             num_inputs=num_inputs if num_inputs != \"*\" else 0)\n        assert descriptor not in ops, descriptor\n        ops[descriptor] = constructor\n\n    # Sort the generated snippets to ensure that the generation is deterministic\n    env = {'constructors': sorted(list(ops.values()))}\n    write(out, 'aten_dispatch.h', ATEN_DISPATCH_H, env)\n    write(out, 'aten_dispatch.cpp', ATEN_DISPATCH_CPP, env)\n\n\ndef main():\n    parser = argparse.ArgumentParser(\n        description='Generate JIT op dispatch')\n    parser.add_argument('declarations', metavar='DECL',\n                        help='path to Declarations.yaml')\n    parser.add_argument('out', metavar='OUT',\n                        help='path to output directory')\n    args = parser.parse_args()\n    gen_jit_dispatch(args.declarations, args.out)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "tools/jit/gen_jit_dispatch.py"}], "after_files": [{"content": "import os\nimport argparse\nfrom itertools import count\nfrom ..autograd.utils import CodeTemplate, write\nfrom ..autograd.gen_autograd import load_aten_declarations\n\ntemplate_path = os.path.join(os.path.dirname(__file__), 'templates')\n\nATEN_DISPATCH_H = CodeTemplate.from_file(template_path + '/aten_dispatch.h')\nATEN_DISPATCH_CPP = CodeTemplate.from_file(template_path + '/aten_dispatch.cpp')\n\nATTR_METHOD_MAP = {\n    'int64_t': 'i',\n    'IntList': 'is',\n    'Scalar': 't',\n    'bool': 'i',\n    'double': 'f',\n    'std::array<bool,2>': 'is',\n    'std::array<bool,3>': 'is',\n}\n\nTYPE_CASTS = {\n    'std::array<bool,2>': 'as_bool_array<2>',\n    'std::array<bool,3>': 'as_bool_array<3>',\n    'Scalar': 'Scalar',\n    'IntList': 'std::vector<int64_t>',\n}\n\nATTR_ASSIGNMENT = CodeTemplate(\"\"\"\\\nauto ${name} = ${type_cast}(node->${method}(stringToSymbol(\"${name}\")));\\\n\"\"\")\n\nCALL_NAMESPACE = CodeTemplate(\"at::${name}(${args})\")\nCALL_METHOD = CodeTemplate(\"TensorTemporary(inputs[0]).value().${name}(${args})\")\n\nCONSTRUCTOR = CodeTemplate(\"\"\"\\\n{\"${descriptor}\", [](Node *node) {\n  ${assignments}\n  return TensorOp([=](const list_of_retainable & inputs,\n                      list_of_retainable & outputs) {\n    autograd::profiler::RecordFunction record(\"${name}\");\n    AutoGPU device_guard(deviceForInputs(inputs));\n    pack_list(outputs, ${call});\n  }, \"${name}\", ${num_inputs});\n}},\n\"\"\")\n\n\ndef is_jit_op(decl):\n    return (not decl['api_name'].endswith('_') and\n            not decl['name'].endswith('_out') and\n            not any(arg['simple_type'] == 'Generator' for arg in decl['arguments']) and\n            not any(arg['simple_type'] == 'SparseTensor' for arg in decl['arguments']) and\n            not any(arg['simple_type'] == 'Storage' for arg in decl['arguments']) and\n            any(arg['simple_type'] in {'Tensor', 'TensorList'} for arg in decl['arguments']) and\n            'Tensor' in decl['return_type'])\n\n\ndef gen_jit_dispatch(declarations, out):\n    aten_decls = load_aten_declarations(declarations)\n    jit_decls = [d for d in aten_decls if is_jit_op(d)]\n\n    def is_tensor_arg(arg):\n        return arg['simple_type'] in {'Tensor', 'TensorList'}\n\n    ops = {}\n    for decl in jit_decls:\n        arguments = decl['arguments']\n        name = decl['name']\n        scalar_args = [arg for arg in arguments if not is_tensor_arg(arg)]\n        has_tensorlist = any(arg['simple_type'] == 'TensorList' for arg in arguments)\n\n        # Descriptor is a unique identified for a particular overload of an op\n        attr_names = sorted([arg['name'] for arg in scalar_args])\n        num_inputs = len(arguments) - len(scalar_args) if not has_tensorlist else \"*\"\n        descriptor = '-'.join([decl['name'], str(num_inputs)] + attr_names)\n\n        # All scalar args need to be assigned, so they can be captured by a lambda\n        assignments = [ATTR_ASSIGNMENT.substitute(type=arg['simple_type'],\n                                                  type_cast=TYPE_CASTS.get(arg['simple_type'], arg['simple_type']),\n                                                  name=arg['name'],\n                                                  method=ATTR_METHOD_MAP[arg['simple_type']])\n                       for arg in scalar_args]\n\n        # Generate the actuall ATen call. This gets a bit tricky because of\n        # TensorList arguments, and functions that are only available as methods.\n        if 'namespace' in decl['method_of']:\n            if has_tensorlist:\n                if sum(map(is_tensor_arg, arguments)) != 1:\n                    # TODO: support this\n                    continue\n                args = ['TensorTemporaryList(inputs)' if is_tensor_arg(arg) else arg['name']\n                        for arg in arguments]\n            else:\n                tensor_id = iter(count(start=0))\n                args = ['TensorTemporary(inputs[{}]).value()'.format(\n                    next(tensor_id)) if is_tensor_arg(arg) else arg['name']\n                    for arg in arguments]\n            call = CALL_NAMESPACE.substitute(name=name, args=args)\n        else:\n            tensor_id = iter(count(start=1))\n            args = ['TensorTemporary(inputs[{}]).value()'.format(next(tensor_id)) if is_tensor_arg(arg) else arg['name']\n                    for arg in arguments[1:]]\n            call = CALL_METHOD.substitute(name=name, args=args)\n\n        constructor = CONSTRUCTOR.substitute(descriptor=descriptor, name=name, call=call,\n                                             assignments=assignments,\n                                             # num_inputs is only used in AutogradClosure, which\n                                             # is going to be removed soon anyway. There's no good value\n                                             # we can provide for cat.\n                                             num_inputs=num_inputs if num_inputs != \"*\" else 0)\n        assert descriptor not in ops, descriptor\n        ops[descriptor] = constructor\n\n    # Sort the generated snippets to ensure that the generation is deterministic\n    env = {'constructors': sorted(list(ops.values()))}\n    write(out, 'aten_dispatch.h', ATEN_DISPATCH_H, env)\n    write(out, 'aten_dispatch.cpp', ATEN_DISPATCH_CPP, env)\n\n\ndef main():\n    parser = argparse.ArgumentParser(\n        description='Generate JIT op dispatch')\n    parser.add_argument('declarations', metavar='DECL',\n                        help='path to Declarations.yaml')\n    parser.add_argument('out', metavar='OUT',\n                        help='path to output directory')\n    args = parser.parse_args()\n    gen_jit_dispatch(args.declarations, args.out)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "tools/jit/gen_jit_dispatch.py"}]}