Ejemplo n.º 1
0
def test(**kwargs):
    config.parse(kwargs)

    # prepare data
    test_data = Vertebrae_Dataset(
        config.data_root, config.test_paths,
        phase='test')  # 注意这里不要加balance=False,否则生成的Dataset会包含混合型
    test_dataloader = DataLoader(test_data,
                                 batch_size=config.batch_size,
                                 shuffle=False,
                                 num_workers=config.num_workers)

    # test_data = FrameDiff_Dataset(config.data_root, config.test_paths, phase='test', balance=config.data_balance)
    # test_dataloader = DataLoader(test_data, batch_size=config.batch_size, shuffle=False, num_workers=config.num_workers)
    print('Test Image:', test_data.__len__())

    # prepare model
    # model = ResNet34(num_classes=config.num_classes)
    # model = DenseNet121(num_classes=config.num_classes)
    # model = CheXPre_DenseNet121(num_classes=config.num_classes)
    # model = MultiResDenseNet121(num_classes=config.num_classes)
    # model = Vgg19(num_classes=config.num_classes)
    model = MultiResVgg19(num_classes=config.num_classes)

    if config.load_model_path:
        model.load(config.load_model_path)
        print('Model has been loaded!')
    else:
        print("Don't load model")
    if config.use_gpu:
        model.cuda()
    if config.parallel:
        model = torch.nn.DataParallel(
            model, device_ids=[x for x in range(config.num_of_gpu)])
    model.eval()

    test_cm = meter.ConfusionMeter(config.num_classes)
    softmax = functional.softmax

    # go through the model
    for i, (image, label, image_path) in tqdm(enumerate(test_dataloader)):
        img = Variable(image, volatile=True)
        target = Variable(label)
        if config.use_gpu:
            img = img.cuda()
            target = target.cuda()

        score = model(img)

        test_cm.add(softmax(score, dim=1).data, target.data)

    SE, SP, ACC = calculate_index(test_cm.value())

    print('confusion matrix:')
    print(test_cm.value())
    print('Sensitivity:', SE)
    print('Specificity:', SP)
    print('test accuracy:', ACC)
Ejemplo n.º 2
0
def test(
    **kwargs
):  # 注释掉LSTM_CRF.py里的_get_lstm_features函数里的self.hidden = self.init_hidden()
    config.parse(kwargs)

    # prepare data
    test_roots = [os.path.join(config.data_root, 'Features_Normal')]

    test_data = Feature_Dataset(test_roots, config.test_paths, phase='test')
    test_dataloader = DataLoader(test_data,
                                 batch_size=1,
                                 shuffle=False,
                                 num_workers=config.num_workers)
    print('Test Feature Lists:', test_data.__len__())

    # prepare model
    model = BiLSTM_CRF(tag_to_ix=tag_to_ix,
                       embedding_dim=EMBEDDING_DIM,
                       hidden_dim=HIDDEN_DIM,
                       num_layers=NUM_LAYERS)

    if config.load_model_path:
        model.load(config.load_model_path)
    if config.use_gpu:
        model.cuda()
    model.eval()

    # metric
    test_cm = [[0] * 3, [0] * 3, [0] * 3]

    # go through the model
    for i, (features, labels,
            feature_paths) in tqdm(enumerate(test_dataloader)):
        # prepare input
        target = torch.LongTensor([tag_to_ix[t[0]] for t in labels])

        feat = Variable(features.squeeze())
        # target = Variable(target)
        if config.use_gpu:
            feat = feat.cuda()
            # target = target.cuda()

        result = model(feat)  # (score, predict list)

        for t, r in zip(target, result[1]):
            test_cm[t][r] += 1

    SE, SP, ACC = calculate_index(test_cm)

    print('confusion matrix:')
    print(test_cm)
    print('Sensitivity:', SE)
    print('Specificity:', SP)
    print('test accuracy:', ACC)
