We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Ensemble decoding is broken
@flauted 
Ensemble decoding is not tested I think and it is broken on master.
onmt/decoders/ensemble.py", line 133, in load_test_model
    if field is not None and 'vocab' in field.__dict__:
AttributeError: 'list' object has no attribute '__dict__'

To replicate, just run the translate command with the same model twice in argument -model x x

Thanks.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `onmt/decoders/ensemble.py`
Content:
```
1 """
2 Ensemble decoding.
3 
4 Decodes using multiple models simultaneously,
5 combining their prediction distributions by averaging.
6 All models in the ensemble must share a target vocabulary.
7 """
8 
9 import torch
10 import torch.nn as nn
11 
12 from onmt.encoders.encoder import EncoderBase
13 from onmt.models import NMTModel
14 import onmt.model_builder
15 
16 
17 class EnsembleDecoderOutput(object):
18     """ Wrapper around multiple decoder final hidden states """
19     def __init__(self, model_dec_outs):
20         self.model_dec_outs = tuple(model_dec_outs)
21 
22     def squeeze(self, dim=None):
23         """
24         Delegate squeeze to avoid modifying
25         :obj:`Translator.translate_batch()`
26         """
27         return EnsembleDecoderOutput([
28             x.squeeze(dim) for x in self.model_dec_outs])
29 
30     def __getitem__(self, index):
31         return self.model_dec_outs[index]
32 
33 
34 class EnsembleEncoder(EncoderBase):
35     """ Dummy Encoder that delegates to individual real Encoders """
36     def __init__(self, model_encoders):
37         super(EnsembleEncoder, self).__init__()
38         self.model_encoders = nn.ModuleList(model_encoders)
39 
40     def forward(self, src, lengths=None):
41         enc_hidden, memory_bank, _ = zip(*[
42             model_encoder(src, lengths)
43             for model_encoder in self.model_encoders])
44         return enc_hidden, memory_bank, lengths
45 
46 
47 class EnsembleDecoder(nn.Module):
48     """ Dummy Decoder that delegates to individual real Decoders """
49     def __init__(self, model_decoders):
50         super(EnsembleDecoder, self).__init__()
51         self.model_decoders = nn.ModuleList(model_decoders)
52 
53     def forward(self, tgt, memory_bank, memory_lengths=None, step=None):
54         """ See :obj:`RNNDecoderBase.forward()` """
55         # Memory_lengths is a single tensor shared between all models.
56         # This assumption will not hold if Translator is modified
57         # to calculate memory_lengths as something other than the length
58         # of the input.
59         dec_outs, attns = zip(*[
60             model_decoder(
61                 tgt, memory_bank[i], memory_lengths, step=step)
62             for i, model_decoder in enumerate(self.model_decoders)])
63         mean_attns = self.combine_attns(attns)
64         return EnsembleDecoderOutput(dec_outs), mean_attns
65 
66     def combine_attns(self, attns):
67         result = {}
68         for key in attns[0].keys():
69             result[key] = torch.stack([attn[key] for attn in attns]).mean(0)
70         return result
71 
72     def init_state(self, src, memory_bank, enc_hidden):
73         """ See :obj:`RNNDecoderBase.init_state()` """
74         for i, model_decoder in enumerate(self.model_decoders):
75             model_decoder.init_state(src, memory_bank[i], enc_hidden[i])
76 
77     def map_state(self, fn):
78         for model_decoder in self.model_decoders:
79             model_decoder.map_state(fn)
80 
81 
82 class EnsembleGenerator(nn.Module):
83     """
84     Dummy Generator that delegates to individual real Generators,
85     and then averages the resulting target distributions.
86     """
87     def __init__(self, model_generators, raw_probs=False):
88         super(EnsembleGenerator, self).__init__()
89         self.model_generators = nn.ModuleList(model_generators)
90         self._raw_probs = raw_probs
91 
92     def forward(self, hidden, attn=None, src_map=None):
93         """
94         Compute a distribution over the target dictionary
95         by averaging distributions from models in the ensemble.
96         All models in the ensemble must share a target vocabulary.
97         """
98         distributions = torch.stack(
99                 [mg(h) if attn is None else mg(h, attn, src_map)
100                  for h, mg in zip(hidden, self.model_generators)]
101             )
102         if self._raw_probs:
103             return torch.log(torch.exp(distributions).mean(0))
104         else:
105             return distributions.mean(0)
106 
107 
108 class EnsembleModel(NMTModel):
109     """ Dummy NMTModel wrapping individual real NMTModels """
110     def __init__(self, models, raw_probs=False):
111         encoder = EnsembleEncoder(model.encoder for model in models)
112         decoder = EnsembleDecoder(model.decoder for model in models)
113         super(EnsembleModel, self).__init__(encoder, decoder)
114         self.generator = EnsembleGenerator(
115             [model.generator for model in models], raw_probs)
116         self.models = nn.ModuleList(models)
117 
118 
119 def load_test_model(opt):
120     """ Read in multiple models for ensemble """
121     shared_fields = None
122     shared_model_opt = None
123     models = []
124     for model_path in opt.models:
125         fields, model, model_opt = \
126             onmt.model_builder.load_test_model(opt, model_path=model_path)
127         if shared_fields is None:
128             shared_fields = fields
129         else:
130             for key, field in fields.items():
131                 if field is not None and 'vocab' in field.__dict__:
132                     assert field.vocab.stoi == shared_fields[key].vocab.stoi, \
133                         'Ensemble models must use the same preprocessed data'
134         models.append(model)
135         if shared_model_opt is None:
136             shared_model_opt = model_opt
137     ensemble_model = EnsembleModel(models, opt.avg_raw_probs)
138     return shared_fields, ensemble_model, shared_model_opt
139
```
--- 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()

