diff --git a/Colab_notebooks/Latest_Notebook_versions.csv b/Colab_notebooks/Latest_Notebook_versions.csv index 915be68..54efd4a 100644 --- a/Colab_notebooks/Latest_Notebook_versions.csv +++ b/Colab_notebooks/Latest_Notebook_versions.csv @@ -14,7 +14,7 @@ fnet (2D),1.14.1 fnet (3D),1.13.1 U-Net (2D),2.2.1 U-Net (3D),2.2.1 -U-Net (2D) multilabel,2.1.2 +U-Net (2D) multilabel,2.1.3 Kaibu,1.13.2 MaskRCNN,1.14.1 Noise2Void (2D),1.16.2 diff --git a/Colab_notebooks/U-Net_2D_Multilabel_ZeroCostDL4Mic.ipynb b/Colab_notebooks/U-Net_2D_Multilabel_ZeroCostDL4Mic.ipynb index 0445bd8..f9abcd9 100644 --- a/Colab_notebooks/U-Net_2D_Multilabel_ZeroCostDL4Mic.ipynb +++ b/Colab_notebooks/U-Net_2D_Multilabel_ZeroCostDL4Mic.ipynb @@ -157,14 +157,16 @@ "source": [ "#@markdown ##Play to install U-Net dependencies\n", "# Install packages which are not included in Google Colab\n", - "!pip install data\n", + "!pip install -q data\n", "!pip install -q tifffile # contains tools to operate tiff-files\n", "!pip install -q wget\n", "!pip install -q fpdf2\n", "!pip install -q PTable # Nice tables\n", "!pip install -q zarr\n", "!pip install -q imagecodecs\n", - "!pip install \"bioimageio.core>=0.5,<0.6\"" + "!pip install -q bioimageio.core==0.6.9\n", + "!pip install -q tf-keras==2.15\n", + "!pip install -q tensorflow==2.15" ] }, { @@ -205,10 +207,9 @@ "outputs": [], "source": [ "from __future__ import print_function\n", - "Notebook_version = '2.1.2'\n", + "Notebook_version = '2.1.3'\n", "Network = 'U-Net (2D) multilabel'\n", "\n", - "\n", "from builtins import any as b_any\n", "\n", "def get_requirements_path():\n", @@ -319,12 +320,16 @@ "\n", "# BioImage Model Zoo\n", "from shutil import rmtree\n", - "from bioimageio.core.build_spec import build_model, add_weights\n", - "from bioimageio.core.resource_tests import test_model\n", - "from bioimageio.core.weight_converter.keras import convert_weights_to_tensorflow_saved_model_bundle\n", - "from bioimageio.core import load_raw_resource_description, load_resource_description\n", + "import bioimageio.spec.model.v0_5 as bioimageio_spec\n", + "from bioimageio.spec import save_bioimageio_package\n", + "from bioimageio.spec._internal.io import FileDescr\n", + "import bioimageio.core as bioimageio_core\n", "from zipfile import ZipFile\n", "import requests\n", + "from bioimageio.spec.pretty_validation_errors import (\n", + " enable_pretty_validation_errors_in_ipynb,\n", + ")\n", + "enable_pretty_validation_errors_in_ipynb()\n", "\n", "#Create a variable to get and store relative base path\n", "base_path = os.getcwd()\n", @@ -687,7 +692,7 @@ " model.summary()\n", "\n", " if(pretrained_weights):\n", - " \tmodel.load_weights(pretrained_weights);\n", + " model.load_weights(pretrained_weights)\n", "\n", " return model\n", "\n", @@ -785,6 +790,57 @@ " mask[mask <= threshold] = 0\n", " return mask\n", "\n", + "# BMZ model export functions\n", + "def make_author(author_input_info: str):\n", + " \"\"\"\n", + " Create an Author object from a string input.\n", + "\n", + " Args:\n", + " author_input_info: A string containing the author's name and affiliation.\n", + "\n", + " Returns:\n", + " An Author object\n", + " \"\"\"\n", + " if author_input_info.strip() == '':\n", + " return None\n", + "\n", + " auth_order = ['name', 'affiliation', 'email', 'orcid', 'github_user']\n", + " auth_dict = {}\n", + "\n", + " auth_info_split = author_input_info.split(',')\n", + "\n", + " for i in range(len(auth_info_split)):\n", + " if auth_info_split[i].strip() == 'None' or auth_info_split[i].strip() == '':\n", + " continue\n", + " else:\n", + " auth_dict[auth_order[i]] = auth_info_split[i].strip()\n", + "\n", + " return bioimageio_spec.Author(**auth_dict)\n", + "\n", + "def make_maintainer(maintainer_input_info: str):\n", + " \"\"\"\n", + " Create an Author object from a string input.\n", + "\n", + " Args:\n", + " author_input_info: A string containing the author's name and affiliation.\n", + "\n", + " Returns:\n", + " An Author object\n", + " \"\"\"\n", + " maint_order = [ 'github_user', 'name', 'affiliation', 'email', 'orcid']\n", + " maint_dict = {}\n", + "\n", + " maint_info_split = maintainer_input_info.split(',')\n", + "\n", + " for i in range(len(maint_info_split)):\n", + " if maint_info_split[i].strip() == 'None' or maint_info_split[i].strip() == '':\n", + " continue\n", + " else:\n", + " maint_dict[maint_order[i]] = maint_info_split[i].strip()\n", + "\n", + " return bioimageio_spec.Maintainer(**maint_dict)\n", + "\n", + "\n", "# -------------- Other definitions -----------\n", "W = '\\033[0m' # white (normal)\n", "R = '\\033[31m' # red\n", @@ -807,7 +863,7 @@ "if Notebook_version == Latest_Notebook_version:\n", " print(\"This notebook is up-to-date.\")\n", "else:\n", - " print(bcolors.WARNING +\"A new version of this notebook has been released. We recommend that you download it at https://github.com/HenriquesLab/ZeroCostDL4Mic/wiki\")\n", + " print(bcolors.WARNING +\"A new version of this notebook has been released. We recommend that you download it at https://github.com/HenriquesLab/ZeroCostDL4Mic/wiki\"+W)\n", "\n", "\n", "def pdf_export(trained = False, augmentation = False, pretrained_model = False):\n", @@ -905,7 +961,7 @@ " if Use_Default_Advanced_Parameters:\n", " pdf.cell(200, 5, txt='Default Advanced Parameters were enabled')\n", " pdf.cell(200, 5, txt='The following parameters were used for training:')\n", - " pdf.ln(1)\n", + " pdf.ln(3)\n", " html = \"\"\"\n", " \n", " \n", @@ -913,36 +969,36 @@ " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", "
Value
number_of_epochs{0}number_of_epochs{0}
patch_size{1}patch_size{1}
batch_size{2}batch_size{2}
number_of_steps{3}number_of_steps{3}
percentage_validation{4}percentage_validation{4}
initial_learning_rate{5}initial_learning_rate{5}
pooling_steps{6}pooling_steps{6}
min_fraction{7}min_fraction{7}
\n", " \"\"\".format(number_of_epochs, str(patch_width)+'x'+str(patch_height), batch_size, number_of_steps, percentage_validation, initial_learning_rate, pooling_steps, min_fraction)\n", " pdf.write_html(html)\n", @@ -1148,21 +1204,10 @@ "source": [ "#@markdown ##Run this cell to check if you have GPU access\n", "\n", - "if tf.test.gpu_device_name()=='':\n", - " print('You do not have GPU access.')\n", - " print('Did you change your runtime ?')\n", - " print('If the runtime setting is correct then Google did not allocate a GPU for your session')\n", - " print('Expect slow performance. To access GPU try reconnecting later')\n", - "\n", - "else:\n", - " print('You have GPU access')\n", - " !nvidia-smi\n", - "\n", - "# from tensorflow.python.client import device_lib\n", - "# device_lib.list_local_devices()\n", - "\n", - "# print the tensorflow version\n", - "print('Tensorflow version is ' + str(tf.__version__))\n" + "!if type nvidia-smi >/dev/null 2>&1; then \\\n", + " echo \"You have GPU access\"; nvidia-smi; \\\n", + " else \\\n", + " echo -e \"You do not have GPU access.\\nDid you change your runtime?\\nIf the runtime setting is correct then Google did not allocate a GPU for your session\\nExpect slow performance. To access GPU try reconnecting later\"; fi" ] }, { @@ -1175,7 +1220,7 @@ "---\n", " To use this notebook on the data present in your Google Drive, you need to mount your Google Drive to this notebook.\n", "\n", - " Play the cell below to mount your Google Drive and follow the link. In the new browser window, select your drive and select 'Allow', copy the code, paste into the cell and press enter. This will give Colab access to the data on the drive.\n", + " Play the cell below to mount your Google Drive. Click on **Connect to Google Drive** and a window will pop up. You will need to sign in tour Google Account, follow the steps and click **Continue**. This will give Colab access to the data on the drive.\n", "\n", " Once this is done, your data are available in the **Files** tab on the top left of notebook." ] @@ -1191,13 +1236,9 @@ "source": [ "#@markdown ##Play the cell to connect your Google Drive to Colab\n", "\n", - "#@markdown * Click on the URL.\n", - "\n", - "#@markdown * Sign in your Google Account.\n", + "#@markdown * Click on **Connect to Google Drive**.\n", "\n", - "#@markdown * Copy the authorization code.\n", - "\n", - "#@markdown * Enter the authorization code.\n", + "#@markdown * A new window, will pop up. Sign in your Google Account.\n", "\n", "#@markdown * Click on \"Files\" site on the right. Refresh the site. Your Google Drive folder should now be available here as \"drive\".\n", "\n", @@ -1536,7 +1577,7 @@ "\n", " **You do not need to run this section if you want to train a network from scratch**.\n", "\n", - " This option allows you to use pre-trained models from the [BioImage Model Zoo](https://bioimage.io/#/) and fine-tune them to analyse new data. Choose `bioimageio_model` and provide the ID in `bioimageio_model_id` (e.g., \"creative-panda\" or \"10.5281/zenodo.5817052\").\n", + " This option allows you to use pre-trained models from the [BioImage Model Zoo](https://bioimage.io/#/) and fine-tune them to analyse new data. Choose `bioimageio_model` and provide the ID in `bioimageio_model_id` (e.g., \"placid-llama\" or \"10.5281/zenodo.5817052\").\n", "\n", " This option also allows you to perform training over multiple Colab runtimes or to do transfer learning using models trained outside of ZeroCostDL4Mic. Choose `Model_from_file` and provide the `pretrained_model_path`.\n", "\n", @@ -1553,6 +1594,8 @@ "outputs": [], "source": [ "# @markdown ##Loading weights from a pre-trained network\n", + "from bioimageio.core import load_description\n", + "from bioimageio.spec.utils import download\n", "\n", "Use_pretrained_model = False #@param {type:\"boolean\"}\n", "pretrained_model_choice = \"BioImage Model Zoo\" #@param [\"Model_from_file\", \"BioImage Model Zoo\"]\n", @@ -1573,33 +1616,32 @@ " h5_file_path = os.path.join(pretrained_model_path, \"weights_\"+Weights_choice+\".hdf5\")\n", " qc_path = os.path.join(pretrained_model_path, 'Quality Control', 'training_evaluation.csv')\n", " elif pretrained_model_choice == \"BioImage Model Zoo\":\n", - "\n", - " model_spec = load_resource_description(bioimageio_model_id)\n", - " if \"keras_hdf5\" not in biomodel.weights:\n", + " model_spec = load_description(bioimageio_model_id)\n", + " if \"keras_hdf5\" not in model_spec.weights.model_fields_set:\n", " print(\"Invalid bioimageio model\")\n", " h5_file_path = \"no-model\"\n", " qc_path = \"no-qc\"\n", " else:\n", - " h5_file_path = str(biomodel.weights[\"keras_hdf5\"].source)\n", + " h5_file_path = str(download(model_spec.weights.keras_hdf5.source).path)\n", " try:\n", - " attachments = biomodel.attachments.files\n", - " qc_path = [fname for fname in attachments if fname.endswith(\"training_evaluation.csv\")][0]\n", - " qc_path = os.path.join(base_path + \"//bioimageio_pretrained_model\", qc_path)\n", + " attachments = model_spec.attachments.files\n", + " qc_path = str(download([fname for fname in attachments if str(fname).endswith(\"training_evaluation.csv\")][0]).path)\n", + " # qc_path = os.path.join(base_path + \"//bioimageio_pretrained_model\", qc_path)\n", " except Exception:\n", " qc_path = \"no-qc\"\n", "\n", "# --------------------- Check the model exist ------------------------\n", - "# If the model path chosen does not contain a pretrain model then use_pretrained_model is disabled,\n", + "\n", " if not os.path.exists(h5_file_path):\n", + " # If the model path chosen does not contain a pretrain model then use_pretrained_model is disabled,\n", " print(R+'WARNING: pretrained model does not exist')\n", " Use_pretrained_model = False\n", + " else:\n", + " # If the model path contains a pretrain model, we load the training rate\n", "\n", - "\n", - "# If the model path contains a pretrain model, we load the training rate,\n", - " if os.path.exists(h5_file_path):\n", - "#Here we check if the learning rate can be loaded from the quality control folder\n", - " # if os.path.exists(os.path.join(pretrained_model_path, 'Quality Control', 'training_evaluation.csv')):\n", " if os.path.exists(qc_path):\n", + " #Here we check if the learning rate can be loaded from the quality control folder\n", + " # if os.path.exists(os.path.join(pretrained_model_path, 'Quality Control', 'training_evaluation.csv')):\n", "\n", " # with open(os.path.join(pretrained_model_path, 'Quality Control', 'training_evaluation.csv'),'r') as csvfile:\n", " with open(qc_path,'r') as csvfile:\n", @@ -1607,7 +1649,7 @@ " #print(csvRead)\n", "\n", " if \"learning rate\" in csvRead.columns: #Here we check that the learning rate column exist (compatibility with model trained un ZeroCostDL4Mic bellow 1.4)\n", - " print(\"pretrained network learning rate found\")\n", + " print(\"A 'learning rate' attribute was found on provided pre-trained models.\")\n", " #find the last learning rate\n", " lastLearningRate = csvRead[\"learning rate\"].iloc[-1]\n", " #Find the learning rate corresponding to the lowest validation loss\n", @@ -1616,28 +1658,29 @@ " bestLearningRate = min_val_loss['learning rate'].iloc[-1]\n", "\n", " if Weights_choice == \"last\":\n", - " print('Last learning rate: '+str(lastLearningRate))\n", - "\n", - " if Weights_choice == \"best\":\n", - " print('Learning rate of best validation loss: '+str(bestLearningRate))\n", + " print(f'You will be loading \\033[1mlast\\033[0m learning rate: {lastLearningRate}')\n", + " elif Weights_choice == \"best\":\n", + " print(f'You will be loading the learning rate of \\033[1mbest\\033[0m validation loss: {bestLearningRate}')\n", + " else:\n", + " #if the column does not exist, then initial learning rate is used instead\n", + " print(f\"{bcolors.WARNING}WARNING: The learning rate cannot be identified from the pretrained network{W}\")\n", + " print(f\"{bcolors.WARNING}Default learning rate of {initial_learning_rate} will be used instead{W}\")\n", "\n", - " if not \"learning rate\" in csvRead.columns: #if the column does not exist, then initial learning rate is used instead\n", " bestLearningRate = initial_learning_rate\n", " lastLearningRate = initial_learning_rate\n", - " print(bcolors.WARNING+'WARNING: The learning rate cannot be identified from the pretrained network. Default learning rate of '+str(bestLearningRate)+' will be used instead' + W)\n", - "\n", - "#Compatibility with models trained outside ZeroCostDL4Mic but default learning rate will be used\n", - " if not os.path.exists(os.path.join(pretrained_model_path, 'Quality Control', 'training_evaluation.csv')):\n", - " print(bcolors.WARNING+'WARNING: The learning rate cannot be identified from the pretrained network. Default learning rate of '+str(initial_learning_rate)+' will be used instead'+ W)\n", + " else:\n", + " #Compatibility with models trained outside ZeroCostDL4Mic but default learning rate will be used\n", + " print(f\"{bcolors.WARNING}Sorry, 'training_evaluation.csv' does not exists or was not correctly loaded.{W}\")\n", + " print(f\"{bcolors.WARNING}Default learning rate of {initial_learning_rate} will be used instead{W}\")\n", " bestLearningRate = initial_learning_rate\n", " lastLearningRate = initial_learning_rate\n", "\n", "\n", "# Display info about the pretrained model to be loaded (or not)\n", "if Use_pretrained_model:\n", - " print('Weights found in:')\n", - " print(h5_file_path)\n", - " print('will be loaded prior to training.')\n", + " print('-'*50)\n", + " print(f'Weights found in: {h5_file_path}')\n", + " print('They will be loaded prior to training.')\n", "\n", "else:\n", " print(R+'No pretrained network will be used.')\n", @@ -1724,15 +1767,17 @@ "# Load the pretrained weights\n", "if Use_pretrained_model:\n", " try:\n", + " print(\"Weights correctly loaded.\")\n", " model.load_weights(h5_file_path)\n", " except:\n", - " print(bcolors.WARNING + \"The pretrained model could not be loaded as the configuration of the network is different.\")\n", - " print(\"Please, read the model specifications and check the parameters in Section 3.1\" + W)\n", + " print(f\"{bcolors.WARNING}The pretrained model could not be loaded as the configuration of the network is different.\")\n", + " print(\"Please, read the model specifications and check the parameters in Section 3.1\")\n", + " print(f\"It might probably be the pooling steps attribute, please take a look to it.{W}\")\n", "\n", - "# except:\n", - "# print(\"The pretrained model could not be loaded. Please, check the parameters of the pre-trained model architecture.\")\n", "config_model= model.optimizer.get_config()\n", - "print(config_model)\n", + "print(\"Configuration of model's optimizer:\")\n", + "for k,v in config_model.items():\n", + " print(f\"{k} : {v}\")\n", "\n", "\n", "# ------------------ Failsafes ------------------\n", @@ -2131,34 +2176,48 @@ "source": [ "# ------------- User input ------------\n", "# information about the model\n", - "#@markdown ##Introduce the information to document your model:\n", + "#@markdown ##Insert the information to document your model:\n", "Trained_model_name = \"\" #@param {type:\"string\"}\n", - "Trained_model_authors = \"[Author 1 name, Author 2 name]\" #@param {type:\"string\"}\n", - "Trained_model_authors_affiliation = \"[Author affiliation, Author 2 affiliation]\" #@param {type:\"string\"}\n", "Trained_model_description = \"\" #@param {type:\"string\"}\n", - "Trained_model_license = 'MIT'#@param {type:\"string\"}\n", + "\n", + "#@markdown ###Author(s) - insert information separated by commas:\n", + "Trained_model_author_1 = \"Author 1 name, *Author 1 affiliation, *Author 1 email, *Author 1 ORCID, *Author 1 Github User\" #@param {type:\"string\"}\n", + "Trained_model_author_2 = \"Author 2 name, *Author 2 affiliation, *Author 2 email, *Author 2 ORCID, *Author 2 Github User\" #@param {type:\"string\"}\n", + "\n", + "# @markdown ###Model Packager:\n", + "packager_same_as_author = True #@param {type:\"boolean\"}\n", + "#@markdown - If not, please, provide the following information:\n", + "Trained_model_packager = \"Packager name, *Packager affiliation, *Packager email, *Packager ORCID, *Packager Github User\" #@param {type:\"string\"}\n", + "\n", + "# @markdown ###Model Maintainer:\n", + "maintainer_same_as_author = True #@param {type:\"boolean\"}\n", + "#@markdown - If not, please, provide the following information:\n", + "Trained_model_maintainer = \"Maintainer Github User, *Maintainer name, *Maintainer affiliation, *Maintainer email, *Maintainer ORCID\" #@param {type:\"string\"}\n", + "\n", + "# @markdown ###License:\n", + "Trained_model_license = 'CC-BY-4.0' #@param {type:\"string\"}\n", + "\n", "Trained_model_references = [\"Falk et al. Nature Methods 2019\", \"Ronneberger et al. arXiv in 2015\", \"Lucas von Chamier et al. biorXiv 2020\"]\n", "Trained_model_DOI = [\"https://doi.org/10.1038/s41592-018-0261-2\",\"https://doi.org/10.1007/978-3-319-24574-4_28\", \"https://doi.org/10.1101/2020.03.20.000133\"]\n", "\n", "# Training data\n", "# ---------------------------------------\n", "#@markdown ##Include information about training data (optional):\n", - "include_training_data = True #@param {type: \"boolean\"}\n", + "include_training_data = False #@param {type: \"boolean\"}\n", "#@markdown ### - If it is published in the BioImage Model Zoo, please, provide the ID\n", - "data_from_bioimage_model_zoo = True #@param {type: \"boolean\"}\n", + "data_from_bioimage_model_zoo = False #@param {type: \"boolean\"}\n", "training_data_ID = ''#@param {type:\"string\"}\n", - "#@markdown ### - If not, please provide the URL tot he data and a short description\n", + "#@markdown ### - If not, please provide the URL to the data and a short description to be added to the README.md file\n", "training_data_source = ''#@param {type:\"string\"}\n", "training_data_description = ''#@param {type:\"string\"}\n", "\n", - "\n", - "\n", - "# Add example image information\n", + "# Add input image information\n", "# ---------------------------------------\n", - "#@markdown ##Introduce the voxel size (pixel size for each Z-slice and the distance between Z-salices) (in microns) of the image provided as an example of the model processing:\n", + "#@markdown ##Indicate the minimum x/y size of the image (in pixels) and step size (in pixels) to be used for block/tiling:\n", "# information about the example image\n", - "PixelSize = 1 #@param {type:\"number\"}\n", - "#@markdown ##Do you want to choose the exampleimage?\n", + "min_size = 64 #@param {type:\"number\"}\n", + "step_size = 16 #@param {type:\"number\"}\n", + "#@markdown ##Do you want to choose the example image?\n", "default_example_image = True #@param {type:\"boolean\"}\n", "#@markdown ###If not, please input:\n", "fileID = \"\" #@param {type:\"string\"}\n", @@ -2170,6 +2229,7 @@ "# Load the model\n", "model = load_model(os.path.join(full_QC_model_path, 'weights_best.hdf5'),\n", " custom_objects={'_weighted_binary_crossentropy': weighted_binary_crossentropy(np.ones(2))})\n", + "\n", "# ------------- Execute bioimage model zoo configuration ------------\n", "# Create a model without compilation so it can be used in any other environment.\n", "# remove the custom loss function from the model, so that it can be used outside of this notebook\n", @@ -2177,14 +2237,38 @@ "weight_path = os.path.join(full_QC_model_path, 'keras_weights.hdf5')\n", "unet.save(weight_path)\n", "\n", + "# training data source\n", + "if data_from_bioimage_model_zoo:\n", + " training_data = {'id' : training_data_ID}\n", + "else:\n", + " training_data = None\n", + "\n", + "# create the author/maintainer/packager spec input\n", + "author_1_spec = make_author(Trained_model_author_1)\n", + "authors = [author_1_spec]\n", + "\n", + "# check if author 2 was filled\n", + "if 'Author 2 name' not in Trained_model_author_2:\n", + " author_2_spec = make_author(Trained_model_author_2)\n", + " authors.append(author_2_spec)\n", + "\n", + "if packager_same_as_author:\n", + " packager_spec = author_1_spec\n", + "else:\n", + " packager_spec = make_author(Trained_model_packager)\n", + "\n", + "if maintainer_same_as_author:\n", + " if author_1_spec.github_user != None:\n", + " maintainer_from_author = [str(author_1_spec.github_user), str(author_1_spec.name), str(author_1_spec.affiliation), str(author_1_spec.email), str(author_1_spec.orcid)]\n", + " maintainer_str = ', '.join(maintainer_from_author)\n", + " maintainer_spec = make_maintainer(maintainer_str)\n", + " else:\n", + " print('Please, provide the author GitHub username in the author information')\n", + "else:\n", + " maintainer_spec = make_maintainer(Trained_model_maintainer)\n", "\n", - "# create the author spec input\n", - "auth_names = Trained_model_authors[1:-1].split(\",\")\n", - "auth_affs = Trained_model_authors_affiliation[1:-1].split(\",\")\n", - "assert len(auth_names) == len(auth_affs)\n", - "authors = [{\"name\": auth_name, \"affiliation\": auth_aff} for auth_name, auth_aff in zip(auth_names, auth_affs)]\n", "\n", - "# I would recommend using CCBY-4 as licencese\n", + "# I would recommend using CCBY-4 as licence\n", "license = Trained_model_license\n", "\n", "# where to save the model\n", @@ -2193,70 +2277,39 @@ "output_path = os.path.join(output_root, f\"{Trained_model_name}.zip\")\n", "\n", "# create a markdown readme with information\n", - "readme_path = os.path.join(output_root, \"README.md\")\n", - "with open(readme_path, \"w\") as f:\n", - " f.write(\"Visit https://github.com/HenriquesLab/ZeroCostDL4Mic/wiki\")\n", + "documentation_path = os.path.join(output_root, \"README.md\")\n", + "with open(documentation_path, \"w\") as f:\n", + " f.write(\"Visit https://github.com/HenriquesLab/ZeroCostDL4Mic/wiki \\n\\n This was an automatically generated README.md. \\n\\n\")\n", "\n", "# create the citation input spec\n", "assert len(Trained_model_DOI) == len(Trained_model_references)\n", - "citations = [{'text': text, 'doi': doi} for text, doi in zip(Trained_model_references, Trained_model_DOI)]\n", + "citations = [{'text': text, 'doi': doi.replace('https://doi.org/', '')} for text, doi in zip(Trained_model_references, Trained_model_DOI)]\n", + "citation_spec = [bioimageio_spec.CiteEntry(**c) for c in citations]\n", "\n", "# create the training data\n", "if include_training_data:\n", " if data_from_bioimage_model_zoo:\n", " training_data = {\"id\": training_data_ID}\n", " else:\n", - " training_data = {\"source\": training_data_source,\n", - " \"description\": training_data_description}\n", + " with open(documentation_path, \"a\") as f:\n", + " f.write(f'Training data: {training_data_source} \\n\\n and description: {training_data_description} \\n\\n')\n", + " training_data = None\n", "else:\n", - " training_data={}\n", - "\n", - "# create the input spec\n", - "def normalizePercentile(x, pmin=1, pmax=99.8, axis=None, clip=False, eps=1e-20, dtype=np.float32):\n", - " \"\"\"This function is adapted from Martin Weigert\"\"\"\n", - " \"\"\"Percentile-based image normalization.\"\"\"\n", - "\n", - " mi = np.percentile(x,pmin,axis=axis,keepdims=True)\n", - " ma = np.percentile(x,pmax,axis=axis,keepdims=True)\n", - " return normalize_mi_ma(x, mi, ma, clip=clip, eps=eps, dtype=dtype)\n", + " training_data = None\n", "\n", "\n", + "# load the input image, crop it if necessary, and save as numpy file\n", + "# The crop will be centered to get an image with some content.\n", + "input_img = io.imread(fileID, as_gray = True).astype(np.float32)\n", + "assert input_img.ndim == 2,'Example input image is not a 2D grayscale image. Please, provide a 2D grayscale image.'\n", "\n", - "min_percentile = 1\n", - "max_percentile = 99.8\n", - "shape = [sh for sh in unet.input.shape]\n", "# batch should never be constrained\n", + "shape = [sh for sh in unet.input.shape]\n", "assert shape[0] is None\n", "shape[0] = 1 # batch is set to 1 for bioimage.io\n", "assert all(sh is not None for sh in shape) # make sure all other shapes are fixed\n", - "pixel_size = {\"x\": PixelSize, \"y\": PixelSize}\n", - "kwargs = dict(\n", - " input_names=[\"input\"],\n", - " input_axes=[\"bxyc\"],\n", - " pixel_sizes=[pixel_size],\n", - " preprocessing=[[{\"name\": \"scale_range\", \"kwargs\": {\"min_percentile\": min_percentile,\n", - " \"max_percentile\": max_percentile,\n", - " \"mode\": \"per_sample\",\n", - " \"axes\": \"xyc\"}}]])\n", - "\n", - "shape = tuple(shape)\n", - "\n", - "postprocessing = None\n", - "\n", - "output_spec = dict(\n", - " output_names=[\"output\"],\n", - " output_axes=[\"bxyc\"],\n", - " postprocessing=postprocessing,\n", - " output_reference=[\"input\"],\n", - " output_scale=[[1,1,1,3]], # consider changing it if the input has more than one channel\n", - " output_offset=[4*[0]]\n", - ")\n", - "kwargs.update(output_spec)\n", - "\n", - "# load the input image, crop it if necessary, and save as numpy file\n", - "# The crop will be centered to get an image with some content.\n", - "test_img = io.imread(fileID, as_gray = True)\n", "\n", + "test_img = input_img\n", "\n", "x_size = int(test_img.shape[0]/2)\n", "x_size = x_size-int(shape[1]/2)\n", @@ -2267,28 +2320,58 @@ "test_img = test_img[x_size : x_size + shape[1],\n", " y_size : y_size + shape[2]]\n", "\n", - "assert test_img.shape == shape[1:3], f\"{test_img.shape}, {shape}\"\n", "# Save the test image\n", - "test_in_path = os.path.join(output_root, \"test_input.npy\")\n", - "np.save(test_in_path, test_img[None, ..., None]) # add batch and channel axis\n", - "# Normalize the image before adding batch and channel dimensions\n", + "test_input_path = os.path.join(output_root, \"test_input.npy\")\n", + "np.save(test_input_path, test_img[None, ..., None])\n", + "\n", + "# run prediction on the input image and save the result as expected output\n", "test_img = normalizePercentile(test_img)\n", "test_img = test_img[None, ..., None]\n", "test_prediction = unet.predict(test_img)\n", - "\n", - "# run prediction on the input image and save the result as expected output\n", "test_prediction = np.squeeze(test_prediction)\n", "assert test_prediction.ndim == 3\n", - "test_prediction = test_prediction[None, ...] # add batch axis\n", - "test_out_path = os.path.join(output_root, \"test_output.npy\")\n", - "np.save(test_out_path, test_prediction)\n", "\n", + "shape_pred = test_prediction.shape\n", + "channel_pred_idx = shape_pred.index(min(shape_pred))\n", + "n_channels = shape_pred[channel_pred_idx]\n", + "\n", + "test_prediction = test_prediction[None, ...]\n", + "test_output_path = os.path.join(output_root, \"test_output.npy\")\n", + "np.save(test_output_path, test_prediction)\n", + "\n", + "# create the channel names for the output\n", + "channel_names = []\n", + "\n", + "for idx in range(n_channels):\n", + " channel_names.append(f'channel{idx}')\n", + "\n", + "# create the input tensor\n", + "input_tensor = bioimageio_spec.InputTensorDescr(id=bioimageio_spec.TensorId('input0'),\n", + " description= 'This is the test input tensor created from the example image.',\n", + " axes=[bioimageio_spec.BatchAxis(id='batch', description='', type='batch', size=None),\n", + " bioimageio_spec.SpaceInputAxis(size=bioimageio_spec.ParameterizedSize(min=min_size, step=step_size), id='y', description='', type='space', unit=None, scale=1.0, concatenable=False),\n", + " bioimageio_spec.SpaceInputAxis(size=bioimageio_spec.ParameterizedSize(min=min_size, step=step_size), id='x', description='', type='space', unit=None, scale=1.0, concatenable=False),\n", + " bioimageio_spec.ChannelAxis(id='channel', description='', type='channel', channel_names=['channel0'])],\n", + " test_tensor = bioimageio_spec.FileDescr(source = test_input_path),\n", + " preprocessing = [bioimageio_spec.EnsureDtypeDescr(kwargs=bioimageio_spec.EnsureDtypeKwargs(dtype=\"float32\")),\n", + " bioimageio_spec.ScaleRangeDescr(kwargs=bioimageio_spec.ScaleRangeKwargs(axes = ['x','y'], min_percentile = 1.0 , max_percentile = 99.8) ),\n", + " ],\n", + " )\n", + "\n", + "\n", + "\n", + "# create the output tensor\n", + "output_tensor = bioimageio_spec.OutputTensorDescr( axes=[bioimageio_spec.BatchAxis(id='batch', description='', type='batch', size=None),\n", + " bioimageio_spec.SpaceOutputAxis(size=bioimageio_spec.SizeReference(tensor_id=bioimageio_spec.TensorId('input0'), axis_id='y', offset=0), id='y', description='', type='space', unit=None, scale=1.0),\n", + " bioimageio_spec.SpaceOutputAxis( size=bioimageio_spec.SizeReference(tensor_id=bioimageio_spec.TensorId('input0'), axis_id='x', offset=0), id='x', description='', type='space', unit=None, scale=1.0),\n", + " bioimageio_spec.ChannelAxis(id='channel', description='', type='channel', channel_names=channel_names)],\n", + " test_tensor = bioimageio_spec.FileDescr(source = test_output_path) )\n", + "\n", + "attachments = []\n", "# attach the QC report to the model (if it exists)\n", "qc_path = os.path.join(full_QC_model_path, 'Quality Control', 'training_evaluation.csv')\n", "if os.path.exists(qc_path):\n", - " attachments = {\"files\": [qc_path]}\n", - "else:\n", - " attachments = None\n", + " attachments.append(FileDescr(source = qc_path))\n", "\n", "# Include a post-processing deepImageJ macro\n", "macro = \"Contours2InstanceSegmentation.ijm\"\n", @@ -2300,47 +2383,55 @@ " raise RuntimeError(f\"An error occured when downloading {url}: {r.text}\")\n", " with open(path, \"w\") as f:\n", " f.write(r.text)\n", - "attachments = {\"files\": attachments[\"files\"] + [path]}\n", - "\n", - "# export the model with keras weihgts\n", - "build_model(\n", - " weight_uri=weight_path,\n", - " test_inputs=[test_in_path],\n", - " test_outputs=[test_out_path],\n", - " name=Trained_model_name,\n", - " description=Trained_model_description,\n", - " authors=authors,\n", - " tags=['zerocostdl4mic', 'deepimagej', 'segmentation', 'tem', 'unet'],\n", - " license=license,\n", - " documentation=readme_path,\n", - " cite=citations,\n", - " output_path=output_path,\n", - " add_deepimagej_config=True,\n", - " tensorflow_version=tf.__version__,\n", - " attachments=attachments,\n", - " training_data = training_data,\n", - " **kwargs\n", - ")\n", + "attachments.append(FileDescr(source = path))\n", + "\n", + "# make cover image\n", + "cover = np.squeeze(test_img)\n", + "pred_cover = np.squeeze(test_prediction)\n", + "\n", + "for idx in range(1, n_channels):\n", + " if channel_pred_idx == 0:\n", + " cover = np.concatenate((cover, pred_cover[idx,:,:]), axis=1)\n", + " elif channel_pred_idx == 1:\n", + " cover = np.concatenate((cover, pred_cover[:,idx,:]), axis=1)\n", + " elif channel_pred_idx == 2:\n", + " cover = np.concatenate((cover, pred_cover[:,:,idx]), axis=1)\n", "\n", - "# convert the keras weights to tensorflow and add them to the model\n", - "tf_weight_path = os.path.join(full_QC_model_path, \"tf_weights\")\n", - "# we need to make sure that the tf weight folder does not exist\n", - "if os.path.exists(tf_weight_path):\n", - " rmtree(tf_weight_path)\n", - "convert_weights_to_tensorflow_saved_model_bundle(output_path, tf_weight_path + \".zip\")\n", - "add_weights(output_path, tf_weight_path + \".zip\", output_path, tensorflow_version=tf.__version__)\n", - "\n", - "# check that the model works for keras and tensorflow\n", - "res = test_model(output_path, weight_format=\"keras_hdf5\")\n", - "success = True\n", - "if res[-1][\"error\"] is not None:\n", - " success = False\n", - " print(\"test-model failed for keras weights:\", res[-1][\"error\"])\n", - "\n", - "res = test_model(output_path, weight_format=\"tensorflow_saved_model_bundle\")\n", - "if res[-1][\"error\"] is not None:\n", - " success = False\n", - " print(\"test-model failed for tensorflow weights:\", res[-1][\"error\"])\n", + "cover_path = os.path.join(output_root, \"cover.png\")\n", + "plt.imsave(cover_path, cover, cmap='gray')\n", + "\n", + "# make weights description\n", + "unet_tf_weights = bioimageio_spec.KerasHdf5WeightsDescr(source=weight_path, tensorflow_version=tf.__version__)\n", + "unet_weights = bioimageio_spec.WeightsDescr(keras_hdf5=unet_tf_weights)\n", + "\n", + "# create model description for export\n", + "model_description = bioimageio_spec.ModelDescr(name=Trained_model_name,\n", + " description=Trained_model_description,\n", + " covers=[cover_path],\n", + " authors=authors,\n", + " attachments=attachments,\n", + " cite=citation_spec,\n", + " license=license,\n", + "\n", + " maintainers=[maintainer_spec],\n", + " tags=['zerocostdl4mic', 'deepimagej', 'segmentation', 'unet'],\n", + " documentation= documentation_path,\n", + " inputs=[input_tensor],\n", + " outputs=[output_tensor],\n", + " packaged_by=[packager_spec],\n", + " weights=unet_weights,\n", + " training_data=training_data,\n", + "\n", + " )\n", + "\n", + "\n", + "# test model\n", + "summary = bioimageio_core.test_model(model_description, weight_format=\"keras_hdf5\")\n", + "summary.display()\n", + "\n", + "success = summary.status == \"passed\"\n", + "\n", + "save_bioimageio_package(model_description, output_path=Path(output_path))\n", "\n", "if success:\n", " print(\"The bioimage.io model was successfully exported to\", output_path)\n", @@ -2434,7 +2525,7 @@ "\n", "\n", "unet = load_model(os.path.join(Prediction_model_path, Prediction_model_name, 'weights_best.hdf5'), custom_objects={'_weighted_binary_crossentropy': weighted_binary_crossentropy(np.ones(2))})\n", - "Input_size = unet.layers[0].output_shape[1:3]\n", + "Input_size = unet.layers[0].output_shape[0][1:3]\n", "print('Model input size: '+str(Input_size[0])+'x'+str(Input_size[1]))\n", "\n", "# Create a list of sources\n", @@ -2497,6 +2588,13 @@ "# **7. Version log**\n", "\n", "---\n", + "**v2.1.3**: \n", + "\n", + "* Updated Bioimage.IO model export to latest version (core-0.6.9, spec-0.5.3.2)\n", + "* Fixed model importation from Bioimage.IO\n", + "* Fixed Tensorflow version to 2.15\n", + "* Bug fixes\n", + "\n", "**v2.1.2**: \n", "\n", "* Correct for data loading to avoid .DS_Store or similar\n", @@ -2524,11 +2622,11 @@ "metadata": { "accelerator": "GPU", "colab": { + "gpuType": "T4", "provenance": [] }, "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", + "display_name": "Python 3", "name": "python3" }, "language_info": { @@ -2541,7 +2639,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.9.19" } }, "nbformat": 4, diff --git a/requirements_files/2D_UNet_multilabel_requirements_simple.txt b/requirements_files/2D_UNet_multilabel_requirements_simple.txt index e8b74bb..f35e096 100644 --- a/requirements_files/2D_UNet_multilabel_requirements_simple.txt +++ b/requirements_files/2D_UNet_multilabel_requirements_simple.txt @@ -1,25 +1,24 @@ # Requirements for U_Net_2D_Multilabel_ZeroCostDL4Mic.ipynb PTable==0.9.2 -Pillow==8.4.0 -bioimageio.core==0.5.9 +Pillow==10.4.0 +bioimageio.core==0.6.9 data==0.4 -fpdf2==2.7.4 -future==0.18.3 -google==2.0.3 +fpdf2==2.7.9 +future==1.0.0 h5py==3.10.0 ipywidgets==8.0.7 matplotlib==3.7.1 -numexpr==2.8.4 -numpy==1.22.4 -pandas==1.5.3 +numexpr==2.10.1 +numpy==1.26.4 +pandas==2.1.4 pathlib==1.0.1 -pip==23.1.2 -requests==2.27.1 -scikit-image==0.19.3 -scikit-learn==1.2.2 -scipy==1.10.1 -tensorflow==2.12.0 -tifffile==2023.7.4 -tqdm==4.65.0 +pip==24.1.2 +requests==2.32.3 +scikit-image==0.24.0 +scikit-learn==1.5.2 +scipy==1.13.1 +tensorflow==2.15.0 +tifffile==2024.9.20 +tqdm==4.66.5 wget==3.2 -zarr==2.15.0 +zarr==2.18.3