def multitask_test(**kwargs):
    config.parse(kwargs)

    # prepare data
    test_data = MultiLabel_Dataset(
        config.data_root, config.test_paths,
        phase='test')  # 注意这里不要加balance=False,否则生成的Dataset会包含混合型
    test_dataloader = DataLoader(test_data,
                                 batch_size=config.batch_size,
                                 shuffle=False,
                                 num_workers=config.num_workers)
    print('Test Images:', test_data.__len__())

    # prepare model
    model = MultiTask_DenseNet121(num_classes=2)
    # model = CheXPre_MultiTask_DenseNet121(num_classes=2)

    if config.load_model_path:
        model.load(config.load_model_path)
    if config.use_gpu:
        model.cuda()
    model.eval()

    test_cm_1 = meter.ConfusionMeter(2)
    test_cm_2 = meter.ConfusionMeter(2)
    test_cm_total = meter.ConfusionMeter(3)
    softmax = functional.softmax

    # misclassified = []

    # go through the model
    for i, (image, label_1, label_2, label,
            image_path) in tqdm(enumerate(test_dataloader)):
        img = Variable(image, volatile=True)
        target_1 = Variable(label_1)
        target_2 = Variable(label_2)
        target = Variable(label)
        if config.use_gpu:
            img = img.cuda()
            target_1 = target_1.cuda()
            target_2 = target_2.cuda()
            target = target.cuda()

        # go through the model
        score_1, score_2 = model(img)

        p_1, p_2 = softmax(score_1, dim=1), softmax(score_2, dim=1)
        c = []

        # -----------------------------------------------------------------------
        for j in range(p_1.data.size()[0]):  # 将两个支路合并得到最终的预测结果
            if p_1.data[j][1] < 0.5 and p_2.data[j][1] < 0.5:
                c.append([1, 0, 0])
            else:
                if p_1.data[j][1] > p_2.data[j][1]:
                    c.append([0, 1, 0])
                else:
                    c.append([0, 0, 1])
        # -----------------------------------------------------------------------

        # misclassified image path
        # for path, predicted, true_label in zip(image_path, c, target):
        #     if np.argmax(predicted, axis=0) != int(true_label):
        #         misclassified.append((path, np.argmax(predicted, axis=0), int(true_label)))
        # misclassified.extend([(path, np.argmax(predicted, axis=0), int(true_label)) for path, predicted, true_label in zip(image_path, c, target) if np.argmax(predicted, axis=0) != int(true_label)])

        test_cm_1.add(p_1.data, target_1.data)
        test_cm_2.add(p_2.data, target_2.data)
        test_cm_total.add(torch.FloatTensor(c), target.data)

    test_accuracy_1 = 100. * sum([test_cm_1.value()[c][c] for c in range(2)
                                  ]) / test_cm_1.value().sum()
    test_accuracy_2 = 100. * sum([test_cm_2.value()[c][c] for c in range(2)
                                  ]) / test_cm_2.value().sum()
    # test_accuracy_total = 100. * sum([test_cm_total.value()[c][c] for c in range(3)]) / test_cm_total.value().sum()
    SE, SP, ACC = calculate_index(test_cm_total.value())

    print('test_cm_1:\n', test_cm_1.value(), '\ntest_cm_2:\n',
          test_cm_2.value(), '\ntest_cm_total:\n', test_cm_total.value())
    print('test_accuracy_1:', test_accuracy_1, 'test_accuracy_2:',
          test_accuracy_2, 'test_accuracy_total:', ACC)
    print('total sensitivity:', SE)
    print('total specificity:', SP)
def label_based_3class(results_file):
    """
    以标注为基准定位病灶,计算准确率,混合型不加入统计。
    """
    def lesion_predict(dic):
        total = dic['0'] + dic['1'] + dic['2']
        if dic['0'] / total > 0.7:
            re = 0
        elif dic['1'] > dic['2']:
            re = 1
        else:
            re = 2
        return re

    with open(results_file, 'r') as f:
        results = f.readlines()[1:]

    lesions = lesion_localize(results, classes=3,
                              changelabel=True)  # 每个病灶的起始index,并且交换2和3的标签
    # lesions.sort(key=lambda m: m[1]-m[0], reverse=False)
    print('total lesions:', len(lesions))
    # pprint(lesions)

    result_dict = {'0': 0, '1': 0, '2': 0}
    cm = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

    for idx in tqdm(lesions):
        lesion_results = results[idx[0]:idx[1] +
                                 1]  # 这里要有+1,因为list截取一段不包含最后一个index

        # # 抛弃每段病灶的起始和结束的过渡部分
        # length = idx[1]-idx[0]+1
        # if length >= 10:
        #     lesion_results = results[int(idx[0] + length*0.2): int(idx[1]+1 - length*0.2)]
        # elif 5 < length < 10:
        #     lesion_results = results[idx[0]+1: idx[1]]
        # else:
        #     lesion_results = results[idx[0]: idx[1]+1]

        lesion_label = idx[2]

        for x in lesion_results:
            predicted = int(x.strip().split(',')[1])
            if predicted == 3:  # 转换csv中预测的结果
                predicted = 2
            result_dict[str(predicted)] += 1
        # print(idx, result_dict)
        lesion_predicted = lesion_predict(result_dict)

        if lesion_label != 3:  # 对混合型不计入混淆矩阵
            cm[lesion_label][lesion_predicted] += 1

        result_dict = {'0': 0, '1': 0, '2': 0}
    SE, SP, ACC = calculate_index(cm)
    print(cm[0], '\n', cm[1], '\n', cm[2])
    print('SE_0:', SE[0])
    print('SE_1:', SE[1])
    print('SE_2:', SE[2])
    print('SP_0:', SP[0])
    print('SP_1:', SP[1])
    print('SP_2:', SP[2])
    print('ACC:', ACC)
