NifTK / NiftyNet

[unmaintained] An open-source convolutional neural networks platform for research in medical image analysis and image-guided therapy
http://niftynet.io
Apache License 2.0
1.37k stars 406 forks source link

what dose ids mean in dice_hinge.py #34

Closed ghost closed 6 years ago

ghost commented 6 years ago

Dear all, I'm not clear the ids in dice_hinge.py. Why introduce this variable?And what is the role of variables h1 and h2? Besides, compared to the classical dice, what is the advantage of the dice_hinge?

def dice(prediction, ground_truth, weight_map=None):
    ground_truth = tf.to_int64(ground_truth)
    prediction = tf.cast(prediction, tf.float32)
    prediction=tf.nn.softmax(prediction)
    ids = tf.range(tf.to_int64(tf.shape(ground_truth)[0]), dtype=tf.int64)
    ids = tf.stack([ids, ground_truth], axis=1)
    one_hot = tf.SparseTensor(
        indices=ids,
        values=tf.ones_like(ground_truth, dtype=tf.float32),
        dense_shape=tf.to_int64(tf.shape(prediction)))

    dice_numerator = 2.0 * tf.sparse_reduce_sum(
        one_hot * prediction, reduction_axes=[0])
    dice_denominator = \
        tf.reduce_sum(tf.square(prediction), reduction_indices=[0]) + \
        tf.sparse_reduce_sum(one_hot, reduction_axes=[0])
    epsilon_denominator = 0.00001

    dice_score = dice_numerator / (dice_denominator + epsilon_denominator)

    [tf.summary.scalar('Dice{}'.format(i),d) for i,d in enumerate(tf.unstack(dice_score,0))]
    dice_score=tf.Print(dice_score,[dice_score],summarize=10,message='dice')
    h1=tf.square(tf.minimum(0.1,dice_score)*10-1)
    h2=tf.square(tf.minimum(0.01,dice_score)*100-1)

    return 1.0 - tf.reduce_mean(dice_score) + \
           tf.reduce_mean(h1)*10 + \
           tf.reduce_mean(h2)*10
wyli commented 6 years ago

Hi @CourantNg the ids is only used for constructing a SparseTensor which is often a memory-efficient way to represent the discrete segmentation ground truth. For some reason I couldn't locate the dice_hinge function in the repo, do you have a link to the original file?

ghost commented 6 years ago

Hi, @wyli the dice_hinge was downloaded from multi-organ segmentation which is in model zoo. Following is the source code.

# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, division

import numpy as np
import tensorflow as tf

from niftynet.layer.base_layer import Layer

def dice(prediction, ground_truth, weight_map=None):
    ground_truth = tf.to_int64(ground_truth)
    prediction = tf.cast(prediction, tf.float32)
    prediction=tf.nn.softmax(prediction)
    ids = tf.range(tf.to_int64(tf.shape(ground_truth)[0]), dtype=tf.int64)
    ids = tf.stack([ids, ground_truth], axis=1)
    one_hot = tf.SparseTensor(
        indices=ids,
        values=tf.ones_like(ground_truth, dtype=tf.float32),
        dense_shape=tf.to_int64(tf.shape(prediction)))

    dice_numerator = 2.0 * tf.sparse_reduce_sum(
        one_hot * prediction, reduction_axes=[0])
    dice_denominator = \
        tf.reduce_sum(tf.square(prediction), reduction_indices=[0]) + \
        tf.sparse_reduce_sum(one_hot, reduction_axes=[0])
    epsilon_denominator = 0.00001

    dice_score = dice_numerator / (dice_denominator + epsilon_denominator)
    # dice_score.set_shape([n_classes])
    # minimising (1 - dice_coefficients)
    [tf.summary.scalar('Dice{}'.format(i),d) for i,d in enumerate(tf.unstack(dice_score,0))]
    dice_score=tf.Print(dice_score,[dice_score],summarize=10,message='dice')
    h1=tf.square(tf.minimum(0.1,dice_score)*10-1)
    h2=tf.square(tf.minimum(0.01,dice_score)*100-1)

    return 1.0 - tf.reduce_mean(dice_score) + \
           tf.reduce_mean(h1)*10 + \
           tf.reduce_mean(h2)*10
ghost commented 6 years ago

By the way, how the image data is transferred to the network? I can't find where the load_image(filename) function is called in the application_driver.py. Any explanation about the data flow in niftyNet will be very appreciated.

eligibson commented 6 years ago

In multi-class segmentation (especially with highly unbalanced label volumes), some classes can get stuck with very low probabilities very early in training, and never recover. This is probably application specific. The hinge loss weights gradients for classes with very low Dice scores more heavily, so that these classes recover. In my experience, once the classes have Dice scores around 0.1, the risk of stuck classes decreases.

ChandraV76 commented 4 years ago

are the prediction and ground_truth are 1D tensor array?