{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":39272,"databundleVersionId":4629629,"sourceType":"competition"},{"sourceId":4903910,"sourceType":"datasetVersion","datasetId":2782645},{"sourceId":4987179,"sourceType":"datasetVersion","datasetId":2861163},{"sourceId":5021676,"sourceType":"datasetVersion","datasetId":2911144},{"sourceId":5021729,"sourceType":"datasetVersion","datasetId":2914023},{"sourceId":5053955,"sourceType":"datasetVersion","datasetId":2933297},{"sourceId":5055435,"sourceType":"datasetVersion","datasetId":2935273},{"sourceId":5055457,"sourceType":"datasetVersion","datasetId":2930701},{"sourceId":5057747,"sourceType":"datasetVersion","datasetId":2936703},{"sourceId":5058374,"sourceType":"datasetVersion","datasetId":2937097},{"sourceId":5066758,"sourceType":"datasetVersion","datasetId":2941865},{"sourceId":5066767,"sourceType":"datasetVersion","datasetId":2941872},{"sourceId":8251096,"sourceType":"datasetVersion","datasetId":4895811},{"sourceId":8251287,"sourceType":"datasetVersion","datasetId":4895948},{"sourceId":8254266,"sourceType":"datasetVersion","datasetId":4898206},{"sourceId":8254498,"sourceType":"datasetVersion","datasetId":4898361},{"sourceId":8254805,"sourceType":"datasetVersion","datasetId":4898596},{"sourceId":8256201,"sourceType":"datasetVersion","datasetId":4899658},{"sourceId":8257041,"sourceType":"datasetVersion","datasetId":4900294},{"sourceId":8257600,"sourceType":"datasetVersion","datasetId":4900681},{"sourceId":8257630,"sourceType":"datasetVersion","datasetId":4900709},{"sourceId":8257798,"sourceType":"datasetVersion","datasetId":4900823},{"sourceId":8258699,"sourceType":"datasetVersion","datasetId":4901418},{"sourceId":8258835,"sourceType":"datasetVersion","datasetId":4901515},{"sourceId":115329502,"sourceType":"kernelVersion"},{"sourceId":119615853,"sourceType":"kernelVersion"}],"dockerImageVersionId":30381,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install /kaggle/input/pytorch-1131-cuda116/{torch-1.13.1cu116-cp37-cp37m-linux_x86_64.whl,torchvision-0.14.1cu116-cp37-cp37m-linux_x86_64.whl}","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-output":true,"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:39:32.772206Z","iopub.execute_input":"2025-02-09T08:39:32.772623Z","iopub.status.idle":"2025-02-09T08:41:16.428186Z","shell.execute_reply.started":"2025-02-09T08:39:32.772532Z","shell.execute_reply":"2025-02-09T08:41:16.427233Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -I --no-index --find-links /kaggle/input/offline-rsna-dali-pipeline-pips python-gdcm pydicom pylibjpeg dicomsdl","metadata":{"_kg_hide-output":true,"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:41:16.431077Z","iopub.execute_input":"2025-02-09T08:41:16.43177Z","iopub.status.idle":"2025-02-09T08:41:28.409785Z","shell.execute_reply.started":"2025-02-09T08:41:16.431725Z","shell.execute_reply":"2025-02-09T08:41:28.408516Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -I --no-index --find-links /kaggle/input/dali-nightly-1-23-0 nvidia-dali-nightly-cuda110","metadata":{"_kg_hide-output":true,"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:41:28.411125Z","iopub.execute_input":"2025-02-09T08:41:28.411479Z","iopub.status.idle":"2025-02-09T08:41:49.709346Z","shell.execute_reply.started":"2025-02-09T08:41:28.41145Z","shell.execute_reply":"2025-02-09T08:41:49.70823Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%writefile /opt/conda/lib/python3.7/site-packages/nvidia/dali/plugin/pytorch.py\n# Copyright (c) 2017-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom nvidia.dali.backend import TensorGPU, TensorListGPU\nfrom nvidia.dali.pipeline import Pipeline\nimport nvidia.dali.ops as ops\nfrom nvidia.dali import types\nfrom nvidia.dali.plugin.base_iterator import _DaliBaseIterator\nfrom nvidia.dali.plugin.base_iterator import LastBatchPolicy\nimport torch\nimport torch.utils.dlpack as torch_dlpack\nimport ctypes\nimport numpy as np\n\nto_torch_type = {\n    types.DALIDataType.FLOAT:   torch.float32,\n    types.DALIDataType.FLOAT64: torch.float64,\n    types.DALIDataType.FLOAT16: torch.float16,\n    types.DALIDataType.UINT8:   torch.uint8,\n    types.DALIDataType.INT8:    torch.int8,\n    types.DALIDataType.INT16:   torch.int16,\n    types.DALIDataType.UINT16:  torch.int16,\n    types.DALIDataType.INT32:   torch.int32,\n    types.DALIDataType.INT64:   torch.int64\n}\n\n\ndef feed_ndarray(dali_tensor, arr, cuda_stream=None):\n    \"\"\"\n    Copy contents of DALI tensor to PyTorch's Tensor.\n\n    Parameters\n    ----------\n    `dali_tensor` : nvidia.dali.backend.TensorCPU or nvidia.dali.backend.TensorGPU\n                    Tensor from which to copy\n    `arr` : torch.Tensor\n            Destination of the copy\n    `cuda_stream` : torch.cuda.Stream, cudaStream_t or any value that can be cast to cudaStream_t.\n                    CUDA stream to be used for the copy\n                    (if not provided, an internal user stream will be selected)\n                    In most cases, using pytorch's current stream is expected (for example,\n                    if we are copying to a tensor allocated with torch.zeros(...))\n    \"\"\"\n    dali_type = to_torch_type[dali_tensor.dtype]\n\n    assert dali_type == arr.dtype, (\"The element type of DALI Tensor/TensorList\"\n                                    \" doesn't match the element type of the target PyTorch Tensor: \"\n                                    \"{} vs {}\".format(dali_type, arr.dtype))\n    assert dali_tensor.shape() == list(arr.size()), \\\n        (\"Shapes do not match: DALI tensor has size {0}, but PyTorch Tensor has size {1}\".\n            format(dali_tensor.shape(), list(arr.size())))\n    cuda_stream = types._raw_cuda_stream(cuda_stream)\n\n    # turn raw int to a c void pointer\n    c_type_pointer = ctypes.c_void_p(arr.data_ptr())\n    if isinstance(dali_tensor, (TensorGPU, TensorListGPU)):\n        stream = None if cuda_stream is None else ctypes.c_void_p(cuda_stream)\n        dali_tensor.copy_to_external(c_type_pointer, stream, non_blocking=True)\n    else:\n        dali_tensor.copy_to_external(c_type_pointer)\n    return arr\n\n\nclass DALIGenericIterator(_DaliBaseIterator):\n    \"\"\"\n    General DALI iterator for PyTorch. It can return any number of\n    outputs from the DALI pipeline in the form of PyTorch's Tensors.\n\n    Parameters\n    ----------\n    pipelines : list of nvidia.dali.Pipeline\n                List of pipelines to use\n    output_map : list of str\n                List of strings which maps consecutive outputs\n                of DALI pipelines to user specified name.\n                Outputs will be returned from iterator as dictionary\n                of those names.\n                Each name should be distinct\n    size : int, default = -1\n                Number of samples in the shard for the wrapped pipeline (if there is more than\n                one it is a sum)\n                Providing -1 means that the iterator will work until StopIteration is raised\n                from the inside of iter_setup(). The options `last_batch_policy` and\n                `last_batch_padded` don't work in such case. It works with only one pipeline inside\n                the iterator.\n                Mutually exclusive with `reader_name` argument\n    reader_name : str, default = None\n                Name of the reader which will be queried to the shard size, number of shards and\n                all other properties necessary to count properly the number of relevant and padded\n                samples that iterator needs to deal with. It automatically sets `last_batch_policy`\n                to PARTIAL when the FILL is used, and `last_batch_padded` accordingly to match\n                the reader's configuration\n    auto_reset : string or bool, optional, default = False\n                Whether the iterator resets itself for the next epoch or it requires reset() to be\n                called explicitly.\n\n                It can be one of the following values:\n\n                * ``\"no\"``, ``False`` or ``None`` - at the end of epoch StopIteration is raised\n                  and reset() needs to be called\n                * ``\"yes\"`` or ``\"True\"``- at the end of epoch StopIteration is raised but reset()\n                  is called internally automatically\n\n    dynamic_shape : any, optional,\n                Parameter used only for backward compatibility.\n    fill_last_batch : bool, optional, default = None\n                **Deprecated** Please use ``last_batch_policy`` instead\n\n                Whether to fill the last batch with data up to 'self.batch_size'.\n                The iterator would return the first integer multiple\n                of self._num_gpus * self.batch_size entries which exceeds 'size'.\n                Setting this flag to False will cause the iterator to return\n                exactly 'size' entries.\n    last_batch_policy: optional, default = LastBatchPolicy.FILL\n                What to do with the last batch when there are not enough samples in the epoch\n                to fully fill it. See :meth:`nvidia.dali.plugin.base_iterator.LastBatchPolicy`\n    last_batch_padded : bool, optional, default = False\n                Whether the last batch provided by DALI is padded with the last sample\n                or it just wraps up. In the conjunction with ``last_batch_policy`` it tells\n                if the iterator returning last batch with data only partially filled with\n                data from the current epoch is dropping padding samples or samples from\n                the next epoch. If set to ``False`` next\n                epoch will end sooner as data from it was consumed but dropped. If set to\n                True next epoch would be the same length as the first one. For this to happen,\n                the option `pad_last_batch` in the reader needs to be set to True as well.\n                It is overwritten when `reader_name` argument is provided\n    prepare_first_batch : bool, optional, default = True\n                Whether DALI should buffer the first batch right after the creation of the iterator,\n                so one batch is already prepared when the iterator is prompted for the data\n\n    Example\n    -------\n    With the data set ``[1,2,3,4,5,6,7]`` and the batch size 2:\n\n    last_batch_policy = LastBatchPolicy.PARTIAL, last_batch_padded = True  -> last batch = ``[7]``,\n    next iteration will return ``[1, 2]``\n\n    last_batch_policy = LastBatchPolicy.PARTIAL, last_batch_padded = False -> last batch = ``[7]``,\n    next iteration will return ``[2, 3]``\n\n    last_batch_policy = LastBatchPolicy.FILL, last_batch_padded = True   -> last batch = ``[7, 7]``,\n    next iteration will return ``[1, 2]``\n\n    last_batch_policy = LastBatchPolicy.FILL, last_batch_padded = False  -> last batch = ``[7, 1]``,\n    next iteration will return ``[2, 3]``\n\n    last_batch_policy = LastBatchPolicy.DROP, last_batch_padded = True   -> last batch = ``[5, 6]``,\n    next iteration will return ``[1, 2]``\n\n    last_batch_policy = LastBatchPolicy.DROP, last_batch_padded = False  -> last batch = ``[5, 6]``,\n    next iteration will return ``[2, 3]``\n    \"\"\"\n\n    def __init__(self,\n                 pipelines,\n                 output_map,\n                 size=-1,\n                 reader_name=None,\n                 auto_reset=False,\n                 fill_last_batch=None,\n                 dynamic_shape=False,\n                 last_batch_padded=False,\n                 last_batch_policy=LastBatchPolicy.FILL,\n                 prepare_first_batch=True):\n\n        # check the assert first as _DaliBaseIterator would run the prefetch\n        assert len(set(output_map)) == len(output_map), \"output_map names should be distinct\"\n        self._output_categories = set(output_map)\n        self.output_map = output_map\n\n        _DaliBaseIterator.__init__(self,\n                                   pipelines,\n                                   size,\n                                   reader_name,\n                                   auto_reset,\n                                   fill_last_batch,\n                                   last_batch_padded,\n                                   last_batch_policy,\n                                   prepare_first_batch=prepare_first_batch)\n\n        self._first_batch = None\n        if self._prepare_first_batch:\n            try:\n                self._first_batch = DALIGenericIterator.__next__(self)\n                # call to `next` sets _ever_consumed to True but if we are just calling it from\n                # here we should set if to False again\n                self._ever_consumed = False\n            except StopIteration:\n                assert False, \"It seems that there is no data in the pipeline. This may happen \" \\\n                       \"if `last_batch_policy` is set to PARTIAL and the requested batch size is \" \\\n                       \"greater than the shard size.\"\n\n    def __next__(self):\n        self._ever_consumed = True\n        if self._first_batch is not None:\n            batch = self._first_batch\n            self._first_batch = None\n            return batch\n\n        # Gather outputs\n        outputs = self._get_outputs()\n\n        data_batches = [None for i in range(self._num_gpus)]\n        for i in range(self._num_gpus):\n            dev_id = self._pipes[i].device_id\n            # initialize dict for all output categories\n            category_outputs = dict()\n            # segregate outputs into categories\n            for j, out in enumerate(outputs[i]):\n                category_outputs[self.output_map[j]] = out\n\n            # Change DALI TensorLists into Tensors\n            category_tensors = dict()\n            category_shapes = dict()\n            for category, out in category_outputs.items():\n                category_tensors[category] = out.as_tensor()\n                category_shapes[category] = category_tensors[category].shape()\n\n            category_torch_type = dict()\n            category_device = dict()\n            torch_gpu_device = None\n            torch_cpu_device = torch.device('cpu')\n            # check category and device\n            for category in self._output_categories:\n                category_torch_type[category] = to_torch_type[category_tensors[category].dtype]\n                if type(category_tensors[category]) is TensorGPU:\n                    if not torch_gpu_device:\n                        torch_gpu_device = torch.device('cuda', dev_id)\n                    category_device[category] = torch_gpu_device\n                else:\n                    category_device[category] = torch_cpu_device\n\n            pyt_tensors = dict()\n            for category in self._output_categories:\n                pyt_tensors[category] = torch.empty(category_shapes[category],\n                                                    dtype=category_torch_type[category],\n                                                    device=category_device[category])\n\n            data_batches[i] = pyt_tensors\n\n            # Copy data from DALI Tensors to torch tensors\n            for category, tensor in category_tensors.items():\n                if isinstance(tensor, (TensorGPU, TensorListGPU)):\n                    # Using same cuda_stream used by torch.zeros to set the memory\n                    stream = torch.cuda.current_stream(device=pyt_tensors[category].device)\n                    feed_ndarray(tensor, pyt_tensors[category], cuda_stream=stream)\n                else:\n                    feed_ndarray(tensor, pyt_tensors[category])\n\n        self._schedule_runs()\n\n        self._advance_and_check_drop_last()\n\n        if self._reader_name:\n            if_drop, left = self._remove_padded()\n            if np.any(if_drop):\n                output = []\n                for batch, to_copy in zip(data_batches, left):\n                    batch = batch.copy()\n                    for category in self._output_categories:\n                        batch[category] = batch[category][0:to_copy]\n                    output.append(batch)\n                return output\n\n        else:\n            if self._last_batch_policy == LastBatchPolicy.PARTIAL and (\n                                          self._counter > self._size) and self._size > 0:\n                # First calculate how much data is required to return exactly self._size entries.\n                diff = self._num_gpus * self.batch_size - (self._counter - self._size)\n                # Figure out how many GPUs to grab from.\n                numGPUs_tograb = int(np.ceil(diff / self.batch_size))\n                # Figure out how many results to grab from the last GPU\n                # (as a fractional GPU batch may be required to bring us\n                # right up to self._size).\n                mod_diff = diff % self.batch_size\n                data_fromlastGPU = mod_diff if mod_diff else self.batch_size\n\n                # Grab the relevant data.\n                # 1) Grab everything from the relevant GPUs.\n                # 2) Grab the right data from the last GPU.\n                # 3) Append data together correctly and return.\n                output = data_batches[0:numGPUs_tograb]\n                output[-1] = output[-1].copy()\n                for category in self._output_categories:\n                    output[-1][category] = output[-1][category][0:data_fromlastGPU]\n                return output\n\n        return data_batches\n\n\nclass DALIClassificationIterator(DALIGenericIterator):\n    \"\"\"\n    DALI iterator for classification tasks for PyTorch. It returns 2 outputs\n    (data and label) in the form of PyTorch's Tensor.\n\n    Calling\n\n    .. code-block:: python\n\n       DALIClassificationIterator(pipelines, reader_name)\n\n    is equivalent to calling\n\n    .. code-block:: python\n\n       DALIGenericIterator(pipelines, [\"data\", \"label\"], reader_name)\n\n    Parameters\n    ----------\n    pipelines : list of nvidia.dali.Pipeline\n                List of pipelines to use\n    size : int, default = -1\n                Number of samples in the shard for the wrapped pipeline (if there is more than\n                one it is a sum)\n                Providing -1 means that the iterator will work until StopIteration is raised\n                from the inside of iter_setup(). The options `last_batch_policy` and\n                `last_batch_padded` don't work in such case. It works with only one pipeline inside\n                the iterator.\n                Mutually exclusive with `reader_name` argument\n    reader_name : str, default = None\n                Name of the reader which will be queried to the shard size, number of shards and\n                all other properties necessary to count properly the number of relevant and padded\n                samples that iterator needs to deal with. It automatically sets `last_batch_policy`\n                to PARTIAL when the FILL is used, and `last_batch_padded` accordingly to match\n                the reader's configuration\n    auto_reset : string or bool, optional, default = False\n                Whether the iterator resets itself for the next epoch or it requires reset() to be\n                called explicitly.\n\n                It can be one of the following values:\n\n                * ``\"no\"``, ``False`` or ``None`` - at the end of epoch StopIteration is raised\n                  and reset() needs to be called\n                * ``\"yes\"`` or ``\"True\"``- at the end of epoch StopIteration is raised but reset()\n                  is called internally automatically\n\n    dynamic_shape : any, optional,\n                Parameter used only for backward compatibility.\n    fill_last_batch : bool, optional, default = None\n                **Deprecated** Please use ``last_batch_policy`` instead\n\n                Whether to fill the last batch with data up to 'self.batch_size'.\n                The iterator would return the first integer multiple\n                of self._num_gpus * self.batch_size entries which exceeds 'size'.\n                Setting this flag to False will cause the iterator to return\n                exactly 'size' entries.\n    last_batch_policy: optional, default = LastBatchPolicy.FILL\n                What to do with the last batch when there are not enough samples in the epoch\n                to fully fill it. See :meth:`nvidia.dali.plugin.base_iterator.LastBatchPolicy`\n    last_batch_padded : bool, optional, default = False\n                Whether the last batch provided by DALI is padded with the last sample\n                or it just wraps up. In the conjunction with ``last_batch_policy`` it tells\n                if the iterator returning last batch with data only partially filled with\n                data from the current epoch is dropping padding samples or samples from\n                the next epoch. If set to ``False`` next\n                epoch will end sooner as data from it was consumed but dropped. If set to\n                True next epoch would be the same length as the first one. For this to happen,\n                the option `pad_last_batch` in the reader needs to be set to True as well.\n                It is overwritten when `reader_name` argument is provided\n    prepare_first_batch : bool, optional, default = True\n                Whether DALI should buffer the first batch right after the creation of the iterator,\n                so one batch is already prepared when the iterator is prompted for the data\n\n    Example\n    -------\n    With the data set ``[1,2,3,4,5,6,7]`` and the batch size 2:\n\n    last_batch_policy = LastBatchPolicy.PARTIAL, last_batch_padded = True  -> last batch = ``[7]``,\n    next iteration will return ``[1, 2]``\n\n    last_batch_policy = LastBatchPolicy.PARTIAL, last_batch_padded = False -> last batch = ``[7]``,\n    next iteration will return ``[2, 3]``\n\n    last_batch_policy = LastBatchPolicy.FILL, last_batch_padded = True   -> last batch = ``[7, 7]``,\n    next iteration will return ``[1, 2]``\n\n    last_batch_policy = LastBatchPolicy.FILL, last_batch_padded = False  -> last batch = ``[7, 1]``,\n    next iteration will return ``[2, 3]``\n\n    last_batch_policy = LastBatchPolicy.DROP, last_batch_padded = True   -> last batch = ``[5, 6]``,\n    next iteration will return ``[1, 2]``\n\n    last_batch_policy = LastBatchPolicy.DROP, last_batch_padded = False  -> last batch = ``[5, 6]``,\n    next iteration will return ``[2, 3]``\n    \"\"\"\n\n    def __init__(self,\n                 pipelines,\n                 size=-1,\n                 reader_name=None,\n                 auto_reset=False,\n                 fill_last_batch=None,\n                 dynamic_shape=False,\n                 last_batch_padded=False,\n                 last_batch_policy=LastBatchPolicy.FILL,\n                 prepare_first_batch=True):\n        super(DALIClassificationIterator, self).__init__(pipelines, [\"data\", \"label\"],\n                                                         size,\n                                                         reader_name=reader_name,\n                                                         auto_reset=auto_reset,\n                                                         fill_last_batch=fill_last_batch,\n                                                         dynamic_shape=dynamic_shape,\n                                                         last_batch_padded=last_batch_padded,\n                                                         last_batch_policy=last_batch_policy,\n                                                         prepare_first_batch=prepare_first_batch)\n\n\nclass TorchPythonFunction(ops.PythonFunctionBase):\n    schema_name = \"TorchPythonFunction\"\n    ops.register_cpu_op('TorchPythonFunction')\n    ops.register_gpu_op('TorchPythonFunction')\n\n    def _torch_stream_wrapper(self, function, *ins):\n        with torch.cuda.stream(self.stream):\n            out = function(*ins)\n        self.stream.synchronize()\n        return out\n\n    def torch_wrapper(self, batch_processing, function, device, *args):\n        func = function if device == 'cpu' else \\\n               lambda *ins: self._torch_stream_wrapper(function, *ins)\n        if batch_processing:\n            return ops.PythonFunction.function_wrapper_batch(func,\n                                                             self.num_outputs,\n                                                             torch.utils.dlpack.from_dlpack,\n                                                             torch.utils.dlpack.to_dlpack,\n                                                             *args)\n        else:\n            return ops.PythonFunction.function_wrapper_per_sample(func,\n                                                                  self.num_outputs,\n                                                                  torch_dlpack.from_dlpack,\n                                                                  torch_dlpack.to_dlpack,\n                                                                  *args)\n\n    def __call__(self, *inputs, **kwargs):\n        pipeline = Pipeline.current()\n        if pipeline is None:\n            Pipeline._raise_no_current_pipeline(\"TorchPythonFunction\")\n        if self.stream is None:\n            self.stream = torch.cuda.Stream(device=pipeline.device_id)\n        return super(TorchPythonFunction, self).__call__(*inputs, **kwargs)\n\n    def __init__(self, function, num_outputs=1, device='cpu', batch_processing=False, **kwargs):\n        self.stream = None\n        super(TorchPythonFunction, self).__init__(impl_name=\"DLTensorPythonFunctionImpl\",\n                                                  function=lambda *ins:\n                                                  self.torch_wrapper(batch_processing,\n                                                                     function, device,\n                                                                     *ins),\n                                                  num_outputs=num_outputs, device=device,\n                                                  batch_processing=batch_processing, **kwargs)\n\n\nops._wrap_op(TorchPythonFunction, \"fn\", __name__)","metadata":{"_kg_hide-input":true,"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:41:49.711343Z","iopub.execute_input":"2025-02-09T08:41:49.711647Z","iopub.status.idle":"2025-02-09T08:41:49.729818Z","shell.execute_reply.started":"2025-02-09T08:41:49.711618Z","shell.execute_reply":"2025-02-09T08:41:49.728798Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Install YOLOX\n!pip install /kaggle/input/yolox-packages/loguru-0.6.0-py3-none-any.whl /kaggle/input/yolox-packages/thop-0.1.1.post2209072238-py3-none-any.whl\n!cp -r /kaggle/input/yolox-packages/pycocotools-2.0.2/pycocotools-2.0.2 /tmp\n!pip install /tmp/pycocotools-2.0.2\n!cp -r /kaggle/input/bcd-yolox/YOLOX /tmp\n%cd /tmp/YOLOX\n!pip install -r requirements.txt\n!pip install -v -e .","metadata":{"_kg_hide-output":true,"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:41:49.730998Z","iopub.execute_input":"2025-02-09T08:41:49.731289Z","iopub.status.idle":"2025-02-09T08:45:03.182214Z","shell.execute_reply.started":"2025-02-09T08:41:49.731263Z","shell.execute_reply":"2025-02-09T08:45:03.181247Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"config_file_template = '''\n\n#!/usr/bin/env python3\n# -*- coding:utf-8 -*-\n# Copyright (c) Megvii, Inc. and its affiliates.\n\nimport os\nimport torch.nn as nn\nfrom yolox.exp import Exp as MyExp\nimport torch\nimport torch.distributed as dist\nfrom yolox.data import get_yolox_datadir\n\nclass Exp(MyExp):\n    def __init__(self):\n        super(Exp, self).__init__()\n        self.depth = 0.33\n        self.width = 0.25\n        self.data_num_workers = 16\n        self.input_size = (416, 416)\n        self.random_size = (10, 20)\n        self.mosaic_scale = (0.5, 1.5)\n        self.test_size = (416, 416)\n        self.mosaic_prob = 0.0\n        self.enable_mixup = False\n        self.mixup_prob = 0.0\n        self.num_classes = 1\n        self.warmup_epochs = 2\n        self.max_epoch = 16\n        self.exp_name = os.path.split(os.path.realpath(__file__))[1].split(\".\")[0]\n\n    def get_model(self, sublinear=False):\n\n        def init_yolo(M):\n            for m in M.modules():\n                if isinstance(m, nn.BatchNorm2d):\n                    m.eps = 1e-3\n                    m.momentum = 0.03\n        if \"model\" not in self.__dict__:\n            from yolox.models import YOLOX, YOLOPAFPN, YOLOXHead\n            in_channels = [256, 512, 1024]\n            # NANO model use depthwise = True, which is main difference.\n            backbone = YOLOPAFPN(\n                self.depth, self.width, in_channels=in_channels,\n                act=self.act, depthwise=True,\n            )\n            head = YOLOXHead(\n                self.num_classes, self.width, in_channels=in_channels,\n                act=self.act, depthwise=True\n            )\n            self.model = YOLOX(backbone, head)\n\n        self.model.apply(init_yolo)\n        self.model.head.initialize_biases(1e-2)\n        return self.model\n\n    def get_data_loader(self, batch_size, is_distributed, no_aug=False, cache_img=False):\n        from yolox.data import (\n            VOCDetection,\n            TrainTransform,\n            YoloBatchSampler,\n            DataLoader,\n            InfiniteSampler,\n            MosaicDetection,\n            worker_init_reset_seed,\n        )\n        from yolox.utils import (\n            wait_for_the_master,\n            get_local_rank,\n        )\n        local_rank = get_local_rank()\n\n        with wait_for_the_master(local_rank):\n            dataset = VOCDetection(\n                data_dir=os.path.join(get_yolox_datadir(), \"VOCdevkit\"),\n                image_sets=[('2007', 'trainval')],\n                img_size=self.input_size,\n                preproc=TrainTransform(\n                    max_labels=50,\n                    flip_prob=self.flip_prob,\n                    hsv_prob=self.hsv_prob),\n                cache=cache_img,\n            )\n\n        dataset = MosaicDetection(\n            dataset,\n            mosaic=not no_aug,\n            img_size=self.input_size,\n            preproc=TrainTransform(\n                max_labels=120,\n                flip_prob=self.flip_prob,\n                hsv_prob=self.hsv_prob),\n            degrees=self.degrees,\n            translate=self.translate,\n            mosaic_scale=self.mosaic_scale,\n            mixup_scale=self.mixup_scale,\n            shear=self.shear,\n            enable_mixup=self.enable_mixup,\n            mosaic_prob=self.mosaic_prob,\n            mixup_prob=self.mixup_prob,\n        )\n\n        self.dataset = dataset\n\n        if is_distributed:\n            batch_size = batch_size // dist.get_world_size()\n\n        sampler = InfiniteSampler(\n            len(self.dataset), seed=self.seed if self.seed else 0\n        )\n\n        batch_sampler = YoloBatchSampler(\n            sampler=sampler,\n            batch_size=batch_size,\n            drop_last=False,\n            mosaic=not no_aug,\n        )\n\n        dataloader_kwargs = {\"num_workers\": self.data_num_workers, \"pin_memory\": True}\n        dataloader_kwargs[\"batch_sampler\"] = batch_sampler\n\n        # Make sure each process has different random seed, especially for 'fork' method\n        dataloader_kwargs[\"worker_init_fn\"] = worker_init_reset_seed\n\n        train_loader = DataLoader(self.dataset, **dataloader_kwargs)\n\n        return train_loader\n\n    def get_eval_loader(self, batch_size, is_distributed, testdev=False, legacy=False):\n        from yolox.data import VOCDetection, ValTransform\n\n        valdataset = VOCDetection(\n            data_dir=os.path.join(get_yolox_datadir(), \"VOCdevkit\"),\n            image_sets=[('2007', 'trainval')],\n            img_size=self.test_size,\n            preproc=ValTransform(legacy=legacy),\n        )\n\n        if is_distributed:\n            batch_size = batch_size // dist.get_world_size()\n            sampler = torch.utils.data.distributed.DistributedSampler(\n                valdataset, shuffle=False\n            )\n        else:\n            sampler = torch.utils.data.SequentialSampler(valdataset)\n\n        dataloader_kwargs = {\n            \"num_workers\": self.data_num_workers,\n            \"pin_memory\": True,\n            \"sampler\": sampler,\n        }\n        dataloader_kwargs[\"batch_size\"] = batch_size\n        val_loader = torch.utils.data.DataLoader(valdataset, **dataloader_kwargs)\n\n        return val_loader\n\n    def get_evaluator(self, batch_size, is_distributed, testdev=False, legacy=False):\n        from yolox.evaluators import VOCEvaluator\n\n        val_loader = self.get_eval_loader(batch_size, is_distributed, testdev, legacy)\n        evaluator = VOCEvaluator(\n            dataloader=val_loader,\n            img_size=self.test_size,\n            confthre=self.test_conf,\n            nmsthre=self.nmsthre,\n            num_classes=self.num_classes,\n        )\n        return evaluator\n\n'''\n\nwith open('BCD_config.py', 'w') as f:\n    f.write(config_file_template)","metadata":{"_kg_hide-input":true,"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:45:03.183707Z","iopub.execute_input":"2025-02-09T08:45:03.18401Z","iopub.status.idle":"2025-02-09T08:45:03.193064Z","shell.execute_reply.started":"2025-02-09T08:45:03.183981Z","shell.execute_reply":"2025-02-09T08:45:03.192059Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport gc\nimport sys\nimport glob\nfrom yolox.utils import postprocess\nfrom yolox.data.data_augment import ValTransform\nimport warnings\nwarnings.filterwarnings(\"ignore\")\nimport os\nimport glob\nimport torch\nimport importlib\nimport cv2\nimport pandas as pd\nfrom PIL import Image\nimport numpy as np\nfrom tqdm.notebook import tqdm\nfrom torch.utils.data import Dataset\nfrom IPython.display import display\nfrom torch.utils.data import ConcatDataset, DataLoader\nimport cupy as cp\nimport numpy as np\nimport pandas as pd\n\nimport cv2\nimport torch\nimport pydicom\nimport dicomsdl\nimport matplotlib\n\nfrom tqdm.notebook import tqdm\nimport matplotlib.pyplot as plt\nfrom builtins import StopIteration\nfrom joblib import Parallel, delayed\nfrom pydicom.filebase import DicomBytesIO\n\nimport torch.nn as nn\nimport albumentations as albu\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\n\nimport nvidia.dali.fn as fn\nimport nvidia.dali.ops as ops\nimport nvidia.dali.types as types\nfrom nvidia.dali import pipeline_def\nfrom nvidia.dali.pipeline import Pipeline\nfrom nvidia.dali.types import DALIDataType\nfrom nvidia.dali.plugin.pytorch import DALIGenericIterator\nfrom nvidia.dali.plugin.numba.fn.experimental import numba_function\nimport os\nimport sys\nimport cv2\nimport glob\nimport gdcm\nimport json\nimport shutil\nimport pydicom\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport dicomsdl\nimport torch\nimport torch.nn.functional as F\nimport nvidia.dali.fn as fn\nimport nvidia.dali.types as types\nfrom nvidia.dali import pipeline_def\nfrom nvidia.dali.types import DALIDataType\nfrom pydicom.filebase import DicomBytesIO\nfrom nvidia.dali.plugin.pytorch import feed_ndarray, to_torch_type\nfrom tqdm.notebook import tqdm\nfrom joblib import Parallel, delayed\nimport torch\nfrom typing import Optional\nimport yaml\nimport pandas as pd\nfrom torch.utils.data import Dataset\nfrom torch.utils.data import DataLoader\nimport albumentations as A\nimport cv2\nimport numpy as np\nimport pandas as pd\nfrom albumentations.pytorch import ToTensorV2\nfrom typing import Optional\nimport yaml\nimport torch\n# import einops\nfrom pytorch_lightning import LightningDataModule, LightningModule, Trainer\nimport sys\nsys.path.append('/kaggle/input/timm0612/pytorch-image-models')\nimport timm\nfrom nvidia.dali.backend import ReleaseUnusedMemory","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:45:03.196937Z","iopub.execute_input":"2025-02-09T08:45:03.1976Z","iopub.status.idle":"2025-02-09T08:45:10.585766Z","shell.execute_reply.started":"2025-02-09T08:45:03.197563Z","shell.execute_reply":"2025-02-09T08:45:10.584904Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#SOURCE = 'test'\nSOURCE = 'train'\nCV = False\nDEBUG_NUM = 500\nFOLD4CV = 1\nBATCH_SIZE = 12\nDALI_BATCH = 12\nONE_FOLD = False\n\n\nMODEL_PATH = [\n    '/kaggle/input/0225-tfeffv2s-nano-machineonehot-mix3-emb32-2ext/3/epoch11-patient_val_pF10.4770-threshold0.3800.ckpt',\n    '/kaggle/input/0225-nano-tfeffv2s-metaonehot-emb96-mix03-2ext/1/1/epoch10-patient_val_pF10.5596-threshold0.4400.ckpt',\n    '/kaggle/input/0225-nano-tfeffv2s-metaonehot-emb96-mix03-2ext/2/2/epoch12-patient_val_pF10.5043-threshold0.3900.ckpt',\n    '/kaggle/input/effnetv2-1536960-mix3-2ex-yolox/effnetv2_1536960_mix3_2ex_yolox/0/epoch11-patient_val_pF10.5073-threshold0.4100.ckpt'\n]\n\n\n# MODEL_PATH = ['/kaggle/input/0217-tfeffv2s-mix02-machineonehot-emb32-2ext/1/1/epoch11-patient_val_pF10.6105-threshold0.4700.ckpt',]\n\nclass Config:\n    \n#     debug = True\n    debug = False\n    \n    img_dir_debug = '../input/rsna-breast-cancer-detection/train_images'\n    df_path_debug = '/kaggle/input/rsna-breast-cancer-detection/train.csv'\n\n    img_dir = f'/kaggle/input/rsna-breast-cancer-detection/{SOURCE}_images'\n    df_path = f'/kaggle/input/rsna-breast-cancer-detection/{SOURCE}.csv'\n    \n    oimg_dir = '/tmp/imgs' # output image dir\n#     oimg_dir = '/kaggle/working' # output image dir\n\n    # roi pipeline \n    batch_size = DALI_BATCH\n    resize_height_to = 640 # yolov5 image size\n    factor = 4 # image downscale factor - saves memory\n#     out_img_size = 1024 # output image size -> outputs ratio 1024x512\n    \n    TARGET_HEIGHT = 1536\n    TARGET_WIDTH = 960\n    \n    TARGET_HEIGHT_WIDTH_RATIO = TARGET_HEIGHT / TARGET_WIDTH    \n    \n    # dali pipeline args\n    pipeline_args = {\n        'batch_size': DALI_BATCH,\n        'num_threads': 2,\n        'device_id': 0,\n        'py_num_workers': 4,\n        'exec_async': False,\n        'exec_pipelined': False\n    }\n    \n    # dataloader\n    num_workers = 4\n    in_chans = 3\n    cnn_batch_size = BATCH_SIZE\n#     model_name = 'tf_efficientnet_b0_ns'\n    \n#     threshold = 0.5\n    \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:50:16.27327Z","iopub.execute_input":"2025-02-09T08:50:16.273614Z","iopub.status.idle":"2025-02-09T08:50:16.28198Z","shell.execute_reply.started":"2025-02-09T08:50:16.27359Z","shell.execute_reply":"2025-02-09T08:50:16.28105Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def __read_metadata(fn):\n    f = open(fn, 'rb')\n    md = f.read(400)\n    f.close()\n    offset = md.index(b'1.2.840.10008.1.2.4.') + 20\n    return md[offset] == 57","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:50:16.283806Z","iopub.execute_input":"2025-02-09T08:50:16.284488Z","iopub.status.idle":"2025-02-09T08:50:16.299742Z","shell.execute_reply.started":"2025-02-09T08:50:16.284453Z","shell.execute_reply":"2025-02-09T08:50:16.298852Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if Config.debug:\n    Config.df_path =Config.df_path_debug\n    Config.img_dir =Config.img_dir_debug\n    df = pd.read_csv(Config.df_path)\n    df = df.sample(2000).reset_index(drop = True)\nelse:\n    df = pd.read_csv(Config.df_path)\n\nif SOURCE == 'train': \n    if CV:\n        from sklearn.model_selection import StratifiedKFold,StratifiedGroupKFold\n        skf = StratifiedGroupKFold(n_splits=4,shuffle=False)\n        for n, (train_index, val_index) in enumerate(skf.split(df, df['cancer'],df['patient_id'])):\n            df.loc[val_index, 'fold'] = int(n)\n        df['fold'] = df['fold'].astype(int)    \n        df = df[df['fold']==FOLD4CV]\n    #else: df = df[:DEBUG_NUM]\n    else: df = df.loc[[i for i in range(1,5000)]]\n        \n# df = df[df['laterality']=='R'].reset_index(drop=True)\n\n## Lejun code:\ndf_origin = pd.read_csv(Config.df_path)\ndf_origin = df_origin.loc[[i for i in range(1,5000)]]\n    \ndf['pis'] = Config.img_dir + '/' + df.patient_id.astype(str) + '/' + df.image_id.astype(str) + '.dcm'\ndf['path']= Config.oimg_dir + '/' + df.patient_id.astype(str) + '_' + df.image_id.astype(str) + '.png'\n    \n# low overhead so we can increase n_jobs to max cpu usage\nis_j2k = np.array(Parallel(n_jobs = 24)(delayed(__read_metadata)(ipath) for ipath in tqdm(df.pis.values.tolist())))\ndf_j2k = df.loc[is_j2k]\ndf_jll = df.loc[~is_j2k]\n\nos.makedirs(Config.oimg_dir,exist_ok=True)\n\nprint('j2k:', len(df_j2k), 'jll:', len(df_jll))\n\n###############33\ndisplay(df_origin)\n\ndf_origin[\"prediction_id\"] = df_origin[\"patient_id\"].astype(str) + \"_\" + df_origin[\"laterality\"].astype(str)\n\ndf_origin['key'] = df_origin['patient_id'].astype(str) + '_' + df_origin['image_id'].astype(str)\n############\n\n#display(test_df.head())\n#display(test_df)\n#display(test_df.shape)\n\n#df = df.merge(test_df[['key', 'laterality', 'view', \"patient_id\", \"image_id\", 'prediction_id']], on=['key'])\n# del model; g\n\ndf_origin = df_origin.groupby([\"prediction_id\"]).agg({\"cancer\": \"mean\"}).reset_index()\ndf_origin[\"cancer\"] = df_origin[\"cancer\"].astype(int)\ndisplay(\"==\")\ndisplay(df_origin)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:35.827009Z","iopub.execute_input":"2025-02-09T08:51:35.827382Z","iopub.status.idle":"2025-02-09T08:51:36.116975Z","shell.execute_reply.started":"2025-02-09T08:51:35.827351Z","shell.execute_reply":"2025-02-09T08:51:36.116205Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for i in [1,2]:\n    df[f'site{i}'] = 0\n    df.loc[df[df.site_id==f'site{i}'].index, f'site{i}'] = 1\ndf ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.118499Z","iopub.execute_input":"2025-02-09T08:51:36.118769Z","iopub.status.idle":"2025-02-09T08:51:36.144503Z","shell.execute_reply.started":"2025-02-09T08:51:36.118745Z","shell.execute_reply":"2025-02-09T08:51:36.143594Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"SAVE_FOLDER = \"/tmp/output/\"\nos.makedirs(SAVE_FOLDER, exist_ok=True)\nEXTENSION = 'png'\ndf['filepath'] = df.apply(lambda x: f'{SAVE_FOLDER}/{x.patient_id}/{x.image_id}.{EXTENSION}', axis=1)\ndf['prediction_id'] = df.apply(lambda x: str(x.patient_id)+'_'+str(x.laterality), axis=1)\npids = df.patient_id.unique()\nfor patient_id in tqdm(pids):\n    os.makedirs(f'{SAVE_FOLDER}/{patient_id}', exist_ok=True)\n    \npids = df.prediction_id.unique()\ndata = {}\nfor (patient_id, laterality), df_this in df.groupby(['patient_id', 'laterality']):\n    data[f'{patient_id}_{laterality}'] = df_this.sort_values(['laterality', 'view'])\n    \nlen(data)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.145611Z","iopub.execute_input":"2025-02-09T08:51:36.145885Z","iopub.status.idle":"2025-02-09T08:51:36.240917Z","shell.execute_reply.started":"2025-02-09T08:51:36.145863Z","shell.execute_reply":"2025-02-09T08:51:36.240218Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_size = 416\nnum_classes = 1\nconfthre = 0.1\nnmsthre = 0.45\nCOCO_CLASSES = (\n  \"Breast\",\n)\n\n# get YOLOX experiment\ncurrent_exp = importlib.import_module('BCD_config')\nexp = current_exp.Exp()\n\n# get YOLOX model\nyolo_model = exp.get_model()\n\n# get custom trained checkpoint\nCHECKPOINT_FILE = '/kaggle/input/bcd-yolox-weight/BCD_nano/best_ckpt.pth'\nckpt_file = CHECKPOINT_FILE\nckpt = torch.load(ckpt_file, map_location=\"cpu\")\nyolo_model.load_state_dict(ckpt[\"model\"])\nyolo_model.cuda()\nyolo_model.eval()\nz=1\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.241866Z","iopub.execute_input":"2025-02-09T08:51:36.24208Z","iopub.status.idle":"2025-02-09T08:51:36.388609Z","shell.execute_reply.started":"2025-02-09T08:51:36.24206Z","shell.execute_reply":"2025-02-09T08:51:36.387896Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"machine_map = {\n    21:0,\n    29:1,\n    48:2,\n    49:3,\n    93:4,\n    170:5,\n    190:6,\n    197:7,\n    210:8,\n    216:9,\n}\n\nmachine_ls = [21, 29, 48, 49, 93, 170, 190, 197, 210, 216]\n\ndef map_fn(x):\n    if x in machine_ls: return machine_map[x]\n    else: return 100","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.391654Z","iopub.execute_input":"2025-02-09T08:51:36.392164Z","iopub.status.idle":"2025-02-09T08:51:36.397154Z","shell.execute_reply.started":"2025-02-09T08:51:36.392137Z","shell.execute_reply":"2025-02-09T08:51:36.396216Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class J2KIterator(object):\n    def __init__(self, df, batch_size):\n        self.df = df\n        self.batch_size = batch_size\n\n    @staticmethod\n    def convert_dicom_to_j2k(patient_id, image_id):\n        dcmfile = pydicom.dcmread(f'{Config.img_dir}/{patient_id}/{image_id}.dcm')\n        with open(f'{Config.img_dir}/{patient_id}/{image_id}.dcm', 'rb') as fp:\n            raw = DicomBytesIO(fp.read())\n            ds = pydicom.dcmread(raw)\n        offset = ds.PixelData.find(b\"\\x00\\x00\\x00\\x0C\")\n#         print(ds.pixel_array.shape)\n\n#         return np.frombuffer(ds.PixelData[offset:], dtype=np.uint8), dcmfile.PhotometricInterpretation == 'MONOCHROME1' , ds.pixel_array.shape[0] , ds.pixel_array.shape[1]\n        return np.frombuffer(ds.PixelData[offset:], dtype=np.uint8), dcmfile.PhotometricInterpretation == 'MONOCHROME1' , ds.Rows , ds.Columns\n\n    def __len__(self):\n        return int(np.ceil(len(self.df) / self.batch_size))\n\n    def __iter__(self):\n        self.i = 0\n        self.n = len(self.df)\n        return self\n\n    def __next__(self):\n        if self.i >= self.n:\n            raise StopIteration\n\n        compressed_imgs = []\n        is_monochrome_imgs = []\n        p_ids = []\n        i_ids = []\n        m_ids = []\n        s_ids = []\n        v_ids = []\n        l_ids = []\n        orign_h = []\n        orign_w = []\n\n        df = self.df.iloc[range(self.i, min(self.i + self.batch_size, self.n))]\n        \n        for p_id, i_id, m_id, s_id, v_id, l_id in df[['patient_id', 'image_id', 'machine_id', 'site_id', 'view', 'laterality']].values:\n            compressed_img, is_monochrome_img,h,w = self.convert_dicom_to_j2k(p_id, i_id)\n            orign_h.append(np.array([h], dtype=np.int64))\n            orign_w.append(np.array([w], dtype=np.int64))            \n#             print(np.expand_dims(compressed_img, axis=2).shape)\n            compressed_imgs.append(compressed_img)\n            is_monochrome_imgs.append(np.array([is_monochrome_img], dtype=np.bool_))\n            p_ids.append(np.array([p_id], dtype=np.int64))\n            i_ids.append(np.array([i_id], dtype=np.int64))\n            \n            if s_id==1: s_ids.append(np.array([1, 0], dtype=np.float32))\n            else: s_ids.append(np.array([0, 1], dtype=np.float32))\n                \n            if v_id=='CC': v_ids.append(np.array([1, 0], dtype=np.float32))\n            else: v_ids.append(np.array([0, 1], dtype=np.float32))\n    \n            m_id = map_fn(m_id)\n            machine_enc = np.array([0 for _ in range(10)], dtype=np.float32)\n            \n            if m_id<=9: \n                machine_enc[m_id] = 1.\n\n            m_ids.append(machine_enc)\n            \n            if l_id=='L': l_ids.append(0)\n            else: l_ids.append(1)\n            \n        self.i += self.batch_size\n\n        return compressed_imgs, is_monochrome_imgs, p_ids, i_ids, m_ids, s_ids, v_ids, l_ids, orign_h, orign_w\n\n\nclass JLLIterator(object):\n    def __init__(self, df, batch_size):\n        self.df = df\n        self.batch_size = batch_size\n\n    @staticmethod\n    def norm_img(img):\n        i_max = img.max()\n        i_min = img.min()\n        return (255 * ((m - i_min) / (i_max - i_min))).astype(np.uint8)\n\n    @staticmethod\n    def decompress_jll(dm):\n        info = dm.getPixelDataInfo()\n        img = np.empty((info['Rows'], info['Cols']), dtype=info['dtype'])\n        dm.copyFrameData(0, img)\n        return img\n\n    def process_img(self, patient_id, image_id):\n        dm = dicomsdl.open(f'{Config.img_dir}/{patient_id}/{image_id}.dcm')\n\n        #         img = norm_img(decompress_jll(dm))\n\n        #         if dm.PhotometricInterpretation== 'MONOCHROME1':\n        #             img = 255 - img\n\n        #         return img\n\n        return self.decompress_jll(dm).astype(np.uint16), dm.PhotometricInterpretation == 'MONOCHROME1'\n\n    def __len__(self):\n        return int(np.ceil(len(self.df) / self.batch_size))\n\n    def __iter__(self):\n        self.i = 0\n        self.n = len(self.df)\n        return self\n\n    def __next__(self):\n        if self.i >= self.n:\n            raise StopIteration\n\n        decompressed_imgs = []\n        is_monochrome_imgs = []\n        p_ids = []\n        i_ids = []\n        m_ids = []\n        s_ids = []\n        v_ids = []\n        l_ids = []\n        orign_h = []\n        orign_w = []\n\n#         df = self.df.iloc[range(self.i, min(self.i + self.batch_size, self.n))]\n        df = self.df.iloc[range(self.i, min(self.i + self.batch_size, self.n))]\n            \n        for p_id, i_id, m_id, s_id, v_id, l_id in df[['patient_id', 'image_id', 'machine_id', 'site_id', 'view', 'laterality']].values:\n            decompressed_img, is_monochrome_img = self.process_img(p_id, i_id)\n            (h, w, _)= np.expand_dims(decompressed_img, axis=2).shape\n            orign_h.append(np.array([h], dtype=np.int64))\n            orign_w.append(np.array([w], dtype=np.int64))   \n            \n            decompressed_imgs.append(np.expand_dims(decompressed_img, axis=2))\n            is_monochrome_imgs.append(np.array([is_monochrome_img], dtype=np.bool_))\n            p_ids.append(np.array([p_id], dtype=np.int64))\n            i_ids.append(np.array([i_id], dtype=np.int64))\n\n            if s_id==1: s_ids.append(np.array([1, 0], dtype=np.float32))\n            else: s_ids.append(np.array([0, 1], dtype=np.float32))\n                \n            if v_id=='CC': v_ids.append(np.array([1, 0], dtype=np.float32))\n            else: v_ids.append(np.array([0, 1], dtype=np.float32))\n            \n            m_id = map_fn(m_id)\n            machine_enc = np.array([0 for _ in range(10)], dtype=np.float32)\n            \n            if m_id<=9: \n                machine_enc[m_id] = 1.\n\n            m_ids.append(machine_enc)\n            \n            if l_id=='L': l_ids.append(0)\n            else: l_ids.append(1)\n            \n        self.i += self.batch_size\n\n        return decompressed_imgs, is_monochrome_imgs, p_ids, i_ids, m_ids, s_ids, v_ids, l_ids, orign_h, orign_w","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.398626Z","iopub.execute_input":"2025-02-09T08:51:36.399065Z","iopub.status.idle":"2025-02-09T08:51:36.42539Z","shell.execute_reply.started":"2025-02-09T08:51:36.39903Z","shell.execute_reply":"2025-02-09T08:51:36.424426Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"J2Ki = J2KIterator(df_j2k, Config.batch_size)\nJLLi = JLLIterator(df_jll, Config.batch_size)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.426639Z","iopub.execute_input":"2025-02-09T08:51:36.426995Z","iopub.status.idle":"2025-02-09T08:51:36.438628Z","shell.execute_reply.started":"2025-02-09T08:51:36.426952Z","shell.execute_reply":"2025-02-09T08:51:36.43794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def normalize_img(in_img):\n    min_ = in_img.min()\n    max_ = in_img.max()\n    return (255 * (in_img - min_) / (max_ - min_ )).astype(cp.uint8)\n\ndef get_img_size(in_img):\n    shape = in_img.shape\n#     print(shape)\n    return \n\ndef mux(condition, true_case, false_case):\n    neg_condition = condition ^ True\n    return condition * true_case + neg_condition * false_case\n\n\ndef common_pipeline(imgs, is_monochromes, p_ids, i_ids, m_ids, s_ids, v_ids, l_ids, orign_h, orign_w):\n    # to lower information loss\n    imgs = fn.resize(imgs,\n#                      resize_x=int(Config.resize_height_to * Config.factor), \n                     resize_y=int(Config.resize_height_to * Config.factor),\n                     # interp_type = types.INTERP_NN\n                    )\n#     print(imgs.shape)\n    # normalize\n    imgs = fn.cast(imgs, dtype=types.INT32)  # weird bug with python_function and unsigned ints\n    imgs = fn.python_function(imgs, device='gpu', function=normalize_img, batch_processing=False)\n#     fn.python_function(imgs, device='gpu', function=get_img_size, batch_processing=False)\n    # monochrome invert using mux\n    imgs_inverted = 255 - imgs\n    imgs = mux(is_monochromes, imgs_inverted, imgs)\n    imgs = fn.cast(imgs, dtype=types.UINT8)\n    \n\n    # pad to the right to be square\n    imgs = fn.pad(imgs, axes=(1,), shape=(int(Config.resize_height_to * Config.factor)), )\n    \n    # resize for model\n    imgs_2roi = fn.resize(imgs, resize_x=test_size,resize_y=test_size) / 255\n    \n    return imgs_2roi, imgs, p_ids, i_ids, m_ids, s_ids, v_ids, orign_h, orign_w","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.439561Z","iopub.execute_input":"2025-02-09T08:51:36.439807Z","iopub.status.idle":"2025-02-09T08:51:36.451664Z","shell.execute_reply.started":"2025-02-09T08:51:36.439785Z","shell.execute_reply":"2025-02-09T08:51:36.450825Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"@pipeline_def\ndef j2k_decode_pipeline():\n    imgs, is_monochromes, p_ids, i_ids, m_ids, s_ids, v_ids, l_ids, orign_h, orign_w = fn.external_source(\n        source=J2Ki, num_outputs=10, device=\"cpu\", dtype=[types.UINT8, types.BOOL, types.INT64, types.INT64, types.FLOAT, types.FLOAT, types.FLOAT, types.INT8, types.INT64, types.INT64],\n    )\n\n    imgs = fn.experimental.decoders.image(\n        imgs, device='mixed', output_type=types.ANY_DATA, dtype=DALIDataType.UINT16\n    )\n\n    return common_pipeline(imgs, is_monochromes, p_ids, i_ids, m_ids, s_ids, v_ids, l_ids, orign_h, orign_w)\n\n\n@pipeline_def\ndef jll_process_pipeline():\n    imgs, is_monochromes, p_ids, i_ids, m_ids, s_ids, v_ids, l_ids, orign_h, orign_w = fn.external_source(\n        source=JLLi, num_outputs=10, device=\"gpu\", dtype=[types.UINT16, types.BOOL, types.INT64, types.INT64, types.FLOAT, types.FLOAT, types.FLOAT, types.INT8, types.INT64, types.INT64],\n    )\n\n    imgs = fn.reinterpret(imgs, layout=\"HWC\")\n\n    return common_pipeline(imgs, is_monochromes, p_ids, i_ids, m_ids, s_ids, v_ids, l_ids, orign_h, orign_w)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.452795Z","iopub.execute_input":"2025-02-09T08:51:36.45321Z","iopub.status.idle":"2025-02-09T08:51:36.469692Z","shell.execute_reply.started":"2025-02-09T08:51:36.45316Z","shell.execute_reply":"2025-02-09T08:51:36.468794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = A.Compose([ToTensorV2()])\nimage_size = (1280, 800)\n\ndef _p(d):\n    if len(d) > 0 and len(d[0]) >= 1:\n        return d[0].numpy()\n    return np.array([0, 0, Config.resize_height_to, Config.resize_height_to, 1,1, 0])\n\ndef preprocess(data, yolo_model, transform=transform, save=True):\n    imgs_2roi = data[0]['imgs_2roi']\n    imgs = data[0]['imgs'].cpu().numpy()\n    p_ids = data[0]['p_ids'].cpu().numpy()\n    i_ids = data[0]['i_ids'].cpu().numpy()\n    orign_h = data[0]['orign_h'].cpu().numpy()\n    orign_w = data[0]['orign_w'].cpu().numpy()\n\n    B, _, _, _ = imgs.shape\n\n    with torch.no_grad():\n        \n        outputs =yolo_model(imgs_2roi.expand(-1, -1, -1, 3).permute(0, 3, 1, 2)*255)\n        outputs = postprocess(outputs, num_classes, confthre,nmsthre, class_agnostic=False)\n        # dets -> 32 x (x y x y conf cls)\n\n        # keep best\n        dets = np.array([\n                _p(d.cpu()) for d in outputs\n            ])\n\n    dets[:, 4] = dets[:, 4]*dets[:, 5]\n    cls_ = dets[:, 4].astype(np.bool_)\n    xyxy = dets[:, [0, 1, 2, 3]] / test_size\n    xyxy = np.clip(xyxy, 0, 1)\n\n    result = torch.zeros([B, Config.in_chans, Config.TARGET_HEIGHT, Config.TARGET_WIDTH], dtype=torch.float32)\n\n    for idx, (img, (xmin, ymin, xmax, ymax), lr, p_id, i_id, o_h , o_w) in enumerate(zip(imgs, xyxy, cls_, p_ids, i_ids,orign_h, orign_w)):\n        h, w, _ = img.shape\n        img = np.squeeze(img)\n        \n        current_size = int(Config.resize_height_to * Config.factor)\n        factor = current_size / o_h\n        nopad_w = int(factor*o_w)\n        \n        xmin = (xmin * w).astype(np.uint16)\n        xmax = (xmax * w).astype(np.uint16)\n        ymin = (ymin * h).astype(np.uint16)\n        ymax = (ymax * h).astype(np.uint16)\n        if xmax > nopad_w:\n            xmax = nopad_w\n\n        if lr:\n            img = np.fliplr(img)\n            xmin = w - xmin\n            xmax = w - xmax\n            xmin, xmax = xmax, xmin\n\n\n        resulting_crop_h = ymax - ymin\n        resulting_crop_w = xmax - xmin\n\n        if (1.6 * resulting_crop_w) < resulting_crop_h: # increase width\n            # how much more width do I need to add?\n            needed_width = int(resulting_crop_h // 1.6) - resulting_crop_w\n\n            # can I meet width without going past image?\n            if needed_width + xmax > w:\n                # padding/resizing is required (I use padding, in this case)\n                difference = xmax + needed_width - w\n\n                img = cv2.copyMakeBorder(img, 0, 0, difference, 0, cv2.BORDER_CONSTANT, value = 0)\n\n                # no need to offset bbox since origin is top left\n\n            # expand bbox by needed width\n            xmax += needed_width\n\n        elif (1.6 * resulting_crop_w) > resulting_crop_h: # increase height\n            # how much more height do I need to add?\n            needed_height = int(resulting_crop_w * 1.6) - resulting_crop_h\n\n            # can I meet height without going past image?\n            if ymin - needed_height < 0:\n                # padding/resizing is required (I use padding in this case)\n                difference = needed_height - ymin\n\n                img = cv2.copyMakeBorder(img, difference, 0, 0, 0, cv2.BORDER_CONSTANT, value = 0)\n\n                # offset bbox values to new origin\n                ymin += difference\n                ymax += difference\n\n            ymin -= needed_height\n        if lr:\n            img = np.fliplr(img)\n            h, w = img.shape\n\n            xmin = w - xmin\n            xmax = w - xmax\n            xmin, xmax = xmax, xmin\n#         print([h,w])\n#         print([xmin,xmax,ymin,ymax])\n#         print([current_size,nopad_w])\n#         if xmax > nopad_w:\n#             xmax = nopad_w\n\n        img = img[ymin:ymax, xmin:xmax]\n\n        h, w = img.shape\n\n        img = cv2.resize(\n            img, dsize=(Config.TARGET_WIDTH , Config.TARGET_HEIGHT), interpolation=cv2.INTER_LINEAR\n        )\n        if save:\n            image = cv2.resize(\n                img, dsize=(image_size[1], image_size[0]), interpolation=cv2.INTER_LINEAR\n            )\n            cv2.imwrite(f'{SAVE_FOLDER}/{p_ids[idx][0]}/{i_ids[idx][0]}.png', image)\n            \n        if Config.in_chans == 3:\n            img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)\n        img = img.astype(np.float32) / 255\n        img = transform(image=img)[\"image\"]\n\n        result[idx, :, :, :]  = img\n\n    return result, data[0]['m_ids'], data[0]['s_ids'], data[0]['v_ids']# torch.tensor(data[0]['m_ids'])\n            \n\nclass CustomDALIGenericIterator(DALIGenericIterator):\n    def __init__(self, length, pipelines, yolo_model, **argw):\n        self.model = yolo_model\n        self._len = length \n        super().__init__(pipelines, ['imgs_2roi', 'imgs', 'p_ids', 'i_ids', 'm_ids', 's_ids', 'v_ids', 'orign_h', 'orign_w'], **argw)\n    \n    def __next__(self):\n        batch = super().__next__()\n        batch = preprocess(batch, self.model)\n        return batch\n    \n    def __len__(self):\n        return self._len","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.471241Z","iopub.execute_input":"2025-02-09T08:51:36.471601Z","iopub.status.idle":"2025-02-09T08:51:36.502326Z","shell.execute_reply.started":"2025-02-09T08:51:36.471568Z","shell.execute_reply":"2025-02-09T08:51:36.501423Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DEBUG = False\nif DEBUG:\n    j2k_pipe = j2k_decode_pipeline(**Config.pipeline_args)\n    jll_pipe = jll_process_pipeline(**Config.pipeline_args)\n    dali_iter = CustomDALIGenericIterator(length=len(JLLi), pipelines=[jll_pipe], yolo_model=yolo_model)\n    with tqdm(dali_iter, desc='Inference', mininterval=30) as progress:\n        for batch_idx, batch in enumerate(progress):\n            pass\n    del j2k_pipe, jll_pipe, dali_iter\n    gc.collect()\n    DEBUG = False","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.503756Z","iopub.execute_input":"2025-02-09T08:51:36.504046Z","iopub.status.idle":"2025-02-09T08:51:36.513846Z","shell.execute_reply.started":"2025-02-09T08:51:36.504023Z","shell.execute_reply":"2025-02-09T08:51:36.512935Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Config_YAML(dict):\n    def __getattr__(self, key):\n        try:\n            val = self[key]\n        except KeyError:\n            return super().__getattr__(key)\n        if isinstance(val, dict):\n            return Config_YAML(val)\n        return val\n\ndef load_config(path: str, default_path: Optional[str]) -> Config_YAML:\n    with open(path) as f:\n        cfg = Config_YAML(yaml.full_load(f))\n    if default_path is not None:\n        # set keys not included in `path` by default\n        with open(default_path) as f:\n            default_cfg = Config_YAML(yaml.full_load(f))\n        for key, val in default_cfg.items():\n            if key not in cfg:\n                print(f\"used default config {key}: {val}\")\n                cfg[key] = val\n    return cfg","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.514887Z","iopub.execute_input":"2025-02-09T08:51:36.515132Z","iopub.status.idle":"2025-02-09T08:51:36.530185Z","shell.execute_reply.started":"2025-02-09T08:51:36.515109Z","shell.execute_reply":"2025-02-09T08:51:36.529159Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class BCDModel(LightningModule):\n    def __init__(self, cfg: dict, out_dir=None):\n        super().__init__()\n        if not isinstance(cfg, Config):\n            cfg = Config_YAML(cfg)\n        self.save_hyperparameters(cfg, ignore=[\"id_class_nums\"])\n        self.test_results_fp = None\n        self.out_dir=out_dir\n\n        # NN architecture\n        self.backbone = timm.create_model(\n            cfg.model_name,\n            in_chans=cfg.in_channel,\n            pretrained=False,\n            num_classes=cfg.num_classes,\n        )\n        if cfg.pos_weight == False:\n            self.loss_fn_id = torch.nn.BCEWithLogitsLoss()\n        else:\n            self.loss_fn_id = torch.nn.BCEWithLogitsLoss(pos_weight = torch.tensor([cfg.pos_weight]))\n        self.val_loss_fn_id = torch.nn.BCEWithLogitsLoss()\n\n    def forward(self, x):\n        x = self.backbone(x)\n        return x\n    \nclass BCDModel_machine(LightningModule):\n    def __init__(self, cfg: dict, out_dir=None):\n        super().__init__()\n        if not isinstance(cfg, Config):\n            cfg = Config_YAML(cfg)\n        self.save_hyperparameters(cfg, ignore=[\"id_class_nums\"])\n        self.test_results_fp = None\n        self.out_dir=out_dir\n\n        self.backbone = timm.create_model(\n            cfg.model_name,\n            in_chans=cfg.in_channel,\n            pretrained=False\n        )\n\n        clsn = self.backbone.default_cfg['classifier']\n        n_features = self.backbone._modules[clsn].in_features\n        self.backbone._modules[clsn] = nn.Identity()\n        \n        self.nn_emb = nn.Linear(in_features=10, out_features=32)\n        self.nn_cancer = nn.Linear(in_features=n_features+32, out_features=cfg.num_classes)\n\n    def forward(self, x, meta):\n        image_fea = self.backbone(x)\n        meta_fea = self.nn_emb(meta)\n        fea = torch.cat((image_fea, meta_fea), dim=1)\n        out = self.nn_cancer(fea)\n        return out\n    \nclass BCDModel_meta(LightningModule):\n    def __init__(self, cfg: dict, out_dir=None):\n        super().__init__()\n        if not isinstance(cfg, Config):\n            cfg = Config_YAML(cfg)\n        self.save_hyperparameters(cfg, ignore=[\"id_class_nums\"])\n        self.test_results_fp = None\n        self.out_dir=out_dir\n\n        self.backbone = timm.create_model(\n            cfg.model_name,\n            in_chans=cfg.in_channel,\n            pretrained=False\n        )\n\n        clsn = self.backbone.default_cfg['classifier']\n        n_features = self.backbone._modules[clsn].in_features\n        self.backbone._modules[clsn] = nn.Identity()\n        \n        self.nn_emb = nn.Linear(in_features=14, out_features=96)\n        self.nn_cancer = nn.Linear(in_features=n_features+96, out_features=cfg.num_classes)\n\n    def forward(self, x, meta):\n        image_fea = self.backbone(x)\n        meta_fea = self.nn_emb(meta)\n        fea = torch.cat((image_fea, meta_fea), dim=1)\n        out = self.nn_cancer(fea)\n        return out","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.531475Z","iopub.execute_input":"2025-02-09T08:51:36.531747Z","iopub.status.idle":"2025-02-09T08:51:36.548812Z","shell.execute_reply.started":"2025-02-09T08:51:36.531711Z","shell.execute_reply":"2025-02-09T08:51:36.547871Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict(models, loader):\n    \"\"\"\n    Torch predict function.\n\n    Args:\n        model (torch model): Model to predict with.\n        dataset (CustomDataset): Dataset to predict on.\n        loss_config (dict): Loss config, used for activation functions.\n        batch_size (int, optional): Batch size. Defaults to 64.\n        device (str, optional): Device for torch. Defaults to \"cuda\".\n\n    Returns:\n        numpy array [len(dataset) x num_classes]: Predictions.\n    \"\"\"\n    preds = [[] for _ in range(len(models))]\n\n    for x, machine, site, view in tqdm(loader):\n        x = x.cuda()\n        meta = torch.cat([machine, site, view], dim=1).cuda()\n        machine = machine.cuda()\n        with torch.no_grad():\n            for i, model in enumerate(models):\n                if i <= 0:\n                    outputs = model(x, machine).sigmoid()\n#                     outputs += model(torch.flip(x, dims=[3]), machine).sigmoid()\n#                     outputs /= 2.0\n                elif i <= 2:\n                    \n                    outputs = model(x, meta).sigmoid()\n#                     outputs += model(torch.flip(x, dims=[3]), meta).sigmoid()       \n#                     outputs /= 2.0\n                else:\n                    outputs = model(x).sigmoid()\n#                     outputs += model(torch.flip(x, dims=[3])).sigmoid()\n#                     outputs /= 2.0\n                outputs = outputs.cpu().numpy()\n                preds[i].append(outputs)\n    for i in range(len(models)):\n        preds[i] = np.nan_to_num(np.concatenate(preds[i]))\n        \n    preds = np.mean(preds,0)\n    \n    return preds","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.552582Z","iopub.execute_input":"2025-02-09T08:51:36.55283Z","iopub.status.idle":"2025-02-09T08:51:36.566211Z","shell.execute_reply.started":"2025-02-09T08:51:36.552808Z","shell.execute_reply":"2025-02-09T08:51:36.565388Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Model_path = '/kaggle/input/convnext-nano-1536960-13ep-external/'\nconv_cfg =load_config(\"/kaggle/input/config/pseudo_convnext_nano_1536960.yaml\", \"/kaggle/input/config/default.yaml\")\neff_cfg =load_config(\"/kaggle/input/config/pseudo_effnetv2_1536960.yaml\", \"/kaggle/input/config/default.yaml\")\nif (SOURCE == 'train' and CV==True) or ONE_FOLD: weight_path = (glob.glob(Model_path + '*/1/*pF1*.ckpt'))   \nelse: weight_path = sorted(glob.glob(Model_path + '/*/*/*pF1*.ckpt'))\nif MODEL_PATH != []: weight_path = MODEL_PATH\nmodels = []\nfor fold,weight in tqdm(enumerate(weight_path)):\n    cfg = eff_cfg\n\n    if fold<=0: model = BCDModel_machine(cfg)\n    elif fold<=2: model = BCDModel_meta(cfg)\n    else: model = BCDModel(cfg)\n\n    model = model.load_from_checkpoint(weight,map_location='cuda:0')\n    model = model.cuda()\n    model.eval()\n    models.append(model)\nweight_path","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:36.567517Z","iopub.execute_input":"2025-02-09T08:51:36.567847Z","iopub.status.idle":"2025-02-09T08:51:40.836562Z","shell.execute_reply.started":"2025-02-09T08:51:36.567816Z","shell.execute_reply":"2025-02-09T08:51:40.835731Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if(len(df_jll)!=0):\n\n    jll_pipe = jll_process_pipeline(**Config.pipeline_args)\n    jll_iter = CustomDALIGenericIterator(length=len(JLLi), pipelines=[jll_pipe], yolo_model=yolo_model)\n    preds = predict(models, jll_iter)\n\n    if SOURCE != 'train': df_jll['cancer'] = preds\n    else: df_jll['cancer_pred'] = preds\n        \n    del jll_pipe, jll_iter, preds\n    gc.collect()\n    torch.cuda.empty_cache()\n    ReleaseUnusedMemory()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:51:40.83796Z","iopub.execute_input":"2025-02-09T08:51:40.838638Z","iopub.status.idle":"2025-02-09T08:52:02.399405Z","shell.execute_reply.started":"2025-02-09T08:51:40.8386Z","shell.execute_reply":"2025-02-09T08:52:02.398573Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"j2k_pipe = j2k_decode_pipeline(**Config.pipeline_args)\nj2k_iter = CustomDALIGenericIterator(length=len(J2Ki), pipelines=[j2k_pipe], yolo_model=yolo_model)\npreds = predict(models, j2k_iter)\n\nif SOURCE!='train': df_j2k['cancer'] = preds\nelse: df_j2k['cancer_pred'] = preds\n\ndel j2k_pipe, j2k_iter, models, preds\ngc.collect()\ntorch.cuda.empty_cache()\nReleaseUnusedMemory()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:52:02.401284Z","iopub.execute_input":"2025-02-09T08:52:02.401586Z","iopub.status.idle":"2025-02-09T08:52:16.87569Z","shell.execute_reply.started":"2025-02-09T08:52:02.401561Z","shell.execute_reply":"2025-02-09T08:52:16.874395Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_mean = pd.concat([df_jll, df_j2k]).reset_index(drop=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:52:16.877008Z","iopub.execute_input":"2025-02-09T08:52:16.877336Z","iopub.status.idle":"2025-02-09T08:52:16.885777Z","shell.execute_reply.started":"2025-02-09T08:52:16.877311Z","shell.execute_reply":"2025-02-09T08:52:16.884812Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## LSTM Inference","metadata":{}},{"cell_type":"code","source":"meta_ch = 2\nmeta_dim = 32\nmeta_cols = [f'site{i}' for i in [1,2]]\nmeta_cols","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:52:16.887Z","iopub.execute_input":"2025-02-09T08:52:16.887294Z","iopub.status.idle":"2025-02-09T08:52:16.961252Z","shell.execute_reply.started":"2025-02-09T08:52:16.887271Z","shell.execute_reply":"2025-02-09T08:52:16.960339Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import albumentations\nfrom torch.utils.data import Dataset\n\nin_chans = 1\nout_dim = 1\nn_slices = 4\n\nclass RSNADataset(Dataset):\n    def __init__(self, data, pids):\n\n        self.data = data\n        self.pids = pids\n        self.transform = albumentations.Compose([])\n\n    def __len__(self):\n        return len(self.pids)\n\n    def __getitem__(self, index):\n        pid = self.pids[index]\n        df_this = self.data[pid]\n\n        indices = list(range(n_slices))\n\n        images = np.zeros((n_slices, 1, image_size[0], image_size[1]))\n        metas = []\n        for i in indices:\n            idx = i % df_this.shape[0]\n            row = df_this.iloc[idx]\n            image = cv2.imread(os.path.join(row.filepath), 0)\n            image = self.transform(image=image)['image']\n            image = image.astype(np.float32) / 255.\n            images[i, 0] = image\n            metas.append(row[meta_cols])\n\n        return torch.tensor(images).float(), len(df_this), row.prediction_id, torch.tensor(metas).float()\n    \n\ndef collate_fn(batch):\n    images, lens, pred_ids, metas = list(zip(*batch))\n    images = torch.stack(images)\n    lens = list(lens)\n    pred_ids = list(pred_ids)\n    metas = torch.stack(metas)\n    return images, lens, pred_ids, metas\n\nclass TimmLSTMModel(nn.Module):\n    def __init__(self, backbone, pretrained=False, meta=False):\n        super(TimmLSTMModel, self).__init__()\n\n        self.encoder = timm.create_model(\n            backbone,\n            in_chans=in_chans,\n            num_classes=out_dim,\n            features_only=False,\n            pretrained=pretrained\n        )\n        self.meta = meta\n        \n        if 'efficient' in backbone:\n            hdim = self.encoder.conv_head.out_channels\n            self.encoder.classifier = nn.Identity()\n        elif 'convnext' in backbone:\n            hdim = self.encoder.head.fc.in_features\n            self.encoder.head.fc = nn.Identity()\n            \n        if self.meta:\n            self.meta_mlp = nn.Sequential(\n                nn.Linear(meta_ch, 32),\n                nn.BatchNorm1d(32),\n                nn.LeakyReLU(0.1),\n                nn.Linear(32, meta_dim),\n            )                \n\n        self.lstm = nn.LSTM(hdim + (meta_dim if self.meta else 0), 256, num_layers=2, dropout=0, bidirectional=True, batch_first=True)\n        self.head = nn.Sequential(\n            nn.Linear(512, 256),\n            nn.BatchNorm1d(256),\n            nn.Dropout(0),\n            nn.LeakyReLU(0.1),\n            nn.Linear(256, out_dim),\n        )\n\n\n    def forward(self, x, metas):  # (bs, ns, ch=1, sz, sz)\n        bs = x.shape[0]\n        x = x.view(bs * n_slices, in_chans, image_size[0], image_size[1])\n        feat = self.encoder(x)\n        feat = feat.view(bs, n_slices, -1)\n\n        if self.meta:\n            metas = metas.view(bs * n_slices, meta_ch)\n            feat_meta = self.meta_mlp(metas)\n            feat_meta = feat_meta.view(bs, n_slices, -1)\n            feat = torch.cat([feat, feat_meta], -1)\n        \n        feat, _ = self.lstm(feat)\n        feat = feat.contiguous().view(bs * n_slices, 512)\n        logits = self.head(feat)\n        logits = logits.view(bs, -1)\n        return logits     ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:52:16.962434Z","iopub.execute_input":"2025-02-09T08:52:16.96279Z","iopub.status.idle":"2025-02-09T08:52:16.979987Z","shell.execute_reply.started":"2025-02-09T08:52:16.962757Z","shell.execute_reply":"2025-02-09T08:52:16.979071Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"models = []\n\nbackbone = 'convnext_tiny_384_in22ft1k'\nfor fold in [0,4]:  # 0 4\n    model_file = f'/kaggle/input/convnt-lstm-1280x800pos3x-20ep-4ext-savebysite-yol/convnt_lstm_1280x800pos3x_20ep_4ext_savebysite_yolox_fold{fold}_best.pth'\n    sd = torch.load(model_file, map_location='cpu')\n    if 'model_state_dict' in sd.keys():\n        sd = sd['model_state_dict']\n    sd = {k[7:] if k.startswith('module.') else k: sd[k] for k in sd.keys()}\n    model = TimmLSTMModel(backbone)\n    model.load_state_dict(sd, strict=True)\n    model.cuda()\n    model.eval()\n    models.append(model)\n    \nbackbone = 'tf_efficientnetv2_s_in21ft1k'\nfor fold in [2,3,4]:\n    model_file = f'/kaggle/input/v2s-lstm-1280x800pos3x-20ep-4ext-savebysite-5e6/v2s_lstm_1280x800pos3x_20ep_4ext_savebysite_5e6_fold{fold}_best.pth'\n    sd = torch.load(model_file, map_location='cpu')\n    if 'model_state_dict' in sd.keys():\n        sd = sd['model_state_dict']\n    sd = {k[7:] if k.startswith('module.') else k: sd[k] for k in sd.keys()}\n    model = TimmLSTMModel(backbone)\n    model.load_state_dict(sd, strict=True)\n    model.cuda()\n    model.eval()\n    models.append(model)\n\nbackbone = 'convnext_tiny_384_in22ft1k'\nfor fold in [1]:\n    model_file = f'/kaggle/input/yolonano-convnt-lstm-1280x800pos3x-20ep-4ext-saveb/convnt_lstm_1280x800pos3x_20ep_4ext_savebysite_yolonano_fold{fold}_best.pth'\n    sd = torch.load(model_file, map_location='cpu')\n    if 'model_state_dict' in sd.keys():\n        sd = sd['model_state_dict']\n    sd = {k[7:] if k.startswith('module.') else k: sd[k] for k in sd.keys()}\n    model = TimmLSTMModel(backbone)\n    model.load_state_dict(sd, strict=True)\n    model.cuda()\n    model.eval()\n    models.append(model)\n\nbackbone = 'convnext_tiny_384_in22ft1k'\nfor fold in [3]:\n    model_file = f'/kaggle/input/convnt-lstm-1280x800pos3x-20ep-4ext-savebysite-sit/convnt_lstm_1280x800pos3x_20ep_4ext_savebysite_sitemeta_fold{fold}_best.pth'\n    sd = torch.load(model_file, map_location='cpu')\n    if 'model_state_dict' in sd.keys():\n        sd = sd['model_state_dict']\n    sd = {k[7:] if k.startswith('module.') else k: sd[k] for k in sd.keys()}\n    model = TimmLSTMModel(backbone, meta=True)\n    model.load_state_dict(sd, strict=True)\n    model.cuda()\n    model.eval()\n    models.append(model)  \n    \nlen(models)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:52:16.981135Z","iopub.execute_input":"2025-02-09T08:52:16.981434Z","iopub.status.idle":"2025-02-09T08:52:20.736132Z","shell.execute_reply.started":"2025-02-09T08:52:16.98141Z","shell.execute_reply":"2025-02-09T08:52:20.735217Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import albumentations\nfrom torch.utils.data import Dataset\n\nPROBS = []\nPRED_IDS = []\ndataset_test = RSNADataset(data, pids)\nloader_test = torch.utils.data.DataLoader(dataset_test, batch_size=2, shuffle=False, num_workers=4, collate_fn=collate_fn)\nbar = tqdm(loader_test)\n\nwith torch.no_grad():\n    for images, lens, pred_ids, metas in bar:\n        images = images.cuda()\n        metas = metas.cuda()\n        probs = torch.stack([model(images, metas).sigmoid() for model in models], 0).mean(0)\n        \n        probs_this = []\n        for i in range(images.shape[0]):\n            probs_this.append(probs[i, :lens[i]].mean())\n        probs_this = torch.stack(probs_this)\n        PROBS.append(probs_this.detach().cpu())\n        PRED_IDS = PRED_IDS + pred_ids","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:52:20.737405Z","iopub.execute_input":"2025-02-09T08:52:20.737805Z","iopub.status.idle":"2025-02-09T08:53:11.766271Z","shell.execute_reply.started":"2025-02-09T08:52:20.737778Z","shell.execute_reply":"2025-02-09T08:53:11.764959Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PROBS = torch.cat(PROBS).numpy()\n\n# df_sub = pd.DataFrame({\n#     'prediction_id': PRED_IDS,\n#     'cancer': (np.array(PROBS) > THRESHOLD).astype(float)\n# })\n\n# df_sub.to_csv('/kaggle/working/submission.csv', index=False)\n\ndf_lstm = pd.DataFrame({\n    'prediction_id': PRED_IDS,\n    'cancer': np.array(PROBS)\n})","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:53:11.767913Z","iopub.execute_input":"2025-02-09T08:53:11.768294Z","iopub.status.idle":"2025-02-09T08:53:11.776229Z","shell.execute_reply.started":"2025-02-09T08:53:11.768257Z","shell.execute_reply":"2025-02-09T08:53:11.775374Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_mean['prediction_id'] = df_mean['patient_id'].astype(str) + '_' + df_mean['laterality']\ntry:\n    df_mean = df_mean[['prediction_id', 'cancer_pred']]\n    df_mean = df_mean.rename({'cancer_pred': 'cancer'}, axis=1)\nexcept:\n    df_mean[['prediction_id', 'cancer']]\ndf_mean = df_mean.groupby(\"prediction_id\").mean().reset_index()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:53:11.777461Z","iopub.execute_input":"2025-02-09T08:53:11.777914Z","iopub.status.idle":"2025-02-09T08:53:11.793798Z","shell.execute_reply.started":"2025-02-09T08:53:11.777881Z","shell.execute_reply":"2025-02-09T08:53:11.792911Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.merge(df_mean, df_lstm, on=['prediction_id'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:53:11.794846Z","iopub.execute_input":"2025-02-09T08:53:11.795211Z","iopub.status.idle":"2025-02-09T08:53:11.805283Z","shell.execute_reply.started":"2025-02-09T08:53:11.795154Z","shell.execute_reply":"2025-02-09T08:53:11.804329Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ENSEMBLE_WEIGHT = [3,8]\n\ndf['cancer'] = (df['cancer_x']*ENSEMBLE_WEIGHT[0] + df['cancer_y']*ENSEMBLE_WEIGHT[1]) / sum(ENSEMBLE_WEIGHT)\ndf = df[['prediction_id', 'cancer']]\n# df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:53:11.806448Z","iopub.execute_input":"2025-02-09T08:53:11.806748Z","iopub.status.idle":"2025-02-09T08:53:11.818496Z","shell.execute_reply.started":"2025-02-09T08:53:11.806718Z","shell.execute_reply":"2025-02-09T08:53:11.817541Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"THRESHOLD = 0.46\ndf[\"cancer\"] = (df[\"cancer\"] > THRESHOLD).astype(int)\ndf.to_csv('/kaggle/working/submission.csv', index = False)\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:53:11.819748Z","iopub.execute_input":"2025-02-09T08:53:11.820091Z","iopub.status.idle":"2025-02-09T08:53:11.839366Z","shell.execute_reply.started":"2025-02-09T08:53:11.820062Z","shell.execute_reply":"2025-02-09T08:53:11.838529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_origin.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:54:27.256131Z","iopub.execute_input":"2025-02-09T08:54:27.257044Z","iopub.status.idle":"2025-02-09T08:54:27.26559Z","shell.execute_reply.started":"2025-02-09T08:54:27.257012Z","shell.execute_reply":"2025-02-09T08:54:27.264505Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"display(df_origin.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:55:23.288137Z","iopub.execute_input":"2025-02-09T08:55:23.288662Z","iopub.status.idle":"2025-02-09T08:55:23.294841Z","shell.execute_reply.started":"2025-02-09T08:55:23.288631Z","shell.execute_reply":"2025-02-09T08:55:23.293859Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"display(df.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T08:55:51.353173Z","iopub.execute_input":"2025-02-09T08:55:51.353568Z","iopub.status.idle":"2025-02-09T08:55:51.359502Z","shell.execute_reply.started":"2025-02-09T08:55:51.35354Z","shell.execute_reply":"2025-02-09T08:55:51.358542Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mask = df_origin[\"cancer\"] != df[\"cancer\"]\ndifference =  df_origin[mask]\n\ndisplay(difference)\ndisplay(difference.shape)\ndifference.to_csv('/kaggle/working/3rd_difference.csv', index = False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-09T09:00:28.164695Z","iopub.execute_input":"2025-02-09T09:00:28.165061Z","iopub.status.idle":"2025-02-09T09:00:28.177124Z","shell.execute_reply.started":"2025-02-09T09:00:28.165032Z","shell.execute_reply":"2025-02-09T09:00:28.176247Z"}},"outputs":[],"execution_count":null}]}