Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Noninteractive run of notebooks and flake8 checks #107

Merged
merged 63 commits into from
Jan 27, 2021
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
d466995
start of automatic and update occ. sens.
rijobro Jan 12, 2021
b4a5063
current progress
rijobro Jan 12, 2021
a5d961e
current progress
rijobro Jan 12, 2021
432ff45
current progress
rijobro Jan 12, 2021
41023c2
current progress
rijobro Jan 13, 2021
eb2b957
vae
rijobro Jan 13, 2021
bec8927
models ensemble
rijobro Jan 13, 2021
64cf6cc
layer_wise_learning_rate
rijobro Jan 13, 2021
7a634bf
gan
rijobro Jan 13, 2021
536277c
Merge remote-tracking branch 'MONAI/master' into noninteractive_run
rijobro Jan 13, 2021
87ccfe5
3d_classification
rijobro Jan 13, 2021
bb4725a
add 3d_segmentation as well as flake
rijobro Jan 13, 2021
a9e9df9
transform speed
rijobro Jan 13, 2021
d46ad99
autopep8
rijobro Jan 13, 2021
be1048b
update runner
rijobro Jan 13, 2021
5fffbe6
flake8 support added
rijobro Jan 13, 2021
fd2640d
max_num_epochs->max_epochs
rijobro Jan 14, 2021
a1b35fa
check that max_epochs exists unless not expected
rijobro Jan 14, 2021
47210c6
uncomment executing notebook
rijobro Jan 14, 2021
7fb0ae9
check pip install
rijobro Jan 14, 2021
360633f
ignore temp files
rijobro Jan 14, 2021
e332c92
no noqa for indented import monai
rijobro Jan 14, 2021
4b8f80c
dont check for indented import monai
rijobro Jan 14, 2021
de2939c
flake8 changes
rijobro Jan 14, 2021
fb1d425
magic pip installs
rijobro Jan 14, 2021
32b5fa0
autofixes
rijobro Jan 14, 2021
900fcc4
use ! instead of % for pip install
rijobro Jan 14, 2021
919514d
so far
rijobro Jan 14, 2021
6152fe2
current progress. add black, isort, autoflake
rijobro Jan 14, 2021
252a269
current progress
rijobro Jan 14, 2021
fbea800
update class lung lesion notebook
rijobro Jan 14, 2021
b0d3b9f
class lung lesion
rijobro Jan 14, 2021
d12a92b
current progress
rijobro Jan 14, 2021
f01d585
current progress
rijobro Jan 14, 2021
af18daf
finished
rijobro Jan 14, 2021
33e7c60
Merge remote-tracking branch 'MONAI/master' into noninteractive_run
rijobro Jan 14, 2021
d5a3d87
finished
rijobro Jan 14, 2021
6b06a80
Merge branch 'noninteractive_run' of https://github.com/rijobro/tutor…
rijobro Jan 14, 2021
0dd96b0
remove pip install of pinned pytorch version
rijobro Jan 15, 2021
3968b3f
= list() to = []
rijobro Jan 15, 2021
c61cfd1
[DLMED] fix dyunet notebook issue
Nic-Ma Jan 19, 2021
9ea603d
correct faulty import
rijobro Jan 19, 2021
5f0ae23
pep8 for dynunet
rijobro Jan 20, 2021
51b519a
all working
rijobro Jan 20, 2021
79675df
add missing quotations
rijobro Jan 20, 2021
8803d51
remove personal file path
rijobro Jan 21, 2021
783425b
remove NiftiDataset
rijobro Jan 21, 2021
434e246
Merge branch 'noninteractive_run' of https://github.com/rijobro/tutor…
rijobro Jan 21, 2021
f7deb35
dont remove EOL whitespace from comments
rijobro Jan 21, 2021
8190097
Merge remote-tracking branch 'MONAI/master' into noninteractive_run
rijobro Jan 27, 2021
22563f2
2d_classification
rijobro Jan 27, 2021
e9a2b25
re-add spaces
rijobro Jan 27, 2021
f5e60f5
spaces
rijobro Jan 27, 2021
e8c6c39
last spaces
rijobro Jan 27, 2021
f31e4d1
merge
rijobro Jan 27, 2021
cc5df07
final changes
rijobro Jan 27, 2021
54f9d5d
notification at end
rijobro Jan 27, 2021
905500c
notification on exit
rijobro Jan 27, 2021
47cdbf2
add github action
rijobro Jan 27, 2021
9ad89af
data subfolder
rijobro Jan 27, 2021
5fadfff
make folder if necessary
rijobro Jan 27, 2021
9a37268
add flake8 to requirements
rijobro Jan 27, 2021
516bc6c
change test name
rijobro Jan 27, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ temp/
.idea/

