|
26 | 26 | "This jupyter notebook can be run on any computer with a standard browser and no prior installation of any programming language is required. It can run remotely over the Internet, free of charge, thanks to Google Colaboratory. To connect with Colab, click on one of the two blue checkboxes above. Check that \"colab\" appears in the address bar. You can right-click on \"Open in Colab\" and select \"Open in new tab\" if the left click does not work for you. Familiarize yourself with the drop-down menus near the top of the window. You can edit the notebook during the session, for example substituting your own image files for the image files used in this demo. Experiment by changing the parameters of functions. It is not possible for an ordinary user to permanently change this version of the notebook on GitHub or Colab, so you cannot inadvertently mess it up. Use the notebook's File Menu if you wish to save your own (changed) notebook.\n", |
27 | 27 | "\n", |
28 | 28 | "To run the notebook on any platform, except for Colab, set up your Python environment, as explained in the\n", |
29 | | - "[README](https://github.com/TIA-Lab/tiatoolbox/blob/master/README.md#install-python-package) file." |
| 29 | + "[README](https://github.com/TIA-Lab/tiatoolbox/blob/master/README.md#install-python-package) file.\n", |
| 30 | + "\n" |
30 | 31 | ] |
31 | 32 | }, |
32 | 33 | { |
|
37 | 38 | "source": [ |
38 | 39 | "## About this demo\n", |
39 | 40 | "\n", |
40 | | - "In this example, we will show how to extract features from a pretrained PyTorch model that exists outside TIAToolbox, using the WSI inference engines provided by TIAToolbox." |
| 41 | + "In this example, we will show how to extract features from a pretrained PyTorch model that exists outside TIAToolbox, using the WSI inference engines provided by TIAToolbox.\n", |
| 42 | + "\n" |
41 | 43 | ] |
42 | 44 | }, |
43 | 45 | { |
|
174 | 176 | "warnings.filterwarnings(\"ignore\", message=\".*The 'nopython' keyword.*\")\n", |
175 | 177 | "\n", |
176 | 178 | "# Downloading data and files\n", |
177 | | - "import shutil\n", |
178 | 179 | "from pathlib import Path\n", |
179 | 180 | "\n", |
180 | 181 | "import matplotlib as mpl\n", |
181 | 182 | "import matplotlib.pyplot as plt\n", |
182 | 183 | "import numpy as np\n", |
183 | | - "import requests\n", |
| 184 | + "import umap\n", |
184 | 185 | "\n", |
185 | | - "# Data processing and visualization\n", |
186 | | - "import matplotlib as mpl\n", |
187 | | - "import matplotlib.pyplot as plt\n", |
188 | | - "import numpy as np\n", |
| 186 | + "# Import some extra modules\n", |
| 187 | + "from huggingface_hub import notebook_login\n", |
189 | 188 | "\n", |
| 189 | + "# Data processing and visualization\n", |
190 | 190 | "# TIAToolbox for WSI loading and processing\n", |
191 | 191 | "from tiatoolbox import logger\n", |
192 | 192 | "from tiatoolbox.models.architecture.vanilla import TimmBackbone\n", |
193 | | - "from tiatoolbox.models.engine.semantic_segmentor import DeepFeatureExtractor, IOSegmentorConfig\n", |
| 193 | + "from tiatoolbox.models.engine.semantic_segmentor import (\n", |
| 194 | + " DeepFeatureExtractor,\n", |
| 195 | + " IOSegmentorConfig,\n", |
| 196 | + ")\n", |
194 | 197 | "from tiatoolbox.utils.misc import download_data\n", |
195 | 198 | "from tiatoolbox.wsicore.wsireader import WSIReader\n", |
196 | 199 | "\n", |
197 | | - "# Import some extra modules\n", |
198 | | - "from huggingface_hub import notebook_login\n", |
199 | | - "import umap\n", |
200 | | - "\n", |
201 | 200 | "mpl.rcParams[\"figure.dpi\"] = 300 # for high resolution figure in notebook\n", |
202 | 201 | "mpl.rcParams[\"figure.facecolor\"] = \"white\" # To make sure text is visible in dark mode" |
203 | 202 | ] |
|
259 | 258 | "\n", |
260 | 259 | "> In Colab, if you click the files icon (see below) in the vertical toolbar on the left hand side then you can see all the files which the code in this notebook can access. The data will appear here when it is downloaded.\n", |
261 | 260 | ">\n", |
262 | | - "> \n" |
| 261 | + "> \n", |
| 262 | + "\n" |
263 | 263 | ] |
264 | 264 | }, |
265 | 265 | { |
|
301 | 301 | "\n", |
302 | 302 | "In this section, we extract deep features using foudnation models. These features could be used to train a downstream model. These models require access to HuggingFace, so please ensure that you have a University linked account if you are using this for research.\n", |
303 | 303 | "\n", |
304 | | - "We then sign in to HuggingFace." |
| 304 | + "We then sign in to HuggingFace.\n", |
| 305 | + "\n" |
305 | 306 | ] |
306 | 307 | }, |
307 | 308 | { |
|
334 | 335 | "source": [ |
335 | 336 | "Next, we create the model using pretrained network architectures. For other models available with the `Timm` library, such as Computational Pathology specific foundation models. use `TimmBackbone` (e.g. EfficientNet, UNI, Prov-GigaPath, H-optimus-0). For standard CNN model architectures available with PyTorch (e.g. AlexNet, ResNet, DenseNet, Inception, etc.) use instead `CNNBackbone`.\n", |
336 | 337 | "\n", |
337 | | - "In the below example we use the `UNI` model. However, this can be changed to other computational pathology specific foundation models by changing the `backbone` argument to `prov-gigapath` or `H-optimus-0`. When using foundation models, please ensure to cite the corresponding paper and follow the specific access requirements. Certain models require the user to have linked their GitHub and HuggingFace accounts, and to have had their model access request accepted, subjected to certain conditions, such as for [UNI](https://huggingface.co/MahmoodLab/UNI) and [Prov-GigaPath](https://huggingface.co/prov-gigapath/prov-gigapath). Other models have no such requirment, such as [H-optimius-0](https://huggingface.co/bioptimus/H-optimus-0). \n", |
| 338 | + "In the below example we use the `UNI` model. However, this can be changed to other computational pathology specific foundation models by changing the `backbone` argument to `prov-gigapath` or `H-optimus-0`. When using foundation models, please ensure to cite the corresponding paper and follow the specific access requirements. Certain models require the user to have linked their GitHub and HuggingFace accounts, and to have had their model access request accepted, subjected to certain conditions, such as for [UNI](https://huggingface.co/MahmoodLab/UNI) and [Prov-GigaPath](https://huggingface.co/prov-gigapath/prov-gigapath). Other models have no such requirment, such as [H-optimius-0](https://huggingface.co/bioptimus/H-optimus-0).\n", |
338 | 339 | "\n", |
339 | | - "We also provide an `IOSegmentorConfig' specifying the input/output patch shape and resolution for processing and saving the output.\n", |
| 340 | + "We also provide an \\`IOSegmentorConfig' specifying the input/output patch shape and resolution for processing and saving the output.\n", |
340 | 341 | "\n", |
341 | | - "Finally, we use the `DeepFeatureExtractor` to extract these deep features, per patch, from the WSI. A mask is automatically generated to gudie the patch extraction process (and to ignore background)." |
| 342 | + "Finally, we use the `DeepFeatureExtractor` to extract these deep features, per patch, from the WSI. A mask is automatically generated to gudie the patch extraction process (and to ignore background).\n", |
| 343 | + "\n" |
342 | 344 | ] |
343 | 345 | }, |
344 | 346 | { |
|
373 | 375 | "\n", |
374 | 376 | "# create the feature extractor and run it on the WSI\n", |
375 | 377 | "extractor = DeepFeatureExtractor(\n", |
376 | | - " model=model, \n", |
377 | | - " auto_generate_mask=True, \n", |
378 | | - " batch_size=32, \n", |
379 | | - " num_loader_workers=4, \n", |
380 | | - " num_postproc_workers=4\n", |
381 | | - " )\n", |
| 378 | + " model=model,\n", |
| 379 | + " auto_generate_mask=True,\n", |
| 380 | + " batch_size=32,\n", |
| 381 | + " num_loader_workers=4,\n", |
| 382 | + " num_postproc_workers=4,\n", |
| 383 | + ")\n", |
382 | 384 | "\n", |
383 | 385 | "out = extractor.predict(\n", |
384 | 386 | " imgs=[wsi_path],\n", |
385 | | - " mode=\"wsi\", \n", |
386 | | - " ioconfig=wsi_ioconfig, \n", |
| 387 | + " mode=\"wsi\",\n", |
| 388 | + " ioconfig=wsi_ioconfig,\n", |
387 | 389 | " save_dir=global_save_dir / \"wsi_features\",\n", |
388 | 390 | " device=\"cuda\" if ON_GPU == True else \"cpu\",\n", |
389 | | - " )" |
| 391 | + ")" |
390 | 392 | ] |
391 | 393 | }, |
392 | 394 | { |
|
397 | 399 | "\n", |
398 | 400 | "These deep features could be used to train a downstream model, but in this section, in order to get some intuition for what the features represent, we will use a UMAP reduction to visualise the features in RGB space. The points labelled in a similar colour should have similar features, so we can check if the features naturally separate out into the different tissue regions when we overlay the UMAP reduction on the WSI thumbnail.\n", |
399 | 401 | "\n", |
400 | | - "In the output above, the method returns a list of the paths to its inputs and to the processed outputs saved on the disk. This can be used to load the results for processing and visualisation." |
| 402 | + "In the output above, the method returns a list of the paths to its inputs and to the processed outputs saved on the disk. This can be used to load the results for processing and visualisation.\n", |
| 403 | + "\n" |
401 | 404 | ] |
402 | 405 | }, |
403 | 406 | { |
|
438 | 441 | ], |
439 | 442 | "source": [ |
440 | 443 | "# First we define a function to calculate the umap reduction\n", |
441 | | - "def umap_reducer(\n", |
442 | | - " x: np.ndarray,\n", |
443 | | - " dims: int = 3,\n", |
444 | | - " nns: int = 10\n", |
445 | | - " ) -> np.ndarray:\n", |
| 444 | + "def umap_reducer(x: np.ndarray, dims: int = 3, nns: int = 10) -> np.ndarray:\n", |
446 | 445 | " \"\"\"UMAP reduction of the input data.\"\"\"\n", |
447 | | - " reducer = umap.UMAP(n_neighbors=nns, n_components=dims, metric=\"manhattan\", spread=0.5, random_state=2)\n", |
| 446 | + " reducer = umap.UMAP(\n", |
| 447 | + " n_neighbors=nns,\n", |
| 448 | + " n_components=dims,\n", |
| 449 | + " metric=\"manhattan\",\n", |
| 450 | + " spread=0.5,\n", |
| 451 | + " random_state=2,\n", |
| 452 | + " )\n", |
448 | 453 | " reduced = reducer.fit_transform(x)\n", |
449 | 454 | " reduced -= reduced.min(axis=0)\n", |
450 | 455 | " reduced /= reduced.max(axis=0)\n", |
451 | 456 | " return reduced\n", |
452 | 457 | "\n", |
| 458 | + "\n", |
453 | 459 | "# load the features output by our feature extractor\n", |
454 | 460 | "pos = np.load(global_save_dir / \"wsi_features\" / \"0.position.npy\")\n", |
455 | 461 | "feats = np.load(global_save_dir / \"wsi_features\" / \"0.features.0.npy\")\n", |
456 | | - "pos = pos / 8 # as we extracted at 0.5mpp, and we are overlaying on a thumbnail at 4mpp\n", |
| 462 | + "pos = pos / 8 # as we extracted at 0.5mpp, and we are overlaying on a thumbnail at 4mpp\n", |
457 | 463 | "\n", |
458 | 464 | "# reduce the features into 3 dimensional (rgb) space\n", |
459 | 465 | "reduced = umap_reducer(feats)\n", |
|
471 | 477 | "# plot the feature map reduction\n", |
472 | 478 | "plt.figure()\n", |
473 | 479 | "plt.imshow(wsi_overview)\n", |
474 | | - "plt.scatter(pos[:,0], pos[:,1], c=reduced, s=1, alpha=0.5)\n", |
| 480 | + "plt.scatter(pos[:, 0], pos[:, 1], c=reduced, s=1, alpha=0.5)\n", |
475 | 481 | "plt.axis(\"off\")\n", |
476 | 482 | "plt.title(\"UMAP reduction of features\")" |
477 | 483 | ] |
|
480 | 486 | "cell_type": "markdown", |
481 | 487 | "metadata": {}, |
482 | 488 | "source": [ |
483 | | - "We see that the feature map from our feature encoder, capture similar information about the tissue types in the WSI, since different tissue types appear to have different colours. This is a good sanity check that our models are working as expected." |
| 489 | + "We see that the feature map from our feature encoder, capture similar information about the tissue types in the WSI, since different tissue types appear to have different colours. This is a good sanity check that our models are working as expected.\n", |
| 490 | + "\n" |
484 | 491 | ] |
485 | 492 | } |
486 | 493 | ], |
|
0 commit comments