def _computeWeight(self, Y): """This function computes the weights of a manual segmentation. The weights are computed based on the loss function used. Args: `Y`: labels. Returns: `W`: weights """ if self.loss == WeightedCrossEntropy_DistanceMap: return np2cuda(surfacedist(Y), self.dev) elif self.loss == WeightedCrossEntropy_ClassBalance: # Number of voxels per image numvox = np.prod(Y.shape[2:]) # Number of 1s in each channel in each sample ones = np.sum(Y, axis=(2,3,4)) # The weights are inversely proportional to the number of ones # so that if there are very few voxels from one category weights_ = 1 - ones/numvox Y = np.moveaxis(np.moveaxis(Y, 0, -1), 0, -1) weights = np.moveaxis(np.moveaxis(Y*weights_, -1, 0), -1, 0) return np2cuda(np.sum(weights, axis=1), self.dev) else: return None
def _loadSubject(self, idx): """This function will load a single subject. Args: `idx`: Index of the subject that will be read. Returns: `X`: raw brain scan. `Y`: labels. `id_`: id/name of the scan. `W`: weights (or None) """ target = self.list[idx] study, timepoint, subject = target.split("/")[-4:-1] id_ = study + "_" + timepoint + "_" + subject X = nib.load(target + "scan.nii.gz").get_data() X = np.moveaxis(X, -1, 0) # Move depth to the beginning X = np.expand_dims(X, axis=0) # Add channel dim X = np.expand_dims(X, axis=0) # Add batch dim Y = nib.load(target + "scan_lesion" + self.seg + ".nii.gz").get_data() Y = np.moveaxis(Y, -1, 0) # Move depth to the beginning Y = np.stack([1.0 * (Y == j) for j in range(2)], axis=0) Y = np.expand_dims(Y, 0) #BCWHD W = self._computeWeight(Y) return np2cuda(X, self.dev), np2cuda(Y, self.dev), id_, W
def _loadSubject(self, idx): """This function will load a single subject. Args: `idx`: Index of the subject that will be read. Returns: `X`: raw brain scan. `Y`: labels. `id_`: id/name of the scan. `W`: weights (or None) """ target = self.list[idx] study, timepoint, subject = target.split("/")[-4:-1] id_ = study + "_" + timepoint + "_" + subject X = nib.load(target+"scan.nii.gz").get_data() X = np.moveaxis(X, -1, 0) # Move channels to the beginning X = np.moveaxis(X, -1, 1) # Move depth after channels X = np.expand_dims(X, axis=0) if os.path.isfile(target+"scan"+self.ext+".nii.gz"): Y = nib.load(target+"scan"+self.ext+".nii.gz").get_data() Y = np.moveaxis(Y, -1, 0) # Move depth to the beginning Y = np.stack([1.0*(Y==j) for j in range(2)], axis=0) else: #Y = np.ones(list(X.shape[2:])) Y = np.ones([2] + list(X.shape[2:])) Y[1,:,:,:] = 0 Y = np.expand_dims(Y, 0) #BCWHD W = self._computeWeight(Y) return np2cuda(X, self.dev), np2cuda(Y, self.dev), id_, W
def _loadSubject(self, idx): """This function loads a single subject. Args: `idx` Index of self.list of the subject that will be loaded. Returns: `X`: brain scan normalized to have 0-mean 1-std. `Y`: labels (0s are the background, 1s are the lesion). `id_`: id/name (path) of the scan. """ target = self.list[idx] X = nib.load(target + self.scanName).get_data() X = (X - X.mean()) / X.std() # 0-mean 1-std normalization X = np.moveaxis(X, -1, 0) # Move channels or depth to the first axis. if len( X.shape ) == 3: # Original image dimensions were HWD (no modality/channel) X = np.expand_dims(X, axis=0) # CDHW format, where C is 1. elif len(X.shape) == 4: # ORiginal image dimensions were HWDC X = np.moveaxis(X, -1, 1) # Move "depth" to the second axis. else: raise Exception("Image `" + target + self.scanName + "` have too many dimensions: " + str(X.shape)) X = np.expand_dims(X, axis=0) # BCDHW format X = np2cuda(X, self.dev) try: Y = nib.load(target + self.labelName).get_data() Y = np.moveaxis(Y, -1, 0) # DHW format Y = np.stack([1.0 * (Y == j) for j in range(2)], axis=0) # CDHW format Y = np.expand_dims(Y, 0) # BCDHW format Y = np2cuda(Y, self.dev) except FileNotFoundError: # This can only happen during "eval" mode. # If it happens, we cannot evaluate how well the predictions are # but the script will generate the predictions anyway. Y = None return X, Y, target
def main(config, Model, data, base_path, _run): log("Start " + ex.get_experiment_info()["name"]) base_path = base_path + str(_run._id) + "/" config["base_path"] = base_path # Load the volume we want to study # In theory, any of them should be okay test_data = data("test", loss=config["loss_fn"], dev=config["device"]) X, Y, id_, W = test_data[0] X = X.cpu().numpy() # Model model = Model(config) model.to(config["device"]) model.eval() if config["model_state"] == "": raise Exception("A model needs to be loaded") model.load_state_dict(torch.load(config["model_state"])) mmin = np.min(X) mmax = np.max(X) # Target voxels. I will study how modifying other voxels affects this particular one. t1, t2, t3 = 9, 80, 80 with torch.no_grad(): log("Checking in Depth dimension. Reference: {},{},{}".format( t1, t2, t3)) results = np.zeros(X.shape[2]) for i in range(X.shape[2]): # Studying in Depth (first) dimension if i % 50 == 0: log("{}/{}".format(i, X.shape[2] - 1)) vol = np.copy(X) vol[0, 0, i, t2, t3] = mmin pred_min = model(np2cuda(vol, config["device"])) pred_min = pred_min[0].cpu().numpy() vol = np.copy(X) vol[0, 0, i, t2, t3] = mmax pred_max = model(np2cuda(vol, config["device"])) pred_max = pred_max[0].cpu().numpy() results[i] = np.max( np.abs(pred_min[0, :, t1, t2, t3] - pred_max[0, :, t1, t2, t3])) r = np.where(results != 0)[0][[0, -1]] log("Receptive field range in Depth-dim: {}. Size: {}".format( r, r[1] - r[0] + 1)) log("Checking in Height dimension. Reference: {},{},{}".format( t1, t2, t3)) results = np.zeros(X.shape[3]) for i in range(X.shape[3]): # Studying in Depth (first) dimension if i % 50 == 0: log("{}/{}".format(i, X.shape[3] - 1)) vol = np.copy(X) vol[0, 0, t1, i, t3] = mmin pred_min = model(np2cuda(vol, config["device"])) pred_min = pred_min[0].cpu().numpy() vol = np.copy(X) vol[0, 0, t1, i, t3] = mmax pred_max = model(np2cuda(vol, config["device"])) pred_max = pred_max[0].cpu().numpy() results[i] = np.max( np.abs(pred_min[0, :, t1, t2, t3] - pred_max[0, :, t1, t2, t3])) r = np.where(results != 0)[0][[0, -1]] log("Receptive field range in Height-dim: {}. Size: {}".format( r, r[1] - r[0] + 1)) log("Checking in Width dimension. Reference: {},{},{}".format( t1, t2, t3)) results = np.zeros(X.shape[4]) for i in range(X.shape[4]): # Studying in Depth (first) dimension if i % 50 == 0: log("{}/{}".format(i, X.shape[4] - 1)) vol = np.copy(X) vol[0, 0, t1, t2, i] = mmin pred_min = model(np2cuda(vol, config["device"])) pred_min = pred_min[0].cpu().numpy() vol = np.copy(X) vol[0, 0, t1, t2, i] = mmax pred_max = model(np2cuda(vol, config["device"])) pred_max = pred_max[0].cpu().numpy() results[i] = np.max( np.abs(pred_min[0, :, t1, t2, t3] - pred_max[0, :, t1, t2, t3])) r = np.where(results != 0)[0][[0, -1]] log("Receptive field range in Width-dim: {}. Size: {}".format( r, r[1] - r[0] + 1))