def predict_based_4class(results_file):
    """
    以预测的结果为基准定位病灶,计算准确率,统计混合型。
    """

    with open(results_file, 'r') as f:
        results = f.readlines()[1:]

    # ============================ Step1:将预测结果按照阈值和判断方法截断 =================================

    len_threshold = 5

    truncated_results = []  # 将读入的结果按照不同病人的id,是否超过长度阈值的判断方法截断,便于后续操作
    temp = []
    for i, x in enumerate(results):
        image_path = x.strip().split(',')[0]
        predict = int(x.strip().split(',')[1])
        label = int(x.strip().split(',')[2])
        prob_1 = x.strip().split(',')[3]
        prob_2 = x.strip().split(',')[4]
        prob_3 = x.strip().split(',')[5]

        if not temp:  # 如果temp为空,即这是一段脊骨结果的第一张slice
            temp.append([image_path, predict, label, prob_1, prob_2, prob_3])
        else:
            patient_id = image_path.split('/')[2]
            prepatient_id = results[i - 1].strip().split(',')[0].split('/')[2]

            if patient_id == prepatient_id:
                temp.append(
                    [image_path, predict, label, prob_1, prob_2, prob_3])
            else:  # 如果当前slice的病人id和上一张不同,则应该从这里截断
                if len(temp) >= len_threshold:  # 对于本身长度就少于t的病灶直接舍弃
                    truncated_results.append(temp)
                # truncated_results.append(temp)
                temp = [[image_path, predict, label, prob_1, prob_2, prob_3]]

    # pprint(truncated_results[7])
    # print(len(truncated_results[7]))

    # ============================ Step2:将单张预测结果以病灶为单位进行修正 =================================

    processed_results = []

    for res in tqdm(truncated_results):
        # 对于每一段截断脊骨,判断第一张的label
        for i, x in enumerate(res):
            if i + len_threshold <= len(res):
                res_next = [res[i + j][1] for j in range(len_threshold)]
                # print(res_next)
                # print([x[1]] * len_threshold)
                if res_next == [x[1]] * len_threshold:
                    prepredict = x[1]
                    break
                else:
                    pass
            else:
                pass
        else:  # 如果for循环里没有执行过break,即没有连续t个相同的slice,取这一段slice中数量最多的predict
            d = {'0': 0, '1': 0, '2': 0, '3': 0}
            for x in res:
                d[str(x[1])] += 1
            prepredict = int(
                sorted(d.items(), key=lambda y: y[1], reverse=True)[0][0])

        for i, x in enumerate(res):
            if x[1] == prepredict:  # 如果当前slice的predict和上一张一致,则直接加入
                processed_results.append(x[:3])
            else:
                if i + len_threshold > len(
                        res
                ):  # 如果当前slice的predict和上一张不一致,但是剩余的slice数不足t张,则修改为和之前一致
                    processed_results.append([x[0], prepredict, x[2]])
                else:
                    res_next = [res[i + j][1] for j in range(len_threshold)]
                    if res_next == [
                            x[1]
                    ] * len_threshold:  # 如果当前slice和predict和上一张不一致,且之后连续相同的超过t张,则直接加入并修改prepredict
                        processed_results.append(x[:3])
                        prepredict = x[1]
                    else:  # 如果当前slice和predict和上一张不一致,且之后连续相同的不足t张,则修改为和之前一致
                        processed_results.append([x[0], prepredict, x[2]])

    write_csv('results/processed_results.csv', ['path', 'predict', 'label'],
              processed_results)

    # ============================== Step3:由单张结果得到病灶结果并统计指标 ====================================

    with open('results/processed_results.csv', 'r') as f:
        processed_results = f.readlines()[1:]
    predict_lesions = predict_lesion_localize(processed_results, classes=4)
    label_lesions = lesion_localize(processed_results,
                                    classes=4,
                                    changelabel=False)
    # pprint(lesions[:10])
    # pprint(label_lesions[:10])

    IOU_threshold = 0.5
    cm = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

    for preles in tqdm(predict_lesions):
        prestart, preend, predict = preles[0], preles[1], preles[2]
        pre_slice_index = [x for x in range(prestart, preend + 1)]

        label_slice_index = {'0': [], '1': [], '2': [], '3': []}
        for lables in label_lesions:
            labstart, labend, label = lables[0], lables[1], lables[2]
            if prestart > labend or preend < labstart:  # 如果无交集
                pass
            else:
                # print(labstart, labend, prestart, preend)
                for x in range(labstart, labend + 1):
                    label_slice_index[str(label)].append(x)

        # print(len(label_slice_index['0']))
        IOU = [
            len(set(pre_slice_index) & set(label_slice_index['0'])) /
            len(set(pre_slice_index) | set(label_slice_index['0'])),
            len(set(pre_slice_index) & set(label_slice_index['1'])) /
            len(set(pre_slice_index) | set(label_slice_index['1'])),
            len(set(pre_slice_index) & set(label_slice_index['2'])) /
            len(set(pre_slice_index) | set(label_slice_index['2'])),
            len(set(pre_slice_index) & set(label_slice_index['3'])) /
            len(set(pre_slice_index) | set(label_slice_index['3']))
        ]
        # print(set(pre_slice_index))
        # print(set(label_slice_index['0']))
        # print(len(set(pre_slice_index) & set(label_slice_index['0'])))
        # print("====================")

        # true_label = int(np.argmax(IOU[1:])) + 1  # 如果三类病中IOU最大的超过阈值则以此为label,否则label为0
        # if IOU[true_label] < IOU_threshold:
        #     true_label = 0
        if IOU[predict] > IOU_threshold:
            true_label = predict
        else:
            true_label = int(np.argmax(IOU))

        cm[true_label][predict] += 1

    SE, SP, ACC = calculate_index(cm)

    print('confusion matrix')
    print(cm[0], '\n', cm[1], '\n', cm[2], '\n', cm[3])
    print('SE_1:', SE[1])
    print('SE_2:', SE[2])
    print('SE_3:', SE[3])
    print('SP_1:', SP[1])
    print('SP_2:', SP[2])
    print('SP_3:', SP[3])
    print('ACC:', ACC)
