We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
explain command cannot find the model 
When I try to infer an image with a model included in the project using the command 'explain', I get the error : 
**AttributeError: 'Tree' object has no attribute 'models'**

However, when I check the project info I see that the model is successfully added to the project, and the model can also produce annotations with 'model run' command 

Any help will be appreciated.
![Screenshot from 2022-07-28 11-34-46](https://user-images.githubusercontent.com/110161019/181460641-5c25f77e-f7fb-4347-9ab3-efc14f912b03.png)
 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `datumaro/cli/commands/explain.py`
Content:
```
1 # Copyright (C) 2019-2021 Intel Corporation
2 #
3 # SPDX-License-Identifier: MIT
4 
5 import argparse
6 import logging as log
7 import os
8 import os.path as osp
9 
10 from datumaro.util.image import is_image, load_image, save_image
11 from datumaro.util.scope import scope_add, scoped
12 
13 from ..util import MultilineFormatter
14 from ..util.errors import CliException
15 from ..util.project import load_project, parse_full_revpath
16 
17 
18 def build_parser(parser_ctor=argparse.ArgumentParser):
19     parser = parser_ctor(
20         help="Run Explainable AI algorithm",
21         description="""
22         Runs an explainable AI algorithm for a model.|n
23         |n
24         This tool is supposed to help an AI developer to debug
25         a model and a dataset. Basically, it executes inference and
26         tries to find problems in the trained model - determine decision
27         boundaries and belief intervals for the classifier.|n
28         |n
29         Currently, the only available algorithm is
30         RISE (https://arxiv.org/pdf/1806.07421.pdf), which runs
31         inference and then re-runs a model multiple times
32         on each image to produce a heatmap of activations for
33         each output of the first inference. As a result, we obtain
34         few heatmaps, which shows, how image pixels affected
35         the inference result. This algorithm doesn't require any special
36         information about the model, but it requires the model to
37         return all the outputs and confidences. Check the User Manual
38         for usage examples.|n
39         Supported scenarios:|n
40         - RISE for classification|n
41         - RISE for Object Detection|n
42         |n
43         This command has the following syntax:|n
44         |s|s%(prog)s <image path or revpath>|n
45         |n
46         <image path> - a path to the file.|n
47         <revpath> - either a dataset path or a revision path. The full
48         syntax is:|n
49         - Dataset paths:|n
50         |s|s- <dataset path>[ :<format> ]|n
51         - Revision paths:|n
52         |s|s- <project path> [ @<rev> ] [ :<target> ]|n
53         |s|s- <rev> [ :<target> ]|n
54         |s|s- <target>|n
55         Parts can be enclosed in quotes.|n
56         |n
57         The current project (-p/--project) is used as a context for plugins
58         and models. It is used when there is a dataset path in target.
59         When not specified, the current project's working tree is used.|n
60         |n
61         Examples:|n
62         - Run RISE on an image, display results:|n
63         |s|s%(prog)s path/to/image.jpg -m mymodel rise --max-samples 50|n
64         |n
65         - Run RISE on a source revision:|n
66         |s|s%(prog)s HEAD~1:source-1 -m model rise
67         """,
68         formatter_class=MultilineFormatter,
69     )
70 
71     parser.add_argument(
72         "target",
73         nargs="?",
74         default=None,
75         help="Inference target - image, revpath (default: project)",
76     )
77     parser.add_argument("-m", "--model", required=True, help="Model to use for inference")
78     parser.add_argument(
79         "-o",
80         "--output-dir",
81         dest="save_dir",
82         default=None,
83         help="Directory to save output (default: display only)",
84     )
85 
86     method_sp = parser.add_subparsers(dest="algorithm")
87 
88     rise_parser = method_sp.add_parser(
89         "rise",
90         description="""
91         RISE: Randomized Input Sampling for
92         Explanation of Black-box Models algorithm|n
93         |n
94         See explanations at: https://arxiv.org/pdf/1806.07421.pdf
95         """,
96         formatter_class=MultilineFormatter,
97     )
98     rise_parser.add_argument(
99         "-s",
100         "--max-samples",
101         default=None,
102         type=int,
103         help="Number of algorithm iterations (default: mask size ^ 2)",
104     )
105     rise_parser.add_argument(
106         "--mw",
107         "--mask-width",
108         dest="mask_width",
109         default=7,
110         type=int,
111         help="Mask width (default: %(default)s)",
112     )
113     rise_parser.add_argument(
114         "--mh",
115         "--mask-height",
116         dest="mask_height",
117         default=7,
118         type=int,
119         help="Mask height (default: %(default)s)",
120     )
121     rise_parser.add_argument(
122         "--prob",
123         default=0.5,
124         type=float,
125         help="Mask pixel inclusion probability (default: %(default)s)",
126     )
127     rise_parser.add_argument(
128         "--iou",
129         "--iou-thresh",
130         dest="iou_thresh",
131         default=0.9,
132         type=float,
133         help="IoU match threshold for detections (default: %(default)s)",
134     )
135     rise_parser.add_argument(
136         "--nms",
137         "--nms-iou-thresh",
138         dest="nms_iou_thresh",
139         default=0.0,
140         type=float,
141         help="IoU match threshold in Non-maxima suppression (default: no NMS)",
142     )
143     rise_parser.add_argument(
144         "--conf",
145         "--det-conf-thresh",
146         dest="det_conf_thresh",
147         default=0.0,
148         type=float,
149         help="Confidence threshold for detections (default: include all)",
150     )
151     rise_parser.add_argument(
152         "-b",
153         "--batch-size",
154         default=1,
155         type=int,
156         help="Inference batch size (default: %(default)s)",
157     )
158     rise_parser.add_argument(
159         "--display", action="store_true", help="Visualize results during computations"
160     )
161 
162     parser.add_argument(
163         "-p",
164         "--project",
165         dest="project_dir",
166         help="Directory of the project to operate on (default: current dir)",
167     )
168     parser.set_defaults(command=explain_command)
169 
170     return parser
171 
172 
173 def get_sensitive_args():
174     return {
175         explain_command: [
176             "target",
177             "model",
178             "save_dir",
179             "project_dir",
180         ],
181     }
182 
183 
184 @scoped
185 def explain_command(args):
186     import cv2
187     from matplotlib import cm
188 
189     project = scope_add(load_project(args.project_dir))
190 
191     model = project.working_tree.models.make_executable_model(args.model)
192 
193     if str(args.algorithm).lower() != "rise":
194         raise CliException("Explanation algorithm except for rise is not yet implemented.")
195 
196     from datumaro.components.algorithms.rise import RISE
197 
198     rise = RISE(
199         model,
200         max_samples=args.max_samples,
201         mask_width=args.mask_width,
202         mask_height=args.mask_height,
203         prob=args.prob,
204         iou_thresh=args.iou_thresh,
205         nms_thresh=args.nms_iou_thresh,
206         det_conf_thresh=args.det_conf_thresh,
207         batch_size=args.batch_size,
208     )
209 
210     if args.target and is_image(args.target):
211         image_path = args.target
212         image = load_image(image_path)
213 
214         log.info("Running inference explanation for '%s'" % image_path)
215         heatmap_iter = rise.apply(image, progressive=args.display)
216 
217         image = image / 255.0
218         file_name = osp.splitext(osp.basename(image_path))[0]
219         if args.display:
220             for i, heatmaps in enumerate(heatmap_iter):
221                 for j, heatmap in enumerate(heatmaps):
222                     hm_painted = cm.jet(heatmap)[:, :, 2::-1]
223                     disp = (image + hm_painted) / 2
224                     cv2.imshow("heatmap-%s" % j, hm_painted)
225                     cv2.imshow(file_name + "-heatmap-%s" % j, disp)
226                 cv2.waitKey(10)
227                 print("Iter", i, "of", args.max_samples, end="\r")
228         else:
229             heatmaps = next(heatmap_iter)
230 
231         if args.save_dir is not None:
232             log.info("Saving inference heatmaps at '%s'" % args.save_dir)
233             os.makedirs(args.save_dir, exist_ok=True)
234 
235             for j, heatmap in enumerate(heatmaps):
236                 save_path = osp.join(args.save_dir, file_name + "-heatmap-%s.png" % j)
237                 save_image(save_path, heatmap * 255.0)
238         else:
239             for j, heatmap in enumerate(heatmaps):
240                 disp = (image + cm.jet(heatmap)[:, :, 2::-1]) / 2
241                 cv2.imshow(file_name + "-heatmap-%s" % j, disp)
242             cv2.waitKey(0)
243 
244     else:
245         dataset, target_project = parse_full_revpath(args.target or "project", project)
246         if target_project:
247             scope_add(target_project)
248 
249         log.info("Running inference explanation for '%s'" % args.target)
250 
251         for item in dataset:
252             image = item.image.data
253             if image is None:
254                 log.warning("Item %s does not have image data. Skipping.", item.id)
255                 continue
256 
257             heatmap_iter = rise.apply(image)
258 
259             image = image / 255.0
260             heatmaps = next(heatmap_iter)
261 
262             if args.save_dir is not None:
263                 log.info("Saving inference heatmaps to '%s'" % args.save_dir)
264                 os.makedirs(args.save_dir, exist_ok=True)
265 
266                 for j, heatmap in enumerate(heatmaps):
267                     save_image(
268                         osp.join(args.save_dir, item.id + "-heatmap-%s.png" % j),
269                         heatmap * 255.0,
270                         create_dir=True,
271                     )
272 
273             if not args.save_dir or args.display:
274                 for j, heatmap in enumerate(heatmaps):
275                     disp = (image + cm.jet(heatmap)[:, :, 2::-1]) / 2
276                     cv2.imshow(item.id + "-heatmap-%s" % j, disp)
277                 cv2.waitKey(0)
278 
279     return 0
280
```
--- 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/datumaro/cli/commands/explain.py b/datumaro/cli/commands/explain.py
--- a/datumaro/cli/commands/explain.py
+++ b/datumaro/cli/commands/explain.py
@@ -188,7 +188,13 @@
 
     project = scope_add(load_project(args.project_dir))
 
-    model = project.working_tree.models.make_executable_model(args.model)
+    if args.model not in project.models:
+        raise CliException(
+            f"{args.model} has not been registered in this project. "
+            f"This is a list of registered model names: {list(project.models.keys())}"
+        )
+
+    model = project.make_model(args.model)
 
     if str(args.algorithm).lower() != "rise":
         raise CliException("Explanation algorithm except for rise is not yet implemented.")

{"golden_diff": "diff --git a/datumaro/cli/commands/explain.py b/datumaro/cli/commands/explain.py\n--- a/datumaro/cli/commands/explain.py\n+++ b/datumaro/cli/commands/explain.py\n@@ -188,7 +188,13 @@\n \n     project = scope_add(load_project(args.project_dir))\n \n-    model = project.working_tree.models.make_executable_model(args.model)\n+    if args.model not in project.models:\n+        raise CliException(\n+            f\"{args.model} has not been registered in this project. \"\n+            f\"This is a list of registered model names: {list(project.models.keys())}\"\n+        )\n+\n+    model = project.make_model(args.model)\n \n     if str(args.algorithm).lower() != \"rise\":\n         raise CliException(\"Explanation algorithm except for rise is not yet implemented.\")\n", "issue": "explain command cannot find the model \nWhen I try to infer an image with a model included in the project using the command 'explain', I get the error : \r\n**AttributeError: 'Tree' object has no attribute 'models'**\r\n\r\nHowever, when I check the project info I see that the model is successfully added to the project, and the model can also produce annotations with 'model run' command \r\n\r\nAny help will be appreciated.\r\n![Screenshot from 2022-07-28 11-34-46](https://user-images.githubusercontent.com/110161019/181460641-5c25f77e-f7fb-4347-9ab3-efc14f912b03.png)\r\n \n", "before_files": [{"content": "# Copyright (C) 2019-2021 Intel Corporation\n#\n# SPDX-License-Identifier: MIT\n\nimport argparse\nimport logging as log\nimport os\nimport os.path as osp\n\nfrom datumaro.util.image import is_image, load_image, save_image\nfrom datumaro.util.scope import scope_add, scoped\n\nfrom ..util import MultilineFormatter\nfrom ..util.errors import CliException\nfrom ..util.project import load_project, parse_full_revpath\n\n\ndef build_parser(parser_ctor=argparse.ArgumentParser):\n    parser = parser_ctor(\n        help=\"Run Explainable AI algorithm\",\n        description=\"\"\"\n        Runs an explainable AI algorithm for a model.|n\n        |n\n        This tool is supposed to help an AI developer to debug\n        a model and a dataset. Basically, it executes inference and\n        tries to find problems in the trained model - determine decision\n        boundaries and belief intervals for the classifier.|n\n        |n\n        Currently, the only available algorithm is\n        RISE (https://arxiv.org/pdf/1806.07421.pdf), which runs\n        inference and then re-runs a model multiple times\n        on each image to produce a heatmap of activations for\n        each output of the first inference. As a result, we obtain\n        few heatmaps, which shows, how image pixels affected\n        the inference result. This algorithm doesn't require any special\n        information about the model, but it requires the model to\n        return all the outputs and confidences. Check the User Manual\n        for usage examples.|n\n        Supported scenarios:|n\n        - RISE for classification|n\n        - RISE for Object Detection|n\n        |n\n        This command has the following syntax:|n\n        |s|s%(prog)s <image path or revpath>|n\n        |n\n        <image path> - a path to the file.|n\n        <revpath> - either a dataset path or a revision path. The full\n        syntax is:|n\n        - Dataset paths:|n\n        |s|s- <dataset path>[ :<format> ]|n\n        - Revision paths:|n\n        |s|s- <project path> [ @<rev> ] [ :<target> ]|n\n        |s|s- <rev> [ :<target> ]|n\n        |s|s- <target>|n\n        Parts can be enclosed in quotes.|n\n        |n\n        The current project (-p/--project) is used as a context for plugins\n        and models. It is used when there is a dataset path in target.\n        When not specified, the current project's working tree is used.|n\n        |n\n        Examples:|n\n        - Run RISE on an image, display results:|n\n        |s|s%(prog)s path/to/image.jpg -m mymodel rise --max-samples 50|n\n        |n\n        - Run RISE on a source revision:|n\n        |s|s%(prog)s HEAD~1:source-1 -m model rise\n        \"\"\",\n        formatter_class=MultilineFormatter,\n    )\n\n    parser.add_argument(\n        \"target\",\n        nargs=\"?\",\n        default=None,\n        help=\"Inference target - image, revpath (default: project)\",\n    )\n    parser.add_argument(\"-m\", \"--model\", required=True, help=\"Model to use for inference\")\n    parser.add_argument(\n        \"-o\",\n        \"--output-dir\",\n        dest=\"save_dir\",\n        default=None,\n        help=\"Directory to save output (default: display only)\",\n    )\n\n    method_sp = parser.add_subparsers(dest=\"algorithm\")\n\n    rise_parser = method_sp.add_parser(\n        \"rise\",\n        description=\"\"\"\n        RISE: Randomized Input Sampling for\n        Explanation of Black-box Models algorithm|n\n        |n\n        See explanations at: https://arxiv.org/pdf/1806.07421.pdf\n        \"\"\",\n        formatter_class=MultilineFormatter,\n    )\n    rise_parser.add_argument(\n        \"-s\",\n        \"--max-samples\",\n        default=None,\n        type=int,\n        help=\"Number of algorithm iterations (default: mask size ^ 2)\",\n    )\n    rise_parser.add_argument(\n        \"--mw\",\n        \"--mask-width\",\n        dest=\"mask_width\",\n        default=7,\n        type=int,\n        help=\"Mask width (default: %(default)s)\",\n    )\n    rise_parser.add_argument(\n        \"--mh\",\n        \"--mask-height\",\n        dest=\"mask_height\",\n        default=7,\n        type=int,\n        help=\"Mask height (default: %(default)s)\",\n    )\n    rise_parser.add_argument(\n        \"--prob\",\n        default=0.5,\n        type=float,\n        help=\"Mask pixel inclusion probability (default: %(default)s)\",\n    )\n    rise_parser.add_argument(\n        \"--iou\",\n        \"--iou-thresh\",\n        dest=\"iou_thresh\",\n        default=0.9,\n        type=float,\n        help=\"IoU match threshold for detections (default: %(default)s)\",\n    )\n    rise_parser.add_argument(\n        \"--nms\",\n        \"--nms-iou-thresh\",\n        dest=\"nms_iou_thresh\",\n        default=0.0,\n        type=float,\n        help=\"IoU match threshold in Non-maxima suppression (default: no NMS)\",\n    )\n    rise_parser.add_argument(\n        \"--conf\",\n        \"--det-conf-thresh\",\n        dest=\"det_conf_thresh\",\n        default=0.0,\n        type=float,\n        help=\"Confidence threshold for detections (default: include all)\",\n    )\n    rise_parser.add_argument(\n        \"-b\",\n        \"--batch-size\",\n        default=1,\n        type=int,\n        help=\"Inference batch size (default: %(default)s)\",\n    )\n    rise_parser.add_argument(\n        \"--display\", action=\"store_true\", help=\"Visualize results during computations\"\n    )\n\n    parser.add_argument(\n        \"-p\",\n        \"--project\",\n        dest=\"project_dir\",\n        help=\"Directory of the project to operate on (default: current dir)\",\n    )\n    parser.set_defaults(command=explain_command)\n\n    return parser\n\n\ndef get_sensitive_args():\n    return {\n        explain_command: [\n            \"target\",\n            \"model\",\n            \"save_dir\",\n            \"project_dir\",\n        ],\n    }\n\n\n@scoped\ndef explain_command(args):\n    import cv2\n    from matplotlib import cm\n\n    project = scope_add(load_project(args.project_dir))\n\n    model = project.working_tree.models.make_executable_model(args.model)\n\n    if str(args.algorithm).lower() != \"rise\":\n        raise CliException(\"Explanation algorithm except for rise is not yet implemented.\")\n\n    from datumaro.components.algorithms.rise import RISE\n\n    rise = RISE(\n        model,\n        max_samples=args.max_samples,\n        mask_width=args.mask_width,\n        mask_height=args.mask_height,\n        prob=args.prob,\n        iou_thresh=args.iou_thresh,\n        nms_thresh=args.nms_iou_thresh,\n        det_conf_thresh=args.det_conf_thresh,\n        batch_size=args.batch_size,\n    )\n\n    if args.target and is_image(args.target):\n        image_path = args.target\n        image = load_image(image_path)\n\n        log.info(\"Running inference explanation for '%s'\" % image_path)\n        heatmap_iter = rise.apply(image, progressive=args.display)\n\n        image = image / 255.0\n        file_name = osp.splitext(osp.basename(image_path))[0]\n        if args.display:\n            for i, heatmaps in enumerate(heatmap_iter):\n                for j, heatmap in enumerate(heatmaps):\n                    hm_painted = cm.jet(heatmap)[:, :, 2::-1]\n                    disp = (image + hm_painted) / 2\n                    cv2.imshow(\"heatmap-%s\" % j, hm_painted)\n                    cv2.imshow(file_name + \"-heatmap-%s\" % j, disp)\n                cv2.waitKey(10)\n                print(\"Iter\", i, \"of\", args.max_samples, end=\"\\r\")\n        else:\n            heatmaps = next(heatmap_iter)\n\n        if args.save_dir is not None:\n            log.info(\"Saving inference heatmaps at '%s'\" % args.save_dir)\n            os.makedirs(args.save_dir, exist_ok=True)\n\n            for j, heatmap in enumerate(heatmaps):\n                save_path = osp.join(args.save_dir, file_name + \"-heatmap-%s.png\" % j)\n                save_image(save_path, heatmap * 255.0)\n        else:\n            for j, heatmap in enumerate(heatmaps):\n                disp = (image + cm.jet(heatmap)[:, :, 2::-1]) / 2\n                cv2.imshow(file_name + \"-heatmap-%s\" % j, disp)\n            cv2.waitKey(0)\n\n    else:\n        dataset, target_project = parse_full_revpath(args.target or \"project\", project)\n        if target_project:\n            scope_add(target_project)\n\n        log.info(\"Running inference explanation for '%s'\" % args.target)\n\n        for item in dataset:\n            image = item.image.data\n            if image is None:\n                log.warning(\"Item %s does not have image data. Skipping.\", item.id)\n                continue\n\n            heatmap_iter = rise.apply(image)\n\n            image = image / 255.0\n            heatmaps = next(heatmap_iter)\n\n            if args.save_dir is not None:\n                log.info(\"Saving inference heatmaps to '%s'\" % args.save_dir)\n                os.makedirs(args.save_dir, exist_ok=True)\n\n                for j, heatmap in enumerate(heatmaps):\n                    save_image(\n                        osp.join(args.save_dir, item.id + \"-heatmap-%s.png\" % j),\n                        heatmap * 255.0,\n                        create_dir=True,\n                    )\n\n            if not args.save_dir or args.display:\n                for j, heatmap in enumerate(heatmaps):\n                    disp = (image + cm.jet(heatmap)[:, :, 2::-1]) / 2\n                    cv2.imshow(item.id + \"-heatmap-%s\" % j, disp)\n                cv2.waitKey(0)\n\n    return 0\n", "path": "datumaro/cli/commands/explain.py"}], "after_files": [{"content": "# Copyright (C) 2019-2021 Intel Corporation\n#\n# SPDX-License-Identifier: MIT\n\nimport argparse\nimport logging as log\nimport os\nimport os.path as osp\n\nfrom datumaro.util.image import is_image, load_image, save_image\nfrom datumaro.util.scope import scope_add, scoped\n\nfrom ..util import MultilineFormatter\nfrom ..util.errors import CliException\nfrom ..util.project import load_project, parse_full_revpath\n\n\ndef build_parser(parser_ctor=argparse.ArgumentParser):\n    parser = parser_ctor(\n        help=\"Run Explainable AI algorithm\",\n        description=\"\"\"\n        Runs an explainable AI algorithm for a model.|n\n        |n\n        This tool is supposed to help an AI developer to debug\n        a model and a dataset. Basically, it executes inference and\n        tries to find problems in the trained model - determine decision\n        boundaries and belief intervals for the classifier.|n\n        |n\n        Currently, the only available algorithm is\n        RISE (https://arxiv.org/pdf/1806.07421.pdf), which runs\n        inference and then re-runs a model multiple times\n        on each image to produce a heatmap of activations for\n        each output of the first inference. As a result, we obtain\n        few heatmaps, which shows, how image pixels affected\n        the inference result. This algorithm doesn't require any special\n        information about the model, but it requires the model to\n        return all the outputs and confidences. Check the User Manual\n        for usage examples.|n\n        Supported scenarios:|n\n        - RISE for classification|n\n        - RISE for Object Detection|n\n        |n\n        This command has the following syntax:|n\n        |s|s%(prog)s <image path or revpath>|n\n        |n\n        <image path> - a path to the file.|n\n        <revpath> - either a dataset path or a revision path. The full\n        syntax is:|n\n        - Dataset paths:|n\n        |s|s- <dataset path>[ :<format> ]|n\n        - Revision paths:|n\n        |s|s- <project path> [ @<rev> ] [ :<target> ]|n\n        |s|s- <rev> [ :<target> ]|n\n        |s|s- <target>|n\n        Parts can be enclosed in quotes.|n\n        |n\n        The current project (-p/--project) is used as a context for plugins\n        and models. It is used when there is a dataset path in target.\n        When not specified, the current project's working tree is used.|n\n        |n\n        Examples:|n\n        - Run RISE on an image, display results:|n\n        |s|s%(prog)s path/to/image.jpg -m mymodel rise --max-samples 50|n\n        |n\n        - Run RISE on a source revision:|n\n        |s|s%(prog)s HEAD~1:source-1 -m model rise\n        \"\"\",\n        formatter_class=MultilineFormatter,\n    )\n\n    parser.add_argument(\n        \"target\",\n        nargs=\"?\",\n        default=None,\n        help=\"Inference target - image, revpath (default: project)\",\n    )\n    parser.add_argument(\"-m\", \"--model\", required=True, help=\"Model to use for inference\")\n    parser.add_argument(\n        \"-o\",\n        \"--output-dir\",\n        dest=\"save_dir\",\n        default=None,\n        help=\"Directory to save output (default: display only)\",\n    )\n\n    method_sp = parser.add_subparsers(dest=\"algorithm\")\n\n    rise_parser = method_sp.add_parser(\n        \"rise\",\n        description=\"\"\"\n        RISE: Randomized Input Sampling for\n        Explanation of Black-box Models algorithm|n\n        |n\n        See explanations at: https://arxiv.org/pdf/1806.07421.pdf\n        \"\"\",\n        formatter_class=MultilineFormatter,\n    )\n    rise_parser.add_argument(\n        \"-s\",\n        \"--max-samples\",\n        default=None,\n        type=int,\n        help=\"Number of algorithm iterations (default: mask size ^ 2)\",\n    )\n    rise_parser.add_argument(\n        \"--mw\",\n        \"--mask-width\",\n        dest=\"mask_width\",\n        default=7,\n        type=int,\n        help=\"Mask width (default: %(default)s)\",\n    )\n    rise_parser.add_argument(\n        \"--mh\",\n        \"--mask-height\",\n        dest=\"mask_height\",\n        default=7,\n        type=int,\n        help=\"Mask height (default: %(default)s)\",\n    )\n    rise_parser.add_argument(\n        \"--prob\",\n        default=0.5,\n        type=float,\n        help=\"Mask pixel inclusion probability (default: %(default)s)\",\n    )\n    rise_parser.add_argument(\n        \"--iou\",\n        \"--iou-thresh\",\n        dest=\"iou_thresh\",\n        default=0.9,\n        type=float,\n        help=\"IoU match threshold for detections (default: %(default)s)\",\n    )\n    rise_parser.add_argument(\n        \"--nms\",\n        \"--nms-iou-thresh\",\n        dest=\"nms_iou_thresh\",\n        default=0.0,\n        type=float,\n        help=\"IoU match threshold in Non-maxima suppression (default: no NMS)\",\n    )\n    rise_parser.add_argument(\n        \"--conf\",\n        \"--det-conf-thresh\",\n        dest=\"det_conf_thresh\",\n        default=0.0,\n        type=float,\n        help=\"Confidence threshold for detections (default: include all)\",\n    )\n    rise_parser.add_argument(\n        \"-b\",\n        \"--batch-size\",\n        default=1,\n        type=int,\n        help=\"Inference batch size (default: %(default)s)\",\n    )\n    rise_parser.add_argument(\n        \"--display\", action=\"store_true\", help=\"Visualize results during computations\"\n    )\n\n    parser.add_argument(\n        \"-p\",\n        \"--project\",\n        dest=\"project_dir\",\n        help=\"Directory of the project to operate on (default: current dir)\",\n    )\n    parser.set_defaults(command=explain_command)\n\n    return parser\n\n\ndef get_sensitive_args():\n    return {\n        explain_command: [\n            \"target\",\n            \"model\",\n            \"save_dir\",\n            \"project_dir\",\n        ],\n    }\n\n\n@scoped\ndef explain_command(args):\n    import cv2\n    from matplotlib import cm\n\n    project = scope_add(load_project(args.project_dir))\n\n    if args.model not in project.models:\n        raise CliException(\n            f\"{args.model} has not been registered in this project. \"\n            f\"This is a list of registered model names: {list(project.models.keys())}\"\n        )\n\n    model = project.make_model(args.model)\n\n    if str(args.algorithm).lower() != \"rise\":\n        raise CliException(\"Explanation algorithm except for rise is not yet implemented.\")\n\n    from datumaro.components.algorithms.rise import RISE\n\n    rise = RISE(\n        model,\n        max_samples=args.max_samples,\n        mask_width=args.mask_width,\n        mask_height=args.mask_height,\n        prob=args.prob,\n        iou_thresh=args.iou_thresh,\n        nms_thresh=args.nms_iou_thresh,\n        det_conf_thresh=args.det_conf_thresh,\n        batch_size=args.batch_size,\n    )\n\n    if args.target and is_image(args.target):\n        image_path = args.target\n        image = load_image(image_path)\n\n        log.info(\"Running inference explanation for '%s'\" % image_path)\n        heatmap_iter = rise.apply(image, progressive=args.display)\n\n        image = image / 255.0\n        file_name = osp.splitext(osp.basename(image_path))[0]\n        if args.display:\n            for i, heatmaps in enumerate(heatmap_iter):\n                for j, heatmap in enumerate(heatmaps):\n                    hm_painted = cm.jet(heatmap)[:, :, 2::-1]\n                    disp = (image + hm_painted) / 2\n                    cv2.imshow(\"heatmap-%s\" % j, hm_painted)\n                    cv2.imshow(file_name + \"-heatmap-%s\" % j, disp)\n                cv2.waitKey(10)\n                print(\"Iter\", i, \"of\", args.max_samples, end=\"\\r\")\n        else:\n            heatmaps = next(heatmap_iter)\n\n        if args.save_dir is not None:\n            log.info(\"Saving inference heatmaps at '%s'\" % args.save_dir)\n            os.makedirs(args.save_dir, exist_ok=True)\n\n            for j, heatmap in enumerate(heatmaps):\n                save_path = osp.join(args.save_dir, file_name + \"-heatmap-%s.png\" % j)\n                save_image(save_path, heatmap * 255.0)\n        else:\n            for j, heatmap in enumerate(heatmaps):\n                disp = (image + cm.jet(heatmap)[:, :, 2::-1]) / 2\n                cv2.imshow(file_name + \"-heatmap-%s\" % j, disp)\n            cv2.waitKey(0)\n\n    else:\n        dataset, target_project = parse_full_revpath(args.target or \"project\", project)\n        if target_project:\n            scope_add(target_project)\n\n        log.info(\"Running inference explanation for '%s'\" % args.target)\n\n        for item in dataset:\n            image = item.image.data\n            if image is None:\n                log.warning(\"Item %s does not have image data. Skipping.\", item.id)\n                continue\n\n            heatmap_iter = rise.apply(image)\n\n            image = image / 255.0\n            heatmaps = next(heatmap_iter)\n\n            if args.save_dir is not None:\n                log.info(\"Saving inference heatmaps to '%s'\" % args.save_dir)\n                os.makedirs(args.save_dir, exist_ok=True)\n\n                for j, heatmap in enumerate(heatmaps):\n                    save_image(\n                        osp.join(args.save_dir, item.id + \"-heatmap-%s.png\" % j),\n                        heatmap * 255.0,\n                        create_dir=True,\n                    )\n\n            if not args.save_dir or args.display:\n                for j, heatmap in enumerate(heatmaps):\n                    disp = (image + cm.jet(heatmap)[:, :, 2::-1]) / 2\n                    cv2.imshow(item.id + \"-heatmap-%s\" % j, disp)\n                cv2.waitKey(0)\n\n    return 0\n", "path": "datumaro/cli/commands/explain.py"}]}