*~
._*

# Remove .pyre temporary config files
.pyre
Expand All @@ -133,3 +134,7 @@ tests/testing_data/*Hippocampus*

# saved networks
*.pth

# Ignore torch saves
*/torch/runs
logs
116 changes: 57 additions & 59 deletions 2d_classification/mednist_tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,8 @@
"metadata": {},
"outputs": [],
"source": [
"try:\n",
" import monai\n",
"except ImportError:\n",
" %pip install -q \"monai[pillow, tqdm]\""
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"scrolled": true,
"tags": []
},
"outputs": [],
"source": [
"!python -c \"import monai\" || pip install -q \"monai[pillow, tqdm]\"\n",
"!python -c \"import matplotlib\" || pip install -q matplotlib\n",
"%matplotlib inline"
]
},
Expand Down Expand Up @@ -107,12 +94,12 @@
"import os\n",
"import shutil\n",
"import tempfile\n",
"\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import PIL\n",
"import torch\n",
"import numpy as np\n",
"from sklearn.metrics import classification_report\n",
"\n",
"from monai.apps import download_and_extract\n",
"from monai.config import print_config\n",
"from monai.metrics import compute_roc_auc\n",
Expand All @@ -138,8 +125,8 @@
"source": [
"## Setup data directory\n",
"\n",
"You can specify a directory with the `MONAI_DATA_DIRECTORY` environment variable. \n",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these blanks in Markdown doc are to make the next sentence in a new line, that's Markdown gramma I think.
Thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to be tricky to solve, but thanks for pointing it out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've committed a temporary fix f7deb35 pending answer from here: mwouts/jupytext#723.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, could you please update the PR to ignore the blanks?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done that, but I'll have to revert all these accidental changes manually.

"This allows you to save results and reuse downloads. \n",
"You can specify a directory with the `MONAI_DATA_DIRECTORY` environment variable.\n",
"This allows you to save results and reuse downloads.\n",
"If not specified a temporary directory will be used."
]
},
Expand Down Expand Up @@ -219,8 +206,8 @@
"source": [
"## Read image filenames from the dataset folders\n",
"\n",
"First of all, check the dataset files and show some statistics. \n",
"There are 6 folders in the dataset: Hand, AbdomenCT, CXR, ChestCT, BreastMRI, HeadCT, \n",
"First of all, check the dataset files and show some statistics.\n",
"There are 6 folders in the dataset: Hand, AbdomenCT, CXR, ChestCT, BreastMRI, HeadCT,\n",
"which should be used as the labels to train our classification model."
]
},
Expand All @@ -243,7 +230,8 @@
}
],
"source": [
"class_names = sorted(x for x in os.listdir(data_dir) if os.path.isdir(os.path.join(data_dir, x)))\n",
"class_names = sorted(x for x in os.listdir(data_dir)\n",
" if os.path.isdir(os.path.join(data_dir, x)))\n",
"num_class = len(class_names)\n",
"image_files = [\n",
" [\n",
Expand Down Expand Up @@ -331,12 +319,12 @@
"source": [
"val_frac = 0.1\n",
"test_frac = 0.1\n",
"train_x = list()\n",
"train_y = list()\n",
"val_x = list()\n",
"val_y = list()\n",
"test_x = list()\n",
"test_y = list()\n",
"train_x = []\n",
"train_y = []\n",
"val_x = []\n",
"val_y = []\n",
"test_x = []\n",
"test_y = []\n",
"\n",
"for i in range(num_total):\n",
" rann = np.random.random()\n",
Expand All @@ -350,7 +338,9 @@
" train_x.append(image_files_list[i])\n",
" train_y.append(image_class[i])\n",
"\n",
"print(f\"Training count: {len(train_x)}, Validation count: {len(val_x)}, Test count: {len(test_x)}\")"
"print(\n",
" f\"Training count: {len(train_x)}, Validation count: \"\n",
" f\"{len(val_x)}, Test count: {len(test_x)}\")"
]
},
{
Expand Down Expand Up @@ -378,7 +368,8 @@
" ]\n",
")\n",
"\n",
"val_transforms = Compose([LoadImage(image_only=True), AddChannel(), ScaleIntensity(), ToTensor()])"
"val_transforms = Compose(\n",
" [LoadImage(image_only=True), AddChannel(), ScaleIntensity(), ToTensor()])"
]
},
{
Expand All @@ -401,13 +392,16 @@
"\n",
"\n",
"train_ds = MedNISTDataset(train_x, train_y, train_transforms)\n",
"train_loader = torch.utils.data.DataLoader(train_ds, batch_size=300, shuffle=True, num_workers=10)\n",
"train_loader = torch.utils.data.DataLoader(\n",
" train_ds, batch_size=300, shuffle=True, num_workers=10)\n",
"\n",
"val_ds = MedNISTDataset(val_x, val_y, val_transforms)\n",
"val_loader = torch.utils.data.DataLoader(val_ds, batch_size=300, num_workers=10)\n",
"val_loader = torch.utils.data.DataLoader(\n",
" val_ds, batch_size=300, num_workers=10)\n",
"\n",
"test_ds = MedNISTDataset(test_x, test_y, val_transforms)\n",
"test_loader = torch.utils.data.DataLoader(test_ds, batch_size=300, num_workers=10)"
"test_loader = torch.utils.data.DataLoader(\n",
" test_ds, batch_size=300, num_workers=10)"
]
},
{
Expand All @@ -417,8 +411,8 @@
"## Define network and optimizer\n",
"\n",
"1. Set learning rate for how much the model is updated per batch.\n",
"1. Set total epoch number, as we have shuffle and random transforms, so the training data of every epoch is different. \n",
"And as this is just a get start tutorial, let's just train 4 epochs. \n",
"1. Set total epoch number, as we have shuffle and random transforms, so the training data of every epoch is different.\n",
"And as this is just a get start tutorial, let's just train 4 epochs.\n",
"If train 10 epochs, the model can achieve 100% accuracy on test dataset.\n",
"1. Use DenseNet from MONAI and move to GPU devide, this DenseNet can support both 2D and 3D classification tasks.\n",
"1. Use Adam optimizer."
Expand All @@ -431,10 +425,11 @@
"outputs": [],
"source": [
"device = torch.device(\"cuda:0\")\n",
"model = densenet121(spatial_dims=2, in_channels=1, out_channels=num_class).to(device)\n",
"model = densenet121(spatial_dims=2, in_channels=1,\n",
" out_channels=num_class).to(device)\n",
"loss_function = torch.nn.CrossEntropyLoss()\n",
"optimizer = torch.optim.Adam(model.parameters(), 1e-5)\n",
"max_num_epochs = 4\n",
"max_epochs = 4\n",
"val_interval = 1"
]
},
Expand All @@ -444,7 +439,7 @@
"source": [
"## Model training\n",
"\n",
"Execute a typical PyTorch training that run epoch loop and step loop, and do validation after every epoch. \n",
"Execute a typical PyTorch training that run epoch loop and step loop, and do validation after every epoch.\n",
"Will save the model weights to file if got best validation accuracy."
]
},
Expand Down Expand Up @@ -1130,12 +1125,12 @@
"source": [
"best_metric = -1\n",
"best_metric_epoch = -1\n",
"epoch_loss_values = list()\n",
"metric_values = list()\n",
"epoch_loss_values = []\n",
"metric_values = []\n",
"\n",
"for epoch in range(max_num_epochs):\n",
"for epoch in range(max_epochs):\n",
" print(\"-\" * 10)\n",
" print(f\"epoch {epoch + 1}/{max_num_epochs}\")\n",
" print(f\"epoch {epoch + 1}/{max_epochs}\")\n",
" model.train()\n",
" epoch_loss = 0\n",
" step = 0\n",
Expand All @@ -1148,7 +1143,9 @@
" loss.backward()\n",
" optimizer.step()\n",
" epoch_loss += loss.item()\n",
" print(f\"{step}/{len(train_ds) // train_loader.batch_size}, train_loss: {loss.item():.4f}\")\n",
" print(\n",
" f\"{step}/{len(train_ds) // train_loader.batch_size}, \"\n",
" f\"train_loss: {loss.item():.4f}\")\n",
" epoch_len = len(train_ds) // train_loader.batch_size\n",
" epoch_loss /= step\n",
" epoch_loss_values.append(epoch_loss)\n",
Expand All @@ -1166,22 +1163,27 @@
" )\n",
" y_pred = torch.cat([y_pred, model(val_images)], dim=0)\n",
" y = torch.cat([y, val_labels], dim=0)\n",
" auc_metric = compute_roc_auc(y_pred, y, to_onehot_y=True, softmax=True)\n",
" auc_metric = compute_roc_auc(\n",
" y_pred, y, to_onehot_y=True, softmax=True)\n",
" metric_values.append(auc_metric)\n",
" acc_value = torch.eq(y_pred.argmax(dim=1), y)\n",
" acc_metric = acc_value.sum().item() / len(acc_value)\n",
" if auc_metric > best_metric:\n",
" best_metric = auc_metric\n",
" best_metric_epoch = epoch + 1\n",
" torch.save(model.state_dict(), os.path.join(root_dir, \"best_metric_model.pth\"))\n",
" torch.save(model.state_dict(), os.path.join(\n",
" root_dir, \"best_metric_model.pth\"))\n",
" print(\"saved new best metric model\")\n",
" print(\n",
" f\"current epoch: {epoch + 1} current AUC: {auc_metric:.4f}\"\n",
" f\" current accuracy: {acc_metric:.4f} best AUC: {best_metric:.4f}\"\n",
" f\" current accuracy: {acc_metric:.4f}\"\n",
" f\" best AUC: {best_metric:.4f}\"\n",
" f\" at epoch: {best_metric_epoch}\"\n",
" )\n",
"\n",
"print(f\"train completed, best_metric: {best_metric:.4f} at epoch: {best_metric_epoch}\")"
"print(\n",
" f\"train completed, best_metric: {best_metric:.4f} \"\n",
" f\"at epoch: {best_metric_epoch}\")"
]
},
{
Expand Down Expand Up @@ -1232,8 +1234,8 @@
"source": [
"## Evaluate the model on test dataset\n",
"\n",
"After training and validation, we already got the best model on validation test. \n",
"We need to evaluate the model on test dataset to check whether it's robust and not over-fitting. \n",
"After training and validation, we already got the best model on validation test.\n",
"We need to evaluate the model on test dataset to check whether it's robust and not over-fitting.\n",
"We'll use these predictions to generate a classification report."
]
},
Expand All @@ -1243,10 +1245,11 @@
"metadata": {},
"outputs": [],
"source": [
"model.load_state_dict(torch.load(os.path.join(root_dir, \"best_metric_model.pth\")))\n",
"model.load_state_dict(torch.load(\n",
" os.path.join(root_dir, \"best_metric_model.pth\")))\n",
"model.eval()\n",
"y_true = list()\n",
"y_pred = list()\n",
"y_true = []\n",
"y_pred = []\n",
"with torch.no_grad():\n",
" for test_data in test_loader:\n",
" test_images, test_labels = (\n",
Expand Down Expand Up @@ -1288,13 +1291,8 @@
}
],
"source": [
"try:\n",
" import sklean\n",
"except ImportError:\n",
" %pip install -qU sklearn\n",
"from sklearn.metrics import classification_report\n",
"\n",
"print(classification_report(y_true, y_pred, target_names=class_names, digits=4))"
"print(classification_report(\n",
" y_true, y_pred, target_names=class_names, digits=4))"
]
},
{
Expand Down
Loading