```

diff --git a/onmt/decoders/ensemble.py b/onmt/decoders/ensemble.py
--- a/onmt/decoders/ensemble.py
+++ b/onmt/decoders/ensemble.py
@@ -58,7 +58,8 @@
         # of the input.
         dec_outs, attns = zip(*[
             model_decoder(
-                tgt, memory_bank[i], memory_lengths, step=step)
+                tgt, memory_bank[i],
+                memory_lengths=memory_lengths, step=step)
             for i, model_decoder in enumerate(self.model_decoders)])
         mean_attns = self.combine_attns(attns)
         return EnsembleDecoderOutput(dec_outs), mean_attns
@@ -130,9 +131,25 @@
             shared_fields = fields
         else:
             for key, field in fields.items():
-                if field is not None and 'vocab' in field.__dict__:
-                    assert field.vocab.stoi == shared_fields[key].vocab.stoi, \
-                        'Ensemble models must use the same preprocessed data'
+                assert len(field) == 1
+                n, f = field[0]
+                try:
+                    f_iter = iter(f)
+                except TypeError:
+                    f_iter = [(n, f)]
+                for sn, sf in f_iter:
+                    if sf is not None and 'vocab' in sf.__dict__:
+                        sh_field = shared_fields[key]
+                        assert len(sh_field) == 1
+                        sh_n, sh_f = sh_field[0]
+                        try:
+                            sh_f_iter = iter(sh_f)
+                        except TypeError:
+                            sh_f_iter = [(sh_n, sh_f)]
+                        sh_f_dict = dict(sh_f_iter)
+                        assert sf.vocab.stoi == sh_f_dict[sn].vocab.stoi, \
+                            "Ensemble models must use the same " \
+                            "preprocessed data"
         models.append(model)
         if shared_model_opt is None:
             shared_model_opt = model_opt

{"golden_diff": "diff --git a/onmt/decoders/ensemble.py b/onmt/decoders/ensemble.py\n--- a/onmt/decoders/ensemble.py\n+++ b/onmt/decoders/ensemble.py\n@@ -58,7 +58,8 @@\n         # of the input.\n         dec_outs, attns = zip(*[\n             model_decoder(\n-                tgt, memory_bank[i], memory_lengths, step=step)\n+                tgt, memory_bank[i],\n+                memory_lengths=memory_lengths, step=step)\n             for i, model_decoder in enumerate(self.model_decoders)])\n         mean_attns = self.combine_attns(attns)\n         return EnsembleDecoderOutput(dec_outs), mean_attns\n@@ -130,9 +131,25 @@\n             shared_fields = fields\n         else:\n             for key, field in fields.items():\n-                if field is not None and 'vocab' in field.__dict__:\n-                    assert field.vocab.stoi == shared_fields[key].vocab.stoi, \\\n-                        'Ensemble models must use the same preprocessed data'\n+                assert len(field) == 1\n+                n, f = field[0]\n+                try:\n+                    f_iter = iter(f)\n+                except TypeError:\n+                    f_iter = [(n, f)]\n+                for sn, sf in f_iter:\n+                    if sf is not None and 'vocab' in sf.__dict__:\n+                        sh_field = shared_fields[key]\n+                        assert len(sh_field) == 1\n+                        sh_n, sh_f = sh_field[0]\n+                        try:\n+                            sh_f_iter = iter(sh_f)\n+                        except TypeError:\n+                            sh_f_iter = [(sh_n, sh_f)]\n+                        sh_f_dict = dict(sh_f_iter)\n+                        assert sf.vocab.stoi == sh_f_dict[sn].vocab.stoi, \\\n+                            \"Ensemble models must use the same \" \\\n+                            \"preprocessed data\"\n         models.append(model)\n         if shared_model_opt is None:\n             shared_model_opt = model_opt\n", "issue": "Ensemble decoding is broken\n@flauted \r\nEnsemble decoding is not tested I think and it is broken on master.\r\nonmt/decoders/ensemble.py\", line 133, in load_test_model\r\n    if field is not None and 'vocab' in field.__dict__:\r\nAttributeError: 'list' object has no attribute '__dict__'\r\n\r\nTo replicate, just run the translate command with the same model twice in argument -model x x\r\n\r\nThanks.\n", "before_files": [{"content": "\"\"\"\nEnsemble decoding.\n\nDecodes using multiple models simultaneously,\ncombining their prediction distributions by averaging.\nAll models in the ensemble must share a target vocabulary.\n\"\"\"\n\nimport torch\nimport torch.nn as nn\n\nfrom onmt.encoders.encoder import EncoderBase\nfrom onmt.models import NMTModel\nimport onmt.model_builder\n\n\nclass EnsembleDecoderOutput(object):\n    \"\"\" Wrapper around multiple decoder final hidden states \"\"\"\n    def __init__(self, model_dec_outs):\n        self.model_dec_outs = tuple(model_dec_outs)\n\n    def squeeze(self, dim=None):\n        \"\"\"\n        Delegate squeeze to avoid modifying\n        :obj:`Translator.translate_batch()`\n        \"\"\"\n        return EnsembleDecoderOutput([\n            x.squeeze(dim) for x in self.model_dec_outs])\n\n    def __getitem__(self, index):\n        return self.model_dec_outs[index]\n\n\nclass EnsembleEncoder(EncoderBase):\n    \"\"\" Dummy Encoder that delegates to individual real Encoders \"\"\"\n    def __init__(self, model_encoders):\n        super(EnsembleEncoder, self).__init__()\n        self.model_encoders = nn.ModuleList(model_encoders)\n\n    def forward(self, src, lengths=None):\n        enc_hidden, memory_bank, _ = zip(*[\n            model_encoder(src, lengths)\n            for model_encoder in self.model_encoders])\n        return enc_hidden, memory_bank, lengths\n\n\nclass EnsembleDecoder(nn.Module):\n    \"\"\" Dummy Decoder that delegates to individual real Decoders \"\"\"\n    def __init__(self, model_decoders):\n        super(EnsembleDecoder, self).__init__()\n        self.model_decoders = nn.ModuleList(model_decoders)\n\n    def forward(self, tgt, memory_bank, memory_lengths=None, step=None):\n        \"\"\" See :obj:`RNNDecoderBase.forward()` \"\"\"\n        # Memory_lengths is a single tensor shared between all models.\n        # This assumption will not hold if Translator is modified\n        # to calculate memory_lengths as something other than the length\n        # of the input.\n        dec_outs, attns = zip(*[\n            model_decoder(\n                tgt, memory_bank[i], memory_lengths, step=step)\n            for i, model_decoder in enumerate(self.model_decoders)])\n        mean_attns = self.combine_attns(attns)\n        return EnsembleDecoderOutput(dec_outs), mean_attns\n\n    def combine_attns(self, attns):\n        result = {}\n        for key in attns[0].keys():\n            result[key] = torch.stack([attn[key] for attn in attns]).mean(0)\n        return result\n\n    def init_state(self, src, memory_bank, enc_hidden):\n        \"\"\" See :obj:`RNNDecoderBase.init_state()` \"\"\"\n        for i, model_decoder in enumerate(self.model_decoders):\n            model_decoder.init_state(src, memory_bank[i], enc_hidden[i])\n\n    def map_state(self, fn):\n        for model_decoder in self.model_decoders:\n            model_decoder.map_state(fn)\n\n\nclass EnsembleGenerator(nn.Module):\n    \"\"\"\n    Dummy Generator that delegates to individual real Generators,\n    and then averages the resulting target distributions.\n    \"\"\"\n    def __init__(self, model_generators, raw_probs=False):\n        super(EnsembleGenerator, self).__init__()\n        self.model_generators = nn.ModuleList(model_generators)\n        self._raw_probs = raw_probs\n\n    def forward(self, hidden, attn=None, src_map=None):\n        \"\"\"\n        Compute a distribution over the target dictionary\n        by averaging distributions from models in the ensemble.\n        All models in the ensemble must share a target vocabulary.\n        \"\"\"\n        distributions = torch.stack(\n                [mg(h) if attn is None else mg(h, attn, src_map)\n                 for h, mg in zip(hidden, self.model_generators)]\n            )\n        if self._raw_probs:\n            return torch.log(torch.exp(distributions).mean(0))\n        else:\n            return distributions.mean(0)\n\n\nclass EnsembleModel(NMTModel):\n    \"\"\" Dummy NMTModel wrapping individual real NMTModels \"\"\"\n    def __init__(self, models, raw_probs=False):\n        encoder = EnsembleEncoder(model.encoder for model in models)\n        decoder = EnsembleDecoder(model.decoder for model in models)\n        super(EnsembleModel, self).__init__(encoder, decoder)\n        self.generator = EnsembleGenerator(\n            [model.generator for model in models], raw_probs)\n        self.models = nn.ModuleList(models)\n\n\ndef load_test_model(opt):\n    \"\"\" Read in multiple models for ensemble \"\"\"\n    shared_fields = None\n    shared_model_opt = None\n    models = []\n    for model_path in opt.models:\n        fields, model, model_opt = \\\n            onmt.model_builder.load_test_model(opt, model_path=model_path)\n        if shared_fields is None:\n            shared_fields = fields\n        else:\n            for key, field in fields.items():\n                if field is not None and 'vocab' in field.__dict__:\n                    assert field.vocab.stoi == shared_fields[key].vocab.stoi, \\\n                        'Ensemble models must use the same preprocessed data'\n        models.append(model)\n        if shared_model_opt is None:\n            shared_model_opt = model_opt\n    ensemble_model = EnsembleModel(models, opt.avg_raw_probs)\n    return shared_fields, ensemble_model, shared_model_opt\n", "path": "onmt/decoders/ensemble.py"}], "after_files": [{"content": "\"\"\"\nEnsemble decoding.\n\nDecodes using multiple models simultaneously,\ncombining their prediction distributions by averaging.\nAll models in the ensemble must share a target vocabulary.\n\"\"\"\n\nimport torch\nimport torch.nn as nn\n\nfrom onmt.encoders.encoder import EncoderBase\nfrom onmt.models import NMTModel\nimport onmt.model_builder\n\n\nclass EnsembleDecoderOutput(object):\n    \"\"\" Wrapper around multiple decoder final hidden states \"\"\"\n    def __init__(self, model_dec_outs):\n        self.model_dec_outs = tuple(model_dec_outs)\n\n    def squeeze(self, dim=None):\n        \"\"\"\n        Delegate squeeze to avoid modifying\n        :obj:`Translator.translate_batch()`\n        \"\"\"\n        return EnsembleDecoderOutput([\n            x.squeeze(dim) for x in self.model_dec_outs])\n\n    def __getitem__(self, index):\n        return self.model_dec_outs[index]\n\n\nclass EnsembleEncoder(EncoderBase):\n    \"\"\" Dummy Encoder that delegates to individual real Encoders \"\"\"\n    def __init__(self, model_encoders):\n        super(EnsembleEncoder, self).__init__()\n        self.model_encoders = nn.ModuleList(model_encoders)\n\n    def forward(self, src, lengths=None):\n        enc_hidden, memory_bank, _ = zip(*[\n            model_encoder(src, lengths)\n            for model_encoder in self.model_encoders])\n        return enc_hidden, memory_bank, lengths\n\n\nclass EnsembleDecoder(nn.Module):\n    \"\"\" Dummy Decoder that delegates to individual real Decoders \"\"\"\n    def __init__(self, model_decoders):\n        super(EnsembleDecoder, self).__init__()\n        self.model_decoders = nn.ModuleList(model_decoders)\n\n    def forward(self, tgt, memory_bank, memory_lengths=None, step=None):\n        \"\"\" See :obj:`RNNDecoderBase.forward()` \"\"\"\n        # Memory_lengths is a single tensor shared between all models.\n        # This assumption will not hold if Translator is modified\n        # to calculate memory_lengths as something other than the length\n        # of the input.\n        dec_outs, attns = zip(*[\n            model_decoder(\n                tgt, memory_bank[i],\n                memory_lengths=memory_lengths, step=step)\n            for i, model_decoder in enumerate(self.model_decoders)])\n        mean_attns = self.combine_attns(attns)\n        return EnsembleDecoderOutput(dec_outs), mean_attns\n\n    def combine_attns(self, attns):\n        result = {}\n        for key in attns[0].keys():\n            result[key] = torch.stack([attn[key] for attn in attns]).mean(0)\n        return result\n\n    def init_state(self, src, memory_bank, enc_hidden):\n        \"\"\" See :obj:`RNNDecoderBase.init_state()` \"\"\"\n        for i, model_decoder in enumerate(self.model_decoders):\n            model_decoder.init_state(src, memory_bank[i], enc_hidden[i])\n\n    def map_state(self, fn):\n        for model_decoder in self.model_decoders:\n            model_decoder.map_state(fn)\n\n\nclass EnsembleGenerator(nn.Module):\n    \"\"\"\n    Dummy Generator that delegates to individual real Generators,\n    and then averages the resulting target distributions.\n    \"\"\"\n    def __init__(self, model_generators, raw_probs=False):\n        super(EnsembleGenerator, self).__init__()\n        self.model_generators = nn.ModuleList(model_generators)\n        self._raw_probs = raw_probs\n\n    def forward(self, hidden, attn=None, src_map=None):\n        \"\"\"\n        Compute a distribution over the target dictionary\n        by averaging distributions from models in the ensemble.\n        All models in the ensemble must share a target vocabulary.\n        \"\"\"\n        distributions = torch.stack(\n                [mg(h) if attn is None else mg(h, attn, src_map)\n                 for h, mg in zip(hidden, self.model_generators)]\n            )\n        if self._raw_probs:\n            return torch.log(torch.exp(distributions).mean(0))\n        else:\n            return distributions.mean(0)\n\n\nclass EnsembleModel(NMTModel):\n    \"\"\" Dummy NMTModel wrapping individual real NMTModels \"\"\"\n    def __init__(self, models, raw_probs=False):\n        encoder = EnsembleEncoder(model.encoder for model in models)\n        decoder = EnsembleDecoder(model.decoder for model in models)\n        super(EnsembleModel, self).__init__(encoder, decoder)\n        self.generator = EnsembleGenerator(\n            [model.generator for model in models], raw_probs)\n        self.models = nn.ModuleList(models)\n\n\ndef load_test_model(opt, dummy_opt):\n    \"\"\" Read in multiple models for ensemble \"\"\"\n    shared_fields = None\n    shared_model_opt = None\n    models = []\n    for model_path in opt.models:\n        fields, model, model_opt = \\\n            onmt.model_builder.load_test_model(opt,\n                                               dummy_opt,\n                                               model_path=model_path)\n        if shared_fields is None:\n            shared_fields = fields\n        else:\n            for key, field in fields.items():\n                assert len(field) == 1\n                n, f = field[0]\n                try:\n                    f_iter = iter(f)\n                except TypeError:\n                    f_iter = [(n, f)]\n                for sn, sf in f_iter:\n                    if sf is not None and 'vocab' in sf.__dict__:\n                        sh_field = shared_fields[key]\n                        assert len(sh_field) == 1\n                        sh_n, sh_f = sh_field[0]\n                        try:\n                            sh_f_iter = iter(sh_f)\n                        except TypeError:\n                            sh_f_iter = [(sh_n, sh_f)]\n                        sh_f_dict = dict(sh_f_iter)\n                        assert sf.vocab.stoi == sh_f_dict[sn].vocab.stoi, \\\n                            \"Ensemble models must use the same \" \\\n                            \"preprocessed data\"\n        models.append(model)\n        if shared_model_opt is None:\n            shared_model_opt = model_opt\n    ensemble_model = EnsembleModel(models, opt.avg_raw_probs)\n    return shared_fields, ensemble_model, shared_model_opt\n", "path": "onmt/decoders/ensemble.py"}]}