def label_based_4class(results_file):
    """
    以标注为基准定位病灶,计算准确率,统计混合型。
    """
    def lesion_predict(dic):
        total = dic['0'] + dic['1'] + dic['2']
        pos_total = dic['1'] + dic['2']
        if dic['0'] / total > 0.7:
            re = 0
        elif dic['1'] / pos_total > 0.7:
            re = 1
        elif dic['2'] / pos_total > 0.7:
            re = 3
        else:
            re = 2  # 当成骨和溶骨占比均小于0.7时记为混合型
        return re

    with open(results_file, 'r') as f:
        results = f.readlines()[1:]

    lesions = lesion_localize(results, classes=4,
                              changelabel=False)  # 每个病灶的起始index
    # lesions.sort(key=lambda m: m[1]-m[0], reverse=False)
    print('total lesions:', len(lesions))
    # pprint(lesions)

    result_dict = {'0': 0, '1': 0, '2': 0}
    cm = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

    for idx in tqdm(lesions):
        lesion_results = results[idx[0]:idx[1] +
                                 1]  # 这里要有+1,因为list截取一段不包含最后一个index

        # # 抛弃每段病灶的起始和结束的过度部分
        # length = idx[1]-idx[0]+1
        # if length >= 10:
        #     lesion_results = results[int(idx[0] + length*0.2): int(idx[1]+1 - length*0.2)]
        # elif 5 < length < 10:
        #     lesion_results = results[idx[0]+1: idx[1]]
        # else:
        #     lesion_results = results[idx[0]: idx[1]+1]

        lesion_label = idx[2]

        for x in lesion_results:
            predicted = int(x.strip().split(',')[1])
            if predicted == 3:  # 转换csv中预测的label
                predicted = 2
            result_dict[str(predicted)] += 1
        # print(idx, result_dict)
        lesion_predicted = lesion_predict(result_dict)

        cm[lesion_label][lesion_predicted] += 1

        result_dict = {'0': 0, '1': 0, '2': 0}
    print(cm[0], '\n', cm[1], '\n', cm[2], '\n', cm[3])
    print((cm[0][0] + cm[1][1] + cm[2][2] + cm[3][3]) / np.sum(cm))

    SE, SP, ACC = calculate_index(cm)
    print(cm[0], '\n', cm[1], '\n', cm[2])
    print('SE_1:', SE[1])
    print('SE_2:', SE[2])
    print('SE_3:', SE[3])
    print('SP_1:', SP[1])
    print('SP_2:', SP[2])
    print('SP_3:', SP[3])
    print('ACC:', ACC)