From 1e4727f33933da83642f92d3dfb897a4feafdadd Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Tue, 12 Jul 2022 12:12:28 -0400 Subject: [PATCH 01/19] Create 1.0.0 --- DDIG/SynthStrip/1.0.0 | 1 + 1 file changed, 1 insertion(+) create mode 100644 DDIG/SynthStrip/1.0.0 diff --git a/DDIG/SynthStrip/1.0.0 b/DDIG/SynthStrip/1.0.0 new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/DDIG/SynthStrip/1.0.0 @@ -0,0 +1 @@ + From d3313eb50fbd016df26edf785d9d462971ffc1e8 Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Tue, 12 Jul 2022 12:12:57 -0400 Subject: [PATCH 02/19] Delete DDIG/SynthStrip directory --- DDIG/SynthStrip/1.0.0 | 1 - 1 file changed, 1 deletion(-) delete mode 100644 DDIG/SynthStrip/1.0.0 diff --git a/DDIG/SynthStrip/1.0.0 b/DDIG/SynthStrip/1.0.0 deleted file mode 100644 index 8b137891..00000000 --- a/DDIG/SynthStrip/1.0.0 +++ /dev/null @@ -1 +0,0 @@ - From 0398d4d5d00d7fb9835a2f09704d130173138e60 Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Tue, 12 Jul 2022 12:14:28 -0400 Subject: [PATCH 03/19] Create 1.0.0 --- UCL/SynthStrip/1.0.0 | 1 + 1 file changed, 1 insertion(+) create mode 100644 UCL/SynthStrip/1.0.0 diff --git a/UCL/SynthStrip/1.0.0 b/UCL/SynthStrip/1.0.0 new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/UCL/SynthStrip/1.0.0 @@ -0,0 +1 @@ + From b82c4e86efeb5b91a8be53b5520a717561de916d Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Tue, 12 Jul 2022 12:15:49 -0400 Subject: [PATCH 04/19] Delete 1.0.0 --- UCL/SynthStrip/1.0.0 | 1 - 1 file changed, 1 deletion(-) delete mode 100644 UCL/SynthStrip/1.0.0 diff --git a/UCL/SynthStrip/1.0.0 b/UCL/SynthStrip/1.0.0 deleted file mode 100644 index 8b137891..00000000 --- a/UCL/SynthStrip/1.0.0 +++ /dev/null @@ -1 +0,0 @@ - From 50961678fbc09f58e8c9d9826adf1bb54ae0299f Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Tue, 12 Jul 2022 12:25:08 -0400 Subject: [PATCH 05/19] Create predict.py --- UCL/SynthStrip/predict.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 UCL/SynthStrip/predict.py diff --git a/UCL/SynthStrip/predict.py b/UCL/SynthStrip/predict.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/UCL/SynthStrip/predict.py @@ -0,0 +1 @@ + From 76610632b219900acce305b17fa112db7e147265 Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Wed, 20 Jul 2022 12:06:21 -0400 Subject: [PATCH 06/19] Delete UCL/SynthStrip directory --- UCL/SynthStrip/predict.py | 1 - 1 file changed, 1 deletion(-) delete mode 100644 UCL/SynthStrip/predict.py diff --git a/UCL/SynthStrip/predict.py b/UCL/SynthStrip/predict.py deleted file mode 100644 index 8b137891..00000000 --- a/UCL/SynthStrip/predict.py +++ /dev/null @@ -1 +0,0 @@ - From d4d290474e2413437b99d45edf5fc443df23338c Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Wed, 20 Jul 2022 12:07:09 -0400 Subject: [PATCH 07/19] Create 1.0.0 --- DDIG/SynthStrip/1.0.0 | 1 + 1 file changed, 1 insertion(+) create mode 100644 DDIG/SynthStrip/1.0.0 diff --git a/DDIG/SynthStrip/1.0.0 b/DDIG/SynthStrip/1.0.0 new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/DDIG/SynthStrip/1.0.0 @@ -0,0 +1 @@ + From e6ca89ec79dc8f95ef268481ec03256d29b04631 Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Wed, 20 Jul 2022 12:07:27 -0400 Subject: [PATCH 08/19] Delete DDIG/SynthStrip directory --- DDIG/SynthStrip/1.0.0 | 1 - 1 file changed, 1 deletion(-) delete mode 100644 DDIG/SynthStrip/1.0.0 diff --git a/DDIG/SynthStrip/1.0.0 b/DDIG/SynthStrip/1.0.0 deleted file mode 100644 index 8b137891..00000000 --- a/DDIG/SynthStrip/1.0.0 +++ /dev/null @@ -1 +0,0 @@ - From c9a17802b84a01c6e98b9f92929a2fe561231572 Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Wed, 20 Jul 2022 12:19:26 -0400 Subject: [PATCH 09/19] Create predict.py --- DDIG/SynthStrip/1.0.0/predict.py | 270 +++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 DDIG/SynthStrip/1.0.0/predict.py diff --git a/DDIG/SynthStrip/1.0.0/predict.py b/DDIG/SynthStrip/1.0.0/predict.py new file mode 100644 index 00000000..ff50fa3a --- /dev/null +++ b/DDIG/SynthStrip/1.0.0/predict.py @@ -0,0 +1,270 @@ +"""This code is adapted from FreeSurfer mri_synthstrip.py to be compatible for Nobrainer-zoo. + + +If you use this code, please cite the SynthStrip paper: +SynthStrip: Skull-Stripping for Any Brain Image. +A Hoopes, JS Mora, AV Dalca, B Fischl, M Hoffmann. + +https://github.com/freesurfer/freesurfer/blob/dev/mri_synthstrip/ + + +Copyright 2022 A Hoopes + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the +License. +""" + +#!/usr/bin/env python + +import os +import sys +import torch +import torch +import torch.nn as nn +import numpy as np +import argparse +import surfa as sf +import scipy.ndimage + +description = ''' +Robust, universal skull-stripping for brain images of any +type. If you use SynthStrip in your analysis, please cite: + +SynthStrip: Skull-Stripping for Any Brain Image. +A Hoopes, JS Mora, AV Dalca, B Fischl, M Hoffmann. +''' + +# parse command line +parser = argparse.ArgumentParser(description=description) +parser.add_argument('-i', '--image', metavar='file', required=True, help='Input image to skullstrip.') +parser.add_argument('-o', '--out', metavar='file', help='Save stripped image to path.') +parser.add_argument('-m', '--mask', metavar='file', help='Save binary brain mask to path.') +parser.add_argument('-g', '--gpu', action='store_true', help='Use the GPU.') +parser.add_argument('-b', '--border', default=1, type=int, help='Mask border threshold in mm. Default is 1.') +parser.add_argument('--model', metavar='file', help='Alternative model weights.') +if len(sys.argv) == 1: + parser.print_help() + exit(1) +args = parser.parse_args() + +# sanity check on the inputs +if not args.out and not args.mask: + sf.system.fatal('Must provide at least --out or --mask output flags.') + +# necessary for speed gains (I think) +torch.backends.cudnn.benchmark = True +torch.backends.cudnn.deterministic = True + +# configure GPU device +if args.gpu: + os.environ['CUDA_VISIBLE_DEVICES'] = '0' + device = torch.device('cuda') + device_name = 'GPU' +else: + os.environ['CUDA_VISIBLE_DEVICES'] = '-1' + device = torch.device('cpu') + device_name = 'CPU' + +# configure model +print(f'Configuring model on the {device_name}') + +class StripModel(nn.Module): + + def __init__(self, + nb_features=16, + nb_levels=7, + feat_mult=2, + max_features=64, + nb_conv_per_level=2, + max_pool=2, + return_mask=False): + + super().__init__() + + # dimensionality + ndims = 3 + + # build feature list automatically + if isinstance(nb_features, int): + if nb_levels is None: + raise ValueError('must provide unet nb_levels if nb_features is an integer') + feats = np.round(nb_features * feat_mult ** np.arange(nb_levels)).astype(int) + feats = np.clip(feats, 1, max_features) + nb_features = [ + np.repeat(feats[:-1], nb_conv_per_level), + np.repeat(np.flip(feats), nb_conv_per_level) + ] + elif nb_levels is not None: + raise ValueError('cannot use nb_levels if nb_features is not an integer') + + # extract any surplus (full resolution) decoder convolutions + enc_nf, dec_nf = nb_features + nb_dec_convs = len(enc_nf) + final_convs = dec_nf[nb_dec_convs:] + dec_nf = dec_nf[:nb_dec_convs] + self.nb_levels = int(nb_dec_convs / nb_conv_per_level) + 1 + + if isinstance(max_pool, int): + max_pool = [max_pool] * self.nb_levels + + # cache downsampling / upsampling operations + MaxPooling = getattr(nn, 'MaxPool%dd' % ndims) + self.pooling = [MaxPooling(s) for s in max_pool] + self.upsampling = [nn.Upsample(scale_factor=s, mode='nearest') for s in max_pool] + + # configure encoder (down-sampling path) + prev_nf = 1 + encoder_nfs = [prev_nf] + self.encoder = nn.ModuleList() + for level in range(self.nb_levels - 1): + convs = nn.ModuleList() + for conv in range(nb_conv_per_level): + nf = enc_nf[level * nb_conv_per_level + conv] + convs.append(ConvBlock(ndims, prev_nf, nf)) + prev_nf = nf + self.encoder.append(convs) + encoder_nfs.append(prev_nf) + + # configure decoder (up-sampling path) + encoder_nfs = np.flip(encoder_nfs) + self.decoder = nn.ModuleList() + for level in range(self.nb_levels - 1): + convs = nn.ModuleList() + for conv in range(nb_conv_per_level): + nf = dec_nf[level * nb_conv_per_level + conv] + convs.append(ConvBlock(ndims, prev_nf, nf)) + prev_nf = nf + self.decoder.append(convs) + if level < (self.nb_levels - 1): + prev_nf += encoder_nfs[level] + + # now we take care of any remaining convolutions + self.remaining = nn.ModuleList() + for num, nf in enumerate(final_convs): + self.remaining.append(ConvBlock(ndims, prev_nf, nf)) + prev_nf = nf + + # final convolutions + if return_mask: + self.remaining.append(ConvBlock(ndims, prev_nf, 2, activation=None)) + self.remaining.append(nn.Softmax(dim=1)) + else: + self.remaining.append(ConvBlock(ndims, prev_nf, 1, activation=None)) + + def forward(self, x): + + # encoder forward pass + x_history = [x] + for level, convs in enumerate(self.encoder): + for conv in convs: + x = conv(x) + x_history.append(x) + x = self.pooling[level](x) + + # decoder forward pass with upsampling and concatenation + for level, convs in enumerate(self.decoder): + for conv in convs: + x = conv(x) + if level < (self.nb_levels - 1): + x = self.upsampling[level](x) + x = torch.cat([x, x_history.pop()], dim=1) + + # remaining convs at full resolution + for conv in self.remaining: + x = conv(x) + + return x + +class ConvBlock(nn.Module): + """ + Specific convolutional block followed by leakyrelu for unet. + """ + + def __init__(self, ndims, in_channels, out_channels, stride=1, activation='leaky'): + super().__init__() + + Conv = getattr(nn, 'Conv%dd' % ndims) + self.conv = Conv(in_channels, out_channels, 3, stride, 1) + if activation == 'leaky': + self.activation = nn.LeakyReLU(0.2) + elif activation == None: + self.activation = None + else: + raise ValueError(f'Unknown activation: {activation}') + + def forward(self, x): + out = self.conv(x) + if self.activation is not None: + out = self.activation(out) + return out + +with torch.no_grad(): + model = StripModel() + model.to(device) + model.eval() + +# load model weights +if args.model is not None: + modelfile = args.model + print('Using custom model weights') +else: + version = '1' + print(f'Running SynthStrip model version {version}') + fshome = os.environ.get('FREESURFER_HOME') + if fshome is None: + sf.system.fatal('FREESURFER_HOME env variable must be set! Make sure FreeSurfer is properly sourced.') + modelfile = os.path.join(fshome, 'models', f'synthstrip.{version}.pt') +checkpoint = torch.load(modelfile, map_location=device) +model.load_state_dict(checkpoint['model_state_dict']) + +# load input volume +image = sf.load_volume(args.image) +print(f'Input image read from: {args.image}') + +# frame check +if image.nframes > 1: + sf.system.fatal('Input image cannot have more than 1 frame') + +# conform image and fit to shape with factors of 64 +conformed = image.conform(voxsize=1.0, dtype='float32', method='nearest', orientation='LIA').crop_to_bbox() +target_shape = np.clip(np.ceil(np.array(conformed.shape[:3]) / 64).astype(int) * 64, 192, 320) +conformed = conformed.reshape(target_shape) + +# normalize intensities +conformed -= conformed.min() +conformed = (conformed / conformed.percentile(99)).clip(0, 1) + +# predict the surface distance transform +with torch.no_grad(): + input_tensor = torch.from_numpy(conformed.data[np.newaxis, np.newaxis]).to(device) + sdt = model(input_tensor).cpu().numpy().squeeze() + +# unconform the sdt and extract mask +sdt = conformed.new(sdt).resample_like(image, fill=100) + +# find largest CC (just do this to be safe for now) +components = scipy.ndimage.label(sdt.data < args.border)[0] +bincount = np.bincount(components.flatten())[1:] +mask = (components == (np.argmax(bincount) + 1)) +mask = scipy.ndimage.binary_fill_holes(mask) + +# write the masked output +if args.out: + image[mask == 0] = np.min([0, image.min()]) + image.save(args.out) + print(f'Masked image saved to: {args.out}') + +# write the brain mask +if args.mask: + image.new(mask).save(args.mask) + print(f'Binary brain mask saved to: {args.mask}') + +print('If you use SynthStrip in your analysis, please cite:') +print('----------------------------------------------------') +print('SynthStrip: Skull-Stripping for Any Brain Image.') +print('A Hoopes, JS Mora, AV Dalca, B Fischl, M Hoffmann.') From aa01b106abe5314fe7c58d6c3ab238d7ed47cfb8 Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Wed, 20 Jul 2022 17:19:44 +0100 Subject: [PATCH 10/19] Add files via upload --- DDIG/SynthStrip/1.0.0/Dockerfile | 38 ++++++++++ DDIG/SynthStrip/1.0.0/requirements.txt | 70 +++++++++++++++++++ DDIG/SynthStrip/1.0.0/spec.yaml | 31 ++++++++ DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt | 1 + 4 files changed, 140 insertions(+) create mode 100644 DDIG/SynthStrip/1.0.0/Dockerfile create mode 100644 DDIG/SynthStrip/1.0.0/requirements.txt create mode 100644 DDIG/SynthStrip/1.0.0/spec.yaml create mode 100644 DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt diff --git a/DDIG/SynthStrip/1.0.0/Dockerfile b/DDIG/SynthStrip/1.0.0/Dockerfile new file mode 100644 index 00000000..a7badf79 --- /dev/null +++ b/DDIG/SynthStrip/1.0.0/Dockerfile @@ -0,0 +1,38 @@ +# syntax=docker/dockerfile:1 + +FROM centos:7 + +# copy local data +COPY . /external + +# shell settings +WORKDIR /freesurfer + +# install utils +RUN yum -y update +RUN yum -y install libgomp python3 +RUN yum clean all + +# python packages +RUN pip3 install scipy torch==1.10.2 +RUN pip3 install /external/fsmodule + +# install synthstrip +RUN cp /external/mri_synthstrip /freesurfer/ + +# configure model +ENV FREESURFER_HOME /freesurfer +RUN mkdir -p /freesurfer/models +RUN cp /external/synthstrip.1.pt /freesurfer/models/ + +# setup rest of the env +ENV OS Linux +ENV FSF_OUTPUT_FORMAT nii.gz + +# clean up +RUN rm -rf /external /root/.cache/pip + +ENTRYPOINT ["python3", "/freesurfer/mri_synthstrip"] + +WORKDIR /work +LABEL maintainer="Hoda Rajaei " diff --git a/DDIG/SynthStrip/1.0.0/requirements.txt b/DDIG/SynthStrip/1.0.0/requirements.txt new file mode 100644 index 00000000..ed59c3e6 --- /dev/null +++ b/DDIG/SynthStrip/1.0.0/requirements.txt @@ -0,0 +1,70 @@ +absl-py==0.9.0 +astor==0.8.1 +backcall==0.1.0 +cachetools==4.1.0 +certifi==2020.4.5.1 +chardet==3.0.4 +cloudpickle==1.1.1 +cycler==0.10.0 +decorator==4.4.2 +gast==0.2.2 +google-auth==1.14.0 +google-auth-oauthlib==0.4.1 +google-pasta==0.2.0 +grpcio==1.28.1 +h5py==2.10.0 +idna==2.9 +imageio==2.8.0 +ipython==7.13.0 +ipython-genutils==0.2.0 +jedi==0.17.0 +joblib==0.14.1 +Keras==2.3.1 +Keras-Applications==1.0.8 +Keras-Preprocessing==1.1.0 +kiwisolver==1.2.0 +Markdown==3.2.1 +matplotlib==3.2.1 +myst-parser +nibabel==3.1.0 +numpy==1.18.2 +oauthlib==3.1.0 +opt-einsum==3.2.1 +packaging==20.3 +pandas==1.0.3 +pandoc +parso==0.7.0 +pexpect==4.8.0 +pickleshare==0.7.5 +Pillow==7.1.1 +prompt-toolkit==3.0.5 +protobuf==3.11.3 +ptyprocess==0.6.0 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +Pygments==2.6.1 +pylab-sdk==1.1.2 +pyparsing==2.4.7 +python-dateutil==2.8.1 +pytz==2019.3 +PyYAML==5.3.1 +requests==2.23.0 +requests-oauthlib==1.3.0 +rsa==4.0 +scikit-learn==0.22.2.post1 +scipy==1.4.1 +seaborn==0.10.0 +six==1.14.0 +sklearn==0.0 +sphinx +sphinx_rtd_theme +tensorboard==2.0.2 +tensorflow-estimator==2.0.1 +tensorflow-gpu==2.0.1 +termcolor==1.1.0 +tqdm==4.45.0 +traitlets==4.3.3 +urllib3==1.25.9 +wcwidth==0.1.9 +Werkzeug==1.0.1 +wrapt==1.12.1 \ No newline at end of file diff --git a/DDIG/SynthStrip/1.0.0/spec.yaml b/DDIG/SynthStrip/1.0.0/spec.yaml new file mode 100644 index 00000000..210dd7c2 --- /dev/null +++ b/DDIG/SynthStrip/1.0.0/spec.yaml @@ -0,0 +1,31 @@ +#### container info +image: + singularity: nobrainer-zoo_ddig.sif + docker: neuronets/nobrainer-zoo:ddig + +#### repository info +repository: + repo_url: "https://github.com/freesurfer/freesurfer/tree/dev/mri_synthstrip" + committish: "e935059" + repo_download: True + repo_download_location: f"{REPO_PATH}/{model_nm}-{ver}" + +#### required fields for prediction +inference: + prediction_script: "trained-models/DDIG/SynthStrip/1.0.0/predict.py" + command: f"python3 {MODELS_PATH}/{model}/{model_type}/predict.py --model_path {model_path} -i {infile} -o {outfile}" + # TODO: we should add help for options. + options: + threads: {mandatory: False, argstr: "--threads", type: "int", default: 1} + cpu: {mandatory: False, argstr: "--cpu", is_flag: true} + ct: {mandatury: False, argstr: "--ct", is_flag: true} + #### input data characteristics + data_spec: + infile: {n_files: 1} + outfile: {n_files: 1} + +#### required fields for model training +train: +#### TODO: Add the train spec here + + diff --git a/DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt b/DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt new file mode 100644 index 00000000..cba483be --- /dev/null +++ b/DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt @@ -0,0 +1 @@ +../.git/annex/objects/JG/7x/SHA256E-s30851709--37417f802196186441aae3e7f385d94f8a98c64a88acaeaa2723af995c653e33.1.pt/SHA256E-s30851709--37417f802196186441aae3e7f385d94f8a98c64a88acaeaa2723af995c653e33.1.pt \ No newline at end of file From dc7267f9420d56550d4b46de7c88a16e838a22d8 Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Fri, 22 Jul 2022 18:24:12 -0400 Subject: [PATCH 11/19] Update requirements.txt --- DDIG/SynthStrip/1.0.0/requirements.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/DDIG/SynthStrip/1.0.0/requirements.txt b/DDIG/SynthStrip/1.0.0/requirements.txt index ed59c3e6..047b9ff2 100644 --- a/DDIG/SynthStrip/1.0.0/requirements.txt +++ b/DDIG/SynthStrip/1.0.0/requirements.txt @@ -59,12 +59,10 @@ sklearn==0.0 sphinx sphinx_rtd_theme tensorboard==2.0.2 -tensorflow-estimator==2.0.1 -tensorflow-gpu==2.0.1 termcolor==1.1.0 tqdm==4.45.0 traitlets==4.3.3 urllib3==1.25.9 wcwidth==0.1.9 Werkzeug==1.0.1 -wrapt==1.12.1 \ No newline at end of file +wrapt==1.12.1 From 2914711409540190c3f933aa1c41d442155be0da Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Fri, 22 Jul 2022 18:39:08 -0400 Subject: [PATCH 12/19] Update requirements.txt --- DDIG/SynthStrip/1.0.0/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/DDIG/SynthStrip/1.0.0/requirements.txt b/DDIG/SynthStrip/1.0.0/requirements.txt index 047b9ff2..dfc3acd4 100644 --- a/DDIG/SynthStrip/1.0.0/requirements.txt +++ b/DDIG/SynthStrip/1.0.0/requirements.txt @@ -60,6 +60,7 @@ sphinx sphinx_rtd_theme tensorboard==2.0.2 termcolor==1.1.0 +torch==1.10.2 tqdm==4.45.0 traitlets==4.3.3 urllib3==1.25.9 From b37dd0bd23210dad1541659f08bf2155d2103809 Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Fri, 22 Jul 2022 18:48:53 -0400 Subject: [PATCH 13/19] Update Dockerfile --- DDIG/SynthStrip/1.0.0/Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/DDIG/SynthStrip/1.0.0/Dockerfile b/DDIG/SynthStrip/1.0.0/Dockerfile index a7badf79..8719175e 100644 --- a/DDIG/SynthStrip/1.0.0/Dockerfile +++ b/DDIG/SynthStrip/1.0.0/Dockerfile @@ -2,8 +2,6 @@ FROM centos:7 -# copy local data -COPY . /external # shell settings WORKDIR /freesurfer @@ -14,7 +12,7 @@ RUN yum -y install libgomp python3 RUN yum clean all # python packages -RUN pip3 install scipy torch==1.10.2 +RUN pip3 install scipy surfa torch==1.10.2 RUN pip3 install /external/fsmodule # install synthstrip @@ -22,13 +20,15 @@ RUN cp /external/mri_synthstrip /freesurfer/ # configure model ENV FREESURFER_HOME /freesurfer -RUN mkdir -p /freesurfer/models -RUN cp /external/synthstrip.1.pt /freesurfer/models/ # setup rest of the env ENV OS Linux ENV FSF_OUTPUT_FORMAT nii.gz +COPY requirements.txt requirements.txt +RUN pip install --no-cache-dir -r requirements.txt +RUN pip install --no-cache-dir PyYAML + # clean up RUN rm -rf /external /root/.cache/pip From 1fd08eb2d2b625b55b4773cf6af2476eecbd60cb Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Fri, 22 Jul 2022 18:57:05 -0400 Subject: [PATCH 14/19] Update spec.yaml updated and corrected for model path and model type --- DDIG/SynthStrip/1.0.0/spec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DDIG/SynthStrip/1.0.0/spec.yaml b/DDIG/SynthStrip/1.0.0/spec.yaml index 210dd7c2..fee0ee93 100644 --- a/DDIG/SynthStrip/1.0.0/spec.yaml +++ b/DDIG/SynthStrip/1.0.0/spec.yaml @@ -13,7 +13,7 @@ repository: #### required fields for prediction inference: prediction_script: "trained-models/DDIG/SynthStrip/1.0.0/predict.py" - command: f"python3 {MODELS_PATH}/{model}/{model_type}/predict.py --model_path {model_path} -i {infile} -o {outfile}" + command: f"python3 {MODELS_PATH}/{model}/predict.py --model {model_path} -i {infile} -o {outfile}" # TODO: we should add help for options. options: threads: {mandatory: False, argstr: "--threads", type: "int", default: 1} From f3ee7f1ff505b9302ba5ce2b531929ef0f3dd57c Mon Sep 17 00:00:00 2001 From: Dhritiman Das <14159298+dhritimandas@users.noreply.github.com> Date: Fri, 22 Jul 2022 18:58:44 -0400 Subject: [PATCH 15/19] Update requirements.txt to add surfa here or in the docker file itself ? --- DDIG/SynthStrip/1.0.0/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/DDIG/SynthStrip/1.0.0/requirements.txt b/DDIG/SynthStrip/1.0.0/requirements.txt index dfc3acd4..f0113735 100644 --- a/DDIG/SynthStrip/1.0.0/requirements.txt +++ b/DDIG/SynthStrip/1.0.0/requirements.txt @@ -58,6 +58,7 @@ six==1.14.0 sklearn==0.0 sphinx sphinx_rtd_theme +surfa tensorboard==2.0.2 termcolor==1.1.0 torch==1.10.2 From 691ea4b1f3c34ea281c5f62b65d262f8b89e3aac Mon Sep 17 00:00:00 2001 From: Hoda Rajaei Date: Tue, 26 Jul 2022 16:05:08 -0700 Subject: [PATCH 16/19] modified synthstrip files --- .gitignore | 1 + DDIG/SynthStrip/1.0.0/Dockerfile | 36 ++++--------- DDIG/SynthStrip/1.0.0/predict.py | 1 - DDIG/SynthStrip/1.0.0/requirements.txt | 74 ++------------------------ DDIG/SynthStrip/1.0.0/spec.yaml | 14 ++--- 5 files changed, 23 insertions(+), 103 deletions(-) diff --git a/.gitignore b/.gitignore index 3eff3144..ddc4e3e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_Store ._* .h5 +.idea/* diff --git a/DDIG/SynthStrip/1.0.0/Dockerfile b/DDIG/SynthStrip/1.0.0/Dockerfile index 8719175e..c7a6fad4 100644 --- a/DDIG/SynthStrip/1.0.0/Dockerfile +++ b/DDIG/SynthStrip/1.0.0/Dockerfile @@ -1,38 +1,24 @@ # syntax=docker/dockerfile:1 -FROM centos:7 +FROM pytorch/pytorch:1.11.0-cuda11.3-cudnn8-runtime +RUN apt-get update \ + && apt-get install --yes --quiet --no-install-recommends \ + ca-certificates \ + git \ + libgomp1 \ + gcc \ + && rm -rf /var/lib/apt/lists/* -# shell settings -WORKDIR /freesurfer - -# install utils -RUN yum -y update -RUN yum -y install libgomp python3 -RUN yum clean all +ENV LC_ALL=C.UTF-8 \ + LANG=C.UTF-8 # python packages -RUN pip3 install scipy surfa torch==1.10.2 -RUN pip3 install /external/fsmodule - -# install synthstrip -RUN cp /external/mri_synthstrip /freesurfer/ - -# configure model -ENV FREESURFER_HOME /freesurfer - -# setup rest of the env -ENV OS Linux -ENV FSF_OUTPUT_FORMAT nii.gz - COPY requirements.txt requirements.txt RUN pip install --no-cache-dir -r requirements.txt -RUN pip install --no-cache-dir PyYAML # clean up -RUN rm -rf /external /root/.cache/pip - -ENTRYPOINT ["python3", "/freesurfer/mri_synthstrip"] +RUN rm -rf /root/.cache/pip WORKDIR /work LABEL maintainer="Hoda Rajaei " diff --git a/DDIG/SynthStrip/1.0.0/predict.py b/DDIG/SynthStrip/1.0.0/predict.py index ff50fa3a..76396197 100644 --- a/DDIG/SynthStrip/1.0.0/predict.py +++ b/DDIG/SynthStrip/1.0.0/predict.py @@ -24,7 +24,6 @@ import os import sys import torch -import torch import torch.nn as nn import numpy as np import argparse diff --git a/DDIG/SynthStrip/1.0.0/requirements.txt b/DDIG/SynthStrip/1.0.0/requirements.txt index f0113735..2792c28f 100644 --- a/DDIG/SynthStrip/1.0.0/requirements.txt +++ b/DDIG/SynthStrip/1.0.0/requirements.txt @@ -1,70 +1,4 @@ -absl-py==0.9.0 -astor==0.8.1 -backcall==0.1.0 -cachetools==4.1.0 -certifi==2020.4.5.1 -chardet==3.0.4 -cloudpickle==1.1.1 -cycler==0.10.0 -decorator==4.4.2 -gast==0.2.2 -google-auth==1.14.0 -google-auth-oauthlib==0.4.1 -google-pasta==0.2.0 -grpcio==1.28.1 -h5py==2.10.0 -idna==2.9 -imageio==2.8.0 -ipython==7.13.0 -ipython-genutils==0.2.0 -jedi==0.17.0 -joblib==0.14.1 -Keras==2.3.1 -Keras-Applications==1.0.8 -Keras-Preprocessing==1.1.0 -kiwisolver==1.2.0 -Markdown==3.2.1 -matplotlib==3.2.1 -myst-parser -nibabel==3.1.0 -numpy==1.18.2 -oauthlib==3.1.0 -opt-einsum==3.2.1 -packaging==20.3 -pandas==1.0.3 -pandoc -parso==0.7.0 -pexpect==4.8.0 -pickleshare==0.7.5 -Pillow==7.1.1 -prompt-toolkit==3.0.5 -protobuf==3.11.3 -ptyprocess==0.6.0 -pyasn1==0.4.8 -pyasn1-modules==0.2.8 -Pygments==2.6.1 -pylab-sdk==1.1.2 -pyparsing==2.4.7 -python-dateutil==2.8.1 -pytz==2019.3 -PyYAML==5.3.1 -requests==2.23.0 -requests-oauthlib==1.3.0 -rsa==4.0 -scikit-learn==0.22.2.post1 -scipy==1.4.1 -seaborn==0.10.0 -six==1.14.0 -sklearn==0.0 -sphinx -sphinx_rtd_theme -surfa -tensorboard==2.0.2 -termcolor==1.1.0 -torch==1.10.2 -tqdm==4.45.0 -traitlets==4.3.3 -urllib3==1.25.9 -wcwidth==0.1.9 -Werkzeug==1.0.1 -wrapt==1.12.1 +# pytorch==1.10.2 +scipy==1.8.1 +surfa==0.2.0 +PyYAML diff --git a/DDIG/SynthStrip/1.0.0/spec.yaml b/DDIG/SynthStrip/1.0.0/spec.yaml index fee0ee93..b3bc6dc3 100644 --- a/DDIG/SynthStrip/1.0.0/spec.yaml +++ b/DDIG/SynthStrip/1.0.0/spec.yaml @@ -6,19 +6,19 @@ image: #### repository info repository: repo_url: "https://github.com/freesurfer/freesurfer/tree/dev/mri_synthstrip" - committish: "e935059" - repo_download: True - repo_download_location: f"{REPO_PATH}/{model_nm}-{ver}" + committish: "e935059a" + repo_download: False + repo_download_location: "None" #### required fields for prediction inference: prediction_script: "trained-models/DDIG/SynthStrip/1.0.0/predict.py" command: f"python3 {MODELS_PATH}/{model}/predict.py --model {model_path} -i {infile} -o {outfile}" - # TODO: we should add help for options. + options: - threads: {mandatory: False, argstr: "--threads", type: "int", default: 1} - cpu: {mandatory: False, argstr: "--cpu", is_flag: true} - ct: {mandatury: False, argstr: "--ct", is_flag: true} + mask: {mandatory: False, argstr: "-m", type: "str", help: "Save binary brain mask to path."} + gpu: {mandatory: False, argstr: "-g", is_flag: true, help: "Use the GPU."} + border: {mandatory: False, argstr: "-b", type: "int", default: 1, help: "Mask border threshold in mm. Default is 1."} #### input data characteristics data_spec: infile: {n_files: 1} From 2ff5879c0da040d796e5a5258bc80bc7effbd1c0 Mon Sep 17 00:00:00 2001 From: Hoda Rajaei Date: Tue, 26 Jul 2022 16:54:01 -0700 Subject: [PATCH 17/19] image field is updated in spec.yaml --- DDIG/SynthStrip/1.0.0/spec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DDIG/SynthStrip/1.0.0/spec.yaml b/DDIG/SynthStrip/1.0.0/spec.yaml index b3bc6dc3..18600a48 100644 --- a/DDIG/SynthStrip/1.0.0/spec.yaml +++ b/DDIG/SynthStrip/1.0.0/spec.yaml @@ -1,7 +1,7 @@ #### container info image: - singularity: nobrainer-zoo_ddig.sif - docker: neuronets/nobrainer-zoo:ddig + singularity: nobrainer-zoo_ddig_torch1.11.0.sif + docker: neuronets/nobrainer-zoo:ddig_torch1.11.0 #### repository info repository: From aa8695a54e28b5fe689fe769d0d0708311bf10ee Mon Sep 17 00:00:00 2001 From: Hoda Rajaei Date: Sat, 30 Jul 2022 17:41:20 -0700 Subject: [PATCH 18/19] delete SynthStrip model file --- DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt diff --git a/DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt b/DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt deleted file mode 100644 index cba483be..00000000 --- a/DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt +++ /dev/null @@ -1 +0,0 @@ -../.git/annex/objects/JG/7x/SHA256E-s30851709--37417f802196186441aae3e7f385d94f8a98c64a88acaeaa2723af995c653e33.1.pt/SHA256E-s30851709--37417f802196186441aae3e7f385d94f8a98c64a88acaeaa2723af995c653e33.1.pt \ No newline at end of file From 33a17de7bf9fa998938e8f77111a2120cbd1b3d6 Mon Sep 17 00:00:00 2001 From: Hoda Rajaei Date: Sat, 30 Jul 2022 23:03:08 -0700 Subject: [PATCH 19/19] Synthstrip model added --- DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt | 1 + 1 file changed, 1 insertion(+) create mode 120000 DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt diff --git a/DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt b/DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt new file mode 120000 index 00000000..9febc9a2 --- /dev/null +++ b/DDIG/SynthStrip/1.0.0/weights/synthstrip.1.pt @@ -0,0 +1 @@ +../../../../.git/annex/objects/vx/qw/URL--https&c%%drive.google.com%file%d-d49b348e59ad5db895cc20bfaa87e1d9/URL--https&c%%drive.google.com%file%d-d49b348e59ad5db895cc20bfaa87e1d9 \ No newline at end of file