{
  "id": 222180,
  "title": "Is anyone working with fastai medical?",
  "url": "/competitions/vinbigdata-chest-xray-abnormalities-detection/discussion/222180",
  "author_name": "Charlie Craine",
  "post_date": "2021-02-25T18:02:06.994000",
  "votes": 4,
  "comment_count": 9,
  "views": 0,
  "content": "<p>I'm just curious if anyone is working with fastai medical and bounding boxes. The one thing I've always wanted with fastai is a more elegant solution for bounding boxes. </p>\n<p>I put together a simple notebook to look at the data:<br>\n<a href=\"https://www.kaggle.com/crained/vinbigdata-fastai-get-started\" target=\"_blank\">https://www.kaggle.com/crained/vinbigdata-fastai-get-started</a></p>\n<p>I'd be curious if anyone has worked out cleaner solutions for bounding boxes. </p>",
  "messages": [
    {
      "id": 1218314,
      "postDate": "2021-02-25T18:02:06.993Z",
      "content": "<p>I'm just curious if anyone is working with fastai medical and bounding boxes. The one thing I've always wanted with fastai is a more elegant solution for bounding boxes. </p>\n<p>I put together a simple notebook to look at the data:<br>\n<a href=\"https://www.kaggle.com/crained/vinbigdata-fastai-get-started\" target=\"_blank\">https://www.kaggle.com/crained/vinbigdata-fastai-get-started</a></p>\n<p>I'd be curious if anyone has worked out cleaner solutions for bounding boxes. </p>",
      "rawMarkdown": "I'm just curious if anyone is working with fastai medical and bounding boxes. The one thing I've always wanted with fastai is a more elegant solution for bounding boxes. \n\nI put together a simple notebook to look at the data:\nhttps://www.kaggle.com/crained/vinbigdata-fastai-get-started\n\nI'd be curious if anyone has worked out cleaner solutions for bounding boxes. ",
      "votes": 4
    },
    {
      "id": 1220262,
      "postDate": "2021-02-27T19:14:42.127Z",
      "content": "<p>I have made it work but havent sub'd anything  yet. </p>\n<p>You need to know the internals of fastai transforms and data to make this work, the existing bounding box examples are pretty barebone. When this comp finishes and if my approach is worth anything I'd contribute it to fastai.</p>",
      "rawMarkdown": "I have made it work but havent sub'd anything  yet. \n\nYou need to know the internals of fastai transforms and data to make this work, the existing bounding box examples are pretty barebone. When this comp finishes and if my approach is worth anything I'd contribute it to fastai.",
      "votes": 1,
      "replies": [
        {
          "id": 1220339,
          "postDate": "2021-02-27T21:40:26.253Z",
          "content": "<p>That'd be great to see! </p>",
          "rawMarkdown": "That'd be great to see! ",
          "votes": 1
        }
      ]
    },
    {
      "id": 1218401,
      "postDate": "2021-02-25T20:02:50.707Z",
      "content": "<p>Did you benchmark how fast the DataLoader is? I <a href=\"https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/discussion/211010\" target=\"_blank\">got a bit worried</a> about how long it takes to read the .dicom files - especially when you have limited memory and only two CPUs in a Kaggle notebook (and I think <code>fastai</code> is also using pydicom in the background, which I looked at). For that reason, the main idea I've come up with is to construct something that efficiently (i.e. instead of opening 32 files for a batch of 32, you only access one file once and get the whole batch back) creates a whole batch at a time from a file that contains all images (as single channel images) in a way that can also be parallelized. It seems that when you do that, you want to then construct a fastai-DataLoader and tell it that you are using a batch size of 1 (when in fact, this batch of 1 is the whole batch loaded in one go). That <a href=\"https://www.kaggle.com/bjoernholzhauer/vinbigdata-chest-x-ray-comparing-dataloader-speed\" target=\"_blank\">approach is pretty efficient</a>. In a way, I guess that's what TFRecords do for you, if you use TensorFlow…</p>\n<p>In any case, I don't think fastai is currently perfectly set-up to support this particular task, so I suspect you'd have to define a PyTorch neural network (you can pretty much use the PyTorch implementation of soemthing you find interesting), set-up your own custom Learner and provide it with your own custom DataLoaders (plus you may have to ensure your loss function works with fastai). I'm kind of suspecting someone must already have done this (perhaps for a previous competition), but I'm curious about seeing a nice example.</p>",
      "rawMarkdown": "Did you benchmark how fast the DataLoader is? I [got a bit worried](https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/discussion/211010) about how long it takes to read the .dicom files - especially when you have limited memory and only two CPUs in a Kaggle notebook (and I think `fastai` is also using pydicom in the background, which I looked at). For that reason, the main idea I've come up with is to construct something that efficiently (i.e. instead of opening 32 files for a batch of 32, you only access one file once and get the whole batch back) creates a whole batch at a time from a file that contains all images (as single channel images) in a way that can also be parallelized. It seems that when you do that, you want to then construct a fastai-DataLoader and tell it that you are using a batch size of 1 (when in fact, this batch of 1 is the whole batch loaded in one go). That [approach is pretty efficient](https://www.kaggle.com/bjoernholzhauer/vinbigdata-chest-x-ray-comparing-dataloader-speed). In a way, I guess that's what TFRecords do for you, if you use TensorFlow...\n\nIn any case, I don't think fastai is currently perfectly set-up to support this particular task, so I suspect you'd have to define a PyTorch neural network (you can pretty much use the PyTorch implementation of soemthing you find interesting), set-up your own custom Learner and provide it with your own custom DataLoaders (plus you may have to ensure your loss function works with fastai). I'm kind of suspecting someone must already have done this (perhaps for a previous competition), but I'm curious about seeing a nice example.",
      "votes": 1,
      "replies": [
        {
          "id": 1218480,
          "postDate": "2021-02-25T23:25:50.943Z",
          "content": "<p>I haven't yet. I am working on the bbox notebook now. I pulled in the 1024 dataset with the DICOM data as a CSV. </p>\n<p>I've been working off some of the Wheat competition notebooks. But just was hoping maybe someone had a better solution. Bounding boxes just don't seem really not fully built out. </p>\n<p>I might work on it a bit more but guess I'll have to see if it ends up taking too much time. I used YOLO for that Wheat competition partly because of how limited fastai seemed for bbox. </p>",
          "rawMarkdown": "I haven't yet. I am working on the bbox notebook now. I pulled in the 1024 dataset with the DICOM data as a CSV. \n\nI've been working off some of the Wheat competition notebooks. But just was hoping maybe someone had a better solution. Bounding boxes just don't seem really not fully built out. \n\nI might work on it a bit more but guess I'll have to see if it ends up taking too much time. I used YOLO for that Wheat competition partly because of how limited fastai seemed for bbox. "
        },
        {
          "id": 1220267,
          "postDate": "2021-02-27T19:18:46.273Z",
          "content": "<p>I've coded a decorator similar to <a href=\"https://www.kaggle.com/lru\" target=\"_blank\">@lru</a>_cache that caches dicom reading to disk in it's original size. With that and on the fly resizing (eg to 512x512) a single pass of the whole dataloader takes just a few mins (8 iirc).</p>",
          "rawMarkdown": "I've coded a decorator similar to @lru_cache that caches dicom reading to disk in it's original size. With that and on the fly resizing (eg to 512x512) a single pass of the whole dataloader takes just a few mins (8 iirc).",
          "votes": 1
        },
        {
          "id": 1220340,
          "postDate": "2021-02-27T21:41:19.997Z",
          "content": "<p>Will you release that after the competition too? IT'd be really great to see!</p>",
          "rawMarkdown": "Will you release that after the competition too? IT'd be really great to see!"
        },
        {
          "id": 1220733,
          "postDate": "2021-02-28T09:57:26.750Z",
          "content": "<p>Here you are:</p>\n<pre><code>use_memmap = True\nload_fn = np.load if not use_memmap else partial(np.lib.format.open_memmap, mode='r')\n\ndef cache_to_disk(suffix=\"\",p_cache=p_cache / 'npy'):\n    def _cache_to_disk(func):\n        @functools.wraps(func)\n        def wrapper_decorator(*args, **kwargs):\n            p_cache.mkdir(parents=True, exist_ok=True)\n            p_cached = (p_cache / (str(args[0]) + suffix)).with_suffix(\".npy\")\n            value = None\n            if p_cached.exists():\n                try:\n                    value = load_fn(str(p_cached))\n                except Exception as e:\n                    print(f\"Inconsistent {p_cached}, recaching.\")\n            if value is None:\n                value = func(*args, **kwargs)\n                np.save(str(p_cached),value.cpu().numpy() if isinstance(value,Tensor) else value)\n            return value if isinstance(value,Tensor) else torch.from_numpy(value)\n        return wrapper_decorator\n    return _cache_to_disk\n</code></pre>\n<p>and then:</p>\n<pre><code>@cache_to_disk()\ndef read_dcm(image_id):\n    dcm=Path(p_train / image_id).with_suffix('.dicom').dcmread()\n    img=TensorCTScan(dcm.windowed(getattr(dcm,'WindowWidth', (1&lt;&lt;dcm.HighBit+1) - 1),\n                                  getattr(dcm,'WindowCenter',(1&lt;&lt;dcm.HighBit  ) - 1)))\n    if dcm.PhotometricInterpretation=='MONOCHROME2': img = 1 - img\n    return img\ndef read_image(image_id):\n    img = read_dcm(image_id)\n    img=Image.frombuffer('F',img.shape[::-1],img.numpy())\n    return PILImageBW(img)\n#your other code .....\n</code></pre>",
          "rawMarkdown": "Here you are:\n\n```\nuse_memmap = True\nload_fn = np.load if not use_memmap else partial(np.lib.format.open_memmap, mode='r')\n\ndef cache_to_disk(suffix=\"\",p_cache=p_cache / 'npy'):\n    def _cache_to_disk(func):\n        @functools.wraps(func)\n        def wrapper_decorator(*args, **kwargs):\n            p_cache.mkdir(parents=True, exist_ok=True)\n            p_cached = (p_cache / (str(args[0]) + suffix)).with_suffix(\".npy\")\n            value = None\n            if p_cached.exists():\n                try:\n                    value = load_fn(str(p_cached))\n                except Exception as e:\n                    print(f\"Inconsistent {p_cached}, recaching.\")\n            if value is None:\n                value = func(*args, **kwargs)\n                np.save(str(p_cached),value.cpu().numpy() if isinstance(value,Tensor) else value)\n            return value if isinstance(value,Tensor) else torch.from_numpy(value)\n        return wrapper_decorator\n    return _cache_to_disk\n```\n\nand then:\n\n```\n@cache_to_disk()\ndef read_dcm(image_id):\n    dcm=Path(p_train / image_id).with_suffix('.dicom').dcmread()\n    img=TensorCTScan(dcm.windowed(getattr(dcm,'WindowWidth', (1<<dcm.HighBit+1) - 1),\n                                  getattr(dcm,'WindowCenter',(1<<dcm.HighBit  ) - 1)))\n    if dcm.PhotometricInterpretation=='MONOCHROME2': img = 1 - img\n    return img\ndef read_image(image_id):\n    img = read_dcm(image_id)\n    img=Image.frombuffer('F',img.shape[::-1],img.numpy())\n    return PILImageBW(img)\n#your other code .....\n```\n",
          "votes": 4
        },
        {
          "id": 1220891,
          "postDate": "2021-02-28T13:02:31.533Z",
          "content": "<p><a href=\"https://www.kaggle.com/antorsae\" target=\"_blank\">@antorsae</a> Great. I'll give it a try. I've moved to another object detection framework for now but cannot wait to see your fastai code. It'd be great to see something really good get adopted into the fastai codebase. </p>",
          "rawMarkdown": "@antorsae Great. I'll give it a try. I've moved to another object detection framework for now but cannot wait to see your fastai code. It'd be great to see something really good get adopted into the fastai codebase. "
        },
        {
          "id": 1244388,
          "postDate": "2021-03-19T00:33:47.670Z",
          "content": "<p><a href=\"https://www.kaggle.com/antorsae\" target=\"_blank\">@antorsae</a> are you using fastai for this competition or did you jump to something else? Just curious. I didn't get as far with fastai for this and jumped to other vision detectors. </p>",
          "rawMarkdown": "@antorsae are you using fastai for this competition or did you jump to something else? Just curious. I didn't get as far with fastai for this and jumped to other vision detectors. "
        }
      ]
    }
  ],
  "comments": [
    {
      "id": 1220262,
      "author_name": "Andrés Miguel Torrubia Sáez",
      "author_url": "",
      "post_date": "2021-02-27T19:14:42.127000",
      "content": "<p>I have made it work but havent sub'd anything  yet. </p>\n<p>You need to know the internals of fastai transforms and data to make this work, the existing bounding box examples are pretty barebone. When this comp finishes and if my approach is worth anything I'd contribute it to fastai.</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1220339,
          "author_name": "Charlie Craine",
          "author_url": "",
          "post_date": "2021-02-27T21:40:26.253000",
          "content": "<p>That'd be great to see! </p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1218401,
      "author_name": "Björn",
      "author_url": "",
      "post_date": "2021-02-25T20:02:50.707000",
      "content": "<p>Did you benchmark how fast the DataLoader is? I <a href=\"https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/discussion/211010\" target=\"_blank\">got a bit worried</a> about how long it takes to read the .dicom files - especially when you have limited memory and only two CPUs in a Kaggle notebook (and I think <code>fastai</code> is also using pydicom in the background, which I looked at). For that reason, the main idea I've come up with is to construct something that efficiently (i.e. instead of opening 32 files for a batch of 32, you only access one file once and get the whole batch back) creates a whole batch at a time from a file that contains all images (as single channel images) in a way that can also be parallelized. It seems that when you do that, you want to then construct a fastai-DataLoader and tell it that you are using a batch size of 1 (when in fact, this batch of 1 is the whole batch loaded in one go). That <a href=\"https://www.kaggle.com/bjoernholzhauer/vinbigdata-chest-x-ray-comparing-dataloader-speed\" target=\"_blank\">approach is pretty efficient</a>. In a way, I guess that's what TFRecords do for you, if you use TensorFlow…</p>\n<p>In any case, I don't think fastai is currently perfectly set-up to support this particular task, so I suspect you'd have to define a PyTorch neural network (you can pretty much use the PyTorch implementation of soemthing you find interesting), set-up your own custom Learner and provide it with your own custom DataLoaders (plus you may have to ensure your loss function works with fastai). I'm kind of suspecting someone must already have done this (perhaps for a previous competition), but I'm curious about seeing a nice example.</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1218480,
          "author_name": "Charlie Craine",
          "author_url": "",
          "post_date": "2021-02-25T23:25:50.943000",
          "content": "<p>I haven't yet. I am working on the bbox notebook now. I pulled in the 1024 dataset with the DICOM data as a CSV. </p>\n<p>I've been working off some of the Wheat competition notebooks. But just was hoping maybe someone had a better solution. Bounding boxes just don't seem really not fully built out. </p>\n<p>I might work on it a bit more but guess I'll have to see if it ends up taking too much time. I used YOLO for that Wheat competition partly because of how limited fastai seemed for bbox. </p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 1220267,
          "author_name": "Andrés Miguel Torrubia Sáez",
          "author_url": "",
          "post_date": "2021-02-27T19:18:46.273000",
          "content": "<p>I've coded a decorator similar to <a href=\"https://www.kaggle.com/lru\" target=\"_blank\">@lru</a>_cache that caches dicom reading to disk in it's original size. With that and on the fly resizing (eg to 512x512) a single pass of the whole dataloader takes just a few mins (8 iirc).</p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 1220340,
          "author_name": "Charlie Craine",
          "author_url": "",
          "post_date": "2021-02-27T21:41:19.997000",
          "content": "<p>Will you release that after the competition too? IT'd be really great to see!</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 1220733,
          "author_name": "Andrés Miguel Torrubia Sáez",
          "author_url": "",
          "post_date": "2021-02-28T09:57:26.750000",
          "content": "<p>Here you are:</p>\n<pre><code>use_memmap = True\nload_fn = np.load if not use_memmap else partial(np.lib.format.open_memmap, mode='r')\n\ndef cache_to_disk(suffix=\"\",p_cache=p_cache / 'npy'):\n    def _cache_to_disk(func):\n        @functools.wraps(func)\n        def wrapper_decorator(*args, **kwargs):\n            p_cache.mkdir(parents=True, exist_ok=True)\n            p_cached = (p_cache / (str(args[0]) + suffix)).with_suffix(\".npy\")\n            value = None\n            if p_cached.exists():\n                try:\n                    value = load_fn(str(p_cached))\n                except Exception as e:\n                    print(f\"Inconsistent {p_cached}, recaching.\")\n            if value is None:\n                value = func(*args, **kwargs)\n                np.save(str(p_cached),value.cpu().numpy() if isinstance(value,Tensor) else value)\n            return value if isinstance(value,Tensor) else torch.from_numpy(value)\n        return wrapper_decorator\n    return _cache_to_disk\n</code></pre>\n<p>and then:</p>\n<pre><code>@cache_to_disk()\ndef read_dcm(image_id):\n    dcm=Path(p_train / image_id).with_suffix('.dicom').dcmread()\n    img=TensorCTScan(dcm.windowed(getattr(dcm,'WindowWidth', (1&lt;&lt;dcm.HighBit+1) - 1),\n                                  getattr(dcm,'WindowCenter',(1&lt;&lt;dcm.HighBit  ) - 1)))\n    if dcm.PhotometricInterpretation=='MONOCHROME2': img = 1 - img\n    return img\ndef read_image(image_id):\n    img = read_dcm(image_id)\n    img=Image.frombuffer('F',img.shape[::-1],img.numpy())\n    return PILImageBW(img)\n#your other code .....\n</code></pre>",
          "votes": 4,
          "replies": []
        },
        {
          "id": 1220891,
          "author_name": "Charlie Craine",
          "author_url": "",
          "post_date": "2021-02-28T13:02:31.533000",
          "content": "<p><a href=\"https://www.kaggle.com/antorsae\" target=\"_blank\">@antorsae</a> Great. I'll give it a try. I've moved to another object detection framework for now but cannot wait to see your fastai code. It'd be great to see something really good get adopted into the fastai codebase. </p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 1244388,
          "author_name": "Charlie Craine",
          "author_url": "",
          "post_date": "2021-03-19T00:33:47.670000",
          "content": "<p><a href=\"https://www.kaggle.com/antorsae\" target=\"_blank\">@antorsae</a> are you using fastai for this competition or did you jump to something else? Just curious. I didn't get as far with fastai for this and jumped to other vision detectors. </p>",
          "votes": 0,
          "replies": []
        }
      ]
    }
  ],
  "raw_markdown_by_id": {
    "1218314": "I'm just curious if anyone is working with fastai medical and bounding boxes. The one thing I've always wanted with fastai is a more elegant solution for bounding boxes. \n\nI put together a simple notebook to look at the data:\nhttps://www.kaggle.com/crained/vinbigdata-fastai-get-started\n\nI'd be curious if anyone has worked out cleaner solutions for bounding boxes. ",
    "1220262": "I have made it work but havent sub'd anything  yet. \n\nYou need to know the internals of fastai transforms and data to make this work, the existing bounding box examples are pretty barebone. When this comp finishes and if my approach is worth anything I'd contribute it to fastai.",
    "1218401": "Did you benchmark how fast the DataLoader is? I [got a bit worried](https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/discussion/211010) about how long it takes to read the .dicom files - especially when you have limited memory and only two CPUs in a Kaggle notebook (and I think `fastai` is also using pydicom in the background, which I looked at). For that reason, the main idea I've come up with is to construct something that efficiently (i.e. instead of opening 32 files for a batch of 32, you only access one file once and get the whole batch back) creates a whole batch at a time from a file that contains all images (as single channel images) in a way that can also be parallelized. It seems that when you do that, you want to then construct a fastai-DataLoader and tell it that you are using a batch size of 1 (when in fact, this batch of 1 is the whole batch loaded in one go). That [approach is pretty efficient](https://www.kaggle.com/bjoernholzhauer/vinbigdata-chest-x-ray-comparing-dataloader-speed). In a way, I guess that's what TFRecords do for you, if you use TensorFlow...\n\nIn any case, I don't think fastai is currently perfectly set-up to support this particular task, so I suspect you'd have to define a PyTorch neural network (you can pretty much use the PyTorch implementation of soemthing you find interesting), set-up your own custom Learner and provide it with your own custom DataLoaders (plus you may have to ensure your loss function works with fastai). I'm kind of suspecting someone must already have done this (perhaps for a previous competition), but I'm curious about seeing a nice example."
  }
}