├── Dice_Loss ├── Loss ├── NMS ├── README.md ├── SIFT_Feature_Match ├── Soft-NMS ├── __factory ├── binary_segmentation_hardmining ├── compute_mIOU ├── data_augmentation ├── initialization.py ├── machine learning model ├── medical_image_process ├── optim_loss ├── segmentation_utils ├── sklearn_metrics ├── utils └── warmup-cosine-lr /Dice_Loss: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import torch 5 | import torch.nn as nn 6 | import torch.nn.functional as F 7 | import numpy as np 8 | 9 | 10 | def make_one_hot(input, num_classes): 11 | """Convert class index tensor to one hot encoding tensor. 12 | Args: 13 | input: A tensor of shape [N, 1, *] 14 | num_classes: An int of number of class 15 | Returns: 16 | A tensor of shape [N, num_classes, *] 17 | """ 18 | shape = np.array(input.shape) 19 | shape[1] = num_classes 20 | shape = tuple(shape) 21 | result = torch.zeros(shape) 22 | result = result.scatter_(1, input.cpu(), 1) 23 | 24 | return result 25 | 26 | 27 | class BinaryDiceLoss(nn.Module): 28 | """Dice loss of binary class 29 | Args: 30 | smooth: A float number to smooth loss, and avoid NaN error, default: 1 31 | p: Denominator value: \sum{x^p} + \sum{y^p}, default: 2 32 | predict: A tensor of shape [N, *] 33 | target: A tensor of shape same with predict 34 | reduction: Reduction method to apply, return mean over batch if 'mean', 35 | return sum if 'sum', return a tensor of shape [N,] if 'none' 36 | Returns: 37 | Loss tensor according to arg reduction 38 | Raise: 39 | Exception if unexpected reduction 40 | """ 41 | def __init__(self, smooth=1, p=2, reduction='mean'): 42 | super(BinaryDiceLoss, self).__init__() 43 | self.smooth = smooth 44 | self.p = p 45 | self.reduction = reduction 46 | 47 | def forward(self, predict, target): 48 | assert predict.shape[0] == target.shape[0], "predict & target batch size don't match" 49 | predict = predict.contiguous().view(predict.shape[0], -1) 50 | target = target.contiguous().view(target.shape[0], -1) 51 | 52 | num = torch.sum(torch.mul(predict, target), dim=1) + self.smooth 53 | den = torch.sum(predict.pow(self.p) + target.pow(self.p), dim=1) + self.smooth 54 | 55 | loss = 1 - num / den 56 | 57 | if self.reduction == 'mean': 58 | return loss.mean() 59 | elif self.reduction == 'sum': 60 | return loss.sum() 61 | elif self.reduction == 'none': 62 | return loss 63 | else: 64 | raise Exception('Unexpected reduction {}'.format(self.reduction)) 65 | 66 | 67 | class DiceLoss(nn.Module): 68 | """Dice loss, need one hot encode input 69 | Args: 70 | weight: An array of shape [num_classes,] 71 | ignore_index: class index to ignore 72 | predict: A tensor of shape [N, C, *] 73 | target: A tensor of same shape with predict 74 | other args pass to BinaryDiceLoss 75 | Return: 76 | same as BinaryDiceLoss 77 | """ 78 | def __init__(self, weight=None, ignore_index=None, **kwargs): 79 | super(DiceLoss, self).__init__() 80 | self.kwargs = kwargs 81 | self.weight = weight 82 | self.ignore_index = ignore_index 83 | 84 | def forward(self, predict, target): 85 | assert predict.shape == target.shape, 'predict & target shape do not match' 86 | dice = BinaryDiceLoss(**self.kwargs) 87 | total_loss = 0 88 | predict = F.softmax(predict, dim=1) 89 | 90 | for i in range(target.shape[1]): 91 | if i != self.ignore_index: 92 | dice_loss = dice(predict[:, i], target[:, i]) 93 | if self.weight is not None: 94 | assert self.weight.shape[0] == target.shape[1], \ 95 | 'Expect weight shape [{}], get[{}]'.format(target.shape[1], self.weight.shape[0]) 96 | dice_loss *= self.weights[i] 97 | total_loss += dice_loss 98 | 99 | return total_loss/target.shape[1] 100 | -------------------------------------------------------------------------------- /Loss: -------------------------------------------------------------------------------- 1 | # Focal Loss 2 | class FocalLoss(nn.Module): 3 | def __init__(self, gamma=2): 4 | super().__init__() 5 | self.gamma = gamma 6 | 7 | def forward(self, input, target): 8 | if not (target.size() == input.size()): 9 | raise ValueError("Target size ({}) must be the same as input size ({})" 10 | .format(target.size(), input.size())) 11 | 12 | max_val = (-input).clamp(min=0) 13 | loss = input - input * target + max_val + \ 14 | ((-max_val).exp() + (-input - max_val).exp()).log() 15 | 16 | invprobs = F.logsigmoid(-input * (target * 2.0 - 1.0)) 17 | loss = (invprobs * self.gamma).exp() * loss 18 | 19 | return loss.sum(dim=1).mean() 20 | -------------------------------------------------------------------------------- /NMS: -------------------------------------------------------------------------------- 1 | 2 | # SNMS 3 | #coding=utf-8 4 | import numpy as np 5 | 6 | def py_cpu_nms(dets, thresh): 7 | """Pure Python NMS baseline.""" 8 | # tl_x,tl_y,br_x,br_y及score 9 | x1 = dets[:, 0] 10 | y1 = dets[:, 1] 11 | x2 = dets[:, 2] 12 | y2 = dets[:, 3] 13 | scores = dets[:, 4] 14 | 15 | #计算每个检测框的面积,并对目标检测得分进行降序排序 16 | areas = (x2 - x1 + 1) * (y2 - y1 + 1) 17 | order = scores.argsort()[::-1] 18 | 19 | keep = [] #保留框的结果集合 20 | while order.size > 0: 21 | i = order[0] 22 | keep.append(i)  #保留该类剩余box中得分最高的一个 23 | # 计算最高得分矩形框与剩余矩形框的相交区域 24 | xx1 = np.maximum(x1[i], x1[order[1:]]) 25 | yy1 = np.maximum(y1[i], y1[order[1:]]) 26 | xx2 = np.minimum(x2[i], x2[order[1:]]) 27 | yy2 = np.minimum(y2[i], y2[order[1:]]) 28 | 29 | #计算相交的面积,不重叠时面积为0 30 | w = np.maximum(0.0, xx2 - xx1 + 1) 31 | h = np.maximum(0.0, yy2 - yy1 + 1) 32 | inter = w * h 33 | 34 | #计算IoU:重叠面积 /(面积1+面积2-重叠面积) 35 | ovr = inter / (areas[i] + areas[order[1:]] - inter) 36 | 37 | #保留IoU小于阈值的box 38 | inds = np.where(ovr <= thresh)[0] 39 | order = order[inds + 1] #注意这里索引加了1,因为ovr数组的长度比order数组的长度少一个 40 | 41 | return keep 42 | 43 | if __name__ == '__main__': 44 | dets = np.array([[100,120,170,200,0.98], 45 | [20,40,80,90,0.99], 46 | [20,38,82,88,0.96], 47 | [200,380,282,488,0.9], 48 | [19,38,75,91, 0.8]]) 49 | 50 | py_cpu_nms(dets, 0.5) 51 | 52 | # LNMS 53 | 54 | import numpy as np 55 | from shapely.geometry import Polygon 56 | 57 | def intersection(g, p): 58 | #取g,p中的几何体信息组成多边形 59 | g = Polygon(g[:8].reshape((4, 2))) 60 | p = Polygon(p[:8].reshape((4, 2))) 61 | 62 | # 判断g,p是否为有效的多边形几何体 63 | if not g.is_valid or not p.is_valid: 64 | return 0 65 | 66 | # 取两个几何体的交集和并集 67 | inter = Polygon(g).intersection(Polygon(p)).area 68 | union = g.area + p.area - inter 69 | if union == 0: 70 | return 0 71 | else: 72 | return inter/union 73 | 74 | def weighted_merge(g, p): 75 | # 取g,p两个几何体的加权(权重根据对应的检测得分计算得到) 76 | g[:8] = (g[8] * g[:8] + p[8] * p[:8])/(g[8] + p[8]) 77 | 78 | #合并后的几何体的得分为两个几何体得分的总和 79 | g[8] = (g[8] + p[8]) 80 | return g 81 | 82 | def standard_nms(S, thres): 83 | #标准NMS 84 | order = np.argsort(S[:, 8])[::-1] 85 | keep = [] 86 | while order.size > 0: 87 | i = order[0] 88 | keep.append(i) 89 | ovr = np.array([intersection(S[i], S[t]) for t in order[1:]]) 90 | inds = np.where(ovr <= thres)[0] 91 | order = order[inds+1] 92 | 93 | return S[keep] 94 | 95 | def nms_locality(polys, thres=0.3): 96 | ''' 97 | locality aware nms of EAST 98 | :param polys: a N*9 numpy array. first 8 coordinates, then prob 99 | :return: boxes after nms 100 | ''' 101 | S = [] #合并后的几何体集合 102 | p = None #合并后的几何体 103 | for g in polys: 104 | if p is not None and intersection(g, p) > thres: #若两个几何体的相交面积大于指定的阈值,则进行合并 105 | p = weighted_merge(g, p) 106 | else: #反之,则保留当前的几何体 107 | if p is not None: 108 | S.append(p) 109 | p = g 110 | if p is not None: 111 | S.append(p) 112 | if len(S) == 0: 113 | return np.array([]) 114 | return standard_nms(np.array(S), thres) 115 | 116 | if __name__ == '__main__': 117 | # 343,350,448,135,474,143,369,359 118 | print(Polygon(np.array([[343, 350], [448, 135], 119 | [474, 143], [369, 359]])).area) 120 | 121 | 122 | # rnms 123 | #coding=utf-8 124 | from __future__ import absolute_import 125 | from __future__ import division 126 | from __future__ import print_function 127 | 128 | import numpy as np 129 | import cv2 130 | import tensorflow as tf 131 | 132 | def nms_rotate(decode_boxes, scores, iou_threshold, max_output_size, 133 | use_angle_condition=False, angle_threshold=0, use_gpu=False, gpu_id=0): 134 | """ 135 | :param boxes: format [x_c, y_c, w, h, theta] 136 | :param scores: scores of boxes 137 | :param threshold: iou threshold (0.7 or 0.5) 138 | :param max_output_size: max number of output 139 | :return: the remaining index of boxes 140 | """ 141 | if use_gpu: 142 | #采用gpu方式 143 | keep = nms_rotate_gpu(boxes_list=decode_boxes, 144 | scores=scores, 145 | iou_threshold=iou_threshold, 146 | angle_gap_threshold=angle_threshold, 147 | use_angle_condition=use_angle_condition, 148 | device_id=gpu_id) 149 | 150 | keep = tf.cond( 151 | tf.greater(tf.shape(keep)[0], max_output_size), 152 | true_fn=lambda: tf.slice(keep, [0], [max_output_size]), 153 | false_fn=lambda: keep) 154 | else: #采用cpu方式 155 | keep = tf.py_func(nms_rotate_cpu, 156 | inp=[decode_boxes, scores, iou_threshold, max_output_size], 157 | Tout=tf.int64) 158 | return keep 159 | 160 | def nms_rotate_cpu(boxes, scores, iou_threshold, max_output_size): 161 | keep = [] #保留框的结果集合 162 | order = scores.argsort()[::-1] #对检测结果得分进行降序排序 163 | num = boxes.shape[0] #获取检测框的个数 164 | 165 | suppressed = np.zeros((num), dtype=np.int) 166 | for _i in range(num): 167 | if len(keep) >= max_output_size:  #若当前保留框集合中的个数大于max_output_size时,直接返回 168 | break 169 | 170 | i = order[_i] 171 | if suppressed[i] == 1: #对于抑制的检测框直接跳过 172 | continue 173 | keep.append(i)  #保留当前框的索引 174 | r1 = ((boxes[i, 1], boxes[i, 0]), (boxes[i, 3], boxes[i, 2]), boxes[i, 4]) #根据box信息组合成opencv中的旋转bbox 175 | print("r1:{}".format(r1)) 176 | area_r1 = boxes[i, 2] * boxes[i, 3]  #计算当前检测框的面积 177 | for _j in range(_i + 1, num):  #对剩余的而进行遍历 178 | j = order[_j] 179 | if suppressed[i] == 1: 180 | continue 181 | r2 = ((boxes[j, 1], boxes[j, 0]), (boxes[j, 3], boxes[j, 2]), boxes[j, 4]) 182 | area_r2 = boxes[j, 2] * boxes[j, 3] 183 | inter = 0.0 184 | 185 | int_pts = cv2.rotatedRectangleIntersection(r1, r2)[1] #求两个旋转矩形的交集,并返回相交的点集合 186 | if int_pts is not None: 187 | order_pts = cv2.convexHull(int_pts, returnPoints=True) #求点集的凸边形 188 | int_area = cv2.contourArea(order_pts)  #计算当前点集合组成的凸边形的面积 189 | inter = int_area * 1.0 / (area_r1 + area_r2 - int_area + 0.0000001) 190 | 191 | if inter >= iou_threshold:  #对大于设定阈值的检测框进行滤除 192 | suppressed[j] = 1 193 | 194 | return np.array(keep, np.int64) 195 | 196 | # gpu的实现方式 197 | def nms_rotate_gpu(boxes_list, scores, iou_threshold, use_angle_condition=False, angle_gap_threshold=0, device_id=0): 198 | if use_angle_condition: 199 | y_c, x_c, h, w, theta = tf.unstack(boxes_list, axis=1) 200 | boxes_list = tf.transpose(tf.stack([x_c, y_c, w, h, theta])) 201 | det_tensor = tf.concat([boxes_list, tf.expand_dims(scores, axis=1)], axis=1) 202 | keep = tf.py_func(rotate_gpu_nms, 203 | inp=[det_tensor, iou_threshold, device_id], 204 | Tout=tf.int64) 205 | return keep 206 | else: 207 | y_c, x_c, h, w, theta = tf.unstack(boxes_list, axis=1) 208 | boxes_list = tf.transpose(tf.stack([x_c, y_c, w, h, theta])) 209 | det_tensor = tf.concat([boxes_list, tf.expand_dims(scores, axis=1)], axis=1) 210 | keep = tf.py_func(rotate_gpu_nms, 211 | inp=[det_tensor, iou_threshold, device_id], 212 | Tout=tf.int64) 213 | keep = tf.reshape(keep, [-1]) 214 | return keep 215 | 216 | if __name__ == '__main__': 217 | boxes = np.array([[50, 40, 100, 100, 0], 218 | [60, 50, 100, 100, 0], 219 | [50, 30, 100, 100, -45.], 220 | [200, 190, 100, 100, 0.]]) 221 | 222 | scores = np.array([0.99, 0.88, 0.66, 0.77]) 223 | keep = nms_rotate(tf.convert_to_tensor(boxes, dtype=tf.float32), tf.convert_to_tensor(scores, dtype=tf.float32), 224 | 0.7, 5) 225 | import os 226 | os.environ["CUDA_VISIBLE_DEVICES"] = '0' 227 | with tf.Session() as sess: 228 | print(sess.run(keep)) 229 | 230 | 231 | # PNMS 232 | 233 | #coding=utf-8 234 | import numpy as np 235 | from shapely.geometry import * 236 | 237 | def py_cpu_pnms(dets, thresh): 238 | # 获取检测坐标点及对应的得分 239 | bbox = dets[:, :4] 240 | scores = dets[:, 4]  241 | 242 | #这里文本的标注采用14个点,这里获取的是这14个点的偏移 243 | info_bbox = dets[:, 5:33] 244 | 245 | #保存最终点坐标 246 | pts = [] 247 | for i in xrange(dets.shape[0]): 248 | pts.append([[int(bbox[i, 0]) + info_bbox[i, j], int(bbox[i, 1]) + info_bbox[i, j+1]] for j in xrange(0,28,2)]) 249 | 250 | areas = np.zeros(scores.shape) 251 | #得分降序 252 | order = scores.argsort()[::-1] 253 | inter_areas = np.zeros((scores.shape[0], scores.shape[0])) 254 | 255 | for il in xrange(len(pts)): 256 | #当前点集组成多边形,并计算该多边形的面积 257 | poly = Polygon(pts[il]) 258 | areas[il] = poly.area 259 | 260 | #多剩余的进行遍历 261 | for jl in xrange(il, len(pts)): 262 | polyj = Polygon(pts[jl]) 263 | 264 | #计算两个多边形的交集,并计算对应的面积 265 | inS = poly.intersection(polyj) 266 | inter_areas[il][jl] = inS.area 267 | inter_areas[jl][il] = inS.area 268 | 269 | #下面做法和nms一样 270 | keep = [] 271 | while order.size > 0: 272 | i = order[0] 273 | keep.append(i) 274 | ovr = inter_areas[i][order[1:]] / (areas[i] + areas[order[1:]] - inter_areas[i][order[1:]]) 275 | inds = np.where(ovr <= thresh)[0] 276 | order = order[inds + 1] 277 | 278 | return keep 279 | # MNMS 280 | 281 | #coding=utf-8 282 | ############################################# 283 | # mask nms 实现 284 | # 2018.11.23 add 285 | ############################################# 286 | import cv2 287 | import numpy as np 288 | import imutils 289 | import copy 290 | 291 | EPS=0.00001 292 | 293 | def get_mask(box,mask): 294 | """根据box获取对应的掩膜""" 295 | tmp_mask=np.zeros(mask.shape,dtype="uint8") 296 | tmp=np.array(box.tolist(),dtype=np.int32).reshape(-1,2) 297 | cv2.fillPoly(tmp_mask, [tmp], (255)) 298 | tmp_mask=cv2.bitwise_and(tmp_mask,mask) 299 | return tmp_mask,cv2.countNonZero(tmp_mask) 300 | 301 | 302 | def comput_mmi(area_a,area_b,intersect): 303 | """ 304 | 计算MMI,2018.11.23 add 305 | :param mask_a: 实例文本a的mask的面积 306 | :param mask_b: 实例文本b的mask的面积 307 | :param intersect: 实例文本a和实例文本b的相交面积 308 | :return: 309 | """ 310 | if area_a==0 or area_b==0: 311 | area_a+=EPS 312 | area_b+=EPS 313 | print("the area of text is 0") 314 | return max(float(intersect)/area_a,float(intersect)/area_b) 315 | 316 | 317 | def mask_nms(dets, mask, thres=0.3): 318 | """ 319 | mask nms 实现函数 320 | :param dets: 检测结果,是一个N*9的numpy, 321 | :param mask: 当前检测的mask 322 | :param thres: 检测的阈值 323 | """ 324 | # 获取bbox及对应的score 325 | bbox_infos=dets[:,:8] 326 | scores=dets[:,8] 327 | 328 | keep=[] 329 | order=scores.argsort()[::-1] 330 | print("order:{}".format(order)) 331 | nums=len(bbox_infos) 332 | suppressed=np.zeros((nums), dtype=np.int) 333 | print("lens:{}".format(nums)) 334 | 335 | # 循环遍历 336 | for i in range(nums): 337 | idx=order[i] 338 | if suppressed[idx]==1: 339 | continue 340 | keep.append(idx) 341 | mask_a,area_a=get_mask(bbox_infos[idx],mask) 342 | for j in range(i,nums): 343 | idx_j=order[j] 344 | if suppressed[idx_j]==1: 345 | continue 346 | mask_b, area_b =get_mask(bbox_infos[idx_j],mask) 347 | 348 | # 获取两个文本的相交面积 349 | merge_mask=cv2.bitwise_and(mask_a,mask_b) 350 | area_intersect=cv2.countNonZero(merge_mask) 351 | 352 | #计算MMI 353 | mmi=comput_mmi(area_a,area_b,area_intersect) 354 | # print("area_a:{},area_b:{},inte:{},mmi:{}".format(area_a,area_b,area_intersect,mmi)) 355 | 356 | if mmi >= thres: 357 | suppressed[idx_j] = 1 358 | 359 | return dets[keep] 360 | 361 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # code_zoo -------------------------------------------------------------------------------- /SIFT_Feature_Match: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import cv2 3 | import numpy as np 4 | from matplotlib import pyplot as plt 5 | plt.switch_backend('TkAgg') 6 | import numpy as np 7 | from PIL import Image 8 | plt.switch_backend('TkAgg') 9 | from skimage.measure import label as Label 10 | from skimage.measure import regionprops as Region 11 | 12 | img0_path='/home/didia/us_data/npydata_2/1508788_0_clean.npy' 13 | img1_path='/home/didia/us_data/npydata_2/1508788_1_clean.npy' 14 | ann0_path='/home/didia/us_data/npydata_2/1508788_0_seg.npy' 15 | ann1_path='/home/didia/us_data/npydata_2/1508788_1_seg.npy' 16 | 17 | # 测试 18 | # img1_gray = cv2.cvtColor(cv2.imread('left_01.png'), cv2.COLOR_BGR2GRAY) 19 | # img2_gray =cv2.cvtColor(cv2.imread('right_01.png'), cv2.COLOR_BGR2GRAY) 20 | 21 | save_dir='/home/zrj/lab_project/184_ultrasonic/save_img/' 22 | 23 | img0=np.load(img0_path) 24 | img1=np.load(img1_path) 25 | ann0=np.load(ann0_path) 26 | ann1=np.load(ann1_path) 27 | 28 | def drawMatchesKnn_cv2(img1_gray, kp1, img2_gray, kp2, goodMatch,i,j,ymin,xmin,ymax,xmax,y_1, x_1, y_2, x_2): 29 | h1, w1 = img1_gray.shape 30 | h2, w2 = img2_gray.shape 31 | 32 | vis = np.zeros((max(h1, h2), w1 + w2), np.uint8) 33 | vis[:h1, :w1] = img1_gray 34 | vis[:h2, w1:w1 + w2] = img2_gray 35 | 36 | p1 = [kpp.queryIdx for kpp in goodMatch] 37 | p2 = [kpp.trainIdx for kpp in goodMatch] 38 | 39 | post1 = np.int32([kp1[pp].pt for pp in p1]) 40 | post2 = np.int32([kp2[pp].pt for pp in p2]) + (w1, 0) 41 | 42 | for (x1, y1), (x2, y2) in zip(post1, post2): 43 | if x1 >xmin and x1 < xmax and y1 >ymin and y1 < ymax: 44 | # print (x1,y1),(x2-w1,y2) 45 | cv2.line(vis, (x1, y1), (x2, y2), (0,255,0)) 46 | 47 | cv2.rectangle(vis, (xmin, ymin), (xmax, ymax), (0, 255, 0), 4) 48 | cv2.rectangle(vis, (x_1+w1, y_1), (x_2+w1, y_2), (0, 255, 0), 4) 49 | 50 | cv2.imwrite(save_dir+'img0_'+str(i)+'_'+'img1_'+str(j)+'.png',vis) 51 | 52 | def bbox_cor(ann): 53 | ann_regions = Label(ann) 54 | ann_proposal = Region(ann_regions) 55 | for proposal in ann_proposal: 56 | y1,x1,y2,x2=proposal.bbox 57 | return y1,x1,y2,x2 58 | 59 | 60 | for i in range(212,226): 61 | for j in range(173,212): 62 | img1_gray = img0[i] 63 | img2_gray = img1[j] 64 | y1, x1, y2, x2= bbox_cor(ann0[i]) 65 | y_1, x_1, y_2, x_2= bbox_cor(ann1[j]) 66 | sift = cv2.xfeatures2d.SIFT_create() # 建立SIFT生成器 67 | kp1, des1 = sift.detectAndCompute(img1_gray, None) # 检测SIFT特征点,并计算描述子 68 | kp2, des2 = sift.detectAndCompute(img2_gray, None) 69 | 70 | # BFmatcher with default parms 71 | bf = cv2.BFMatcher(cv2.NORM_L2) # 建立暴力匹配器 72 | matches = bf.knnMatch(des1, des2, k=2) # 使用KNN检测来自A、B图的SIFT特征匹配对,K=2 73 | 74 | goodMatch = [] 75 | for m, n in matches: 76 | # 当最近距离跟次近距离的比值小于ratio值时,保留此匹配对 77 | # if m.distance < 0.75 * n.distance: 78 | goodMatch.append(m) 79 | 80 | drawMatchesKnn_cv2(img1_gray, kp1, img2_gray, kp2, goodMatch,i,j,y1, x1, y2, x2,y_1, x_1, y_2, x_2) 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Soft-NMS: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def softnms(dets, sc, Nt=0.3, sigma=0.5, thresh=0.001, method=2): 4 | """ 5 | softnms 6 | :param dets: boexs 坐标矩阵 format [y1, x1, y2, x2] 7 | :param sc: 每个 boxes 对应的分数 8 | :param Nt: iou 交叠门限 9 | :param sigma: 使用 gaussian 函数的方差 10 | :param thresh: 最后的分数门限 11 | :param method: 使用的方法 12 | :return: 留下的 boxes 的 index 13 | """ 14 | 15 | # indexes concatenate boxes with the last column 16 | N = dets.shape[0] 17 | indexes = np.array([np.arange(N)]) 18 | dets = np.concatenate((dets, indexes.T), axis=1) 19 | 20 | # the order of boxes coordinate is [y1,x1,y2,x2] 21 | y1 = dets[:, 0] 22 | x1 = dets[:, 1] 23 | y2 = dets[:, 2] 24 | x2 = dets[:, 3] 25 | scores = sc 26 | areas = (x2 - x1 + 1) * (y2 - y1 + 1) 27 | 28 | for i in range(N): 29 | # intermediate parameters for later parameters exchange 30 | tBD = dets[i, :].copy() 31 | tscore = scores[i].copy() 32 | tarea = areas[i].copy() 33 | pos = i + 1 34 | 35 | # 36 | if i != N-1: 37 | maxscore = np.max(scores[pos:], axis=0) 38 | maxpos = np.argmax(scores[pos:], axis=0) 39 | else: 40 | maxscore = scores[-1] 41 | maxpos = 0 42 | if tscore < maxscore: 43 | dets[i, :] = dets[maxpos + i + 1, :] 44 | dets[maxpos + i + 1, :] = tBD 45 | tBD = dets[i, :] 46 | 47 | scores[i] = scores[maxpos + i + 1] 48 | scores[maxpos + i + 1] = tscore 49 | tscore = scores[i] 50 | 51 | areas[i] = areas[maxpos + i + 1] 52 | areas[maxpos + i + 1] = tarea 53 | tarea = areas[i] 54 | 55 | # IoU calculate 56 | xx1 = np.maximum(dets[i, 1], dets[pos:, 1]) 57 | yy1 = np.maximum(dets[i, 0], dets[pos:, 0]) 58 | xx2 = np.minimum(dets[i, 3], dets[pos:, 3]) 59 | yy2 = np.minimum(dets[i, 2], dets[pos:, 2]) 60 | 61 | w = np.maximum(0.0, xx2 - xx1 + 1) 62 | h = np.maximum(0.0, yy2 - yy1 + 1) 63 | inter = w * h 64 | ovr = inter / (areas[i] + areas[pos:] - inter) 65 | 66 | # Three methods: 1.linear 2.gaussian 3.original NMS 67 | if method == 1: # linear 68 | weight = np.ones(ovr.shape) 69 | weight[ovr > Nt] = weight[ovr > Nt] - ovr[ovr > Nt] 70 | elif method == 2: # gaussian 71 | weight = np.exp(-(ovr * ovr) / sigma) 72 | else: # original NMS 73 | weight = np.ones(ovr.shape) 74 | weight[ovr > Nt] = 0 75 | 76 | scores[pos:] = weight * scores[pos:] 77 | 78 | # select the boxes and keep the corresponding indexes 79 | inds = dets[:, 4][scores > thresh] 80 | keep = inds.astype(int) 81 | print(keep) 82 | 83 | return keep 84 | -------------------------------------------------------------------------------- /__factory: -------------------------------------------------------------------------------- 1 | """Create data loader""" 2 | __factory = { 3 | 'liver': LiverDataset, # 此处为定义的数据类 4 | } 5 | 6 | def get_names(): 7 | return __factory.keys() 8 | 9 | def init_data_loader(name, dataset, **kwargs): 10 | if name not in __factory.keys(): 11 | raise KeyError("Unknown data loader: {}".format(name)) 12 | return __factory[name](dataset, **kwargs) 13 | 14 | 15 | """Create loss""" 16 | __factory = { 17 | 'dice': DiceLoss, 18 | } 19 | 20 | 21 | def get_names(): 22 | return __factory.keys() 23 | 24 | 25 | def init_loss(name, **kwargs): 26 | if name not in __factory.keys(): 27 | raise KeyError("Unknown loss: {}".format(name)) 28 | return __factory[name](**kwargs) 29 | 30 | """Create dataset""" 31 | __factory = { 32 | 'tumor': Tumor, 33 | 'tumortest': TumorTest 34 | } 35 | 36 | 37 | def get_names(): 38 | return __factory.keys() 39 | 40 | 41 | def init_dataset(name, data_root, config, **kwargs): 42 | if name not in __factory.keys(): 43 | raise KeyError("Unknown dataset: {}".format(name)) 44 | return __factory[name](data_root, config, **kwargs) 45 | -------------------------------------------------------------------------------- /binary_segmentation_hardmining: -------------------------------------------------------------------------------- 1 | def hard_mining(neg_output, neg_labels, num_hard): 2 | l = len(neg_output) 3 | neg_output, idcs = torch.topk(neg_output, l) 4 | idcs = idcs[200:] 5 | interval = num_hard/5 6 | l_devide = l/5 7 | selected_idcs = idcs[:interval] 8 | for i in range(4): 9 | i+=1 10 | selected_idcs = torch.cat((selected_idcs, idcs[i*l_devide: i*l_devide+interval])) 11 | neg_output = torch.index_select(neg_output, 0, selected_idcs) 12 | neg_labels = torch.index_select(neg_labels, 0, selected_idcs) 13 | 14 | return neg_output, neg_labels 15 | 16 | class LossWithHardmining(nn.Module): 17 | def __init__(self, weight=None): 18 | super(LossWithHardmining, self).__init__() 19 | self.bce = nn.BCELoss(weight) 20 | 21 | def forward(self, outputs, targets): 22 | outputs = F.sigmoid(outputs[:,1]) 23 | # print outputs.size() 24 | pos_idcs = targets>0 25 | neg_idcs = targets<1 26 | pos_output = outputs[pos_idcs] 27 | pos_target = targets[pos_idcs].type(torch.FloatTensor).cuda() 28 | neg_output = outputs[neg_idcs] 29 | neg_target = targets[neg_idcs].type(torch.FloatTensor).cuda() 30 | 31 | neg_output, neg_target = hard_mining(neg_output, neg_target, num_hard=4*len(pos_target)) 32 | 33 | pos_loss = self.bce(pos_output, pos_target) 34 | neg_loss = self.bce(neg_output, neg_target) 35 | return pos_loss+neg_loss 36 | 37 | 38 | -------------------------------------------------------------------------------- /compute_mIOU: -------------------------------------------------------------------------------- 1 | # python 版本 2 | def IOU(pred,target,n_classes = args.num_class ): 3 | ious = [] 4 | # ignore IOU for background class 5 | for cls in range(1,n_classes): 6 | pred_inds = pred == cls 7 | target_inds = target == cls 8 | # target_sum = target_inds.sum() 9 | intersection = (pred_inds[target_inds]).sum() 10 | union = pred_inds.sum() + target_inds.sum() - intersection 11 | if union == 0: 12 | ious.append(float('nan')) # If there is no ground truth,do not include in evaluation 13 | else: 14 | ious.append(float(intersection)/float(max(union,1))) 15 | return ious 16 | 17 | # numpy 版本 18 | 19 | #设标签宽W,长H 20 | def fast_hist(a, b, n):#a是转化成一维数组的标签,形状(H×W,);b是转化成一维数组的预测特征图,形状(H×W,);n是类别数目 21 | k = (a > 0) & (a <= n) #k是一个一维bool数组,形状(H×W,);目的是找出标签中需要计算的类别(去掉了背景),假设0是背景 22 | return np.bincount(n * a[k].astype(int) + b[k], minlength=n ** 2).reshape(n, n) 23 | 24 | 25 | def per_class_iu(hist):#分别为每个类别(在这里是19类)计算mIoU,hist的形状(n, n) 26 | ''' 27 | 核心代码 28 | ''' 29 | return np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist))#矩阵的对角线上的值组成的一维数组/矩阵的所有元素之和,返回值形状(n,) 30 | 31 | def compute_mIoU(pred,label,n_classes = args.num_class): 32 | hist = np.zeros((num_classes, n_classes))#hist初始化为全零,在这里的hist的形状是[n_classes, n_classes] 33 | hist += fast_hist(label.flatten(), pred.flatten(), n_classes) #对一张图片计算 n_classes×n_classes 的hist矩阵,并累加 34 | 35 | mIoUs = per_class_iu(hist)#计算逐类别mIoU值 36 | for ind_class in range(n_classes):#逐类别输出一下mIoU值 37 | print(str(round(mIoUs[ind_class] * 100, 2))) 38 | print('===> mIoU: ' + str(round(np.nanmean(mIoUs) * 100, 2)))#在所有验证集图像上求所有类别平均的mIoU值,计算时忽略NaN值 39 | return mIoUs 40 | 41 | 42 | # 混淆矩阵各类指标的实现方式 43 | 44 | import numpy as np 45 | 46 | 47 | class Evaluator(object): 48 | def __init__(self, num_class): 49 | self.num_class = num_class 50 | self.confusion_matrix = np.zeros((self.num_class,)*2) 51 | 52 | def Pixel_Accuracy(self): 53 | Acc = np.diag(self.confusion_matrix).sum() / self.confusion_matrix.sum() 54 | return Acc 55 | 56 | def Pixel_Accuracy_Class(self): 57 | Acc = np.diag(self.confusion_matrix) / self.confusion_matrix.sum(axis=1) 58 | Acc = np.nanmean(Acc) 59 | return Acc 60 | 61 | def Mean_Intersection_over_Union(self): 62 | MIoU = np.diag(self.confusion_matrix) / ( 63 | np.sum(self.confusion_matrix, axis=1) + np.sum(self.confusion_matrix, axis=0) - 64 | np.diag(self.confusion_matrix)) 65 | MIoU = np.nanmean(MIoU) 66 | return MIoU 67 | 68 | def Frequency_Weighted_Intersection_over_Union(self): 69 | freq = np.sum(self.confusion_matrix, axis=1) / np.sum(self.confusion_matrix) 70 | iu = np.diag(self.confusion_matrix) / ( 71 | np.sum(self.confusion_matrix, axis=1) + np.sum(self.confusion_matrix, axis=0) - 72 | np.diag(self.confusion_matrix)) 73 | 74 | FWIoU = (freq[freq > 0] * iu[freq > 0]).sum() 75 | return FWIoU 76 | 77 | def _generate_matrix(self, gt_image, pre_image): 78 | mask = (gt_image >= 0) & (gt_image < self.num_class) 79 | label = self.num_class * gt_image[mask].astype('int') + pre_image[mask] 80 | count = np.bincount(label, minlength=self.num_class**2) 81 | confusion_matrix = count.reshape(self.num_class, self.num_class) 82 | return confusion_matrix 83 | 84 | def add_batch(self, gt_image, pre_image): 85 | assert gt_image.shape == pre_image.shape 86 | self.confusion_matrix += self._generate_matrix(gt_image, pre_image) 87 | 88 | def reset(self): 89 | self.confusion_matrix = np.zeros((self.num_class,) * 2) 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /data_augmentation: -------------------------------------------------------------------------------- 1 | from scipy.ndimage import zoom 2 | from skimage.transform import rotate 3 | import numpy as np 4 | 5 | def crop(image, label, patch_size): 6 | img_size = image.shape[1:] 7 | scale_range = [0.8, 1.2] 8 | scale = np.random.rand() * ( 9 | scale_range[1] - scale_range[0]) + scale_range[0] 10 | crop_size = ( 11 | np.array(patch_size).astype('float') / scale).astype('int') 12 | 13 | start = [] 14 | for i in range(2): 15 | if crop_size[i] > img_size[i]: 16 | start.append(np.random.randint(int((img_size[i]-crop_size[i])/2)-1, 0)) 17 | else: 18 | start.append(np.random.randint(0, img_size[i]-crop_size[i]+1)) 19 | 20 | pad = [[0, 0]] 21 | for i in range(2): 22 | left_pad = max(0, -start[i]) 23 | right_pad = max(0, start[i] + crop_size[i] - img_size[i]) 24 | pad.append([left_pad, right_pad]) 25 | crop = image[:, 26 | max(start[0], 0):min(start[0] + crop_size[0], img_size[0]), 27 | max(start[1], 0):min(start[1] + crop_size[1], img_size[1])] 28 | crop = np.pad(crop, pad, 'constant') 29 | crop_label = label[max(start[0], 0):min(start[0] + crop_size[0], img_size[0]), 30 | max(start[1], 0):min(start[1] + crop_size[1], img_size[1])] 31 | crop_label = np.pad(crop_label, pad[1:], 'constant') 32 | 33 | with warnings.catch_warnings(): 34 | warnings.simplefilter("ignore") 35 | crop = zoom(crop, [1, scale, scale], order=1) 36 | crop_label = zoom(crop_label, [scale, scale], order=1) 37 | newpad = patch_size[0] - crop.shape[1:][0] 38 | if newpad < 0: 39 | crop = crop[:, :newpad, :newpad] 40 | crop_label = crop_label[:newpad, :newpad] 41 | elif newpad > 0: 42 | pad2 = [[0, 0], [0, newpad], [0, newpad]] 43 | crop = np.pad(crop, pad2, 'constant') 44 | crop_label = np.pad(crop_label, pad2[1:], 'constant') 45 | return crop, crop_label 46 | 47 | 48 | def random_rotate(sample, target, angles_range): 49 | angles = np.float32(np.random.uniform(*angles_range)) 50 | rot_sample = sample.copy() 51 | rot_target = target.copy() 52 | for index in range(3): 53 | sample_channel = sample[:, :, index] 54 | target_channel = target[:, :, index] 55 | sample_channel = rotate(sample_channel, angles, resize=False, preserve_range=True) 56 | target_channel = rotate(target_channel, angles, resize=False, preserve_range=True) 57 | rot_sample[:, :, index] = sample_channel 58 | rot_target[:, :, index] = target_channel 59 | return np.float32(rot_sample), np.float32(rot_target) 60 | 61 | def flip(sample, target): 62 | flip_num = np.random.randint(0, 8) 63 | if flip_num == 1: 64 | sample = np.flipud(sample) 65 | target = np.flipud(target) 66 | elif flip_num == 2: 67 | sample = np.fliplr(sample) 68 | target = np.fliplr(target) 69 | elif flip_num == 3: 70 | sample = np.rot90(sample, k=1, axes=(1, 0)) 71 | target = np.rot90(target, k=1, axes=(1, 0)) 72 | elif flip_num == 4: 73 | sample = np.rot90(sample, k=3, axes=(1, 0)) 74 | target = np.rot90(target, k=3, axes=(1, 0)) 75 | elif flip_num == 5: 76 | sample = np.fliplr(sample) 77 | target = np.fliplr(target) 78 | sample = np.rot90(sample, k=1, axes=(1, 0)) 79 | target = np.rot90(target, k=1, axes=(1, 0)) 80 | elif flip_num == 6: 81 | sample = np.fliplr(sample) 82 | target = np.fliplr(target) 83 | sample = np.rot90(sample, k=3, axes=(1, 0)) 84 | target = np.rot90(target, k=3, axes=(1, 0)) 85 | elif flip_num == 7: 86 | sample = np.flipud(sample) 87 | target = np.flipud(target) 88 | sample = np.fliplr(sample) 89 | target = np.fliplr(target) 90 | return sample, target 91 | 92 | 93 | def FlipH(img): 94 | return np.fliplr ( img ) 95 | 96 | 97 | def FlipV(img): 98 | return np.flipud ( img ) 99 | 100 | 101 | def Rotate(img, angle): 102 | return transform.rotate ( img, angle ) 103 | 104 | 105 | def Blur(img, sigma=0.7): 106 | is_colour = len ( img.shape ) == 3 107 | return rescale_intensity ( gaussian ( img, sigma=sigma, multichannel=is_colour ) ) 108 | 109 | def Noise(img, var=0.00001): 110 | return random_noise ( img, mode='gaussian', var=var ) 111 | 112 | 113 | class Zoom: 114 | def __init__(self, p1x, p1y, p2x, p2y): 115 | self.p1x = p1x 116 | self.p1y = p1y 117 | self.p2x = p2x 118 | self.p2y = p2y 119 | 120 | def process(self, img): 121 | h = len ( img ) 122 | w = len ( img[0] ) 123 | 124 | crop_p1x = max ( self.p1x, 0 ) 125 | crop_p1y = max ( self.p1y, 0 ) 126 | crop_p2x = min ( self.p2x, w ) 127 | crop_p2y = min ( self.p2y, h ) 128 | 129 | cropped_img = img[crop_p1y:crop_p2y, crop_p1x:crop_p2x] 130 | 131 | x_pad_before = -min ( 0, self.p1x ) 132 | x_pad_after = max ( 0, self.p2x - w ) 133 | y_pad_before = -min ( 0, self.p1y ) 134 | y_pad_after = max ( 0, self.p2y - h ) 135 | 136 | padding = [(y_pad_before, y_pad_after), (x_pad_before, x_pad_after)] 137 | is_colour = len ( img.shape ) == 3 138 | if is_colour: 139 | padding.append ( (0, 0) ) # colour images have an extra dimension 140 | 141 | padded_img = np.pad ( cropped_img, padding, 'constant' ) 142 | return transform.resize ( padded_img, (h, w) ) 143 | 144 | 145 | class RandomScale ( object ): 146 | """Randomly scales an image 147 | Parameters 148 | ---------- 149 | scale: float or tuple(float) 150 | if **float**, the image is scaled by a factor drawn 151 | randomly from a range (1 - `scale` , 1 + `scale`). If **tuple**, 152 | the `scale` is drawn randomly from values specified by the 153 | tuple 154 | 155 | Returns 156 | ------- 157 | 158 | numpy.ndaaray 159 | Scaled image in the numpy format of shape `HxWxC` 160 | 161 | """ 162 | 163 | def __init__(self, scale=0.2, diff=False): 164 | self.scale = scale 165 | 166 | if type ( self.scale ) == tuple: 167 | assert len ( self.scale ) == 2, "Invalid range" 168 | assert self.scale[0] > -1, "Scale factor can't be less than -1" 169 | assert self.scale[1] > -1, "Scale factor can't be less than -1" 170 | else: 171 | assert self.scale > 0, "Please input a positive float" 172 | self.scale = (max ( -1, -self.scale ), self.scale) 173 | 174 | self.diff = diff 175 | 176 | def __call__(self, img): 177 | # Chose a random digit to scale by 178 | img_shape = img.shape 179 | if self.diff: 180 | scale_x = random.uniform ( *self.scale ) 181 | scale_y = random.uniform ( *self.scale ) 182 | else: 183 | scale_x = random.uniform ( *self.scale ) 184 | scale_y = scale_x 185 | resize_scale_x = 1 + scale_x 186 | resize_scale_y = 1 + scale_y 187 | img = cv2.resize ( img, None, fx=resize_scale_x, fy=resize_scale_y ) 188 | canvas = np.zeros ( img_shape, dtype=np.uint8 ) 189 | y_lim = int ( min ( resize_scale_y, 1 ) * img_shape[0] ) 190 | x_lim = int ( min ( resize_scale_x, 1 ) * img_shape[1] ) 191 | canvas[:y_lim, :x_lim, :] = img[:y_lim, :x_lim, :] 192 | img = canvas 193 | return img 194 | 195 | 196 | class RandomRotate ( object ): 197 | """Randomly rotates an image 198 | 199 | Parameters 200 | ---------- 201 | angle: float or tuple(float) 202 | if **float**, the image is rotated by a factor drawn 203 | randomly from a range (-`angle`, `angle`). If **tuple**, 204 | the `angle` is drawn randomly from values specified by the 205 | tuple 206 | 207 | Returns 208 | ------- 209 | 210 | numpy.ndaaray 211 | Rotated image in the numpy format of shape `HxWxC` 212 | 213 | """ 214 | 215 | def __init__(self, angle=10): 216 | self.angle = angle 217 | 218 | def __call__(self, img): 219 | angles = np.float32 ( np.random.uniform ( *self.angle ) ) 220 | rot_sample = img.copy ( ) 221 | for index in range ( 3 ): 222 | sample_channel = img[:, :, index] 223 | sample_channel = rotate ( sample_channel, angles, resize=False, preserve_range=True ) 224 | rot_sample[:, :, index] = sample_channel 225 | return np.float32 ( rot_sample ) 226 | 227 | 228 | class RandomHSV ( object ): 229 | """HSV Transform to vary hue saturation and brightness 230 | 231 | Hue has a range of 0-179 232 | Saturation and Brightness have a range of 0-255. 233 | Chose the amount you want to change thhe above quantities accordingly. 234 | 235 | 236 | 237 | 238 | Parameters 239 | ---------- 240 | hue : None or int or tuple (int) 241 | If None, the hue of the image is left unchanged. If int, 242 | a random int is uniformly sampled from (-hue, hue) and added to the 243 | hue of the image. If tuple, the int is sampled from the range 244 | specified by the tuple. 245 | 246 | saturation : None or int or tuple(int) 247 | If None, the saturation of the image is left unchanged. If int, 248 | a random int is uniformly sampled from (-saturation, saturation) 249 | and added to the hue of the image. If tuple, the int is sampled 250 | from the range specified by the tuple. 251 | 252 | brightness : None or int or tuple(int) 253 | If None, the brightness of the image is left unchanged. If int, 254 | a random int is uniformly sampled from (-brightness, brightness) 255 | and added to the hue of the image. If tuple, the int is sampled 256 | from the range specified by the tuple. 257 | 258 | Returns 259 | ------- 260 | 261 | numpy.ndaaray 262 | Transformed image in the numpy format of shape `HxWxC` 263 | 264 | numpy.ndarray 265 | Resized bounding box co-ordinates of the format `n x 4` where n is 266 | number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box 267 | 268 | """ 269 | 270 | def __init__(self, hue=None, saturation=None, brightness=None): 271 | if hue: 272 | self.hue = hue 273 | else: 274 | self.hue = 0 275 | 276 | if saturation: 277 | self.saturation = saturation 278 | else: 279 | self.saturation = 0 280 | 281 | if brightness: 282 | self.brightness = brightness 283 | else: 284 | self.brightness = 0 285 | 286 | if type ( self.hue ) != tuple: 287 | self.hue = (-self.hue, self.hue) 288 | 289 | if type ( self.saturation ) != tuple: 290 | self.saturation = (-self.saturation, self.saturation) 291 | 292 | if type ( brightness ) != tuple: 293 | self.brightness = (-self.brightness, self.brightness) 294 | 295 | def __call__(self, img): 296 | 297 | hue = random.randint ( *self.hue ) 298 | saturation = random.randint ( *self.saturation ) 299 | brightness = random.randint ( *self.brightness ) 300 | 301 | img = img.astype ( int ) 302 | 303 | a = np.array ( [hue, saturation, brightness] ).astype ( int ) 304 | img += np.reshape ( a, (1, 1, 3) ) 305 | 306 | img = np.clip ( img, 0, 255 ) 307 | img[:, :, 0] = np.clip ( img[:, :, 0], 0, 179 ) 308 | 309 | img = img.astype ( np.uint8 ) 310 | 311 | return img 312 | -------------------------------------------------------------------------------- /initialization.py: -------------------------------------------------------------------------------- 1 | 2 | def weights_init_xavier(m): 3 | classname = m.__class__.__name__ 4 | # print(classname) 5 | if classname.find('Conv') != -1: 6 | init.xavier_normal(m.weight.data, gain=1) 7 | elif classname.find('Linear') != -1: 8 | init.xavier_normal(m.weight.data, gain=1) 9 | elif classname.find('BatchNorm2d') != -1: 10 | init.uniform(m.weight.data, 1.0, 0.02) 11 | init.constant(m.bias.data, 0.0) 12 | 13 | # usage: 14 | # net.apply(weights_init_xavier) 15 | 16 | 17 | from torch import nn 18 | 19 | 20 | class Initializer: 21 | def __init__(self): 22 | pass 23 | 24 | @staticmethod 25 | def initialize(model, initialization, **kwargs): 26 | 27 | def weights_init(m): 28 | if isinstance(m, nn.Conv2d): 29 | initialization(m.weight.data, **kwargs) 30 | try: 31 | initialization(m.bias.data) 32 | except: 33 | pass 34 | 35 | elif isinstance(m, nn.Linear): 36 | initialization(m.weight.data, **kwargs) 37 | try: 38 | initialization(m.bias.data) 39 | except: 40 | pass 41 | 42 | elif isinstance(m, nn.BatchNorm2d): 43 | m.weight.data.fill_(1.0) 44 | m.bias.data.fill_(0) 45 | 46 | elif isinstance(m, nn.BatchNorm1d): 47 | m.weight.data.fill_(1.0) 48 | m.bias.data.fill_(0) 49 | 50 | model.apply(weights_init) 51 | 52 | # usage 53 | # net = Model() # instantiate the model 54 | 55 | # to apply xavier_uniform: 56 | # Initializer.initialize(model=net, initialization=init.xavier_uniform, gain=init.calculate_gain('relu')) 57 | 58 | # or maybe normal distribution: 59 | # Initializer.initialize(model=net, initialization=init.normal, mean=0, std=0.2) 60 | -------------------------------------------------------------------------------- /machine learning model: -------------------------------------------------------------------------------- 1 | from sklearn.model_selection import GridSearchCV 2 | from sklearn.svm import SVC 3 | from sklearn import metrics 4 | import numpy as np 5 | from sklearn import tree 6 | from sklearn.ensemble import ExtraTreesClassifier, RandomForestClassifier 7 | from sklearn.ensemble import AdaBoostClassifier,GradientBoostingClassifier 8 | from sklearn.linear_model import LogisticRegression,SGDClassifier 9 | from sklearn.neighbors import KNeighborsClassifier 10 | from sklearn.neural_network import MLPClassifier 11 | 12 | def SVM(train_data, train_label, valid_data,valid_label): 13 | scores = ['precision', 'recall'] 14 | for score in scores: 15 | print ( "# Tuning hyper-parameters for %s" % score ) 16 | model = SVC ( ) 17 | param_grid = [{'C': [1e-3, 1e-2, 1e-1, 1, 10, 100, 1000], 'kernel': ['rbf'], 'gamma': [0.001, 0.0001]}, 18 | {'C': [1e-3, 1e-2, 1e-1, 1, 10, 100, 1000], 'kernel': ['linear']}] 19 | grid_search = GridSearchCV ( model, param_grid,cv=5, 20 | scoring='%s_macro' % score, n_jobs=8, verbose=1 ) 21 | grid_search.fit ( train_data, train_label ) 22 | 23 | best_parameters = grid_search.best_estimator_.get_params ( ) 24 | for para, val in list ( best_parameters.items ( ) ): 25 | print ( para, val ) 26 | 27 | valid_pred = grid_search.predict ( valid_data ) 28 | 29 | accuracy_score = metrics.accuracy_score ( valid_label, valid_pred ) 30 | print ( 'accuracy_score' + '\t' + str ( accuracy_score ) ) 31 | precision_score = metrics.precision_score ( valid_label, valid_pred, average='macro' ) 32 | print ( 'precision_score' + '\t' + str ( precision_score ) ) 33 | recall_score = metrics.recall_score ( valid_label, valid_pred, average='macro' ) 34 | print ( 'recall_score' + '\t' + str ( recall_score ) ) 35 | f1_score = metrics.f1_score ( valid_label, valid_pred, average='weighted' ) 36 | print ( 'f1_score' + '\t' + str ( f1_score ) ) 37 | print ( '验证集中患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 1 ) ) ) 38 | print ( '验证集中患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 1] == 1 ) ) ) 39 | print ( '验证集中不患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 0 ) ) ) 40 | print ( '验证集中不患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 0] == 0 ) ) ) 41 | print ( ) 42 | 43 | 44 | def DCTree(train_data, train_label, valid_data,valid_label): 45 | scores = ['precision', 'recall'] 46 | for score in scores: 47 | print ( "# Tuning hyper-parameters for %s" % score ) 48 | model = tree.DecisionTreeClassifier ( ) 49 | param_grid = {'max_depth': range(1, 10)} 50 | grid_search = GridSearchCV ( model, param_grid, cv=5, 51 | scoring='%s_macro' % score, n_jobs=8, verbose=1 ) 52 | grid_search.fit ( train_data, train_label ) 53 | 54 | best_parameters = grid_search.best_estimator_.get_params ( ) 55 | for para, val in list ( best_parameters.items ( ) ): 56 | print ( para, val ) 57 | 58 | valid_pred = grid_search.predict ( valid_data ) 59 | 60 | accuracy_score = metrics.accuracy_score ( valid_label, valid_pred ) 61 | print ( 'accuracy_score' + '\t' + str ( accuracy_score ) ) 62 | precision_score = metrics.precision_score ( valid_label, valid_pred, average='macro' ) 63 | print ( 'precision_score' + '\t' + str ( precision_score ) ) 64 | recall_score = metrics.recall_score ( valid_label, valid_pred, average='macro' ) 65 | print ( 'recall_score' + '\t' + str ( recall_score ) ) 66 | f1_score = metrics.f1_score ( valid_label, valid_pred, average='weighted' ) 67 | print ( 'f1_score' + '\t' + str ( f1_score ) ) 68 | print ( '验证集中患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 1 ) ) ) 69 | print ( '验证集中患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 1] == 1 ) ) ) 70 | print ( '验证集中不患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 0 ) ) ) 71 | print ( '验证集中不患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 0] == 0 ) ) ) 72 | print ( ) 73 | 74 | 75 | 76 | def RF(train_data, train_label, valid_data,valid_label): 77 | scores = ['precision', 'recall'] 78 | for score in scores: 79 | print ( "# Tuning hyper-parameters for %s" % score ) 80 | model = RandomForestClassifier ( ) 81 | param_grid = {'n_estimators':range(10,71,10),'max_depth':range(3,14,2),'min_samples_split':range(50,201,20), 82 | 'min_samples_leaf':range(10,60,10),'max_features':range(3,11,2)} 83 | grid_search = GridSearchCV ( model, param_grid, cv=5, 84 | scoring='%s_macro' % score, n_jobs=8, verbose=1 ) 85 | grid_search.fit ( train_data, train_label ) 86 | 87 | best_parameters = grid_search.best_estimator_.get_params ( ) 88 | for para, val in list ( best_parameters.items ( ) ): 89 | print ( para, val ) 90 | 91 | valid_pred = grid_search.predict ( valid_data ) 92 | 93 | accuracy_score = metrics.accuracy_score ( valid_label, valid_pred ) 94 | print ( 'accuracy_score' + '\t' + str ( accuracy_score ) ) 95 | precision_score = metrics.precision_score ( valid_label, valid_pred, average='macro' ) 96 | print ( 'precision_score' + '\t' + str ( precision_score ) ) 97 | recall_score = metrics.recall_score ( valid_label, valid_pred, average='macro' ) 98 | print ( 'recall_score' + '\t' + str ( recall_score ) ) 99 | f1_score = metrics.f1_score ( valid_label, valid_pred, average='weighted' ) 100 | print ( 'f1_score' + '\t' + str ( f1_score ) ) 101 | print ( '验证集中患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 1 ) ) ) 102 | print ( '验证集中患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 1] == 1 ) ) ) 103 | print ( '验证集中不患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 0 ) ) ) 104 | print ( '验证集中不患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 0] == 0 ) ) ) 105 | print ( ) 106 | 107 | def AdaboostClassifier(train_data, train_label, valid_data,valid_label): 108 | scores = ['precision', 'recall'] 109 | for score in scores: 110 | print ( "# Tuning hyper-parameters for %s" % score ) 111 | model = AdaBoostClassifier ( ) 112 | param_grid = {'n_estimators':[5,10,20,30],'learning_rate':[0.001,0.01,0.1,1]} 113 | grid_search = GridSearchCV ( model, param_grid, cv=5, 114 | scoring='%s_macro' % score, n_jobs=8, verbose=1 ) 115 | grid_search.fit ( train_data, train_label ) 116 | 117 | best_parameters = grid_search.best_estimator_.get_params ( ) 118 | for para, val in list ( best_parameters.items ( ) ): 119 | print ( para, val ) 120 | 121 | valid_pred = grid_search.predict ( valid_data ) 122 | 123 | accuracy_score = metrics.accuracy_score ( valid_label, valid_pred ) 124 | print ( 'accuracy_score' + '\t' + str ( accuracy_score ) ) 125 | precision_score = metrics.precision_score ( valid_label, valid_pred, average='macro' ) 126 | print ( 'precision_score' + '\t' + str ( precision_score ) ) 127 | recall_score = metrics.recall_score ( valid_label, valid_pred, average='macro' ) 128 | print ( 'recall_score' + '\t' + str ( recall_score ) ) 129 | f1_score = metrics.f1_score ( valid_label, valid_pred, average='weighted' ) 130 | print ( 'f1_score' + '\t' + str ( f1_score ) ) 131 | print ( '验证集中患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 1 ) ) ) 132 | print ( '验证集中患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 1] == 1 ) ) ) 133 | print ( '验证集中不患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 0 ) ) ) 134 | print ( '验证集中不患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 0] == 0 ) ) ) 135 | print ( ) 136 | 137 | def GBDT(train_data, train_label, valid_data,valid_label): 138 | scores = ['precision', 'recall'] 139 | for score in scores: 140 | print ( "# Tuning hyper-parameters for %s" % score ) 141 | model = GradientBoostingClassifier ( ) 142 | param_grid = {'n_estimators':[5,10,20,30],'learning_rate':[0.001,0.01,0.1,1], 143 | 'max_depth':range(3,14,2),'min_samples_split':range(50,201,20), 144 | 'min_samples_leaf':range(10,60,10),'max_features':range(3,11,2)} 145 | grid_search = GridSearchCV ( model, param_grid, cv=5, 146 | scoring='%s_macro' % score, n_jobs=8, verbose=1 ) 147 | grid_search.fit ( train_data, train_label ) 148 | 149 | best_parameters = grid_search.best_estimator_.get_params ( ) 150 | for para, val in list ( best_parameters.items ( ) ): 151 | print ( para, val ) 152 | 153 | valid_pred = grid_search.predict ( valid_data ) 154 | 155 | accuracy_score = metrics.accuracy_score ( valid_label, valid_pred ) 156 | print ( 'accuracy_score' + '\t' + str ( accuracy_score ) ) 157 | precision_score = metrics.precision_score ( valid_label, valid_pred, average='macro' ) 158 | print ( 'precision_score' + '\t' + str ( precision_score ) ) 159 | recall_score = metrics.recall_score ( valid_label, valid_pred, average='macro' ) 160 | print ( 'recall_score' + '\t' + str ( recall_score ) ) 161 | f1_score = metrics.f1_score ( valid_label, valid_pred, average='weighted' ) 162 | print ( 'f1_score' + '\t' + str ( f1_score ) ) 163 | print ( '验证集中患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 1 ) ) ) 164 | print ( '验证集中患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 1] == 1 ) ) ) 165 | print ( '验证集中不患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 0 ) ) ) 166 | print ( '验证集中不患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 0] == 0 ) ) ) 167 | print ( ) 168 | 169 | def LG_Classifier(train_data, train_label, valid_data,valid_label): 170 | scores = ['precision', 'recall'] 171 | for score in scores: 172 | print ( "# Tuning hyper-parameters for %s" % score ) 173 | model = LogisticRegression ( ) 174 | param_grid = {'C':[0.001,0.01,0.1,1,5,10],'solver':['newton-cg','lbfgs','sag'],'multi_class':['ovr','multinomial']} 175 | grid_search = GridSearchCV ( model, param_grid, cv=5, 176 | scoring='%s_macro' % score, n_jobs=8, verbose=1 ) 177 | grid_search.fit ( train_data, train_label ) 178 | 179 | best_parameters = grid_search.best_estimator_.get_params ( ) 180 | for para, val in list ( best_parameters.items ( ) ): 181 | print ( para, val ) 182 | 183 | valid_pred = grid_search.predict ( valid_data ) 184 | 185 | accuracy_score = metrics.accuracy_score ( valid_label, valid_pred ) 186 | print ( 'accuracy_score' + '\t' + str ( accuracy_score ) ) 187 | precision_score = metrics.precision_score ( valid_label, valid_pred, average='macro' ) 188 | print ( 'precision_score' + '\t' + str ( precision_score ) ) 189 | recall_score = metrics.recall_score ( valid_label, valid_pred, average='macro' ) 190 | print ( 'recall_score' + '\t' + str ( recall_score ) ) 191 | f1_score = metrics.f1_score ( valid_label, valid_pred, average='weighted' ) 192 | print ( 'f1_score' + '\t' + str ( f1_score ) ) 193 | print ( '验证集中患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 1 ) ) ) 194 | print ( '验证集中患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 1] == 1 ) ) ) 195 | print ( '验证集中不患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 0 ) ) ) 196 | print ( '验证集中不患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 0] == 0 ) ) ) 197 | print ( ) 198 | 199 | 200 | def SGD(train_data, train_label, valid_data,valid_label): 201 | scores = ['precision', 'recall'] 202 | for score in scores: 203 | print ( "# Tuning hyper-parameters for %s" % score ) 204 | model = SGDClassifier ( ) 205 | param_grid = {'alpha':[0.1,0.01,0.001,0.0001,0.00001],'l1_ratio':[0.1,0.2,0.3,0.5,0.6,0.8], 206 | 'max_iter':[5,10,20,30,40,50,100]} 207 | grid_search = GridSearchCV ( model, param_grid, cv=5, 208 | scoring='%s_macro' % score, n_jobs=8, verbose=1 ) 209 | grid_search.fit ( train_data, train_label ) 210 | 211 | best_parameters = grid_search.best_estimator_.get_params ( ) 212 | for para, val in list ( best_parameters.items ( ) ): 213 | print ( para, val ) 214 | 215 | valid_pred = grid_search.predict ( valid_data ) 216 | 217 | accuracy_score = metrics.accuracy_score ( valid_label, valid_pred ) 218 | print ( 'accuracy_score' + '\t' + str ( accuracy_score ) ) 219 | precision_score = metrics.precision_score ( valid_label, valid_pred, average='macro' ) 220 | print ( 'precision_score' + '\t' + str ( precision_score ) ) 221 | recall_score = metrics.recall_score ( valid_label, valid_pred, average='macro' ) 222 | print ( 'recall_score' + '\t' + str ( recall_score ) ) 223 | f1_score = metrics.f1_score ( valid_label, valid_pred, average='weighted' ) 224 | print ( 'f1_score' + '\t' + str ( f1_score ) ) 225 | print ( '验证集中患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 1 ) ) ) 226 | print ( '验证集中患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 1] == 1 ) ) ) 227 | print ( '验证集中不患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 0 ) ) ) 228 | print ( '验证集中不患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 0] == 0 ) ) ) 229 | print ( ) 230 | 231 | 232 | def KNClassifier(train_data, train_label, valid_data,valid_label): 233 | scores = ['precision', 'recall'] 234 | for score in scores: 235 | print ( "# Tuning hyper-parameters for %s" % score ) 236 | model = KNeighborsClassifier ( ) 237 | param_grid = {'weights': ['uniform','distance'],'algorithm':['auto','ball_tree','kd_tree','brute'], 238 | 'n_neighbors':[5,10,20]} 239 | grid_search = GridSearchCV ( model, param_grid, cv=5, 240 | scoring='%s_macro' % score, n_jobs=8, verbose=1 ) 241 | grid_search.fit ( train_data, train_label ) 242 | 243 | best_parameters = grid_search.best_estimator_.get_params ( ) 244 | for para, val in list ( best_parameters.items ( ) ): 245 | print ( para, val ) 246 | 247 | valid_pred = grid_search.predict ( valid_data ) 248 | 249 | accuracy_score = metrics.accuracy_score ( valid_label, valid_pred ) 250 | print ( 'accuracy_score' + '\t' + str ( accuracy_score ) ) 251 | precision_score = metrics.precision_score ( valid_label, valid_pred, average='macro' ) 252 | print ( 'precision_score' + '\t' + str ( precision_score ) ) 253 | recall_score = metrics.recall_score ( valid_label, valid_pred, average='macro' ) 254 | print ( 'recall_score' + '\t' + str ( recall_score ) ) 255 | f1_score = metrics.f1_score ( valid_label, valid_pred, average='weighted' ) 256 | print ( 'f1_score' + '\t' + str ( f1_score ) ) 257 | print ( '验证集中患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 1 ) ) ) 258 | print ( '验证集中患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 1] == 1 ) ) ) 259 | print ( '验证集中不患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 0 ) ) ) 260 | print ( '验证集中不患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 0] == 0 ) ) ) 261 | print ( ) 262 | 263 | 264 | def MLP(train_data, train_label, valid_data, valid_label): 265 | scores = ['precision', 'recall'] 266 | for score in scores: 267 | print ( "# Tuning hyper-parameters for %s" % score ) 268 | model = MLPClassifier ( ) 269 | param_grid = {'hidden_layer_sizes': [(50,50), (20,20,20)], 'activation': ['identity', 'logistic', 'tanh', 'relu'], 270 | 'solver': ['lbfgs', 'sgd', 'adam'],'learning_rate':['invscaling','adaptive'], 271 | 'learning_rate_init':[1, 0.1, 0.01, 0.001, 0.0001]} 272 | grid_search = GridSearchCV ( model, param_grid, cv=5, 273 | scoring='%s_macro' % score, n_jobs=8, verbose=1 ) 274 | grid_search.fit ( train_data, train_label ) 275 | 276 | best_parameters = grid_search.best_estimator_.get_params ( ) 277 | for para, val in list ( best_parameters.items ( ) ): 278 | print ( para, val ) 279 | 280 | valid_pred = grid_search.predict ( valid_data ) 281 | 282 | accuracy_score = metrics.accuracy_score ( valid_label, valid_pred ) 283 | print ( 'accuracy_score' + '\t' + str ( accuracy_score ) ) 284 | precision_score = metrics.precision_score ( valid_label, valid_pred, average='macro' ) 285 | print ( 'precision_score' + '\t' + str ( precision_score ) ) 286 | recall_score = metrics.recall_score ( valid_label, valid_pred, average='macro' ) 287 | print ( 'recall_score' + '\t' + str ( recall_score ) ) 288 | f1_score = metrics.f1_score ( valid_label, valid_pred, average='weighted' ) 289 | print ( 'f1_score' + '\t' + str ( f1_score ) ) 290 | print ( '验证集中患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 1 ) ) ) 291 | print ( '验证集中患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 1] == 1 ) ) ) 292 | print ( '验证集中不患慢阻肺的人数:' + '\t' + str ( np.sum ( valid_label == 0 ) ) ) 293 | print ( '验证集中不患慢阻肺的人数的正确人数:' + '\t' + str ( sum ( valid_pred[valid_label == 0] == 0 ) ) ) 294 | print ( ) 295 | -------------------------------------------------------------------------------- /medical_image_process: -------------------------------------------------------------------------------- 1 | import nibabel as nib 2 | 3 | # 读取nii文件 4 | def read_nii(volume_path): 5 | nii = nib.load(volume_path) 6 | data = nii.get_data() 7 | ax_codes = nib.aff2axcodes(nii.affine) 8 | 9 | return data, ax_codes, nii.header, nii.affine 10 | 11 | def save_nii(data, save_name, header, affine): 12 | new_img = nib.Nifti1Image(data.astype(np.int16), affine, header) 13 | nib.save(new_img, save_name) 14 | 15 | # 读取nrrd文件 16 | def read_nrrd(volume_path): 17 | mapping = { 18 | 'left-posterior-superior': ('L', 'P', 'S'), 19 | "right-anterior-superior": ('R', 'A', 'S'), 20 | "left-anterior-superior": ('L', 'A', 'S'), 21 | 22 | } 23 | data, header = nrrd.read(volume_path) 24 | ax_codes = mapping[header['space']] 25 | 26 | return data, ax_codes, header 27 | 28 | # 当spacing 有较大的方差时要进行resample 29 | def resample(imgs, spacing, new_spacing, order=1): 30 | new_shape = np.round(imgs.shape * spacing / new_spacing) 31 | true_spacing = spacing * imgs.shape / new_shape 32 | resize_factor = new_shape / imgs.shape 33 | imgs = zoom(imgs, resize_factor, mode='nearest', order=order) 34 | return imgs, true_spacing 35 | -------------------------------------------------------------------------------- /optim_loss: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | def lr_poly(base_lr, iter,max_iter,power): 4 | return base_lr*((1-float(iter)/max_iter)**(power)) 5 | # lr_ = lr_poly(base_lr,iter,max_iter,0.9) 6 | 7 | 8 | def init_optim(optim, params, lr, weight_decay): 9 | if optim == 'adam': 10 | return torch.optim.Adam(params, lr=lr, weight_decay=weight_decay) 11 | elif optim == 'sgd': 12 | return torch.optim.SGD(params, lr=lr, momentum=0.9, weight_decay=weight_decay) 13 | elif optim == 'rmsprop': 14 | return torch.optim.RMSprop(params, lr=lr, momentum=0.9, weight_decay=weight_decay) 15 | else: 16 | raise KeyError("Unsupported optim: {}".format(optim)) 17 | 18 | scheduler = lr_scheduler.StepLR(optimizer, step_size=config.STEP_SIZE, gamma=config.GAMMA) 19 | scheduler.step() 20 | -------------------------------------------------------------------------------- /segmentation_utils: -------------------------------------------------------------------------------- 1 | # patch split and combine 2 | 3 | import numpy as np 4 | import torch 5 | from torch import nn 6 | 7 | 8 | class SplitComb(object): 9 | def __init__(self, patch_size, patch_margin): 10 | self.margin = patch_margin 11 | self.side_len = [int(patch_size[0] - patch_margin[0] * 2), 12 | int(patch_size[1] - patch_margin[1] * 2)] 13 | def split(self, data): 14 | assert (self.side_len[0] > self.margin[0] and self.side_len[1] > self.margin[1]) 15 | splits = [] 16 | _, h, w = data.shape 17 | 18 | nh = int(np.ceil(float(h) / self.side_len[0])) 19 | nw = int(np.ceil(float(w) / self.side_len[1])) 20 | 21 | nhw = [nh, nw] 22 | padding = [ 23 | [0, 0], 24 | [self.margin[0], nh * self.side_len[0] - h + self.margin[0]], 25 | [self.margin[1], nw * self.side_len[1] - w + self.margin[1]]] 26 | data = np.pad(data, padding, 'edge') 27 | 28 | for ih in range(nh): 29 | for iw in range(nw): 30 | sh = ih * self.side_len[0] 31 | eh = (ih + 1) * self.side_len[0] + 2 * self.margin[0] 32 | sw = iw * self.side_len[1] 33 | ew = (iw + 1) * self.side_len[1] + 2 * self.margin[1] 34 | 35 | split = data[np.newaxis, :, sh:eh, sw:ew] 36 | splits.append(split) 37 | 38 | splits = np.concatenate(splits, 0) 39 | return splits, nhw, padding 40 | 41 | def combine(self, splits, nhw, padding): 42 | nh, nw = nhw 43 | h = nh * self.side_len[0] + self.margin[0] - padding[1][1] 44 | w = nw * self.side_len[1] + self.margin[1] - padding[2][1] 45 | if splits[0].ndim == 2: 46 | output = np.zeros((h, w)) 47 | elif splits[0].ndim == 3: 48 | output = np.zeros((h, w, splits.shape[-1])) 49 | 50 | idx = 0 51 | for ih in range(nh): 52 | for iw in range(nw): 53 | sh = ih * self.side_len[0] 54 | eh = (ih + 1) * self.side_len[0] 55 | eh = eh if eh < h else h 56 | sw = iw * self.side_len[1] 57 | ew = (iw + 1) * self.side_len[1] 58 | ew = ew if ew < w else w 59 | if splits[0].ndim == 2: 60 | split = splits[idx][ 61 | self.margin[0]:self.margin[0] + eh - sh, 62 | self.margin[1]:self.margin[1] + ew - sw] 63 | output[sh:eh, sw:ew] = split 64 | elif splits[0].ndim == 3: 65 | split = splits[idx][ 66 | self.margin[0]:self.margin[0] + eh - sh, 67 | self.margin[1]:self.margin[1] + ew - sw, :] 68 | output[sh:eh, sw:ew, :] = split 69 | idx += 1 70 | return output 71 | 72 | 73 | # coefficient = 2*|X ∩ Y| / |X|+|Y| Dice Loss = 1 - coefficient 74 | class DiceLoss(nn.Module): 75 | def __init__(self, **kwargs): 76 | super(DiceLoss, self).__init__() 77 | self.sigmoid = nn.Sigmoid() 78 | 79 | def forward(self,output,target): 80 | if not isinstance(target,torch.FloatTensor): 81 | target = target.float() 82 | output = output.view(-1) 83 | pred = self.sigmoid(output) 84 | target = target.view(-1) 85 | smooth = 1. 86 | intersection = (pred * target).sum() 87 | 88 | return 1 - ((2. * intersection + smooth) / (pred.sum() + target.sum() + smooth)) 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /sklearn_metrics: -------------------------------------------------------------------------------- 1 | from sklearn.metrics import accuracy_score, precision_score,recall_score,f1_score 2 | 3 | def metrics(preds,label): 4 | accuracy = accuracy_score ( preds, label ) 5 | precision = precision_score(preds,label,average='macro') 6 | recall = recall_score ( preds, label, average='macro' ) 7 | f1 = f1_score(preds, label) 8 | return accuracy, precision, recall, f1 9 | -------------------------------------------------------------------------------- /utils: -------------------------------------------------------------------------------- 1 | import os 2 | import errno 3 | import sys 4 | import utils 5 | 6 | def mkdir_if_missing(directory): 7 | if not os.path.exists(directory): 8 | try: 9 | os.makedirs(directory) 10 | except OSError as e: 11 | if e.error != errno.EEXIST: 12 | raise 13 | 14 | 15 | class Logger(object): 16 | ''' 17 | Write console output to external text file. 18 | usage: 19 | sys.stdout = utils.Logger( 20 | os.path.join(save_dir, 'log_train-%s.txt' % time.strftime("%Y-%m-%d-%H-%M-%S"))) 21 | ''' 22 | def __init__(self, fpath=None): 23 | self.console = sys.stdout 24 | self.file = None 25 | if fpath is not None: 26 | mkdir_if_missing(os.path,dirname(fpath)) 27 | self.file = open(fpath,'w') 28 | 29 | def __del__(self): 30 | self.close() 31 | 32 | def __enter__(self): 33 | pass 34 | 35 | def __exit__(self, *args): 36 | self.close() 37 | 38 | def write(self,mag): 39 | self.console.write(msg) 40 | if self.file is not NOne: 41 | self.file.write(msg) 42 | 43 | def flush(self): 44 | self.console.flush() 45 | if self.file is not None: 46 | self.file.flush() 47 | os.fsync(self.file.fileno()) 48 | 49 | def close(self): 50 | self.console.close() 51 | if self.file is not None: 52 | self.file.close() 53 | 54 | if use_gpu: 55 | state_dict = model.module.state_dict() 56 | else: 57 | state_dict = model.state_dict() 58 | 59 | def save_checkpoint(state,fpath='checkpoint.pth.tar'): 60 | mkdir_if_missing(os.path.dirname(fpath)) 61 | torch.save(state,fpath) 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /warmup-cosine-lr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | from torch.optim.lr_scheduler import _LRScheduler 4 | from torch.optim.lr_scheduler import ReduceLROnPlateau 5 | import torch 6 | import matplotlib.pyplot as plt 7 | 8 | class GradualWarmupScheduler(_LRScheduler): 9 | def __init__(self, optimizer, multiplier, total_epoch, after_scheduler=None): 10 | self.multiplier = multiplier 11 | self.total_epoch = total_epoch 12 | self.after_scheduler = after_scheduler 13 | self.finished = False 14 | # python2 版本 15 | super (GradualWarmupScheduler,self ).__init__ ( optimizer ) 16 | # python3 版本 17 | # super ( ).__init__ ( optimizer ) # 18 | 19 | def get_lr(self): 20 | if self.last_epoch > self.total_epoch: 21 | if self.after_scheduler: 22 | if not self.finished: 23 | self.after_scheduler.base_lrs = [base_lr * self.multiplier for base_lr in self.base_lrs] 24 | self.finished = True 25 | return self.after_scheduler.get_lr() 26 | return [base_lr * self.multiplier for base_lr in self.base_lrs] 27 | 28 | return [base_lr * ((self.multiplier - 1.) * self.last_epoch / self.total_epoch + 1.) for base_lr in self.base_lrs] 29 | 30 | 31 | def step(self, epoch=None, metrics=None): 32 | if self.finished and self.after_scheduler: 33 | if epoch is None: 34 | self.after_scheduler.step(None) 35 | else: 36 | self.after_scheduler.step(epoch - self.total_epoch) 37 | else: 38 | return super(GradualWarmupScheduler, self).step(epoch) 39 | 40 | if __name__ == '__main__': 41 | v = torch.zeros(10) 42 | optim = torch.optim.SGD([v], lr=0.01) 43 | cosine_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optim, 200, eta_min=0, last_epoch=-1) 44 | scheduler = GradualWarmupScheduler(optim, multiplier=8, total_epoch=5, after_scheduler=cosine_scheduler) 45 | a = [] 46 | b = [] 47 | for epoch in range(1, 200): 48 | scheduler.step(epoch) 49 | a.append(epoch) 50 | b.append(optim.param_groups[0]['lr']) 51 | print(epoch, optim.param_groups[0]['lr']) 52 | 53 | plt.plot(a,b) 54 | plt.show() 55 | --------------------------------------------------------------------------------