├── .gitignore ├── teaser.png ├── voc12 ├── cls_labels.npy ├── train_label.npy ├── 20_class_labels.npy ├── voc12_category_list.txt ├── data.py └── test.txt ├── utils.py ├── LICENSE ├── tool ├── camutils.py ├── iouutils.py ├── metric.py ├── pyutils.py ├── torchutils.py ├── imutils.py └── infer_utils.py ├── script.sh ├── network ├── resnet38_cls.py └── resnet38d.py ├── extract_feature.py ├── README.md ├── infer_cls.py ├── create_pseudo_label.py └── train_cls.py /.gitignore: -------------------------------------------------------------------------------- 1 | README_.md 2 | -------------------------------------------------------------------------------- /teaser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juliachang/SC-CAM/HEAD/teaser.png -------------------------------------------------------------------------------- /voc12/cls_labels.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juliachang/SC-CAM/HEAD/voc12/cls_labels.npy -------------------------------------------------------------------------------- /voc12/train_label.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juliachang/SC-CAM/HEAD/voc12/train_label.npy -------------------------------------------------------------------------------- /voc12/20_class_labels.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juliachang/SC-CAM/HEAD/voc12/20_class_labels.npy -------------------------------------------------------------------------------- /voc12/voc12_category_list.txt: -------------------------------------------------------------------------------- 1 | background 2 | aeroplane 3 | bicycle 4 | bird 5 | boat 6 | bottle 7 | bus 8 | car 9 | cat 10 | chair 11 | cow 12 | diningtable 13 | dog 14 | horse 15 | motorbike 16 | person 17 | pottedplant 18 | sheep 19 | sofa 20 | train 21 | tvmonitor 22 | 23 | and 255 is the ignore label that marks pixels excluded from learning and 24 | evaluation by the PASCAL VOC ground truth. 25 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | from PIL import Image 4 | 5 | 6 | def find_crop_img_label_class_index(): 7 | with open('crop/crop_img_feature/crop_image_filename_list.txt', 'r') as f: 8 | crop_image_filename_list = f.read().split('\n') 9 | f.close() 10 | crop_img_filename_list = crop_image_filename_list[:-1] 11 | 12 | crop_img_label_list = np.load('crop/crop_img_feature/crop_img_label.npy') 13 | print(len(crop_img_filename_list), crop_img_label_list.shape[0]) 14 | 15 | class_dict = {} 16 | for i in range(20): 17 | class_idx_list = np.where(crop_img_label_list == i)[0] 18 | class_dict[i] = class_idx_list 19 | 20 | return class_dict 21 | 22 | class_dict = find_crop_img_label_class_index() 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 juliachang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tool/camutils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from PIL import Image 3 | import matplotlib.pyplot as plt 4 | 5 | 6 | def draw_heatmap(img, hm): 7 | hm = (hm - np.min(hm)) / (np.max(hm) - np.min(hm)) 8 | hm = plt.cm.hot(hm)[:, :, :3] 9 | hm = np.array(Image.fromarray((hm*255).astype(np.uint8), 'RGB').resize((img.shape[1], img.shape[0]), Image.BICUBIC)).astype(np.float)*2 10 | if hm.shape == np.array(img).astype(np.float).shape: 11 | out = (hm + np.array(img).astype(np.float)) / 3 12 | out = Image.fromarray((out / np.max(out) * 255).astype(np.uint8), 'RGB') 13 | return hm, out 14 | 15 | 16 | def dict2npy(cam_dict, gt_label, th): 17 | # gt_cat = np.where(gt_label==1)[0] 18 | # orig_img_size = cam_dict[gt_cat[0]].shape 19 | orig_img_size = cam_dict[gt_label[0]].shape 20 | 21 | 22 | bg_score = [np.ones_like(cam_dict[gt_label[0]])*th] 23 | cam_npy = np.zeros((20, orig_img_size[0], orig_img_size[1])) 24 | # print(cam_npy.shape) # (20, 366, 500) 25 | 26 | for gt in gt_label: 27 | cam_npy[gt] = cam_dict[gt] 28 | 29 | cam_npy = np.concatenate((bg_score, cam_npy), axis=0) 30 | # print(cam_npy.shape) # (21, 366, 500) 31 | return cam_npy 32 | 33 | 34 | def cam_npy_to_label_map(cam_npy): 35 | seg_map = cam_npy.transpose(1,2,0) 36 | seg_map = np.asarray(np.argmax(seg_map, axis=2), dtype=np.int) 37 | # print(seg_map.shape, np.unique(seg_map)) 38 | return seg_map 39 | -------------------------------------------------------------------------------- /tool/iouutils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | 4 | 5 | CAT_LIST = ['background', 'aeroplane', 'bicycle', 'bird', 'boat', 6 | 'bottle', 'bus', 'car', 'cat', 'chair', 7 | 'cow', 'diningtable', 'dog', 'horse', 8 | 'motorbike', 'person', 'pottedplant', 9 | 'sheep', 'sofa', 'train', 10 | 'tvmonitor', 'meanIOU'] 11 | 12 | def _fast_hist(label_true, label_pred, n_class): 13 | mask = (label_true >= 0) & (label_true < n_class) 14 | hist = np.bincount( 15 | n_class * label_true[mask].astype(int) + label_pred[mask], 16 | minlength=n_class ** 2, 17 | ).reshape(n_class, n_class) 18 | return hist 19 | 20 | 21 | 22 | def scores(label_trues, label_preds, n_class): 23 | hist = np.zeros((n_class, n_class)) 24 | for lt, lp in zip(label_trues, label_preds): 25 | hist += _fast_hist(lt.flatten(), lp.flatten(), n_class) 26 | acc = np.diag(hist).sum() / hist.sum() 27 | acc_cls = np.diag(hist) / hist.sum(axis=1) 28 | acc_cls = np.nanmean(acc_cls) 29 | iu = np.diag(hist) / (hist.sum(axis=1) + hist.sum(axis=0) - np.diag(hist)) 30 | valid = hist.sum(axis=1) > 0 # added 31 | mean_iu = np.nanmean(iu[valid]) 32 | freq = hist.sum(axis=1) / hist.sum() 33 | fwavacc = (freq[freq > 0] * iu[freq > 0]).sum() 34 | cls_iu = dict(zip(range(n_class), iu)) 35 | 36 | return { 37 | "Pixel Accuracy": acc, 38 | "Mean Accuracy": acc_cls, 39 | "Frequency Weighted IoU": fwavacc, 40 | "Mean IoU": mean_iu, 41 | "Class IoU": cls_iu, 42 | } 43 | 44 | 45 | def record_score(score, save_path, iou_type): 46 | score_list = [] 47 | 48 | for i in range(21): 49 | score_list.append(score['Class IoU'][i]) 50 | aveJ = score['Mean IoU'] 51 | 52 | with open('{}/iou_{}.txt'.format(save_path, iou_type), 'w') as f: 53 | for num, cls_iou in enumerate(score_list): 54 | print('class {:2d} {:12} IU {:.2f}'.format(num, CAT_LIST[num], round(cls_iou, 3))) 55 | f.write('class {:2d} {:12} IU {:.2f}'.format(num, CAT_LIST[num], round(cls_iou, 3)) + '\n') 56 | print('meanIOU: ' + str(aveJ) + '\n') 57 | f.write('meanIOU: ' + str(aveJ) + '\n') 58 | -------------------------------------------------------------------------------- /script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## 1) [Required] Please specify the path to the PSCAL VOC 2012 dataset (e.g., ~/datasets/VOCdevkit/VOC2012/) 4 | dataset_folder=path_to_dataset_folder 5 | ## 2) [Required] Please specify the path to the folder to save the feature/label/weight (e.g., ./save) 6 | save_folder=path_to_the_folder_for_saving_output_results 7 | ## 3) Please specify the path to the pretrained weight (It is default to save in the folder named weights) 8 | pretrained_model=./weights/ilsvrc-cls_rna-a1_cls1000_ep-0001.params 9 | 10 | ## 4) Please specify the path to the model for each round 11 | R1_extractor_model=./weights/res38_cls.pth 12 | R2_extractor_model=${save_folder}/weight/k10_R1_resnet_cls_ep30.pth 13 | R3_extractor_model=${save_folder}/weight/k10_R2_resnet_cls_ep40.pth 14 | final_model=${save_folder}/weight/k10_R3_resnet_cls_ep50.pth \ 15 | 16 | ## 5) Please specify the path to save the generated response map 17 | save_cam_folder=${save_folder}/final_result 18 | 19 | 20 | 21 | 22 | ## R1 23 | # Extract the feature 24 | python extract_feature.py --weights ${R1_extractor_model} --infer_list ./voc12/train_aug.txt --voc12_root ${dataset_folder} --save_folder ${save_folder} --k_cluster 10 --from_round_nb 0 25 | # Generate the pseudo label 26 | python create_pseudo_label.py --save_folder ${save_folder} --k_cluster 10 --for_round_nb 1 27 | # Train the classifier 28 | python train_cls.py --lr 0.01 --voc12_root ${dataset_folder} --weights ${pretrained_model} --round_nb 1 --save_folder ${save_folder} 29 | 30 | 31 | 32 | ## R2 33 | # Extract the feature 34 | python extract_feature.py --weights ${R2_extractor_model} --infer_list ./voc12/train_aug.txt --voc12_root ${dataset_folder} --save_folder ${save_folder} --k_cluster 10 --from_round_nb 1 35 | # Generate the pseudo label 36 | python create_pseudo_label.py --save_folder ${save_folder} --k_cluster 10 --for_round_nb 2 37 | # Train the classifier 38 | python train_cls.py --lr 0.01 --voc12_root ${dataset_folder} --weights ${pretrained_model} --round_nb 2 --save_folder ${save_folder} 39 | 40 | 41 | 42 | ## R3 43 | # Extract the feature 44 | python extract_feature.py --weights ${R3_extractor_model} --infer_list ./voc12/train_aug.txt --voc12_root ${dataset_folder} --save_folder ${save_folder} --k_cluster 10 --from_round_nb 2 45 | # Generate the pseudo label 46 | python create_pseudo_label.py --save_folder ${save_folder} --k_cluster 10 --for_round_nb 3 47 | # Train the classifier 48 | python train_cls.py --lr 0.01 --voc12_root ${dataset_folder} --weights ${pretrained_model} --round_nb 3 --save_folder ${save_folder} 49 | 50 | 51 | 52 | ## Infer the classifier and generate the response map with the final model 53 | python infer_cls.py --infer_list voc12/train.txt --voc12_root ${dataset_folder} --weights ${final_model} --save_path ${save_cam_folder} --save_out_cam 1 --k_cluster 10 --round_nb 3 54 | -------------------------------------------------------------------------------- /tool/metric.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | import numpy as np 3 | 4 | from multiprocessing import Pool 5 | import copy_reg 6 | import types 7 | def _pickle_method(m): 8 | if m.im_self is None: 9 | return getattr, (m.im_class, m.im_func.func_name) 10 | else: 11 | return getattr, (m.im_self, m.im_func.func_name) 12 | 13 | copy_reg.pickle(types.MethodType, _pickle_method) 14 | 15 | class ConfusionMatrix(object): 16 | 17 | def __init__(self, nclass, classes=None): 18 | self.nclass = nclass 19 | self.classes = classes 20 | self.M = np.zeros((nclass, nclass)) 21 | 22 | def add(self, gt, pred): 23 | assert(np.max(pred) <= self.nclass) 24 | assert(len(gt) == len(pred)) 25 | for i in range(len(gt)): 26 | if not gt[i] == 255: 27 | self.M[gt[i], pred[i]] += 1.0 28 | 29 | def addM(self, matrix): 30 | assert(matrix.shape == self.M.shape) 31 | self.M += matrix 32 | 33 | def __str__(self): 34 | pass 35 | 36 | def recall(self): 37 | recall = 0.0 38 | for i in xrange(self.nclass): 39 | recall += self.M[i, i] / np.sum(self.M[:, i]) 40 | 41 | return recall/self.nclass 42 | 43 | def accuracy(self): 44 | accuracy = 0.0 45 | for i in xrange(self.nclass): 46 | accuracy += self.M[i, i] / np.sum(self.M[i, :]) 47 | 48 | return accuracy/self.nclass 49 | 50 | def jaccard(self): 51 | jaccard = 0.0 52 | jaccard_perclass = [] 53 | for i in xrange(self.nclass): 54 | if not self.M[i, i] == 0: 55 | jaccard_perclass.append(self.M[i, i] / (np.sum(self.M[i, :]) + np.sum(self.M[:, i]) - self.M[i, i])) 56 | 57 | return np.sum(jaccard_perclass)/len(jaccard_perclass), jaccard_perclass, self.M 58 | 59 | def generateM(self, item): 60 | gt, pred = item 61 | m = np.zeros((self.nclass, self.nclass)) 62 | assert(len(gt) == len(pred)) 63 | for i in range(len(gt)): 64 | if gt[i] < self.nclass: #and pred[i] < self.nclass: 65 | m[gt[i], pred[i]] += 1.0 66 | return m 67 | 68 | 69 | if __name__ == '__main__': 70 | args = parse_args() 71 | 72 | m_list = [] 73 | data_list = [] 74 | test_ids = [i.strip() for i in open(args.test_ids) if not i.strip() == ''] 75 | for index, img_id in enumerate(test_ids): 76 | if index % 100 == 0: 77 | print('%d processd'%(index)) 78 | pred_img_path = os.path.join(args.pred_dir, img_id+'.png') 79 | gt_img_path = os.path.join(args.gt_dir, img_id+'.png') 80 | pred = cv2.imread(pred_img_path, cv2.IMREAD_GRAYSCALE) 81 | gt = cv2.imread(gt_img_path, cv2.IMREAD_GRAYSCALE) 82 | # show_all(gt, pred) 83 | data_list.append([gt.flatten(), pred.flatten()]) 84 | 85 | ConfM = ConfusionMatrix(args.class_num) 86 | f = ConfM.generateM 87 | pool = Pool() 88 | m_list = pool.map(f, data_list) 89 | pool.close() 90 | pool.join() 91 | 92 | for m in m_list: 93 | ConfM.addM(m) 94 | 95 | aveJ, j_list, M = ConfM.jaccard() 96 | with open(args.save_path, 'w') as f: 97 | f.write('meanIOU: ' + str(aveJ) + '\n') 98 | f.write(str(j_list)+'\n') 99 | f.write(str(M)+'\n') 100 | -------------------------------------------------------------------------------- /network/resnet38_cls.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | import pdb 5 | import numpy as np 6 | 7 | import network.resnet38d 8 | 9 | 10 | class Net(network.resnet38d.Net): 11 | def __init__(self, k_cluster, from_round_nb): 12 | super().__init__() 13 | 14 | self.k = k_cluster 15 | self.from_round_nb = from_round_nb 16 | print('k_cluster: {}'.format(self.k)) 17 | print('Round: {}'.format(self.from_round_nb)) 18 | 19 | self.dropout7 = torch.nn.Dropout2d(0.5) 20 | 21 | # class 20 22 | if self.from_round_nb == 0: 23 | self.fc8 = nn.Conv2d(4096, 20, 1, bias=False) 24 | 25 | torch.nn.init.xavier_uniform_(self.fc8.weight) 26 | 27 | self.not_training = [self.conv1a, self.b2, self.b2_1, self.b2_2] 28 | self.from_scratch_layers = [self.fc8] 29 | 30 | 31 | # class 20 + class 200 32 | else: 33 | self.fc8_20 = nn.Conv2d(4096, 20, 1, bias=False) 34 | self.fc8_200 = nn.Conv2d(4096, self.k*20, 1, bias=False) 35 | 36 | torch.nn.init.xavier_uniform_(self.fc8_20.weight) 37 | torch.nn.init.xavier_uniform_(self.fc8_200.weight) 38 | 39 | self.not_training = [self.conv1a, self.b2, self.b2_1, self.b2_2] 40 | self.from_scratch_layers = [self.fc8_20, self.fc8_200] 41 | 42 | 43 | 44 | def forward(self, x, from_round_nb): 45 | x = super().forward(x) 46 | x = self.dropout7(x) 47 | x = F.avg_pool2d(x, kernel_size=(x.size(2), x.size(3)), padding=0) 48 | 49 | feature = x 50 | feature = feature.view(feature.size(0), -1) 51 | 52 | # class 20 53 | if from_round_nb == 0: 54 | x = self.fc8(x) 55 | x = x.view(x.size(0), -1) 56 | y = torch.sigmoid(x) 57 | return x, feature, y 58 | 59 | # class 20 + class 200 60 | else: 61 | x_20 = self.fc8_20(x) 62 | x_20 = x_20.view(x_20.size(0), -1) 63 | y_20 = torch.sigmoid(x_20) 64 | 65 | 66 | x_200 = self.fc8_200(x) 67 | x_200 = x_200.view(x_200.size(0), -1) 68 | y_200 = torch.sigmoid(x_200) 69 | 70 | return x_20, feature, y_20, x_200, y_200 71 | 72 | 73 | 74 | def multi_label(self, x): 75 | x = torch.sigmoid(x) 76 | tmp = x.cpu() 77 | tmp = tmp.data.numpy() 78 | _, cls = np.where(tmp>0.5) 79 | 80 | return cls, tmp 81 | 82 | 83 | def forward_cam(self, x): 84 | x = super().forward(x) 85 | x = F.conv2d(x, self.fc8.weight) 86 | x = F.relu(x) 87 | 88 | return x 89 | 90 | 91 | def forward_two_cam(self, x): 92 | x_ = super().forward(x) 93 | 94 | x_20 = F.conv2d(x_, self.fc8_20.weight) 95 | cam_20 = F.relu(x_20) 96 | 97 | x_200 = F.conv2d(x_, self.fc8_200.weight) 98 | cam_200 = F.relu(x_200) 99 | 100 | return cam_20, cam_200 101 | 102 | def get_parameter_groups(self): 103 | groups = ([], [], [], []) 104 | 105 | for m in self.modules(): 106 | 107 | if isinstance(m, nn.Conv2d): 108 | 109 | if m.weight.requires_grad: 110 | if m in self.from_scratch_layers: 111 | groups[2].append(m.weight) 112 | else: 113 | groups[0].append(m.weight) 114 | 115 | if m.bias is not None and m.bias.requires_grad: 116 | 117 | if m in self.from_scratch_layers: 118 | groups[3].append(m.bias) 119 | else: 120 | groups[1].append(m.bias) 121 | 122 | return groups 123 | -------------------------------------------------------------------------------- /extract_feature.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torch.nn as nn 4 | from torch.backends import cudnn 5 | cudnn.enabled = True 6 | import voc12.data 7 | import scipy.misc 8 | import importlib 9 | from torch.utils.data import DataLoader 10 | import torchvision 11 | from tool import imutils, pyutils 12 | import argparse 13 | from PIL import Image 14 | import torch.nn.functional as F 15 | import os 16 | import matplotlib.pyplot as plt 17 | 18 | 19 | 20 | def make_folder(save_folder_path): 21 | if os.path.exists(save_folder_path) == False: 22 | os.mkdir(save_folder_path) 23 | if os.path.exists(os.path.join(save_folder_path, 'feature')) == False: 24 | os.mkdir(os.path.join(save_folder_path, 'feature')) 25 | if os.path.exists(os.path.join(save_folder_path, 'label')) == False: 26 | os.mkdir(os.path.join(save_folder_path, 'label')) 27 | if os.path.exists(os.path.join(save_folder_path, 'log')) == False: 28 | os.mkdir(os.path.join(save_folder_path, 'log')) 29 | if os.path.exists(os.path.join(save_folder_path, 'weight')) == False: 30 | os.mkdir(os.path.join(save_folder_path, 'weight')) 31 | 32 | 33 | if __name__ == '__main__': 34 | 35 | parser = argparse.ArgumentParser() 36 | parser.add_argument("--weights", required=True, default="./weights/res38_cls.pth", type=str, help="the weight of the model") 37 | parser.add_argument("--network", default="network.resnet38_cls", type=str, help="the network of the classifier") 38 | parser.add_argument("--infer_list", default="voc12/val.txt", type=str, help="the filename list for feature extraction") 39 | parser.add_argument("--num_workers", default=8, type=int) 40 | parser.add_argument("--voc12_root", default="/home/julia/datasets/VOC2012", type=str, help="the path to the dataset folder") 41 | parser.add_argument("--from_round_nb", required=True, default=None, type=int, help="the round number of the extracter, e.g., 1st round: from_round_nb=0, 2nd round: from_round_nb=1, and so on") 42 | parser.add_argument("--k_cluster", default=10, type=int, help="the number of the sub-category") 43 | parser.add_argument("--save_folder", required=True, default='./save', type=str, help="the path to save the extracted feature") 44 | 45 | args = parser.parse_args() 46 | 47 | make_folder(args.save_folder) 48 | 49 | model = getattr(importlib.import_module(args.network), 'Net')(args.k_cluster, args.from_round_nb) 50 | model.load_state_dict(torch.load(args.weights)) 51 | 52 | model.eval() 53 | model.cuda() 54 | 55 | infer_dataset = voc12.data.VOC12ClsDatasetMSF(args.infer_list, voc12_root=args.voc12_root, 56 | scales=(1, 0.5, 1.5, 2.0), 57 | inter_transform=torchvision.transforms.Compose( 58 | [np.asarray, 59 | model.normalize, 60 | imutils.HWC_to_CHW 61 | ])) 62 | 63 | infer_data_loader = DataLoader(infer_dataset, shuffle=False, num_workers=args.num_workers, pin_memory=True) 64 | 65 | n_gpus = torch.cuda.device_count() 66 | model_replicas = torch.nn.parallel.replicate(model, list(range(n_gpus))) 67 | 68 | filename_list = [] 69 | image_feature_list = [] 70 | 71 | print('################################ Exteacting features from Round-{} ...... ################################'.format(args.from_round_nb)) 72 | 73 | for iter, (img_name, img_list, label) in enumerate(infer_data_loader): 74 | img_name = img_name[0] 75 | 76 | filename_list.append(img_name) 77 | 78 | # extract feature 79 | if args.from_round_nb == 0: 80 | tmp, feature, _ = model.forward(img_list[0].cuda(), args.from_round_nb) 81 | else: 82 | tmp, feature, y_20, x_200, y_200 = model.forward(img_list[0].cuda(), args.from_round_nb) 83 | 84 | feature = feature[0].cpu().detach().numpy() 85 | image_feature_list.append(feature) 86 | 87 | if iter % 500 == 0: 88 | print('Already extracted: {}/{}'.format(iter, len(infer_data_loader))) 89 | 90 | 91 | image_feature_list = np.array(image_feature_list) 92 | print(image_feature_list.shape) 93 | 94 | # save the extracted feature 95 | save_feature_folder_path = os.path.join(args.save_folder, 'feature') 96 | feature_save_path = os.path.join(save_feature_folder_path, 'R{}_feature.npy'.format(args.from_round_nb)) # R1 feature is for R2 use 97 | np.save(feature_save_path, image_feature_list) 98 | -------------------------------------------------------------------------------- /tool/pyutils.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import time 4 | import sys 5 | 6 | class Logger(object): 7 | def __init__(self, outfile): 8 | self.terminal = sys.stdout 9 | self.log = open(outfile, "w") 10 | sys.stdout = self 11 | 12 | def write(self, message): 13 | self.terminal.write(message) 14 | self.log.write(message) 15 | 16 | def flush(self): 17 | self.terminal.flush() 18 | 19 | 20 | class AverageMeter: 21 | def __init__(self, *keys): 22 | self.__data = dict() 23 | for k in keys: 24 | self.__data[k] = [0.0, 0] 25 | 26 | def add(self, dict): 27 | for k, v in dict.items(): 28 | self.__data[k][0] += v 29 | self.__data[k][1] += 1 30 | 31 | def get(self, *keys): 32 | if len(keys) == 1: 33 | return self.__data[keys[0]][0] / self.__data[keys[0]][1] 34 | else: 35 | v_list = [self.__data[k][0] / self.__data[k][1] for k in keys] 36 | return tuple(v_list) 37 | 38 | def pop(self, key=None): 39 | if key is None: 40 | for k in self.__data.keys(): 41 | self.__data[k] = [0.0, 0] 42 | else: 43 | v = self.get(key) 44 | self.__data[key] = [0.0, 0] 45 | return v 46 | 47 | 48 | class Timer: 49 | def __init__(self, starting_msg = None): 50 | self.start = time.time() 51 | self.stage_start = self.start 52 | 53 | if starting_msg is not None: 54 | print(starting_msg, time.ctime(time.time())) 55 | 56 | 57 | def update_progress(self, progress): 58 | self.elapsed = time.time() - self.start 59 | self.est_total = self.elapsed / progress 60 | self.est_remaining = self.est_total - self.elapsed 61 | self.est_finish = int(self.start + self.est_total) 62 | 63 | 64 | def str_est_finish(self): 65 | return str(time.ctime(self.est_finish)) 66 | 67 | def get_stage_elapsed(self): 68 | return time.time() - self.stage_start 69 | 70 | def reset_stage(self): 71 | self.stage_start = time.time() 72 | 73 | 74 | from multiprocessing.pool import ThreadPool 75 | 76 | class BatchThreader: 77 | 78 | # def __init__(self, func, args_list, batch_size, prefetch_size=4, processes=12): 79 | def __init__(self, func, args_list, batch_size, prefetch_size=4, processes=1): 80 | self.batch_size = batch_size 81 | self.prefetch_size = prefetch_size 82 | 83 | self.pool = ThreadPool(processes=processes) 84 | self.async_result = [] 85 | 86 | self.func = func 87 | self.left_args_list = args_list 88 | self.n_tasks = len(args_list) 89 | 90 | # initial work 91 | self.__start_works(self.__get_n_pending_works()) 92 | 93 | 94 | def __start_works(self, times): 95 | for _ in range(times): 96 | args = self.left_args_list.pop(0) 97 | self.async_result.append( 98 | self.pool.apply_async(self.func, args)) 99 | 100 | 101 | def __get_n_pending_works(self): 102 | return min((self.prefetch_size + 1) * self.batch_size - len(self.async_result) 103 | , len(self.left_args_list)) 104 | 105 | 106 | 107 | def pop_results(self): 108 | 109 | n_inwork = len(self.async_result) 110 | 111 | n_fetch = min(n_inwork, self.batch_size) 112 | rtn = [self.async_result.pop(0).get() 113 | for _ in range(n_fetch)] 114 | 115 | to_fill = self.__get_n_pending_works() 116 | if to_fill == 0: 117 | self.pool.close() 118 | else: 119 | self.__start_works(to_fill) 120 | 121 | return rtn 122 | 123 | 124 | 125 | 126 | def get_indices_of_pairs(radius, size): 127 | 128 | search_dist = [] 129 | 130 | for x in range(1, radius): 131 | search_dist.append((0, x)) 132 | 133 | for y in range(1, radius): 134 | for x in range(-radius + 1, radius): 135 | if x * x + y * y < radius * radius: 136 | search_dist.append((y, x)) 137 | 138 | radius_floor = radius - 1 139 | 140 | full_indices = np.reshape(np.arange(0, size[0]*size[1], dtype=np.int64), 141 | (size[0], size[1])) 142 | 143 | cropped_height = size[0] - radius_floor 144 | cropped_width = size[1] - 2 * radius_floor 145 | 146 | indices_from = np.reshape(full_indices[:-radius_floor, radius_floor:-radius_floor], 147 | [-1]) 148 | 149 | indices_to_list = [] 150 | 151 | for dy, dx in search_dist: 152 | indices_to = full_indices[dy:dy + cropped_height, 153 | radius_floor + dx:radius_floor + dx + cropped_width] 154 | indices_to = np.reshape(indices_to, [-1]) 155 | 156 | indices_to_list.append(indices_to) 157 | 158 | concat_indices_to = np.concatenate(indices_to_list, axis=0) 159 | 160 | return indices_from, concat_indices_to 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Weakly-Supervised Semantic Segmentation via Sub-category Exploration 2 | ![outline](teaser.png) 3 | 4 | 5 | 6 | ## Introduction 7 | The code and trained models of: 8 | 9 | **Weakly-Supervised Semantic Segmentation via Sub-category Exploration, [Yu-Ting Chang](https://scholar.google.com/citations?user=5LRrNYgAAAAJ&hl=en), [Qiaosong Wang](https://scholar.google.com/citations?user=uiTAQLEAAAAJ&hl=en), [Wei-Chih Hung](https://scholar.google.com/citations?user=AjaDLjYAAAAJ&hl=en), [Robinson Piramuthu](https://scholar.google.com/citations?user=2CkqEGcAAAAJ&hl=nl), [Yi-Hsuan Tsai](https://scholar.google.com/citations?user=zjI51wEAAAAJ&hl=en) and [Ming-Hsuan Yang](https://scholar.google.com/citations?user=p9-ohHsAAAAJ&hl=en), CVPR 2020** [[Paper]](https://arxiv.org/abs/2008.01183) 10 | 11 | 12 | We develope a framework to generate semantic segmentation labels of images given their image-level class labels only. We propose a simple yet effective approach to improve the class activation maps by introducing a self-supervised task to discover sub-categories in an unsupervised manner. Our algorithm produces better activation maps, thereby improving the final semantic segmentation performance. 13 | 14 | 15 | 16 | ## Citation 17 | If you find the code useful, please consider citing our paper using the following BibTeX entry. 18 | ``` 19 | @InProceedings{Chang_2020_CVPR, 20 | author = {Chang, Yu-Ting and Wang, Qiaosong and Hung, Wei-Chih and Piramuthu, Robinson and Tsai, Yi-Hsuan and Yang, Ming-Hsuan}, 21 | title = {Weakly-Supervised Semantic Segmentation via Sub-category Exploration}, 22 | booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, 23 | year = {2020} 24 | } 25 | ``` 26 | 27 | 28 | ## Prerequisite 29 | * Tested on Ubuntu 14.04, with Python 3.5, PyTorch 1.0.1, Torchvision 0.2.2, CUDA 9.0, and 1x NVIDIA TITAN X GPU. 30 | * [The PASCAL VOC 2012 development kit](http://host.robots.ox.ac.uk/pascal/VOC/voc2012/): 31 | You need to specify the path ('voc12_root') of your downloaded dev kit. 32 | * To extract the feature for the first round training, you need to download the pretrained weight of the [AffinityNet](https://github.com/jiwoon-ahn/psa) [[res38_cls.pth]](https://drive.google.com/file/d/1xESB7017zlZHqxEWuh1Rb89UhjTGIKOA/view?usp=sharing) 33 | * To train the classification model, you need to download the pretrained weight of the [Mxnet and ResNet-38](https://github.com/itijyou/ademxapp) model [[ilsvrc-cls_rna-a1_cls1000_ep-0001.params]](https://drive.google.com/file/d/1YB3DkHiBeUH5wn6shk93jChvXwfOxwBE/view?usp=sharing) 34 | * Please create a folder named weights and save pretrained models in the folder. 35 | 36 | 37 | 38 | ## Usage 39 | ### Run the whole pipeline 40 | - We iteratively train the model with three rounds to achieve the best performance. You can directly run script.sh to complete the three-round training. 41 | - [Note] To run the whole pipeline, you need to specify the path to the saved model for each round. Please see the command in script.sh. 42 | ``` 43 | bash script.sh 44 | ``` 45 | 46 | ### Run each step 47 | - The iteratively training process includes the step of feature extraction, sub-category label generation, and classification model training. You can use following scripts to run each step. 48 | - [Note] Please specify the argument in the command. You can also check script.sh to see more details. 49 | 50 | #### 1. Extract the feature from the model 51 | ``` 52 | bash python extract_feature.py --weights [your_weights_file] --infer_list ./voc12/train_aug.txt --voc12_root [your_voc12_root_folder] --save_folder [your_save_folder] --from_round_nb [round_number] 53 | ``` 54 | 55 | #### 2. Generate sub-category labels 56 | ``` 57 | bash python create_pseudo_label.py --save_folder [your_save_folder] --k_cluster 10 --for_round_nb [round_number] 58 | ``` 59 | 60 | #### 3. Train the classification model with the parent label and the sub-category label 61 | ``` 62 | bash python train_cls.py --lr 0.01 --voc12_root [your_voc12_root_folder] --weights [your_weights_file] --round_nb [round_number] --save_folder [your_save_folder] 63 | ``` 64 | 65 | ### Infer the classifier and obtain the response map 66 | - With the classification model, you can infer the classifier and generate the response map 67 | ``` 68 | bash python infer_cls.py --infer_list voc12/train.txt --voc12_root [your_voc12_root_folder] --weights [your_weights_file] --save_path [your_save_cam_folder] --save_out_cam 1 --round_nb [round_number] 69 | ``` 70 | 71 | 72 | 73 | ## Results and Trained Models 74 | #### Class Activation Map 75 | 76 | | Model | Train (mIoU) | Val (mIoU) | | 77 | | ------------- |:-------------:|:-----:|:-----:| 78 | | ResNet-38 | 50.9 | 49.6 | [[Weights]](https://drive.google.com/file/d/1Qgd7bC8YnfBs02fdwwMIji9s9xnX7jAt/view?usp=sharing) | 79 | 80 | 81 | 82 | ## Refinement and segmentation network 83 | * Refinement: We adopt the random walk method via affinity to refine the map as pixel-wise pseudo ground truths for semantic segmentation. Please refer to [the repo of AffinityNet](https://github.com/jiwoon-ahn/psa) [1]. 84 | * Segmentation network: We utilize the Deeplab-v2 framework [2] with the ResNet-101 architecture [3] as the 85 | backbone model to train the segmentation network. Please refer to [the repo](https://github.com/kazuto1011/deeplab-pytorch). 86 | 87 | 88 | 89 | ## Reference 90 | 1. Jiwoon Ahn and Suha Kwak. Learning pixel-level semantic affinity with image-level supervision for weakly supervised semantic segmentation. CVPR, 2018. 91 | 2. Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, Kevin Murphy, and Alan L Yuille. Deeplab: Semantic image segmentation with deep convolutional nets, atrous convolution, and fully connected crfs. TPAMI, 2017. 92 | 3. Kaiming He, Xiangyu Zhang, Shaoqing Ren, and Jian Sun. Deep residual learning for image recognition. CVPR, 2016. 93 | -------------------------------------------------------------------------------- /tool/torchutils.py: -------------------------------------------------------------------------------- 1 | 2 | import torch 3 | from torch.utils.data import Dataset 4 | from PIL import Image 5 | import os.path 6 | import random 7 | import numpy as np 8 | from tool import imutils 9 | 10 | class PolyOptimizer(torch.optim.SGD): 11 | 12 | def __init__(self, params, lr, weight_decay, max_step, momentum=0.9): 13 | super().__init__(params, lr, weight_decay) 14 | 15 | self.global_step = 0 16 | self.max_step = max_step 17 | self.momentum = momentum 18 | 19 | self.__initial_lr = [group['lr'] for group in self.param_groups] 20 | 21 | 22 | def step(self, closure=None): 23 | 24 | if self.global_step < self.max_step: 25 | lr_mult = (1 - self.global_step / self.max_step) ** self.momentum 26 | 27 | for i in range(len(self.param_groups)): 28 | self.param_groups[i]['lr'] = self.__initial_lr[i] * lr_mult 29 | 30 | super().step(closure) 31 | 32 | self.global_step += 1 33 | 34 | 35 | class BatchNorm2dFixed(torch.nn.Module): 36 | 37 | def __init__(self, num_features, eps=1e-5): 38 | super(BatchNorm2dFixed, self).__init__() 39 | self.num_features = num_features 40 | self.eps = eps 41 | self.weight = torch.nn.Parameter(torch.Tensor(num_features)) 42 | self.bias = torch.nn.Parameter(torch.Tensor(num_features)) 43 | self.register_buffer('running_mean', torch.zeros(num_features)) 44 | self.register_buffer('running_var', torch.ones(num_features)) 45 | 46 | 47 | def forward(self, input): 48 | 49 | return F.batch_norm( 50 | input, self.running_mean, self.running_var, self.weight, self.bias, 51 | False, eps=self.eps) 52 | 53 | def __call__(self, x): 54 | return self.forward(x) 55 | 56 | 57 | class SegmentationDataset(Dataset): 58 | def __init__(self, img_name_list_path, img_dir, label_dir, rescale=None, flip=False, cropsize=None, 59 | img_transform=None, mask_transform=None): 60 | self.img_name_list_path = img_name_list_path 61 | self.img_dir = img_dir 62 | self.label_dir = label_dir 63 | 64 | self.img_transform = img_transform 65 | self.mask_transform = mask_transform 66 | 67 | self.img_name_list = open(self.img_name_list_path).read().splitlines() 68 | 69 | self.rescale = rescale 70 | self.flip = flip 71 | self.cropsize = cropsize 72 | 73 | def __len__(self): 74 | return len(self.img_name_list) 75 | 76 | def __getitem__(self, idx): 77 | 78 | name = self.img_name_list[idx] 79 | 80 | img = Image.open(os.path.join(self.img_dir, name + '.jpg')).convert("RGB") 81 | mask = Image.open(os.path.join(self.label_dir, name + '.png')) 82 | 83 | if self.rescale is not None: 84 | s = self.rescale[0] + random.random() * (self.rescale[1] - self.rescale[0]) 85 | adj_size = (round(img.size[0]*s/8)*8, round(img.size[1]*s/8)*8) 86 | img = img.resize(adj_size, resample=Image.CUBIC) 87 | mask = img.resize(adj_size, resample=Image.NEAREST) 88 | 89 | if self.img_transform is not None: 90 | img = self.img_transform(img) 91 | if self.mask_transform is not None: 92 | mask = self.mask_transform(mask) 93 | 94 | if self.cropsize is not None: 95 | img, mask = imutils.random_crop([img, mask], self.cropsize, (0, 255)) 96 | 97 | mask = imutils.RescaleNearest(0.125)(mask) 98 | 99 | if self.flip is True and bool(random.getrandbits(1)): 100 | img = np.flip(img, 1).copy() 101 | mask = np.flip(mask, 1).copy() 102 | 103 | img = np.transpose(img, (2, 0, 1)) 104 | 105 | return name, img, mask 106 | 107 | 108 | class ExtractAffinityLabelInRadius(): 109 | 110 | def __init__(self, cropsize, radius=5): 111 | self.radius = radius 112 | 113 | self.search_dist = [] 114 | 115 | for x in range(1, radius): 116 | self.search_dist.append((0, x)) 117 | 118 | for y in range(1, radius): 119 | for x in range(-radius+1, radius): 120 | if x*x + y*y < radius*radius: 121 | self.search_dist.append((y, x)) 122 | 123 | self.radius_floor = radius-1 124 | 125 | self.crop_height = cropsize - self.radius_floor 126 | self.crop_width = cropsize - 2 * self.radius_floor 127 | return 128 | 129 | def __call__(self, label): 130 | 131 | labels_from = label[:-self.radius_floor, self.radius_floor:-self.radius_floor] 132 | labels_from = np.reshape(labels_from, [-1]) 133 | 134 | labels_to_list = [] 135 | valid_pair_list = [] 136 | 137 | for dy, dx in self.search_dist: 138 | labels_to = label[dy:dy+self.crop_height, self.radius_floor+dx:self.radius_floor+dx+self.crop_width] 139 | labels_to = np.reshape(labels_to, [-1]) 140 | 141 | valid_pair = np.logical_and(np.less(labels_to, 255), np.less(labels_from, 255)) 142 | 143 | labels_to_list.append(labels_to) 144 | valid_pair_list.append(valid_pair) 145 | 146 | bc_labels_from = np.expand_dims(labels_from, 0) 147 | concat_labels_to = np.stack(labels_to_list) 148 | concat_valid_pair = np.stack(valid_pair_list) 149 | 150 | pos_affinity_label = np.equal(bc_labels_from, concat_labels_to) 151 | 152 | bg_pos_affinity_label = np.logical_and(pos_affinity_label, np.equal(bc_labels_from, 0)).astype(np.float32) 153 | 154 | fg_pos_affinity_label = np.logical_and(np.logical_and(pos_affinity_label, np.not_equal(bc_labels_from, 0)), concat_valid_pair).astype(np.float32) 155 | 156 | neg_affinity_label = np.logical_and(np.logical_not(pos_affinity_label), concat_valid_pair).astype(np.float32) 157 | 158 | return bg_pos_affinity_label, fg_pos_affinity_label, neg_affinity_label 159 | 160 | class AffinityFromMaskDataset(SegmentationDataset): 161 | def __init__(self, img_name_list_path, img_dir, label_dir, rescale=None, flip=False, cropsize=None, 162 | img_transform=None, mask_transform=None, radius=5): 163 | super().__init__(img_name_list_path, img_dir, label_dir, rescale, flip, cropsize, img_transform, mask_transform) 164 | 165 | self.radius = radius 166 | 167 | self.extract_aff_lab_func = ExtractAffinityLabelInRadius(cropsize=cropsize//8, radius=radius) 168 | 169 | def __getitem__(self, idx): 170 | name, img, mask = super().__getitem__(idx) 171 | 172 | aff_label = self.extract_aff_lab_func(mask) 173 | 174 | return name, img, aff_label 175 | -------------------------------------------------------------------------------- /infer_cls.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from torch.backends import cudnn 4 | cudnn.enabled = True 5 | import voc12.data 6 | import scipy.misc 7 | import importlib 8 | from torch.utils.data import DataLoader 9 | import torchvision 10 | from tool import imutils, pyutils, iouutils 11 | import argparse 12 | from PIL import Image 13 | import torch.nn.functional as F 14 | import os.path 15 | import matplotlib.pyplot as plt 16 | import cv2 17 | from tool import infer_utils 18 | 19 | 20 | 21 | 22 | cam_20_list = [] 23 | cam_200_list = [] 24 | gt_list = [] 25 | 26 | 27 | 28 | if __name__ == '__main__': 29 | 30 | parser = argparse.ArgumentParser() 31 | parser.add_argument("--weights", required=True, type=str, help="the path to the testing model") 32 | parser.add_argument("--network", default="network.resnet38_cls", type=str) 33 | parser.add_argument("--infer_list", default="voc12/train.txt", type=str) 34 | parser.add_argument("--num_workers", default=8, type=int) 35 | parser.add_argument("--voc12_root", required=True, type=str, help="the path to the dataset folder") 36 | parser.add_argument("--save_crf", default=0, type=int, help="the flag to apply crf") 37 | parser.add_argument("--low_alpha", default=4, type=int, help="crf parameter") 38 | parser.add_argument("--high_alpha", default=32, type=int, help="crf parameter") 39 | parser.add_argument("--save_out_cam", default=0, type=int, help="the flag to save the CAM array") 40 | parser.add_argument("--th", default=0.15, type=float, help="the threshold for the response map") 41 | parser.add_argument("--save_path", required=True, default=None, type=str, help="the path to save the CAM") 42 | parser.add_argument("--k_cluster", required=True, default=10, type=int, help="the number of the sub-category") 43 | parser.add_argument("--round_nb", default=1, type=int, help="the round number of the testing model") 44 | 45 | args = parser.parse_args() 46 | 47 | infer_utils.create_folder(args.save_path) 48 | 49 | model = getattr(importlib.import_module(args.network), 'Net')(args.k_cluster, args.round_nb) 50 | model.load_state_dict(torch.load(args.weights)) 51 | 52 | model.eval() 53 | model.cuda() 54 | 55 | infer_dataset = voc12.data.VOC12ClsDatasetMSF(args.infer_list, voc12_root=args.voc12_root, 56 | scales=(1, 0.5, 1.5, 2.0), 57 | inter_transform=torchvision.transforms.Compose( 58 | [np.asarray, 59 | model.normalize, 60 | imutils.HWC_to_CHW])) 61 | 62 | infer_data_loader = DataLoader(infer_dataset, shuffle=False, num_workers=args.num_workers, pin_memory=True) 63 | 64 | n_gpus = torch.cuda.device_count() 65 | model_replicas = torch.nn.parallel.replicate(model, list(range(n_gpus))) 66 | 67 | for iter, (img_name, img_list, label) in enumerate(infer_data_loader): 68 | img_name = img_name[0]; label = label[0] 69 | 70 | img_path = voc12.data.get_img_path(img_name, args.voc12_root) 71 | orig_img = np.asarray(Image.open(img_path)) 72 | orig_img_size = orig_img.shape[:2] 73 | 74 | gt_cat = np.where(label==1)[0] 75 | label_200 = torch.zeros((20*args.k_cluster)) 76 | # label_200 = torch.zeros((args.k_cluster)) 77 | for cat in gt_cat: 78 | label_200[cat*args.k_cluster:cat*args.k_cluster+args.k_cluster] = 1 79 | # print(np.where(label_200==1)) # convert cls20_label to cls200_label 80 | 81 | 82 | def _work(i, img): 83 | with torch.no_grad(): 84 | with torch.cuda.device(i%n_gpus): 85 | cam, cam_200 = model_replicas[i%n_gpus].forward_two_cam(img.cuda()) 86 | 87 | cam = F.upsample(cam, orig_img_size, mode='bilinear', align_corners=False)[0] 88 | cam = cam.cpu().numpy() * label.clone().view(20, 1, 1).numpy() 89 | if i % 2 == 1: 90 | cam = np.flip(cam, axis=-1) 91 | 92 | cam_200 = F.upsample(cam_200, orig_img_size, mode='bilinear', align_corners=False)[0] 93 | cam_200 = cam_200.cpu().numpy() * label_200.clone().view(20*args.k_cluster, 1, 1).numpy() 94 | # cam_200 = cam_200.cpu().numpy() * label_200.clone().view(args.k_cluster, 1, 1).numpy() ### need to alter args.k_cluster 95 | if i % 2 == 1: 96 | cam_200 = np.flip(cam_200, axis=-1) 97 | 98 | return cam, cam_200 99 | 100 | thread_pool = pyutils.BatchThreader(_work, list(enumerate(img_list)), 101 | batch_size=12, prefetch_size=0, processes=args.num_workers) 102 | 103 | cam_list = thread_pool.pop_results() 104 | 105 | 106 | cam_list_20 = [pair[0] for pair in cam_list] 107 | cam_list_200 = [pair[1] for pair in cam_list] 108 | 109 | # class 20 cam normalization 110 | sum_cam = np.sum(cam_list_20, axis=0) 111 | norm_cam = sum_cam / (np.max(sum_cam, (1, 2), keepdims=True) + 1e-5) 112 | # class 200 cam normalization 113 | norm_cam_200 = infer_utils.cls200_cam_norm(cam_list_200, args.k_cluster) 114 | 115 | 116 | # class 20 cam --> class 20 segmap 117 | cam_dict = infer_utils.cam_npy_to_cam_dict(norm_cam, label) 118 | seg_map = infer_utils.cam_npy_to_label_map(infer_utils.dict2npy(cam_dict, label, args.th)) 119 | cam_20_list.append(seg_map) 120 | cam_20_heatmap = infer_utils.draw_single_heatmap(norm_cam, label, orig_img, args.save_path, img_name) 121 | 122 | 123 | # class 200 cam --> class 200 segmap 124 | cam_dict_200 = infer_utils.cam_npy_to_cam_dict(norm_cam_200, label_200) 125 | merge_200_cam = infer_utils.merge_200_cam_dict(cam_dict_200, label, args.th, args.k_cluster) 126 | cam_dict_200_merge = infer_utils.cam_npy_to_cam_dict(merge_200_cam, label) 127 | seg_map_200 = infer_utils.cam_npy_to_label_map(infer_utils.dict2npy(cam_dict_200_merge, label, args.th)) 128 | cam_200_list.append(seg_map_200) 129 | 130 | 131 | # read groundtruth map 132 | gt_folder_path = os.path.join(args.voc12_root, 'SegmentationClassAug') 133 | gt_map_path = os.path.join(gt_folder_path, img_name + '.png') 134 | gt_map = cv2.imread(gt_map_path, cv2.IMREAD_GRAYSCALE) 135 | gt_list.append(gt_map) 136 | 137 | 138 | if args.save_out_cam == 1: 139 | np.save(os.path.join(args.save_path, 'output_CAM_npy/cls_20', img_name + '.npy'), cam_dict) 140 | # np.save(os.path.join(args.save_path, 'output_CAM_npy/cls_200', img_name + '.npy'), cam_dict_200) 141 | 142 | 143 | def _crf_with_alpha(cam_dict, alpha): 144 | v = np.array(list(cam_dict.values())) 145 | bg_score = np.power(1 - np.max(v, axis=0, keepdims=True), alpha) 146 | bgcam_score = np.concatenate((bg_score, v), axis=0) 147 | crf_score = imutils.crf_inference(orig_img, bgcam_score, labels=bgcam_score.shape[0]) 148 | 149 | n_crf_al = dict() 150 | 151 | n_crf_al[0] = crf_score[0] 152 | for i, key in enumerate(cam_dict.keys()): 153 | n_crf_al[key+1] = crf_score[i+1] 154 | 155 | return n_crf_al 156 | 157 | if args.save_crf == 1: 158 | crf_la = _crf_with_alpha(cam_dict, args.low_alpha) # type(crf_la): 159 | # np.save(os.path.join(args.save_path, 'crf/out_la_crf', img_name + '.npy'), crf_la) 160 | crf_ha = _crf_with_alpha(cam_dict, args.high_alpha) 161 | # np.save(os.path.join(args.save_path, 'crf/out_ha_crf', img_name + '.npy'), crf_ha) 162 | 163 | print("k={} Round-{}| NOW ITER: {}".format(args.k_cluster, args.round_nb, iter)) 164 | 165 | 166 | print(len(cam_20_list), len(gt_list), len(cam_200_list)) 167 | print('NOW K: {} R{}'.format(args.k_cluster, args.round_nb)) 168 | 169 | 170 | score = iouutils.scores(gt_list, cam_20_list, n_class=21) 171 | iouutils.record_score(score, os.path.join(args.save_path, 'IOU'), 'cls20') 172 | 173 | score_200 = iouutils.scores(gt_list, cam_200_list, n_class=21) 174 | iouutils.record_score(score_200, os.path.join(args.save_path, 'IOU'), 'cls200') 175 | -------------------------------------------------------------------------------- /create_pseudo_label.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from sklearn.decomposition import PCA 3 | from sklearn.cluster import KMeans, AffinityPropagation 4 | from sklearn.manifold import TSNE 5 | 6 | import matplotlib.image as mpimg 7 | import matplotlib.pyplot as plt 8 | import matplotlib 9 | from matplotlib.patches import Rectangle 10 | 11 | import scipy.misc as sim 12 | from PIL import Image 13 | import pandas as pd 14 | import shutil 15 | import os 16 | import argparse 17 | 18 | 19 | 20 | def read_train_list(): 21 | with open('./voc12/train_aug.txt', 'r') as r: 22 | filename_list = r.read().split('\n') 23 | r.close() 24 | 25 | filename_list = filename_list[:-1] 26 | for num, filename in enumerate(filename_list): 27 | filename_list[num] = filename[12:23] 28 | return filename_list 29 | 30 | 31 | def make_subclass_label(class_idx, labels, subclass_nb, all_class_kmeans_label): 32 | final_label = [] 33 | 34 | for i in range(len(labels)): 35 | label = [0]*subclass_nb*20 36 | label[class_idx*subclass_nb+labels[i]] = 1 37 | all_class_kmeans_label.append(label) 38 | 39 | return all_class_kmeans_label 40 | 41 | 42 | def generate_merged_label(repeat_list, label_list): 43 | new_label_list = [] 44 | for num, one in enumerate(repeat_list): 45 | merged_label = [] 46 | for i in one: 47 | merged_label.append(label_list[i]) 48 | merged_label = sum(np.array(merged_label)) # merge the kmeans label to make the sub-category label 49 | 50 | nb_subcategory = np.nonzero(merged_label)[0].shape[0] # check the number of sub-category 51 | if len(one) == nb_subcategory: 52 | new_label_list.append(merged_label) 53 | 54 | return new_label_list 55 | 56 | 57 | def create_class_key_in_dict(dict, cls_nb): 58 | for i in range(cls_nb): 59 | dict[i] = [] 60 | 61 | return dict 62 | 63 | 64 | def make_filename_class_dict(filenamelist, labels): 65 | filename_idx_class_dict = {} 66 | filename_idx_class_dict = create_class_key_in_dict(filename_idx_class_dict, 20) 67 | 68 | filename_class_dict = {} 69 | filename_class_dict = create_class_key_in_dict(filename_class_dict, 20) 70 | 71 | for num, one in enumerate(labels): 72 | gt_labels = np.where(one == 1)[0] 73 | for gt in gt_labels: 74 | filename_idx_class_dict[gt].append(num) 75 | filename_class_dict[gt].append(filenamelist[num]) 76 | 77 | return filename_idx_class_dict, filename_class_dict 78 | 79 | 80 | def merge_filename_class_dict(filename_class_dict): 81 | merged_filename_list = [] 82 | for i in range(20): 83 | class_filename_list = filename_class_dict[i] 84 | for one in class_filename_list: 85 | merged_filename_list.append(one) 86 | 87 | return merged_filename_list 88 | 89 | 90 | def generate_repeat_list(filename_list): 91 | repeat_list = [] 92 | for num, one in enumerate(filename_list): 93 | repeat_idx_list = [] 94 | for num_, one_ in enumerate(filename_list): 95 | if one == one_: 96 | repeat_idx_list.append(num_) 97 | repeat_list.append(repeat_idx_list) 98 | 99 | return repeat_list 100 | 101 | 102 | def remove_duplicate_label(repeat_list): 103 | keep_idx_list = [] 104 | remove_idx_list = [] 105 | for repeat_set in repeat_list: 106 | for num, one in enumerate(repeat_set): 107 | if num == 0 and one not in keep_idx_list: 108 | keep_idx_list.append(one) 109 | else: 110 | remove_idx_list.append(one) 111 | 112 | return keep_idx_list, remove_idx_list 113 | 114 | 115 | 116 | def create_train_data(merge_filename_list, new_label_list, keep_idx_list): 117 | label_20 = np.load('./voc12/20_class_labels.npy') 118 | print(len(merge_filename_list), len(new_label_list), label_20.shape) 119 | 120 | train_filename_list = [] 121 | train_label_200 = [] 122 | train_label_20 = [] 123 | for idx in keep_idx_list: 124 | train_filename_list.append(merge_filename_list[idx]) 125 | train_label_200.append(new_label_list[idx]) 126 | train_label_20.append(label_20[idx]) 127 | 128 | tmp = np.where(new_label_list[idx] == 1)[0] 129 | cls200_par = [int(x/10) for x in tmp] 130 | 131 | return train_filename_list, train_label_200, train_label_20 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | if __name__ == '__main__': 140 | parser = argparse.ArgumentParser() 141 | parser.add_argument("--k_cluster", required=True, type=int, help="the number of the sub-category") 142 | parser.add_argument("--for_round_nb", required=True, type=int, help="the round number that the generated pseudo lable will be used, e.g., 1st round: for_round_nb=1, 2nd round: for_round_nb=2, and so on") 143 | parser.add_argument("--save_folder", required=True, default='./save', type=str, help="the path to save the sub-category label") 144 | 145 | args = parser.parse_args() 146 | 147 | feature_folder_path = os.path.join(args.save_folder, 'feature') 148 | 149 | filenamelist = read_train_list() 150 | cls20_label = np.load('./voc12/train_label.npy') 151 | 152 | # make the class dictionary 153 | filename_idx_class_dict, filename_class_dict = make_filename_class_dict(filenamelist, cls20_label) 154 | # make the list with all samples in the class order (consider each object in the image (there could be multiple objects in an image)) 155 | merge_filename_list = merge_filename_class_dict(filename_class_dict) 156 | # find the repeated data index (consider each image) 157 | repeat_list = generate_repeat_list(merge_filename_list) 158 | # find the keep/remove index list 159 | keep_idx_list, remove_idx_list = remove_duplicate_label(repeat_list) 160 | 161 | 162 | 163 | if args.for_round_nb == 1: 164 | features = np.load('{}/R{}_feature.npy'.format(feature_folder_path, args.for_round_nb-1)) 165 | else: 166 | features = np.load('{}/R{}_feature.npy'.format(feature_folder_path, args.for_round_nb-1)) 167 | 168 | print(len(filenamelist), cls20_label.shape, features.shape) # 10582, (10582, 20), (10582, 4096) 169 | 170 | 171 | all_class_kmeans_label = [] 172 | for i in range(20): 173 | filename_idx_list = filename_idx_class_dict[i] 174 | 175 | class_feature_list = [] 176 | for idx in filename_idx_list: 177 | class_feature_list.append(features[idx]) 178 | print('Class {}: {}'.format(i, len(class_feature_list))) 179 | 180 | # apply kmeans 181 | X = class_feature_list 182 | k_cluster = args.k_cluster 183 | max_iter = 300 184 | 185 | k_center = KMeans(n_clusters=k_cluster, random_state=0, max_iter=max_iter).fit(X) 186 | labels = k_center.labels_ 187 | centers = k_center.cluster_centers_ 188 | iter_nb = k_center.n_iter_ 189 | distance = k_center.inertia_ 190 | subclass_nb = k_cluster 191 | 192 | # generate the sub-category label 193 | all_class_kmeans_label = make_subclass_label(i, labels, subclass_nb, all_class_kmeans_label) 194 | 195 | 196 | # merge the kmeans label to make the sub-category label 197 | new_label_list = generate_merged_label(repeat_list, all_class_kmeans_label) 198 | print(len(merge_filename_list), len(new_label_list)) # 16458 199 | 200 | 201 | # create the parent label and the sub-category label as the training data with 202 | train_filename_list, train_label_200, train_label_20 = create_train_data(merge_filename_list, new_label_list, keep_idx_list) 203 | print(len(train_filename_list), len(train_label_200), len(train_label_20)) 204 | 205 | train_label_200 = np.array(train_label_200) 206 | train_label_20 = np.array(train_label_20) 207 | print(train_label_200.shape, train_label_20.shape) # (10582, 200) (10582, 20) 208 | 209 | 210 | with open('{}/label/R{}_train_filename_list.txt'.format(args.save_folder, args.for_round_nb), 'w') as f: 211 | for x in train_filename_list: 212 | line = '{}\n'.format(x) 213 | f.write(line) 214 | f.close() 215 | 216 | np.save('{}/label/R{}_train_label_200.npy'.format(args.save_folder, args.for_round_nb), train_label_200) 217 | np.save('{}/label/R{}_train_label_20.npy'.format(args.save_folder, args.for_round_nb), train_label_20) 218 | 219 | print('##################### k_{} Round-{} pseudo labels are saved at {}/label. #####################'.format(args.k_cluster, args.for_round_nb, args.save_folder)) 220 | print('##################### You can start to train the classification model. #####################') 221 | -------------------------------------------------------------------------------- /network/resnet38d.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch import nn 3 | import numpy as np 4 | import pdb 5 | 6 | import torch.nn.functional as F 7 | 8 | class ResBlock(nn.Module): 9 | def __init__(self, in_channels, mid_channels, out_channels, stride=1, first_dilation=None, dilation=1): 10 | super(ResBlock, self).__init__() 11 | 12 | self.same_shape = (in_channels == out_channels and stride == 1) 13 | 14 | if first_dilation == None: first_dilation = dilation 15 | 16 | self.bn_branch2a = nn.BatchNorm2d(in_channels) 17 | 18 | self.conv_branch2a = nn.Conv2d(in_channels, mid_channels, 3, stride, 19 | padding=first_dilation, dilation=first_dilation, bias=False) 20 | 21 | self.bn_branch2b1 = nn.BatchNorm2d(mid_channels) 22 | 23 | self.conv_branch2b1 = nn.Conv2d(mid_channels, out_channels, 3, padding=dilation, dilation=dilation, bias=False) 24 | 25 | if not self.same_shape: 26 | self.conv_branch1 = nn.Conv2d(in_channels, out_channels, 1, stride, bias=False) 27 | 28 | def forward(self, x, get_x_bn_relu=False): 29 | # pdb.set_trace() 30 | 31 | branch2 = self.bn_branch2a(x) 32 | branch2 = F.relu(branch2) 33 | 34 | x_bn_relu = branch2 35 | 36 | if not self.same_shape: 37 | branch1 = self.conv_branch1(branch2) 38 | else: 39 | branch1 = x 40 | 41 | branch2 = self.conv_branch2a(branch2) 42 | branch2 = self.bn_branch2b1(branch2) 43 | branch2 = F.relu(branch2) 44 | branch2 = self.conv_branch2b1(branch2) 45 | 46 | x = branch1 + branch2 47 | 48 | if get_x_bn_relu: 49 | return x, x_bn_relu 50 | 51 | return x 52 | 53 | def __call__(self, x, get_x_bn_relu=False): 54 | return self.forward(x, get_x_bn_relu=get_x_bn_relu) 55 | 56 | class ResBlock_bot(nn.Module): 57 | def __init__(self, in_channels, out_channels, stride=1, dilation=1, dropout=0.): 58 | super(ResBlock_bot, self).__init__() 59 | 60 | self.same_shape = (in_channels == out_channels and stride == 1) 61 | 62 | self.bn_branch2a = nn.BatchNorm2d(in_channels) 63 | self.conv_branch2a = nn.Conv2d(in_channels, out_channels//4, 1, stride, bias=False) 64 | 65 | self.bn_branch2b1 = nn.BatchNorm2d(out_channels//4) 66 | self.dropout_2b1 = torch.nn.Dropout2d(dropout) 67 | self.conv_branch2b1 = nn.Conv2d(out_channels//4, out_channels//2, 3, padding=dilation, dilation=dilation, bias=False) 68 | 69 | self.bn_branch2b2 = nn.BatchNorm2d(out_channels//2) 70 | self.dropout_2b2 = torch.nn.Dropout2d(dropout) 71 | self.conv_branch2b2 = nn.Conv2d(out_channels//2, out_channels, 1, bias=False) 72 | 73 | if not self.same_shape: 74 | self.conv_branch1 = nn.Conv2d(in_channels, out_channels, 1, stride, bias=False) 75 | 76 | def forward(self, x, get_x_bn_relu=False): 77 | # pdb.set_trace() 78 | 79 | branch2 = self.bn_branch2a(x) 80 | branch2 = F.relu(branch2) 81 | x_bn_relu = branch2 82 | 83 | branch1 = self.conv_branch1(branch2) 84 | 85 | branch2 = self.conv_branch2a(branch2) 86 | 87 | branch2 = self.bn_branch2b1(branch2) 88 | branch2 = F.relu(branch2) 89 | branch2 = self.dropout_2b1(branch2) 90 | branch2 = self.conv_branch2b1(branch2) 91 | 92 | branch2 = self.bn_branch2b2(branch2) 93 | branch2 = F.relu(branch2) 94 | branch2 = self.dropout_2b2(branch2) 95 | branch2 = self.conv_branch2b2(branch2) 96 | 97 | x = branch1 + branch2 98 | 99 | if get_x_bn_relu: 100 | return x, x_bn_relu 101 | 102 | return x 103 | 104 | def __call__(self, x, get_x_bn_relu=False): 105 | return self.forward(x, get_x_bn_relu=get_x_bn_relu) 106 | 107 | class Normalize(): 108 | def __init__(self, mean = (0.485, 0.456, 0.406), std = (0.229, 0.224, 0.225)): 109 | 110 | self.mean = mean 111 | self.std = std 112 | 113 | def __call__(self, img): 114 | imgarr = np.asarray(img) 115 | proc_img = np.empty_like(imgarr, np.float32) 116 | 117 | proc_img[..., 0] = (imgarr[..., 0] / 255. - self.mean[0]) / self.std[0] 118 | proc_img[..., 1] = (imgarr[..., 1] / 255. - self.mean[1]) / self.std[1] 119 | proc_img[..., 2] = (imgarr[..., 2] / 255. - self.mean[2]) / self.std[2] 120 | 121 | return proc_img 122 | 123 | class Net(nn.Module): 124 | def __init__(self): 125 | super(Net, self).__init__() 126 | 127 | self.conv1a = nn.Conv2d(3, 64, 3, padding=1, bias=False) 128 | 129 | self.b2 = ResBlock(64, 128, 128, stride=2) 130 | self.b2_1 = ResBlock(128, 128, 128) 131 | self.b2_2 = ResBlock(128, 128, 128) 132 | 133 | self.b3 = ResBlock(128, 256, 256, stride=2) 134 | self.b3_1 = ResBlock(256, 256, 256) 135 | self.b3_2 = ResBlock(256, 256, 256) 136 | 137 | self.b4 = ResBlock(256, 512, 512, stride=2) 138 | self.b4_1 = ResBlock(512, 512, 512) 139 | self.b4_2 = ResBlock(512, 512, 512) 140 | self.b4_3 = ResBlock(512, 512, 512) 141 | self.b4_4 = ResBlock(512, 512, 512) 142 | self.b4_5 = ResBlock(512, 512, 512) 143 | 144 | self.b5 = ResBlock(512, 512, 1024, stride=1, first_dilation=1, dilation=2) 145 | self.b5_1 = ResBlock(1024, 512, 1024, dilation=2) 146 | self.b5_2 = ResBlock(1024, 512, 1024, dilation=2) 147 | 148 | self.b6 = ResBlock_bot(1024, 2048, stride=1, dilation=4, dropout=0.3) 149 | 150 | self.b7 = ResBlock_bot(2048, 4096, dilation=4, dropout=0.5) 151 | 152 | self.bn7 = nn.BatchNorm2d(4096) 153 | 154 | self.not_training = [self.conv1a] 155 | 156 | self.normalize = Normalize() 157 | 158 | return 159 | 160 | def forward(self, x): 161 | return self.forward_as_dict(x)['conv6'] 162 | 163 | def forward_as_dict(self, x): 164 | # pdb.set_trace() 165 | 166 | x = self.conv1a(x) 167 | 168 | x = self.b2(x) 169 | x = self.b2_1(x) 170 | x = self.b2_2(x) 171 | 172 | x = self.b3(x) 173 | x = self.b3_1(x) 174 | x = self.b3_2(x) 175 | 176 | x = self.b4(x) 177 | x = self.b4_1(x) 178 | x = self.b4_2(x) 179 | x = self.b4_3(x) 180 | x = self.b4_4(x) 181 | x = self.b4_5(x) 182 | 183 | x, conv4 = self.b5(x, get_x_bn_relu=True) 184 | x = self.b5_1(x) 185 | x = self.b5_2(x) 186 | 187 | x, conv5 = self.b6(x, get_x_bn_relu=True) 188 | 189 | x = self.b7(x) 190 | conv6 = F.relu(self.bn7(x)) 191 | # pdb.set_trace() 192 | 193 | return dict({'conv4': conv4, 'conv5': conv5, 'conv6': conv6}) 194 | 195 | 196 | def train(self, mode=True): 197 | 198 | super().train(mode) 199 | 200 | for layer in self.not_training: 201 | 202 | if isinstance(layer, torch.nn.Conv2d): 203 | layer.weight.requires_grad = False 204 | 205 | elif isinstance(layer, torch.nn.Module): 206 | for c in layer.children(): 207 | c.weight.requires_grad = False 208 | if c.bias is not None: 209 | c.bias.requires_grad = False 210 | 211 | for layer in self.modules(): 212 | 213 | if isinstance(layer, torch.nn.BatchNorm2d): 214 | layer.eval() 215 | layer.bias.requires_grad = False 216 | layer.weight.requires_grad = False 217 | 218 | return 219 | 220 | def convert_mxnet_to_torch(filename): 221 | import mxnet 222 | 223 | save_dict = mxnet.nd.load(filename) 224 | 225 | renamed_dict = dict() 226 | 227 | bn_param_mx_pt = {'beta': 'bias', 'gamma': 'weight', 'mean': 'running_mean', 'var': 'running_var'} 228 | 229 | for k, v in save_dict.items(): 230 | 231 | v = torch.from_numpy(v.asnumpy()) 232 | toks = k.split('_') 233 | 234 | if 'conv1a' in toks[0]: 235 | renamed_dict['conv1a.weight'] = v 236 | 237 | elif 'linear1000' in toks[0]: 238 | pass 239 | 240 | elif 'branch' in toks[1]: 241 | 242 | pt_name = [] 243 | 244 | if toks[0][-1] != 'a': 245 | pt_name.append('b' + toks[0][-3] + '_' + toks[0][-1]) 246 | else: 247 | pt_name.append('b' + toks[0][-2]) 248 | 249 | if 'res' in toks[0]: 250 | layer_type = 'conv' 251 | last_name = 'weight' 252 | 253 | else: # 'bn' in toks[0]: 254 | layer_type = 'bn' 255 | last_name = bn_param_mx_pt[toks[-1]] 256 | 257 | pt_name.append(layer_type + '_' + toks[1]) 258 | 259 | pt_name.append(last_name) 260 | 261 | torch_name = '.'.join(pt_name) 262 | renamed_dict[torch_name] = v 263 | 264 | else: 265 | last_name = bn_param_mx_pt[toks[-1]] 266 | renamed_dict['bn7.' + last_name] = v 267 | 268 | return renamed_dict 269 | -------------------------------------------------------------------------------- /tool/imutils.py: -------------------------------------------------------------------------------- 1 | 2 | import PIL.Image 3 | import random 4 | import numpy as np 5 | import torch 6 | from torchvision import transforms 7 | 8 | 9 | class RandomResizeLong(): 10 | 11 | def __init__(self, min_long, max_long): 12 | self.min_long = min_long 13 | self.max_long = max_long 14 | 15 | def __call__(self, img): 16 | 17 | target_long = random.randint(self.min_long, self.max_long) 18 | w, h = img.size 19 | 20 | if w < h: 21 | target_shape = (int(round(w * target_long / h)), target_long) 22 | else: 23 | target_shape = (target_long, int(round(h * target_long / w))) 24 | 25 | img = img.resize(target_shape, resample=PIL.Image.CUBIC) 26 | 27 | return img 28 | 29 | 30 | class RandomCrop(): 31 | 32 | def __init__(self, cropsize): 33 | self.cropsize = cropsize 34 | 35 | def __call__(self, imgarr): 36 | 37 | h, w, c = imgarr.shape 38 | 39 | ch = min(self.cropsize, h) 40 | cw = min(self.cropsize, w) 41 | 42 | w_space = w - self.cropsize 43 | h_space = h - self.cropsize 44 | 45 | if w_space > 0: 46 | cont_left = 0 47 | img_left = random.randrange(w_space+1) 48 | else: 49 | cont_left = random.randrange(-w_space+1) 50 | img_left = 0 51 | 52 | if h_space > 0: 53 | cont_top = 0 54 | img_top = random.randrange(h_space+1) 55 | else: 56 | cont_top = random.randrange(-h_space+1) 57 | img_top = 0 58 | 59 | container = np.zeros((self.cropsize, self.cropsize, imgarr.shape[-1]), np.float32) 60 | container[cont_top:cont_top+ch, cont_left:cont_left+cw] = \ 61 | imgarr[img_top:img_top+ch, img_left:img_left+cw] 62 | 63 | return container 64 | 65 | def get_random_crop_box(imgsize, cropsize): 66 | h, w = imgsize 67 | 68 | ch = min(cropsize, h) 69 | cw = min(cropsize, w) 70 | 71 | w_space = w - cropsize 72 | h_space = h - cropsize 73 | 74 | if w_space > 0: 75 | cont_left = 0 76 | img_left = random.randrange(w_space + 1) 77 | else: 78 | cont_left = random.randrange(-w_space + 1) 79 | img_left = 0 80 | 81 | if h_space > 0: 82 | cont_top = 0 83 | img_top = random.randrange(h_space + 1) 84 | else: 85 | cont_top = random.randrange(-h_space + 1) 86 | img_top = 0 87 | 88 | return cont_top, cont_top+ch, cont_left, cont_left+cw, img_top, img_top+ch, img_left, img_left+cw 89 | 90 | def crop_with_box(img, box): 91 | if len(img.shape) == 3: 92 | img_cont = np.zeros((max(box[1]-box[0], box[4]-box[5]), max(box[3]-box[2], box[7]-box[6]), img.shape[-1]), dtype=img.dtype) 93 | else: 94 | img_cont = np.zeros((max(box[1] - box[0], box[4] - box[5]), max(box[3] - box[2], box[7] - box[6])), dtype=img.dtype) 95 | img_cont[box[0]:box[1], box[2]:box[3]] = img[box[4]:box[5], box[6]:box[7]] 96 | return img_cont 97 | 98 | 99 | def random_crop(images, cropsize, fills): 100 | if isinstance(images[0], PIL.Image.Image): 101 | imgsize = images[0].size[::-1] 102 | else: 103 | imgsize = images[0].shape[:2] 104 | box = get_random_crop_box(imgsize, cropsize) 105 | 106 | new_images = [] 107 | for img, f in zip(images, fills): 108 | 109 | if isinstance(img, PIL.Image.Image): 110 | img = img.crop((box[6], box[4], box[7], box[5])) 111 | cont = PIL.Image.new(img.mode, (cropsize, cropsize)) 112 | cont.paste(img, (box[2], box[0])) 113 | new_images.append(cont) 114 | 115 | else: 116 | if len(img.shape) == 3: 117 | cont = np.ones((cropsize, cropsize, img.shape[2]), img.dtype)*f 118 | else: 119 | cont = np.ones((cropsize, cropsize), img.dtype)*f 120 | cont[box[0]:box[1], box[2]:box[3]] = img[box[4]:box[5], box[6]:box[7]] 121 | new_images.append(cont) 122 | 123 | return new_images 124 | 125 | 126 | class AvgPool2d(): 127 | 128 | def __init__(self, ksize): 129 | self.ksize = ksize 130 | 131 | def __call__(self, img): 132 | import skimage.measure 133 | 134 | return skimage.measure.block_reduce(img, (self.ksize, self.ksize, 1), np.mean) 135 | 136 | 137 | class RandomHorizontalFlip(): 138 | def __init__(self): 139 | return 140 | 141 | def __call__(self, img): 142 | if bool(random.getrandbits(1)): 143 | img = np.fliplr(img).copy() 144 | return img 145 | 146 | 147 | class CenterCrop(): 148 | 149 | def __init__(self, cropsize, default_value=0): 150 | self.cropsize = cropsize 151 | self.default_value = default_value 152 | 153 | def __call__(self, npimg): 154 | 155 | h, w = npimg.shape[:2] 156 | 157 | ch = min(self.cropsize, h) 158 | cw = min(self.cropsize, w) 159 | 160 | sh = h - self.cropsize 161 | sw = w - self.cropsize 162 | 163 | if sw > 0: 164 | cont_left = 0 165 | img_left = int(round(sw / 2)) 166 | else: 167 | cont_left = int(round(-sw / 2)) 168 | img_left = 0 169 | 170 | if sh > 0: 171 | cont_top = 0 172 | img_top = int(round(sh / 2)) 173 | else: 174 | cont_top = int(round(-sh / 2)) 175 | img_top = 0 176 | 177 | if len(npimg.shape) == 2: 178 | container = np.ones((self.cropsize, self.cropsize), npimg.dtype)*self.default_value 179 | else: 180 | container = np.ones((self.cropsize, self.cropsize, npimg.shape[2]), npimg.dtype)*self.default_value 181 | 182 | container[cont_top:cont_top+ch, cont_left:cont_left+cw] = \ 183 | npimg[img_top:img_top+ch, img_left:img_left+cw] 184 | 185 | return container 186 | 187 | 188 | def HWC_to_CHW(img): 189 | return np.transpose(img, (2, 0, 1)) 190 | 191 | 192 | def Scale(img): 193 | return img/255. 194 | 195 | def ToDouble(img): 196 | return img.type(torch.FloatTensor) 197 | 198 | def Flip(img): 199 | transform = transforms.Compose([ 200 | transforms.RandomHorizontalFlip()]) 201 | return transform(img) 202 | 203 | def Crop(imgarr, cropsize): 204 | 205 | h, w, c = imgarr.shape 206 | 207 | ch = min(cropsize, h) 208 | cw = min(cropsize, w) 209 | 210 | w_space = w - cropsize 211 | h_space = h - cropsize 212 | 213 | if w_space > 0: 214 | cont_left = 0 215 | img_left = random.randrange(w_space+1) 216 | else: 217 | cont_left = random.randrange(-w_space+1) 218 | img_left = 0 219 | 220 | if h_space > 0: 221 | cont_top = 0 222 | img_top = random.randrange(h_space+1) 223 | else: 224 | cont_top = random.randrange(-h_space+1) 225 | img_top = 0 226 | 227 | container = np.zeros((cropsize, cropsize, imgarr.shape[-1]), np.float32) 228 | container[cont_top:cont_top+ch, cont_left:cont_left+cw] = \ 229 | imgarr[img_top:img_top+ch, img_left:img_left+cw] 230 | 231 | return container 232 | 233 | def NNormalize(imgarr): 234 | mean = (0.485, 0.456, 0.406) 235 | std = (0.229, 0.224, 0.225) 236 | 237 | # imgarr = np.asarray(img) 238 | proc_img = np.empty_like(imgarr, np.float32) 239 | 240 | proc_img[..., 0] = (imgarr[..., 0] / 255. - mean[0]) / std[0] 241 | proc_img[..., 1] = (imgarr[..., 1] / 255. - mean[1]) / std[1] 242 | proc_img[..., 2] = (imgarr[..., 2] / 255. - mean[2]) / std[2] 243 | 244 | return proc_img 245 | 246 | 247 | def ResizeLong(img, min_long, max_long): 248 | target_long = random.randint(min_long, max_long) 249 | w, h = img.size 250 | 251 | if w < h: 252 | target_shape = (int(round(w * target_long / h)), target_long) 253 | else: 254 | target_shape = (target_long, int(round(h * target_long / w))) 255 | 256 | img = img.resize(target_shape, resample=PIL.Image.CUBIC) 257 | 258 | return img 259 | 260 | def ColorJitter(img): 261 | transform = transforms.Compose([ 262 | transforms.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3, hue=0.1)]) 263 | return transform(img) 264 | 265 | 266 | 267 | 268 | class RescaleNearest(): 269 | def __init__(self, scale): 270 | self.scale = scale 271 | 272 | def __call__(self, npimg): 273 | import cv2 274 | return cv2.resize(npimg, None, fx=self.scale, fy=self.scale, interpolation=cv2.INTER_NEAREST) 275 | 276 | 277 | 278 | 279 | def crf_inference(img, probs, t=10, scale_factor=1, labels=21): 280 | import pydensecrf.densecrf as dcrf 281 | from pydensecrf.utils import unary_from_softmax 282 | 283 | h, w = img.shape[:2] 284 | n_labels = labels 285 | 286 | d = dcrf.DenseCRF2D(w, h, n_labels) 287 | 288 | unary = unary_from_softmax(probs) 289 | unary = np.ascontiguousarray(unary) 290 | 291 | d.setUnaryEnergy(unary) 292 | d.addPairwiseGaussian(sxy=3/scale_factor, compat=3) 293 | d.addPairwiseBilateral(sxy=80/scale_factor, srgb=13, rgbim=np.copy(img), compat=10) 294 | Q = d.inference(t) 295 | 296 | return np.array(Q).reshape((n_labels, h, w)) 297 | -------------------------------------------------------------------------------- /voc12/data.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import torch 4 | from torch.utils.data import Dataset 5 | import PIL.Image 6 | import os.path 7 | import scipy.misc 8 | 9 | import pdb 10 | 11 | IMG_FOLDER_NAME = "JPEGImages" 12 | ANNOT_FOLDER_NAME = "Annotations" 13 | 14 | 15 | CAT_LIST = ['aeroplane', 'bicycle', 'bird', 'boat', 16 | 'bottle', 'bus', 'car', 'cat', 'chair', 17 | 'cow', 'diningtable', 'dog', 'horse', 18 | 'motorbike', 'person', 'pottedplant', 19 | 'sheep', 'sofa', 'train', 20 | 'tvmonitor'] 21 | 22 | CAT_NAME_TO_NUM = dict(zip(CAT_LIST,range(len(CAT_LIST)))) 23 | 24 | def load_image_label_from_xml(img_name, voc12_root): 25 | from xml.dom import minidom 26 | 27 | el_list = minidom.parse(os.path.join(voc12_root, ANNOT_FOLDER_NAME,img_name + '.xml')).getElementsByTagName('name') 28 | 29 | multi_cls_lab = np.zeros((20), np.float32) 30 | 31 | for el in el_list: 32 | cat_name = el.firstChild.data 33 | if cat_name in CAT_LIST: 34 | cat_num = CAT_NAME_TO_NUM[cat_name] 35 | multi_cls_lab[cat_num] = 1.0 36 | 37 | return multi_cls_lab 38 | 39 | def load_image_label_list_from_xml(img_name_list, voc12_root): 40 | 41 | return [load_image_label_from_xml(img_name, voc12_root) for img_name in img_name_list] 42 | 43 | def load_image_label_list_from_npy(img_name_list): 44 | cls_labels_dict = np.load('voc12/cls_labels.npy').item() 45 | 46 | return [cls_labels_dict[img_name] for img_name in img_name_list] 47 | 48 | def get_img_path(img_name, voc12_root): 49 | return os.path.join(voc12_root, IMG_FOLDER_NAME, img_name + '.jpg') 50 | 51 | def load_img_name_list(dataset_path): 52 | img_gt_name_list = open(dataset_path).read().splitlines() 53 | img_name_list = [img_gt_name.split(' ')[0][-15:-4] for img_gt_name in img_gt_name_list] 54 | 55 | return img_name_list 56 | 57 | class VOC12ImageDataset(Dataset): 58 | 59 | def __init__(self, img_name_list_path, voc12_root, transform=None): 60 | self.img_name_list = load_img_name_list(img_name_list_path) 61 | self.voc12_root = voc12_root 62 | self.transform = transform 63 | 64 | def __len__(self): 65 | return len(self.img_name_list) 66 | 67 | def __getitem__(self, idx): 68 | name = self.img_name_list[idx] 69 | 70 | img = PIL.Image.open(get_img_path(name, self.voc12_root)).convert("RGB") 71 | 72 | if self.transform: 73 | img = self.transform(img) 74 | 75 | return name, img 76 | 77 | 78 | class VOC12ClsDataset(VOC12ImageDataset): 79 | 80 | def __init__(self, img_name_list_path, voc12_root, transform=None): 81 | super().__init__(img_name_list_path, voc12_root, transform) 82 | self.label_list = load_image_label_list_from_npy(self.img_name_list) 83 | # self.label_list = [] ### modified 84 | 85 | def __getitem__(self, idx): 86 | name, img = super().__getitem__(idx) 87 | 88 | label = torch.from_numpy(self.label_list[idx]) 89 | 90 | return name, img, label 91 | 92 | 93 | class VOC12ClsDatasetMSF(VOC12ClsDataset): 94 | 95 | def __init__(self, img_name_list_path, voc12_root, scales, inter_transform=None, unit=1): 96 | super().__init__(img_name_list_path, voc12_root, transform=None) 97 | self.scales = scales 98 | self.unit = unit 99 | self.inter_transform = inter_transform 100 | # pdb.set_trace() 101 | 102 | def __getitem__(self, idx): 103 | name, img, label = super().__getitem__(idx) 104 | 105 | rounded_size = (int(round(img.size[0]/self.unit)*self.unit), int(round(img.size[1]/self.unit)*self.unit)) 106 | 107 | ms_img_list = [] 108 | 109 | # Multi Scale 110 | for s in self.scales: 111 | target_size = (round(rounded_size[0]*s), round(rounded_size[1]*s)) 112 | s_img = img.resize(target_size, resample=PIL.Image.CUBIC) 113 | ms_img_list.append(s_img) 114 | 115 | 116 | if self.inter_transform: 117 | for i in range(len(ms_img_list)): 118 | ms_img_list[i] = self.inter_transform(ms_img_list[i]) 119 | 120 | msf_img_list = [] 121 | for i in range(len(ms_img_list)): 122 | msf_img_list.append(ms_img_list[i]) 123 | msf_img_list.append(np.flip(ms_img_list[i], -1).copy()) ##### 124 | 125 | return name, msf_img_list, label 126 | 127 | 128 | class ExtractAffinityLabelInRadius(): 129 | 130 | def __init__(self, cropsize, radius=5): 131 | self.radius = radius 132 | 133 | self.search_dist = [] 134 | 135 | for x in range(1, radius): 136 | self.search_dist.append((0, x)) 137 | 138 | for y in range(1, radius): 139 | for x in range(-radius+1, radius): 140 | if x*x + y*y < radius*radius: 141 | self.search_dist.append((y, x)) 142 | 143 | self.radius_floor = radius-1 144 | 145 | self.crop_height = cropsize - self.radius_floor 146 | self.crop_width = cropsize - 2 * self.radius_floor 147 | return 148 | 149 | def __call__(self, label): 150 | 151 | labels_from = label[:-self.radius_floor, self.radius_floor:-self.radius_floor] 152 | labels_from = np.reshape(labels_from, [-1]) 153 | 154 | labels_to_list = [] 155 | valid_pair_list = [] 156 | 157 | for dy, dx in self.search_dist: 158 | labels_to = label[dy:dy+self.crop_height, self.radius_floor+dx:self.radius_floor+dx+self.crop_width] 159 | labels_to = np.reshape(labels_to, [-1]) 160 | 161 | valid_pair = np.logical_and(np.less(labels_to, 255), np.less(labels_from, 255)) 162 | 163 | labels_to_list.append(labels_to) 164 | valid_pair_list.append(valid_pair) 165 | 166 | bc_labels_from = np.expand_dims(labels_from, 0) 167 | concat_labels_to = np.stack(labels_to_list) 168 | concat_valid_pair = np.stack(valid_pair_list) 169 | 170 | pos_affinity_label = np.equal(bc_labels_from, concat_labels_to) 171 | 172 | bg_pos_affinity_label = np.logical_and(pos_affinity_label, np.equal(bc_labels_from, 0)).astype(np.float32) 173 | 174 | fg_pos_affinity_label = np.logical_and(np.logical_and(pos_affinity_label, np.not_equal(bc_labels_from, 0)), concat_valid_pair).astype(np.float32) 175 | 176 | neg_affinity_label = np.logical_and(np.logical_not(pos_affinity_label), concat_valid_pair).astype(np.float32) 177 | 178 | return torch.from_numpy(bg_pos_affinity_label), torch.from_numpy(fg_pos_affinity_label), torch.from_numpy(neg_affinity_label) 179 | 180 | 181 | class VOC12AffDataset(VOC12ImageDataset): 182 | 183 | def __init__(self, img_name_list_path, label_la_dir, label_ha_dir, cropsize, voc12_root, radius=5, 184 | joint_transform_list=None, img_transform_list=None, label_transform_list=None): 185 | super().__init__(img_name_list_path, voc12_root, transform=None) 186 | 187 | self.label_la_dir = label_la_dir 188 | self.label_ha_dir = label_ha_dir 189 | self.voc12_root = voc12_root 190 | 191 | self.joint_transform_list = joint_transform_list 192 | self.img_transform_list = img_transform_list 193 | self.label_transform_list = label_transform_list 194 | 195 | self.extract_aff_lab_func = ExtractAffinityLabelInRadius(cropsize=cropsize//8, radius=radius) 196 | 197 | def __len__(self): 198 | return len(self.img_name_list) 199 | 200 | def __getitem__(self, idx): 201 | name, img = super().__getitem__(idx) 202 | 203 | label_la_path = os.path.join(self.label_la_dir, name + '.npy') 204 | 205 | label_ha_path = os.path.join(self.label_ha_dir, name + '.npy') 206 | 207 | label_la = np.load(label_la_path).item() 208 | label_ha = np.load(label_ha_path).item() 209 | 210 | label = np.array(list(label_la.values()) + list(label_ha.values())) 211 | label = np.transpose(label, (1, 2, 0)) 212 | 213 | for joint_transform, img_transform, label_transform \ 214 | in zip(self.joint_transform_list, self.img_transform_list, self.label_transform_list): 215 | 216 | if joint_transform: 217 | img_label = np.concatenate((img, label), axis=-1) 218 | img_label = joint_transform(img_label) 219 | img = img_label[..., :3] 220 | label = img_label[..., 3:] 221 | 222 | if img_transform: 223 | img = img_transform(img) 224 | if label_transform: 225 | label = label_transform(label) 226 | 227 | no_score_region = np.max(label, -1) < 1e-5 228 | label_la, label_ha = np.array_split(label, 2, axis=-1) 229 | label_la = np.argmax(label_la, axis=-1).astype(np.uint8) 230 | label_ha = np.argmax(label_ha, axis=-1).astype(np.uint8) 231 | label = label_la.copy() 232 | label[label_la == 0] = 255 233 | label[label_ha == 0] = 0 234 | label[no_score_region] = 255 # mostly outer of cropped region 235 | label = self.extract_aff_lab_func(label) 236 | 237 | return img, label 238 | 239 | 240 | class VOC12AffGtDataset(VOC12ImageDataset): 241 | 242 | def __init__(self, img_name_list_path, label_dir, cropsize, voc12_root, radius=5, 243 | joint_transform_list=None, img_transform_list=None, label_transform_list=None): 244 | super().__init__(img_name_list_path, voc12_root, transform=None) 245 | 246 | self.label_dir = label_dir 247 | self.voc12_root = voc12_root 248 | 249 | self.joint_transform_list = joint_transform_list 250 | self.img_transform_list = img_transform_list 251 | self.label_transform_list = label_transform_list 252 | 253 | self.extract_aff_lab_func = ExtractAffinityLabelInRadius(cropsize=cropsize//8, radius=radius) 254 | 255 | def __len__(self): 256 | return len(self.img_name_list) 257 | 258 | def __getitem__(self, idx): 259 | name, img = super().__getitem__(idx) 260 | 261 | label_path = os.path.join(self.label_dir, name + '.png') 262 | 263 | label = scipy.misc.imread(label_path) 264 | 265 | for joint_transform, img_transform, label_transform \ 266 | in zip(self.joint_transform_list, self.img_transform_list, self.label_transform_list): 267 | 268 | if joint_transform: 269 | img_label = np.concatenate((img, label), axis=-1) 270 | img_label = joint_transform(img_label) 271 | img = img_label[..., :3] 272 | label = img_label[..., 3:] 273 | 274 | if img_transform: 275 | img = img_transform(img) 276 | if label_transform: 277 | label = label_transform(label) 278 | 279 | label = self.extract_aff_lab_func(label) 280 | 281 | return img, label 282 | -------------------------------------------------------------------------------- /train_cls.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from torch.backends import cudnn 4 | cudnn.enabled = True 5 | from torch.utils.data import DataLoader, Dataset 6 | from torchvision import transforms 7 | import torch.optim as optim 8 | import voc12.data 9 | from tool import pyutils, imutils, torchutils 10 | import argparse 11 | import importlib 12 | import torch.nn.functional as F 13 | 14 | import matplotlib.pyplot as plt 15 | import math 16 | from tqdm import tqdm 17 | import collections 18 | 19 | import random 20 | import scipy.misc 21 | import os 22 | from PIL import Image 23 | from tensorboardX import SummaryWriter 24 | 25 | 26 | 27 | def compute_acc(pred_labels, gt_labels): 28 | pred_correct_count = 0 29 | pred_correct_list = [] 30 | for pred_label in pred_labels: 31 | if pred_label in gt_labels: 32 | pred_correct_count += 1 33 | union = len(gt_labels) + len(pred_labels) - pred_correct_count 34 | acc = round(pred_correct_count/union, 4) 35 | return acc 36 | 37 | 38 | def cls200_sum(y_200): 39 | cls20_prob_sum_list = [] 40 | for rou in range(20): 41 | subclass_prob_sum = sum(y_200[rou*k_cluster:rou*k_cluster+k_cluster]) 42 | cls20_prob_sum_list.append(subclass_prob_sum/10) 43 | 44 | cls200_pred_max = np.where(np.array(cls20_prob_sum_list)>0.05)[0] 45 | return cls200_pred_max 46 | 47 | 48 | def get_img_path(img_name, dataset_path): 49 | tmp = os.path.join(dataset_path, img_name + '.jpg') 50 | return tmp 51 | 52 | 53 | 54 | 55 | 56 | class Sub_Class_Dataset(Dataset): 57 | def __init__(self, voc12_root, crop_size, round_nb, k_cluster, save_folder, test=False): 58 | print('############################################## || k_{} / Round {} || ##############################################'.format(k_cluster, round_nb)) 59 | 60 | self.voc12_root = voc12_root 61 | self.crop_size = crop_size 62 | 63 | with open('{}/label/R{}_train_filename_list.txt'.format(save_folder, round_nb), 'r') as f: 64 | self.filename = f.read().split('\n') 65 | f.close() 66 | self.filename = self.filename[:-1] # 16458 67 | 68 | self.label = np.load('{}/label/R{}_train_label_200.npy'.format(save_folder, round_nb)) 69 | self.label = torch.from_numpy(self.label).float() 70 | 71 | self.label_20 = np.load('{}/label/R{}_train_label_20.npy'.format(save_folder, round_nb)) # 16458 72 | 73 | self.label_20 = torch.from_numpy(self.label_20).float() 74 | 75 | print('=='*60) 76 | print('Training Data: image: {} | 20 class label: {} | 200 class label: {}'.format(len(self.filename), self.label_20.shape, self.label.shape)) 77 | print('=='*60) 78 | 79 | 80 | def __getitem__(self, index): 81 | 82 | label_200 = self.label[index] 83 | label_20 = self.label_20[index] 84 | 85 | self.dataset_path = os.path.join(self.voc12_root, 'JPEGImages') 86 | 87 | filename = self.filename[index] 88 | 89 | img = Image.open(get_img_path(filename, self.dataset_path)).convert("RGB") 90 | img = imutils.ResizeLong(img, 256, 512) 91 | img = imutils.Flip(img) 92 | img = imutils.ColorJitter(img) 93 | img = np.array(img) 94 | img = imutils.NNormalize(img) 95 | img = imutils.Crop(img, self.crop_size) 96 | img = img.transpose(2,0,1) 97 | img = torch.from_numpy(img) 98 | 99 | return img, label_20, label_200, filename 100 | 101 | def __len__(self): 102 | return len(self.filename) 103 | 104 | 105 | 106 | 107 | if __name__ == '__main__': 108 | 109 | parser = argparse.ArgumentParser() 110 | parser.add_argument("--batch_size", default=16, type=int) 111 | parser.add_argument("--max_epoches", default=61, type=int) 112 | parser.add_argument("--network", default="network.resnet38_cls", type=str) 113 | parser.add_argument("--lr", default=0.01, type=float) 114 | parser.add_argument("--num_workers", default=8, type=int) 115 | parser.add_argument("--wt_dec", default=5e-4, type=float) 116 | parser.add_argument("--weights", required=True, type=str, help="the path to the pretrained weight ") 117 | parser.add_argument("--train_list", default="voc12/train_aug.txt", type=str) 118 | parser.add_argument("--session_name", default="resnet_cls", type=str) 119 | parser.add_argument("--crop_size", default=224, type=int) 120 | parser.add_argument("--voc12_root", default="/home/julia/datasets/VOC2012", type=str, help="the path to the dataset folder") 121 | parser.add_argument("--subcls_loss_weight", default="5", type=float, help="the weight multiply to the sub-category loss") 122 | parser.add_argument("--round_nb", default="0", type=int, help="the round number of the training classifier, e.g., 1st round: round_nb=1, and so on") 123 | parser.add_argument("--k_cluster", default="10", type=int, help="the number of the sub-category") 124 | parser.add_argument("--save_folder", required=True, default="./save", type=str, help="the path to save the model") 125 | 126 | args = parser.parse_args() 127 | 128 | model = getattr(importlib.import_module(args.network), 'Net')(args.k_cluster, args.round_nb) 129 | 130 | pyutils.Logger(args.session_name + '.log') 131 | 132 | print(vars(args)) 133 | 134 | log_path = os.path.join(args.save_folder, 'log', 'R{}'.format(args.round_nb)) 135 | writer = SummaryWriter('{}'.format(log_path)) 136 | 137 | 138 | train_dataset = Sub_Class_Dataset(voc12_root=args.voc12_root, 139 | crop_size = args.crop_size, 140 | round_nb=args.round_nb, 141 | k_cluster=args.k_cluster, 142 | save_folder=args.save_folder) 143 | 144 | train_data_loader = DataLoader(train_dataset, 145 | batch_size=args.batch_size, 146 | shuffle=True, 147 | num_workers=args.num_workers, 148 | pin_memory=True, 149 | drop_last=True) 150 | 151 | 152 | 153 | max_step = (len(train_dataset) // args.batch_size) * args.max_epoches 154 | 155 | 156 | param_groups = model.get_parameter_groups() 157 | optimizer = torchutils.PolyOptimizer([ 158 | {'params': param_groups[0], 'lr': args.lr, 'weight_decay': args.wt_dec}, 159 | {'params': param_groups[1], 'lr': 2*args.lr, 'weight_decay': 0}, 160 | {'params': param_groups[2], 'lr': 10*args.lr, 'weight_decay': args.wt_dec}, 161 | {'params': param_groups[3], 'lr': 20*args.lr, 'weight_decay': 0} 162 | ], lr=args.lr, weight_decay=args.wt_dec, max_step=max_step) 163 | 164 | 165 | if args.weights[-7:] == '.params': 166 | assert args.network == "network.resnet38_cls" 167 | import network.resnet38d 168 | weights_dict = network.resnet38d.convert_mxnet_to_torch(args.weights) 169 | elif args.weights[-11:] == '.caffemodel': 170 | assert args.network == "network.vgg16_cls" 171 | import network.vgg16d 172 | weights_dict = network.vgg16d.convert_caffe_to_torch(args.weights) 173 | else: 174 | weights_dict = torch.load(args.weights) 175 | 176 | model.load_state_dict(weights_dict, strict=False) 177 | model = torch.nn.DataParallel(model).cuda() 178 | model.train() 179 | 180 | avg_meter = pyutils.AverageMeter('loss') 181 | 182 | timer = pyutils.Timer("Session started: ") 183 | 184 | 185 | parent_labels = np.load('./voc12/cls_labels.npy').tolist() 186 | k_cluster = 10 187 | 188 | 189 | step = 0 190 | for ep in range(args.max_epoches): 191 | ep_count = 0 192 | ep_EM = 0 193 | ep_acc = 0 194 | 195 | ep_p_EM = 0 196 | ep_p_acc = 0 197 | ep_acc_vote = 0 198 | 199 | cls20_ep_EM = 0 200 | cls20_ep_acc = 0 201 | 202 | for iter, (data, label_20, label_200, filename) in tqdm(enumerate(train_data_loader)): 203 | 204 | img = data 205 | label_20 = label_20.cuda(non_blocking=True) 206 | label_200 = label_200.cuda(non_blocking=True) 207 | img_name = filename 208 | 209 | 210 | x_20, _, y_20, x_200, y_200 = model(img, args.round_nb) 211 | 212 | # compute acc for 20 classes 213 | cls20_prob = y_20.cpu().data.numpy() 214 | cls20_gt = label_20.cpu().data.numpy() 215 | for num, one in enumerate(cls20_prob): 216 | ep_count += 1 217 | pass_cls = np.where(one > 0.5)[0] 218 | true_cls_20 = np.where(cls20_gt[num] == 1)[0] 219 | 220 | if np.array_equal(pass_cls, true_cls_20) == True: # exact match 221 | cls20_ep_EM += 1 222 | 223 | acc = compute_acc(pass_cls, true_cls_20) 224 | cls20_ep_acc += acc 225 | 226 | 227 | # compute acc for 200 classes 228 | tmp = y_200.cpu().data.numpy() 229 | tmp_label = label_200.cpu().data.numpy() 230 | for num, one in enumerate(tmp): 231 | pass_cls = np.where(one>0.5)[0] 232 | true_cls_200 = np.where(tmp_label[num] == 1)[0] 233 | 234 | parent_cls = np.where(parent_labels[img_name[num]] == 1)[0] 235 | 236 | cls200_pred_max = cls200_sum(one) 237 | 238 | if np.array_equal(pass_cls, true_cls_200) == True: 239 | ep_EM += 1 240 | 241 | # cls200: acc for 200-->20 (sum) 242 | acc = compute_acc(cls200_pred_max, parent_cls) 243 | ep_acc += acc 244 | 245 | # cls200: acc for 200-->20 (top 1) 246 | pass_map_cls = np.unique([int(m/k_cluster) for m in np.where(one > 0.5)[0]]) 247 | if np.array_equal(pass_map_cls, parent_cls) == True: 248 | ep_p_EM += 1 249 | 250 | p_acc = compute_acc(pass_map_cls, parent_cls) 251 | ep_p_acc += p_acc 252 | 253 | 254 | 255 | avg_ep_EM = round(ep_EM/ep_count, 4) 256 | avg_ep_acc = round(ep_acc/ep_count, 4) 257 | 258 | avg_ep_p_EM = round(ep_p_EM/ep_count, 4) 259 | avg_ep_p_acc = round(ep_p_acc/ep_count, 4) 260 | 261 | avg_cls20_ep_EM = round(cls20_ep_EM/ep_count, 4) 262 | avg_cls20_ep_acc = round(cls20_ep_acc/ep_count, 4) 263 | 264 | cls_20_loss = F.multilabel_soft_margin_loss(x_20, label_20) 265 | cls_200_loss = F.multilabel_soft_margin_loss(x_200, label_200) 266 | 267 | loss = cls_20_loss + (args.subcls_loss_weight*cls_200_loss) 268 | 269 | if iter%100 ==0: 270 | print('k{} R{}| Ep:{} L:{} -20_LOSS:{} -200_LOSS:{} | -cls20:{} | -cls200_Top1:{} -Sum:{}'.format(args.k_cluster, args.round_nb, ep, round(loss.item(), 3), round(cls_20_loss.item(), 3), round(cls_200_loss.item(), 3), avg_cls20_ep_acc, avg_ep_p_acc, avg_ep_acc)) 271 | 272 | avg_meter.add({'loss': cls_200_loss.item()}) 273 | 274 | 275 | optimizer.zero_grad() 276 | loss.backward() 277 | optimizer.step() 278 | torch.cuda.empty_cache() 279 | 280 | writer.add_scalar('20 Classification Loss', cls_20_loss.item(), step) 281 | writer.add_scalar('200 Classification Loss', cls_200_loss.item(), step) 282 | writer.add_scalar('Total Loss', loss.item(), step) 283 | writer.add_scalar('Cls20 Accuracy', avg_cls20_ep_acc, step) 284 | writer.add_scalar('Cls200 Accuracy (Sum)', avg_ep_acc, step) 285 | writer.add_scalar('Cls200 Accuracy (Top1)', avg_ep_p_acc, step) 286 | 287 | step += 1 288 | 289 | if (optimizer.global_step-1)%100 == 0: 290 | timer.update_progress(optimizer.global_step / max_step) 291 | 292 | print('Iter:%5d/%5d' % (optimizer.global_step - 1, max_step), 293 | 'Loss:%.4f' % (avg_meter.pop('loss')), 294 | 'imps:%.1f' % ((iter+1) * args.batch_size / timer.get_stage_elapsed()), 295 | 'Fin:%s' % (timer.str_est_finish()), 296 | 'lr: %.4f' % (optimizer.param_groups[0]['lr']), flush=True) 297 | 298 | 299 | if ep % 10 == 0: 300 | torch.save(model.module.state_dict(), '{}/weight/k{}_R{}_'.format(args.save_folder, args.k_cluster, args.round_nb) + args.session_name + '_ep{}.pth'.format(ep)) 301 | print('Loss: {} achieves the lowest one => Epoch {} weights are saved!'.format(loss, ep)) 302 | -------------------------------------------------------------------------------- /tool/infer_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from PIL import Image 5 | import shutil 6 | import scipy.misc 7 | import math 8 | 9 | 10 | 11 | def create_class_key_in_dict(dict, cls_nb): 12 | for i in range(cls_nb): 13 | dict[i] = [] 14 | return dict 15 | 16 | 17 | def calculate_class_avg_iou(class_iou_dict): 18 | class_mean_iou_dict = {} 19 | for i in range(20): 20 | class_iou_list = class_iou_dict[i] 21 | if len(class_iou_list) != 0: 22 | class_iou_list_mean = round(sum(class_iou_list)/len(class_iou_list), 4) 23 | else: 24 | class_iou_list_mean = 0. 25 | class_mean_iou_dict[i] = class_iou_list_mean 26 | return class_mean_iou_dict 27 | 28 | 29 | def draw_heatmap(img, hm): 30 | hm = plt.cm.hot(hm)[:, :, :3] 31 | hm = np.array(Image.fromarray((hm*255).astype(np.uint8), 'RGB').resize((img.shape[1], img.shape[0]), Image.BICUBIC)).astype(np.float)*2 32 | if hm.shape == np.array(img).astype(np.float).shape: 33 | out = (hm + np.array(img).astype(np.float)) / 3 34 | out = Image.fromarray((out / np.max(out) * 255).astype(np.uint8), 'RGB') 35 | return hm, out 36 | 37 | 38 | def draw_heatmap_array(img, hm): 39 | hm = plt.cm.hot(hm)[:, :, :3] 40 | hm = np.array(Image.fromarray((hm*255).astype(np.uint8), 'RGB').resize((img.shape[1], img.shape[0]), Image.BICUBIC)).astype(np.float)*2 41 | if hm.shape == np.array(img).astype(np.float).shape: 42 | out = (hm + np.array(img).astype(np.float)) / 3 43 | out = (out / np.max(out) * 255).astype(np.uint8) 44 | return hm, out 45 | 46 | 47 | def cls200_vote(y_200, k_cluster): 48 | topk_subcls = np.argsort(y_200[0].detach().cpu().numpy())[-10:][::-1] 49 | topk_cls = np.array(topk_subcls/k_cluster, dtype=np.uint8) 50 | topk_vote = np.unique(topk_cls, return_counts=True) 51 | 52 | p_cls_sum = [] 53 | for p_cls in topk_vote[0]: 54 | subcls_sum = [] 55 | for prob in np.where(topk_cls == p_cls)[0]: 56 | subcls_sum.append(y_200[0][topk_subcls[prob]].item()) 57 | p_cls_sum.append(sum(subcls_sum)) 58 | 59 | cls200_pred_vote = topk_vote[0][np.where(np.array(p_cls_sum) >= 0.5)[0]] 60 | return cls200_pred_vote 61 | 62 | 63 | def cls200_sum(y_200, k_cluster): 64 | cls20_prob_sum_list = [] 65 | for rou in range(20): 66 | subclass_prob_sum = sum(y_200[0][rou*k_cluster:rou*k_cluster+k_cluster].detach().cpu().numpy()) 67 | cls20_prob_sum_list.append(subclass_prob_sum/10) 68 | 69 | cls200_pred_max = np.where(np.array(cls20_prob_sum_list)>0.05)[0] 70 | return cls200_pred_max 71 | 72 | 73 | def cam_subcls_norm(cam, cls20_gt, k_cluster): 74 | for gt in cls20_gt: 75 | subcls_cam = cam[gt*k_cluster:gt*k_cluster+k_cluster] 76 | 77 | norm_cam = subcls_cam / (np.max(subcls_cam, keepdims=True) + 1e-5) 78 | 79 | subcls_norm_cam = np.asarray(norm_cam) 80 | cam[gt*k_cluster:gt*k_cluster+k_cluster] = subcls_norm_cam 81 | return cam 82 | 83 | 84 | def compute_acc(pred_labels, gt_labels): 85 | pred_correct_count = 0 86 | pred_correct_list = [] 87 | for pred_label in pred_labels: 88 | if pred_label in gt_labels: 89 | pred_correct_count += 1 90 | union = len(gt_labels) + len(pred_labels) - pred_correct_count 91 | acc = round(pred_correct_count/union, 4) 92 | return(acc) 93 | 94 | 95 | def compute_iou(gt_labels, cam_np, gt_np, th, class_iou_dict): 96 | iou_list = [] 97 | for label in gt_labels: 98 | cam = cam_np[label] 99 | gt = gt_np[label] 100 | 101 | gt_target_class = label + 1 102 | 103 | gt_y, gt_x = np.where(gt == gt_target_class) 104 | gt_pixel_nb = gt_y.shape[0] # object 105 | 106 | correct_pixel_nb = 0 107 | 108 | cam_y, cam_x = np.where(cam >= th) 109 | high_response_pixel_nb = cam_y.shape[0] # detected 110 | 111 | for pixel in range(gt_y.shape[0]): 112 | if cam[gt_y[pixel]][gt_x[pixel]] >= th: 113 | correct_pixel_nb += 1 # intersection 114 | else: 115 | continue 116 | 117 | union = gt_pixel_nb + high_response_pixel_nb - correct_pixel_nb 118 | 119 | if high_response_pixel_nb != 0: 120 | iou = round(correct_pixel_nb/union, 4) 121 | else: 122 | iou = 0. 123 | iou_list.append(iou) 124 | if high_response_pixel_nb != 0: 125 | precision = round(correct_pixel_nb/high_response_pixel_nb, 4) 126 | else: 127 | precision = 0. 128 | recall = round(correct_pixel_nb/gt_pixel_nb, 4) 129 | class_iou_dict[label].append(iou) 130 | print(label, iou) 131 | return class_iou_dict, iou_list 132 | 133 | 134 | 135 | 136 | def compute_merge_iou(gt_labels, cam_nor, cam_b4_nor, gt_np, th, k, class_iou_dict): 137 | merged_cam_list = [] 138 | for label in gt_labels: 139 | 140 | cam_b4_nor_ = cam_b4_nor[label*k:label*k+k] # (10, 366, 500) 141 | cam_b4_sum = np.sum(cam_b4_nor_, axis=0) # (366, 500) 142 | merge_cam = cam_b4_sum / np.amax(cam_b4_sum) # (366, 500) np.max(merge_cam)=1.0 143 | 144 | 145 | merged_cam_list.append(merge_cam) 146 | 147 | 148 | gt = gt_np[label] 149 | gt_target_class = label + 1 150 | 151 | gt_y, gt_x = np.where(gt == gt_target_class) 152 | gt_pixel_nb = gt_y.shape[0] # object 153 | 154 | correct_pixel_nb = 0 155 | 156 | cam_y, cam_x = np.where(merge_cam >= th) 157 | high_response_pixel_nb = cam_y.shape[0] # detected 158 | 159 | for pixel in range(gt_y.shape[0]): 160 | if merge_cam[gt_y[pixel]][gt_x[pixel]] >= th: 161 | correct_pixel_nb += 1 # intersection 162 | else: 163 | continue 164 | 165 | union = gt_pixel_nb + high_response_pixel_nb - correct_pixel_nb 166 | 167 | if high_response_pixel_nb != 0: 168 | iou = round(correct_pixel_nb/union, 4) 169 | else: 170 | iou = 0. 171 | if high_response_pixel_nb != 0: 172 | precision = round(correct_pixel_nb/high_response_pixel_nb, 4) 173 | else: 174 | precision = 0. 175 | recall = round(correct_pixel_nb/gt_pixel_nb, 4) 176 | class_iou_dict[label].append(iou) 177 | return class_iou_dict, merged_cam_list 178 | 179 | 180 | 181 | def compute_merge_11_iou(gt_labels, cam_20, cam_200, gt_np, th, k, class_all_iou_dict): 182 | merged_cam_list = [] 183 | for label in gt_labels: 184 | parcls_cam = np.expand_dims(cam_20[label], axis=0) 185 | subcls_cam = cam_200[label*k:label*k+k] 186 | 187 | merge_11_cam = np.concatenate((subcls_cam, parcls_cam), axis=0) 188 | merge_11_cam = np.amax(merge_11_cam, axis=0) 189 | merge_cam = merge_11_cam / np.amax(merge_11_cam) 190 | 191 | merged_cam_list.append(merge_cam) 192 | 193 | gt = gt_np[label] 194 | gt_target_class = label + 1 195 | 196 | gt_y, gt_x = np.where(gt == gt_target_class) 197 | gt_pixel_nb = gt_y.shape[0] 198 | 199 | correct_pixel_nb = 0 200 | 201 | cam_y, cam_x = np.where(merge_cam >= th) 202 | high_response_pixel_nb = cam_y.shape[0] 203 | 204 | for pixel in range(gt_y.shape[0]): 205 | if merge_cam[gt_y[pixel]][gt_x[pixel]] >= th: 206 | correct_pixel_nb += 1 207 | else: 208 | continue 209 | 210 | union = gt_pixel_nb + high_response_pixel_nb - correct_pixel_nb 211 | 212 | if high_response_pixel_nb != 0: 213 | iou = round(correct_pixel_nb/union, 4) 214 | else: 215 | iou = 0. 216 | if high_response_pixel_nb != 0: 217 | precision = round(correct_pixel_nb/high_response_pixel_nb, 4) 218 | else: 219 | precision = 0. 220 | recall = round(correct_pixel_nb/gt_pixel_nb, 4) 221 | class_all_iou_dict[label].append(iou) 222 | 223 | return class_all_iou_dict, merged_cam_list 224 | 225 | 226 | 227 | def compute_ub_iou(gt_labels, cam_np, gt_np, th, k, class_iou_dict): 228 | iou_list = [] 229 | all_subclass_iou_list = [] 230 | for l_num, label in enumerate(gt_labels): 231 | subclass_iou_list = [] 232 | cam = cam_np[label*k:label*k+k] 233 | for num, one in enumerate(cam): 234 | merge_cam = one 235 | gt = gt_np[label] 236 | 237 | gt_target_class = label + 1 238 | 239 | gt_y, gt_x = np.where(gt == gt_target_class) 240 | gt_pixel_nb = gt_y.shape[0] 241 | 242 | correct_pixel_nb = 0 243 | 244 | cam_y, cam_x = np.where(merge_cam >= th) 245 | high_response_pixel_nb = cam_y.shape[0] 246 | 247 | for pixel in range(gt_y.shape[0]): 248 | if merge_cam[gt_y[pixel]][gt_x[pixel]] >= th: 249 | correct_pixel_nb += 1 250 | else: 251 | continue 252 | 253 | union = gt_pixel_nb + high_response_pixel_nb - correct_pixel_nb 254 | 255 | 256 | if high_response_pixel_nb != 0: 257 | iou = round(correct_pixel_nb/union, 4) 258 | else: 259 | iou = 0. 260 | subclass_iou_list.append(iou) 261 | 262 | if high_response_pixel_nb != 0: 263 | precision = round(correct_pixel_nb/high_response_pixel_nb, 4) 264 | else: 265 | precision = 0. 266 | recall = round(correct_pixel_nb/gt_pixel_nb, 4) 267 | 268 | print(label, 'subcls_iou_list: {}'.format(subclass_iou_list)) 269 | max_iou = max(subclass_iou_list) 270 | print(max_iou, subclass_iou_list.index(max(subclass_iou_list))) 271 | class_iou_dict[label].append(max_iou) 272 | iou_list.append(max_iou) 273 | 274 | all_subclass_iou_list.append(subclass_iou_list) 275 | return class_iou_dict, iou_list, all_subclass_iou_list 276 | 277 | 278 | 279 | 280 | def count_maxiou_prob(y_200, cls20_gt, all_subclass_iou_list, class_20_iou_list, k_cluster, subclass_top_iou_list, class_200_ub_iou_list, class_ub_iou_dict, img_name): 281 | for i, gt in enumerate(cls20_gt): 282 | subclass_prob = y_200[0][gt*k_cluster:gt*k_cluster+k_cluster].detach().cpu().numpy() 283 | print('pred_score: {}'.format(subclass_prob)) 284 | 285 | ten_subclass_iou_list = all_subclass_iou_list[i] 286 | ten_subclass_iou_list.append(class_20_iou_list[i]) 287 | 288 | subclass_max_idx = ten_subclass_iou_list.index(max(ten_subclass_iou_list)) 289 | pred_subclass = gt*k_cluster+subclass_max_idx 290 | 291 | if subclass_max_idx != 10: 292 | sort_subclass_prob_idx = np.argsort(subclass_prob)[::-1] 293 | top_k_best_iou = np.where(sort_subclass_prob_idx == subclass_max_idx)[0][0] 294 | subclass_top_iou_list[top_k_best_iou] += 1 295 | else: 296 | top_k_best_iou = 10 297 | subclass_top_iou_list[top_k_best_iou] += 1 298 | 299 | 300 | ub_iou = max(class_20_iou_list[i], class_200_ub_iou_list[i]) 301 | class_ub_iou_dict[cls20_gt[i]].append(ub_iou) 302 | print(subclass_top_iou_list) 303 | 304 | line = '{},{},{},{},{}\n'.format(img_name, pred_subclass, top_k_best_iou, ub_iou, class_20_iou_list) 305 | 306 | return class_ub_iou_dict 307 | 308 | 309 | 310 | def merge_topk_iou(y_200, gt_labels, all_subclass_iou_list, cam_np, gt_np, th, k, class_iou_dict): 311 | merged_cam_list = [] 312 | for num, label in enumerate(gt_labels): 313 | subclass_prob = y_200[0][label*k:label*k+k].detach().cpu().numpy() 314 | subclass_iou_list = all_subclass_iou_list[num][:-1] 315 | 316 | cam = cam_np[label*k:label*k+k] 317 | sort_subcls_prob_idx = np.argsort(subclass_prob)[::-1] 318 | 319 | # print(subclass_prob) 320 | # print(subclass_iou_list) 321 | # print(sort_subcls_prob_idx) 322 | 323 | top_k_list = [0, 1, 2, 4, 9] 324 | top_k_iou_list = [] 325 | for top in top_k_list: 326 | merge_k = np.zeros((top+1, cam.shape[1], cam.shape[2])) 327 | target_subcls_cam_idx = sort_subcls_prob_idx[:top+1] 328 | print(top, merge_k.shape, target_subcls_cam_idx) 329 | 330 | for i, idx in enumerate(target_subcls_cam_idx): 331 | merge_k[i] = cam[idx] 332 | 333 | ## norm -> max per pixel 334 | merge_cam = np.amax(merge_k, axis=0) 335 | 336 | # ## sum -> norm 337 | # merge_cam = np.sum(cam, axis=0) / np.amax(cam) 338 | 339 | merged_cam_list.append(merge_cam) 340 | 341 | 342 | gt = gt_np[label] 343 | gt_target_class = label + 1 344 | 345 | gt_y, gt_x = np.where(gt == gt_target_class) 346 | gt_pixel_nb = gt_y.shape[0] # object 347 | 348 | correct_pixel_nb = 0 349 | 350 | cam_y, cam_x = np.where(merge_cam >= th) 351 | high_response_pixel_nb = cam_y.shape[0] # detected 352 | 353 | for pixel in range(gt_y.shape[0]): 354 | if merge_cam[gt_y[pixel]][gt_x[pixel]] >= th: 355 | correct_pixel_nb += 1 # intersection 356 | else: 357 | continue 358 | 359 | union = gt_pixel_nb + high_response_pixel_nb - correct_pixel_nb 360 | 361 | if high_response_pixel_nb != 0: 362 | iou = round(correct_pixel_nb/union, 4) 363 | else: 364 | iou = 0. 365 | if high_response_pixel_nb != 0: 366 | precision = round(correct_pixel_nb/high_response_pixel_nb, 4) 367 | else: 368 | precision = 0. 369 | recall = round(correct_pixel_nb/gt_pixel_nb, 4) 370 | 371 | top_k_iou_list.append(iou) 372 | 373 | return class_iou_dict, merged_cam_list 374 | 375 | 376 | 377 | def vrf_iou_w_distance(cls20_gt): 378 | cls20_w = np.load('./kmeans_subclass/c20_k10/3rd_round/weight_np/R3_cls20_w.npy') # (20, 4096) 379 | cls200_w = np.load('./kmeans_subclass/c20_k10/3rd_round/weight_np/R3_cls200_w.npy') # (200, 4096) 380 | 381 | bike_w = cls20_w[cls20_gt[0]] 382 | sub_human_w = cls200_w[cls20_gt[1]*10:cls20_gt[1]*10+10] 383 | 384 | sub_w_dis_list = [] 385 | for num, sub in enumerate(sub_human_w): 386 | dist = np.linalg.norm(bike_w-sub) 387 | sub_w_dis_list.append(dist) 388 | print('dist_list: {}'.format(sub_w_dis_list)) 389 | print(sub_w_dis_list.index(min(sub_w_dis_list))) 390 | 391 | 392 | def find_200_pseudo_label(image_name, round_nb): 393 | filename_list_path = './kmeans_subclass/c20_k10/{}_round/train/{}_train_filename_list.txt'.format(round_nb, round_nb) 394 | label_20_npy = np.load( './kmeans_subclass/c20_k10/{}_round/train/{}_train_label_20.npy'.format(round_nb, round_nb)) 395 | label_200_npy = np.load('./kmeans_subclass/c20_k10/{}_round/train/{}_train_label_200.npy'.format(round_nb, round_nb)) 396 | 397 | with open(filename_list_path, 'r') as f: 398 | filename_list = f.read().split('\n') 399 | f.close() 400 | 401 | image_idx = filename_list.index(image_name) 402 | label_20 = label_20_npy[image_idx] 403 | label_200 = label_200_npy[image_idx] 404 | 405 | 406 | return label_20, label_200 407 | 408 | 409 | def cam_npy_to_cam_dict(cam_np, label): 410 | cam_dict = {} 411 | idxs = np.where(label==1)[0] 412 | 413 | for idx in idxs: 414 | cam_dict[idx] = cam_np[idx] 415 | 416 | return cam_dict 417 | 418 | 419 | def response_to_label(cam_npy): 420 | seg_map = cam_npy.transpose(1,2,0) 421 | seg_map = np.asarray(np.argmax(seg_map, axis=2), dtype=np.int) 422 | 423 | return seg_map 424 | 425 | 426 | def get_accum_from_dict(par_cls, clust_dict): 427 | accum = 0 428 | for m in range(par_cls): 429 | accum += clust_dict[m] 430 | return accum 431 | 432 | 433 | def cls200_cam_norm(cam_list_200, k_cluster): 434 | cam_200 = np.sum(cam_list_200, axis=0) 435 | norm_cam_200 = np.zeros((cam_200.shape[0], cam_200.shape[1], cam_200.shape[2])) 436 | 437 | for i in range(20): 438 | subcls_cam = cam_200[i*k_cluster:i*k_cluster+k_cluster] 439 | 440 | norm_cam = subcls_cam / (np.max(subcls_cam, keepdims=True) + 1e-5) 441 | 442 | subcls_norm_cam = np.asarray(norm_cam) 443 | norm_cam_200[i*k_cluster:i*k_cluster+k_cluster] = subcls_norm_cam 444 | return norm_cam_200 445 | 446 | 447 | 448 | def cls200_cam_norm_dynamicK(cam_list_200, clust_dict): 449 | 450 | cam_200 = np.sum(cam_list_200, axis=0) 451 | norm_cam_200 = np.zeros((cam_200.shape[0], cam_200.shape[1], cam_200.shape[2])) 452 | for i in range(20): 453 | accum = get_accum_from_dict(i, clust_dict) 454 | 455 | subcls_cam = cam_200[accum:accum+clust_dict[i]] 456 | 457 | norm_cam = subcls_cam / (np.max(subcls_cam, keepdims=True) + 1e-5) 458 | 459 | subcls_norm_cam = np.asarray(norm_cam) 460 | norm_cam_200[accum:accum+clust_dict[i]] = subcls_norm_cam 461 | return norm_cam_200 462 | 463 | 464 | 465 | def dict2npy(cam_dict, gt_label, th): 466 | gt_cat = np.where(gt_label==1)[0] 467 | 468 | orig_img_size = cam_dict[gt_cat[0]].shape 469 | 470 | bg_score = [np.ones_like(cam_dict[gt_cat[0]])*th] 471 | cam_npy = np.zeros((20, orig_img_size[0], orig_img_size[1])) 472 | 473 | for gt in gt_cat: 474 | cam_npy[gt] = cam_dict[gt] 475 | 476 | cam_npy = np.concatenate((bg_score, cam_npy), axis=0) 477 | return cam_npy 478 | 479 | 480 | 481 | def merge_200_cam_dict(cam_dict_200, gt_label, th, k): 482 | gt_cat = np.where(gt_label==1)[0] 483 | 484 | orig_img_size = cam_dict_200[gt_cat[0]*k].shape 485 | 486 | cam_npy = np.zeros((20, orig_img_size[0], orig_img_size[1])) 487 | sub_cam_npy = np.zeros((k, orig_img_size[0], orig_img_size[1])) 488 | 489 | for gt in gt_cat: 490 | for i in range(k): 491 | sub_cam_npy[i] = cam_dict_200[gt*k+i] 492 | sub_cam_max_npy = np.amax(sub_cam_npy, axis=0) 493 | cam_npy[gt] = sub_cam_max_npy 494 | return cam_npy 495 | 496 | 497 | 498 | def cam_npy_to_label_map(cam_npy): 499 | seg_map = cam_npy.transpose(1,2,0) 500 | seg_map = np.asarray(np.argmax(seg_map, axis=2), dtype=np.int) 501 | return seg_map 502 | 503 | 504 | 505 | def cam_npy_to_cam_dict(cam_npy, label): 506 | cam_dict = {} 507 | for i in range(len(label)): 508 | if label[i] > 1e-5: 509 | cam_dict[i] = cam_npy[i] 510 | return cam_dict 511 | 512 | 513 | def cls200_cam_to_cls20_entropy(no_norm_cam_200, k_cluster, norm_cam, save_path, img_name, orig_img, gt_label, save_entropy_heatmap): 514 | gt_cat = np.where(gt_label==1)[0] 515 | 516 | cam_200_entropy_path = '{}/entropy/cls_200/{}'.format(save_path, img_name) 517 | if save_entropy_heatmap == 1: 518 | if os.path.isdir(cam_200_entropy_path): 519 | shutil.rmtree(cam_200_entropy_path) 520 | os.mkdir(cam_200_entropy_path) 521 | 522 | entropy_npy = np.zeros((norm_cam.shape[0], norm_cam.shape[1], norm_cam.shape[2])) 523 | 524 | 525 | for i in range(20): 526 | sub_cams = no_norm_cam_200[i*k_cluster:i*k_cluster+k_cluster] 527 | 528 | sub_cams_sum = np.sum(sub_cams, axis=0) 529 | 530 | sub_cams_sum_10 = sub_cams_sum[np.newaxis, :] 531 | sub_cams_sum_10 = np.repeat(sub_cams_sum_10, k_cluster, axis=0) 532 | prob = sub_cams/(sub_cams_sum_10 + 1e-5) 533 | 534 | prob_log = np.log(prob + 1e-5) / np.log(k_cluster) 535 | 536 | entropy_norm = -(np.sum(prob*prob_log, axis=0)) # entropy normalization 537 | 538 | entropy_norm[entropy_norm<0]=0 539 | entropy_npy[i] = entropy_norm 540 | 541 | if save_entropy_heatmap == 1: 542 | if i in gt_cat: 543 | hm, heatmap = draw_heatmap(orig_img, entropy_norm) 544 | scipy.misc.imsave('{}/entropy/cls_200/{}/{}_{}.png'.format(save_path, img_name, img_name, i), heatmap) 545 | 546 | return entropy_npy 547 | 548 | 549 | def create_folder(inference_dir_path): 550 | 551 | if os.path.exists(inference_dir_path) == True: 552 | shutil.rmtree(inference_dir_path) 553 | 554 | os.mkdir(inference_dir_path) 555 | os.mkdir(os.path.join(inference_dir_path + '/heatmap')) 556 | os.mkdir(os.path.join(inference_dir_path + '/heatmap/cls_20')) 557 | os.mkdir(os.path.join(inference_dir_path + '/heatmap/cls_200')) 558 | os.mkdir(os.path.join(inference_dir_path + '/output_CAM_npy')) 559 | os.mkdir(os.path.join(inference_dir_path + '/output_CAM_npy/cls_20')) 560 | os.mkdir(os.path.join(inference_dir_path + '/output_CAM_npy/cls_200')) 561 | os.mkdir(os.path.join(inference_dir_path + '/IOU')) 562 | os.mkdir(os.path.join(inference_dir_path + '/crf')) 563 | os.mkdir(os.path.join(inference_dir_path + '/crf/out_la_crf')) 564 | os.mkdir(os.path.join(inference_dir_path + '/crf/out_ha_crf')) 565 | 566 | 567 | 568 | 569 | def draw_single_heatmap(norm_cam, gt_label, orig_img, save_path, img_name): 570 | gt_cat = np.where(gt_label==1)[0] 571 | heatmap_list = [] 572 | mask_list = [] 573 | for i, gt in enumerate(gt_cat): 574 | hm, heatmap = draw_heatmap_array(orig_img, norm_cam[gt]) 575 | cam_viz_path = os.path.join(save_path,'heatmap/cls_20', img_name + '_{}.png'.format(gt)) 576 | scipy.misc.imsave(cam_viz_path, heatmap) 577 | 578 | norm_cam_gt = norm_cam[gt] 579 | norm_cam_gt[norm_cam_gt<=0.15]=0 580 | norm_cam_gt[norm_cam_gt>0.15]=255 581 | 582 | heatmap = np.transpose(heatmap, (2, 1, 0)) 583 | heatmap_list.append(heatmap) 584 | mask_list.append(norm_cam_gt) 585 | 586 | return heatmap_list, mask_list 587 | 588 | 589 | 590 | 591 | def draw_heatmap_cls200(norm_cam, gt_label, orig_img): 592 | gt_cat = np.where(gt_label==1)[0] 593 | heatmap_list = [] 594 | for i, gt in enumerate(gt_cat): 595 | heatmap_cat_list = [] 596 | for x in range(10): 597 | hm, heatmap = draw_heatmap_array(orig_img, norm_cam[gt*10+x]) 598 | heatmap = np.transpose(heatmap, (2, 1, 0)) 599 | heatmap_cat_list.append(heatmap) 600 | heatmap_list.append(heatmap_cat_list) 601 | 602 | return heatmap_list 603 | 604 | 605 | def draw_heatmap_cls200_merge(norm_cam, gt_label, orig_img, img_name): 606 | gt_cat = np.where(gt_label==1)[0] 607 | heatmap_list = [] 608 | for i, gt in enumerate(gt_cat): 609 | hm, heatmap = draw_heatmap_array(orig_img, norm_cam[gt]) 610 | scipy.misc.imsave('/home/julia/julia_data/wsss/best/heatmap/cls_200/merge_{}.png'.format(img_name), heatmap) 611 | heatmap = np.transpose(heatmap, (2, 1, 0)) 612 | heatmap_list.append(heatmap) 613 | 614 | return heatmap_list 615 | 616 | 617 | def draw_heatmap_cls200_entropy(norm_cam, gt_label, orig_img): 618 | gt_cat = np.where(gt_label==1)[0] 619 | heatmap_list = [] 620 | mask_list = [] 621 | for i, gt in enumerate(gt_cat): 622 | hm, heatmap = draw_heatmap_array(orig_img, norm_cam[gt]) 623 | 624 | norm_cam_gt = norm_cam[gt] 625 | norm_cam_gt[norm_cam_gt<=0.6]=0 626 | norm_cam_gt[norm_cam_gt>0.6]=255 627 | 628 | heatmap = np.transpose(heatmap, (2, 1, 0)) 629 | heatmap_list.append(heatmap) 630 | mask_list.append(norm_cam_gt) 631 | 632 | return heatmap_list, mask_list 633 | 634 | 635 | def combine_four_images(files, img_name, gt, save_path): 636 | result = Image.new("RGB", (1200, 800)) 637 | 638 | for index, file in enumerate(files): 639 | img = file 640 | img.thumbnail((400, 400), Image.ANTIALIAS) 641 | x = index // 2 * 400 642 | y = index % 2 * 400 643 | w , h = img.size 644 | result.paste(img, (x, y, x + w, y + h)) 645 | result.save(os.path.expanduser('./{}/combine_maps/{}_{}.jpg'.format(save_path, img_name, gt))) 646 | 647 | 648 | def save_combine_response_maps(cam_20_heatmap, cam_200_merge_heatmap, cam_200_entropy_heatmap, cam_20_map, cam_200_entropy_map, orig_img, gt_label, img_name, save_path): 649 | gt_cat = np.where(gt_label==1)[0] 650 | orig_img_out = Image.fromarray(orig_img.astype(np.uint8), 'RGB') 651 | print(len(cam_20_heatmap), len(cam_200_merge_heatmap), len(cam_200_entropy_heatmap)) 652 | 653 | for num, gt in enumerate(gt_cat): 654 | cls20_out = Image.fromarray(np.transpose(cam_20_heatmap[num], (2, 1, 0)).astype(np.uint8), 'RGB') 655 | cls200_merge_out = Image.fromarray(np.transpose(cam_200_merge_heatmap[num], (2, 1, 0)).astype(np.uint8), 'RGB') 656 | cls200_entropy_out = Image.fromarray(np.transpose(cam_200_entropy_heatmap[num], (2, 1, 0)).astype(np.uint8), 'RGB') 657 | cam_20_map_out = Image.fromarray(cam_20_map[num].astype(np.uint8)) 658 | cam_200_entropy_map_out = Image.fromarray(cam_200_entropy_map[num].astype(np.uint8)) 659 | 660 | image_list = [orig_img_out, cls200_merge_out, cls20_out, cls200_entropy_out, cam_20_map_out, cam_200_entropy_map_out] 661 | combine_four_images(image_list, img_name, gt, save_path) 662 | -------------------------------------------------------------------------------- /voc12/test.txt: -------------------------------------------------------------------------------- 1 | /JPEGImages/2008_000006.jpg 2 | /JPEGImages/2008_000011.jpg 3 | /JPEGImages/2008_000012.jpg 4 | /JPEGImages/2008_000018.jpg 5 | /JPEGImages/2008_000024.jpg 6 | /JPEGImages/2008_000030.jpg 7 | /JPEGImages/2008_000031.jpg 8 | /JPEGImages/2008_000046.jpg 9 | /JPEGImages/2008_000047.jpg 10 | /JPEGImages/2008_000048.jpg 11 | /JPEGImages/2008_000057.jpg 12 | /JPEGImages/2008_000058.jpg 13 | /JPEGImages/2008_000068.jpg 14 | /JPEGImages/2008_000072.jpg 15 | /JPEGImages/2008_000079.jpg 16 | /JPEGImages/2008_000081.jpg 17 | /JPEGImages/2008_000083.jpg 18 | /JPEGImages/2008_000088.jpg 19 | /JPEGImages/2008_000094.jpg 20 | /JPEGImages/2008_000101.jpg 21 | /JPEGImages/2008_000104.jpg 22 | /JPEGImages/2008_000106.jpg 23 | /JPEGImages/2008_000108.jpg 24 | /JPEGImages/2008_000110.jpg 25 | /JPEGImages/2008_000111.jpg 26 | /JPEGImages/2008_000126.jpg 27 | /JPEGImages/2008_000127.jpg 28 | /JPEGImages/2008_000129.jpg 29 | /JPEGImages/2008_000130.jpg 30 | /JPEGImages/2008_000135.jpg 31 | /JPEGImages/2008_000150.jpg 32 | /JPEGImages/2008_000152.jpg 33 | /JPEGImages/2008_000156.jpg 34 | /JPEGImages/2008_000159.jpg 35 | /JPEGImages/2008_000160.jpg 36 | /JPEGImages/2008_000161.jpg 37 | /JPEGImages/2008_000166.jpg 38 | /JPEGImages/2008_000167.jpg 39 | /JPEGImages/2008_000168.jpg 40 | /JPEGImages/2008_000169.jpg 41 | /JPEGImages/2008_000171.jpg 42 | /JPEGImages/2008_000175.jpg 43 | /JPEGImages/2008_000178.jpg 44 | /JPEGImages/2008_000186.jpg 45 | /JPEGImages/2008_000198.jpg 46 | /JPEGImages/2008_000206.jpg 47 | /JPEGImages/2008_000208.jpg 48 | /JPEGImages/2008_000209.jpg 49 | /JPEGImages/2008_000211.jpg 50 | /JPEGImages/2008_000220.jpg 51 | /JPEGImages/2008_000224.jpg 52 | /JPEGImages/2008_000230.jpg 53 | /JPEGImages/2008_000240.jpg 54 | /JPEGImages/2008_000248.jpg 55 | /JPEGImages/2008_000249.jpg 56 | /JPEGImages/2008_000250.jpg 57 | /JPEGImages/2008_000256.jpg 58 | /JPEGImages/2008_000279.jpg 59 | /JPEGImages/2008_000282.jpg 60 | /JPEGImages/2008_000285.jpg 61 | /JPEGImages/2008_000286.jpg 62 | /JPEGImages/2008_000296.jpg 63 | /JPEGImages/2008_000300.jpg 64 | /JPEGImages/2008_000322.jpg 65 | /JPEGImages/2008_000324.jpg 66 | /JPEGImages/2008_000337.jpg 67 | /JPEGImages/2008_000366.jpg 68 | /JPEGImages/2008_000369.jpg 69 | /JPEGImages/2008_000377.jpg 70 | /JPEGImages/2008_000384.jpg 71 | /JPEGImages/2008_000390.jpg 72 | /JPEGImages/2008_000404.jpg 73 | /JPEGImages/2008_000411.jpg 74 | /JPEGImages/2008_000434.jpg 75 | /JPEGImages/2008_000440.jpg 76 | /JPEGImages/2008_000460.jpg 77 | /JPEGImages/2008_000467.jpg 78 | /JPEGImages/2008_000478.jpg 79 | /JPEGImages/2008_000485.jpg 80 | /JPEGImages/2008_000487.jpg 81 | /JPEGImages/2008_000490.jpg 82 | /JPEGImages/2008_000503.jpg 83 | /JPEGImages/2008_000504.jpg 84 | /JPEGImages/2008_000507.jpg 85 | /JPEGImages/2008_000513.jpg 86 | /JPEGImages/2008_000523.jpg 87 | /JPEGImages/2008_000529.jpg 88 | /JPEGImages/2008_000556.jpg 89 | /JPEGImages/2008_000565.jpg 90 | /JPEGImages/2008_000580.jpg 91 | /JPEGImages/2008_000590.jpg 92 | /JPEGImages/2008_000596.jpg 93 | /JPEGImages/2008_000597.jpg 94 | /JPEGImages/2008_000600.jpg 95 | /JPEGImages/2008_000603.jpg 96 | /JPEGImages/2008_000604.jpg 97 | /JPEGImages/2008_000612.jpg 98 | /JPEGImages/2008_000617.jpg 99 | /JPEGImages/2008_000621.jpg 100 | /JPEGImages/2008_000627.jpg 101 | /JPEGImages/2008_000633.jpg 102 | /JPEGImages/2008_000643.jpg 103 | /JPEGImages/2008_000644.jpg 104 | /JPEGImages/2008_000649.jpg 105 | /JPEGImages/2008_000651.jpg 106 | /JPEGImages/2008_000664.jpg 107 | /JPEGImages/2008_000665.jpg 108 | /JPEGImages/2008_000680.jpg 109 | /JPEGImages/2008_000681.jpg 110 | /JPEGImages/2008_000684.jpg 111 | /JPEGImages/2008_000685.jpg 112 | /JPEGImages/2008_000688.jpg 113 | /JPEGImages/2008_000693.jpg 114 | /JPEGImages/2008_000698.jpg 115 | /JPEGImages/2008_000707.jpg 116 | /JPEGImages/2008_000709.jpg 117 | /JPEGImages/2008_000712.jpg 118 | /JPEGImages/2008_000747.jpg 119 | /JPEGImages/2008_000751.jpg 120 | /JPEGImages/2008_000754.jpg 121 | /JPEGImages/2008_000762.jpg 122 | /JPEGImages/2008_000767.jpg 123 | /JPEGImages/2008_000768.jpg 124 | /JPEGImages/2008_000773.jpg 125 | /JPEGImages/2008_000774.jpg 126 | /JPEGImages/2008_000779.jpg 127 | /JPEGImages/2008_000797.jpg 128 | /JPEGImages/2008_000813.jpg 129 | /JPEGImages/2008_000816.jpg 130 | /JPEGImages/2008_000846.jpg 131 | /JPEGImages/2008_000866.jpg 132 | /JPEGImages/2008_000871.jpg 133 | /JPEGImages/2008_000872.jpg 134 | /JPEGImages/2008_000891.jpg 135 | /JPEGImages/2008_000892.jpg 136 | /JPEGImages/2008_000894.jpg 137 | /JPEGImages/2008_000896.jpg 138 | /JPEGImages/2008_000898.jpg 139 | /JPEGImages/2008_000909.jpg 140 | /JPEGImages/2008_000913.jpg 141 | /JPEGImages/2008_000920.jpg 142 | /JPEGImages/2008_000933.jpg 143 | /JPEGImages/2008_000935.jpg 144 | /JPEGImages/2008_000937.jpg 145 | /JPEGImages/2008_000938.jpg 146 | /JPEGImages/2008_000954.jpg 147 | /JPEGImages/2008_000958.jpg 148 | /JPEGImages/2008_000963.jpg 149 | /JPEGImages/2008_000967.jpg 150 | /JPEGImages/2008_000974.jpg 151 | /JPEGImages/2008_000986.jpg 152 | /JPEGImages/2008_000994.jpg 153 | /JPEGImages/2008_000995.jpg 154 | /JPEGImages/2008_001008.jpg 155 | /JPEGImages/2008_001010.jpg 156 | /JPEGImages/2008_001014.jpg 157 | /JPEGImages/2008_001016.jpg 158 | /JPEGImages/2008_001025.jpg 159 | /JPEGImages/2008_001029.jpg 160 | /JPEGImages/2008_001037.jpg 161 | /JPEGImages/2008_001059.jpg 162 | /JPEGImages/2008_001061.jpg 163 | /JPEGImages/2008_001072.jpg 164 | /JPEGImages/2008_001124.jpg 165 | /JPEGImages/2008_001126.jpg 166 | /JPEGImages/2008_001131.jpg 167 | /JPEGImages/2008_001138.jpg 168 | /JPEGImages/2008_001144.jpg 169 | /JPEGImages/2008_001151.jpg 170 | /JPEGImages/2008_001156.jpg 171 | /JPEGImages/2008_001179.jpg 172 | /JPEGImages/2008_001181.jpg 173 | /JPEGImages/2008_001184.jpg 174 | /JPEGImages/2008_001186.jpg 175 | /JPEGImages/2008_001197.jpg 176 | /JPEGImages/2008_001207.jpg 177 | /JPEGImages/2008_001212.jpg 178 | /JPEGImages/2008_001233.jpg 179 | /JPEGImages/2008_001234.jpg 180 | /JPEGImages/2008_001258.jpg 181 | /JPEGImages/2008_001268.jpg 182 | /JPEGImages/2008_001279.jpg 183 | /JPEGImages/2008_001281.jpg 184 | /JPEGImages/2008_001288.jpg 185 | /JPEGImages/2008_001291.jpg 186 | /JPEGImages/2008_001298.jpg 187 | /JPEGImages/2008_001309.jpg 188 | /JPEGImages/2008_001315.jpg 189 | /JPEGImages/2008_001316.jpg 190 | /JPEGImages/2008_001319.jpg 191 | /JPEGImages/2008_001327.jpg 192 | /JPEGImages/2008_001328.jpg 193 | /JPEGImages/2008_001332.jpg 194 | /JPEGImages/2008_001341.jpg 195 | /JPEGImages/2008_001347.jpg 196 | /JPEGImages/2008_001355.jpg 197 | /JPEGImages/2008_001378.jpg 198 | /JPEGImages/2008_001386.jpg 199 | /JPEGImages/2008_001400.jpg 200 | /JPEGImages/2008_001409.jpg 201 | /JPEGImages/2008_001411.jpg 202 | /JPEGImages/2008_001416.jpg 203 | /JPEGImages/2008_001418.jpg 204 | /JPEGImages/2008_001435.jpg 205 | /JPEGImages/2008_001459.jpg 206 | /JPEGImages/2008_001469.jpg 207 | /JPEGImages/2008_001474.jpg 208 | /JPEGImages/2008_001477.jpg 209 | /JPEGImages/2008_001483.jpg 210 | /JPEGImages/2008_001484.jpg 211 | /JPEGImages/2008_001485.jpg 212 | /JPEGImages/2008_001496.jpg 213 | /JPEGImages/2008_001507.jpg 214 | /JPEGImages/2008_001511.jpg 215 | /JPEGImages/2008_001519.jpg 216 | /JPEGImages/2008_001557.jpg 217 | /JPEGImages/2008_001567.jpg 218 | /JPEGImages/2008_001570.jpg 219 | /JPEGImages/2008_001571.jpg 220 | /JPEGImages/2008_001572.jpg 221 | /JPEGImages/2008_001579.jpg 222 | /JPEGImages/2008_001587.jpg 223 | /JPEGImages/2008_001608.jpg 224 | /JPEGImages/2008_001611.jpg 225 | /JPEGImages/2008_001614.jpg 226 | /JPEGImages/2008_001621.jpg 227 | /JPEGImages/2008_001639.jpg 228 | /JPEGImages/2008_001658.jpg 229 | /JPEGImages/2008_001678.jpg 230 | /JPEGImages/2008_001700.jpg 231 | /JPEGImages/2008_001713.jpg 232 | /JPEGImages/2008_001720.jpg 233 | /JPEGImages/2008_001755.jpg 234 | /JPEGImages/2008_001779.jpg 235 | /JPEGImages/2008_001785.jpg 236 | /JPEGImages/2008_001793.jpg 237 | /JPEGImages/2008_001794.jpg 238 | /JPEGImages/2008_001803.jpg 239 | /JPEGImages/2008_001818.jpg 240 | /JPEGImages/2008_001848.jpg 241 | /JPEGImages/2008_001855.jpg 242 | /JPEGImages/2008_001857.jpg 243 | /JPEGImages/2008_001861.jpg 244 | /JPEGImages/2008_001875.jpg 245 | /JPEGImages/2008_001878.jpg 246 | /JPEGImages/2008_001886.jpg 247 | /JPEGImages/2008_001897.jpg 248 | /JPEGImages/2008_001916.jpg 249 | /JPEGImages/2008_001925.jpg 250 | /JPEGImages/2008_001949.jpg 251 | /JPEGImages/2008_001953.jpg 252 | /JPEGImages/2008_001972.jpg 253 | /JPEGImages/2008_001999.jpg 254 | /JPEGImages/2008_002027.jpg 255 | /JPEGImages/2008_002040.jpg 256 | /JPEGImages/2008_002057.jpg 257 | /JPEGImages/2008_002070.jpg 258 | /JPEGImages/2008_002075.jpg 259 | /JPEGImages/2008_002095.jpg 260 | /JPEGImages/2008_002104.jpg 261 | /JPEGImages/2008_002105.jpg 262 | /JPEGImages/2008_002106.jpg 263 | /JPEGImages/2008_002136.jpg 264 | /JPEGImages/2008_002137.jpg 265 | /JPEGImages/2008_002147.jpg 266 | /JPEGImages/2008_002149.jpg 267 | /JPEGImages/2008_002163.jpg 268 | /JPEGImages/2008_002173.jpg 269 | /JPEGImages/2008_002174.jpg 270 | /JPEGImages/2008_002184.jpg 271 | /JPEGImages/2008_002186.jpg 272 | /JPEGImages/2008_002188.jpg 273 | /JPEGImages/2008_002190.jpg 274 | /JPEGImages/2008_002203.jpg 275 | /JPEGImages/2008_002211.jpg 276 | /JPEGImages/2008_002217.jpg 277 | /JPEGImages/2008_002228.jpg 278 | /JPEGImages/2008_002233.jpg 279 | /JPEGImages/2008_002246.jpg 280 | /JPEGImages/2008_002257.jpg 281 | /JPEGImages/2008_002261.jpg 282 | /JPEGImages/2008_002285.jpg 283 | /JPEGImages/2008_002287.jpg 284 | /JPEGImages/2008_002295.jpg 285 | /JPEGImages/2008_002303.jpg 286 | /JPEGImages/2008_002306.jpg 287 | /JPEGImages/2008_002309.jpg 288 | /JPEGImages/2008_002310.jpg 289 | /JPEGImages/2008_002318.jpg 290 | /JPEGImages/2008_002320.jpg 291 | /JPEGImages/2008_002332.jpg 292 | /JPEGImages/2008_002337.jpg 293 | /JPEGImages/2008_002345.jpg 294 | /JPEGImages/2008_002348.jpg 295 | /JPEGImages/2008_002352.jpg 296 | /JPEGImages/2008_002360.jpg 297 | /JPEGImages/2008_002381.jpg 298 | /JPEGImages/2008_002387.jpg 299 | /JPEGImages/2008_002388.jpg 300 | /JPEGImages/2008_002393.jpg 301 | /JPEGImages/2008_002406.jpg 302 | /JPEGImages/2008_002440.jpg 303 | /JPEGImages/2008_002455.jpg 304 | /JPEGImages/2008_002460.jpg 305 | /JPEGImages/2008_002462.jpg 306 | /JPEGImages/2008_002480.jpg 307 | /JPEGImages/2008_002518.jpg 308 | /JPEGImages/2008_002525.jpg 309 | /JPEGImages/2008_002535.jpg 310 | /JPEGImages/2008_002544.jpg 311 | /JPEGImages/2008_002553.jpg 312 | /JPEGImages/2008_002569.jpg 313 | /JPEGImages/2008_002572.jpg 314 | /JPEGImages/2008_002587.jpg 315 | /JPEGImages/2008_002635.jpg 316 | /JPEGImages/2008_002655.jpg 317 | /JPEGImages/2008_002695.jpg 318 | /JPEGImages/2008_002702.jpg 319 | /JPEGImages/2008_002706.jpg 320 | /JPEGImages/2008_002707.jpg 321 | /JPEGImages/2008_002722.jpg 322 | /JPEGImages/2008_002745.jpg 323 | /JPEGImages/2008_002757.jpg 324 | /JPEGImages/2008_002779.jpg 325 | /JPEGImages/2008_002805.jpg 326 | /JPEGImages/2008_002871.jpg 327 | /JPEGImages/2008_002895.jpg 328 | /JPEGImages/2008_002905.jpg 329 | /JPEGImages/2008_002923.jpg 330 | /JPEGImages/2008_002927.jpg 331 | /JPEGImages/2008_002939.jpg 332 | /JPEGImages/2008_002941.jpg 333 | /JPEGImages/2008_002962.jpg 334 | /JPEGImages/2008_002975.jpg 335 | /JPEGImages/2008_003000.jpg 336 | /JPEGImages/2008_003031.jpg 337 | /JPEGImages/2008_003038.jpg 338 | /JPEGImages/2008_003042.jpg 339 | /JPEGImages/2008_003069.jpg 340 | /JPEGImages/2008_003070.jpg 341 | /JPEGImages/2008_003115.jpg 342 | /JPEGImages/2008_003116.jpg 343 | /JPEGImages/2008_003130.jpg 344 | /JPEGImages/2008_003137.jpg 345 | /JPEGImages/2008_003138.jpg 346 | /JPEGImages/2008_003139.jpg 347 | /JPEGImages/2008_003165.jpg 348 | /JPEGImages/2008_003171.jpg 349 | /JPEGImages/2008_003176.jpg 350 | /JPEGImages/2008_003192.jpg 351 | /JPEGImages/2008_003194.jpg 352 | /JPEGImages/2008_003195.jpg 353 | /JPEGImages/2008_003198.jpg 354 | /JPEGImages/2008_003227.jpg 355 | /JPEGImages/2008_003247.jpg 356 | /JPEGImages/2008_003262.jpg 357 | /JPEGImages/2008_003298.jpg 358 | /JPEGImages/2008_003299.jpg 359 | /JPEGImages/2008_003307.jpg 360 | /JPEGImages/2008_003337.jpg 361 | /JPEGImages/2008_003353.jpg 362 | /JPEGImages/2008_003355.jpg 363 | /JPEGImages/2008_003363.jpg 364 | /JPEGImages/2008_003383.jpg 365 | /JPEGImages/2008_003389.jpg 366 | /JPEGImages/2008_003392.jpg 367 | /JPEGImages/2008_003399.jpg 368 | /JPEGImages/2008_003436.jpg 369 | /JPEGImages/2008_003457.jpg 370 | /JPEGImages/2008_003465.jpg 371 | /JPEGImages/2008_003481.jpg 372 | /JPEGImages/2008_003539.jpg 373 | /JPEGImages/2008_003548.jpg 374 | /JPEGImages/2008_003550.jpg 375 | /JPEGImages/2008_003567.jpg 376 | /JPEGImages/2008_003568.jpg 377 | /JPEGImages/2008_003606.jpg 378 | /JPEGImages/2008_003615.jpg 379 | /JPEGImages/2008_003654.jpg 380 | /JPEGImages/2008_003670.jpg 381 | /JPEGImages/2008_003700.jpg 382 | /JPEGImages/2008_003705.jpg 383 | /JPEGImages/2008_003727.jpg 384 | /JPEGImages/2008_003731.jpg 385 | /JPEGImages/2008_003734.jpg 386 | /JPEGImages/2008_003760.jpg 387 | /JPEGImages/2008_003804.jpg 388 | /JPEGImages/2008_003807.jpg 389 | /JPEGImages/2008_003810.jpg 390 | /JPEGImages/2008_003822.jpg 391 | /JPEGImages/2008_003833.jpg 392 | /JPEGImages/2008_003877.jpg 393 | /JPEGImages/2008_003879.jpg 394 | /JPEGImages/2008_003895.jpg 395 | /JPEGImages/2008_003901.jpg 396 | /JPEGImages/2008_003903.jpg 397 | /JPEGImages/2008_003911.jpg 398 | /JPEGImages/2008_003919.jpg 399 | /JPEGImages/2008_003927.jpg 400 | /JPEGImages/2008_003937.jpg 401 | /JPEGImages/2008_003946.jpg 402 | /JPEGImages/2008_003950.jpg 403 | /JPEGImages/2008_003955.jpg 404 | /JPEGImages/2008_003981.jpg 405 | /JPEGImages/2008_003991.jpg 406 | /JPEGImages/2008_004009.jpg 407 | /JPEGImages/2008_004039.jpg 408 | /JPEGImages/2008_004052.jpg 409 | /JPEGImages/2008_004063.jpg 410 | /JPEGImages/2008_004070.jpg 411 | /JPEGImages/2008_004078.jpg 412 | /JPEGImages/2008_004104.jpg 413 | /JPEGImages/2008_004139.jpg 414 | /JPEGImages/2008_004177.jpg 415 | /JPEGImages/2008_004181.jpg 416 | /JPEGImages/2008_004200.jpg 417 | /JPEGImages/2008_004219.jpg 418 | /JPEGImages/2008_004236.jpg 419 | /JPEGImages/2008_004250.jpg 420 | /JPEGImages/2008_004266.jpg 421 | /JPEGImages/2008_004299.jpg 422 | /JPEGImages/2008_004320.jpg 423 | /JPEGImages/2008_004334.jpg 424 | /JPEGImages/2008_004343.jpg 425 | /JPEGImages/2008_004349.jpg 426 | /JPEGImages/2008_004366.jpg 427 | /JPEGImages/2008_004386.jpg 428 | /JPEGImages/2008_004401.jpg 429 | /JPEGImages/2008_004423.jpg 430 | /JPEGImages/2008_004448.jpg 431 | /JPEGImages/2008_004481.jpg 432 | /JPEGImages/2008_004516.jpg 433 | /JPEGImages/2008_004536.jpg 434 | /JPEGImages/2008_004582.jpg 435 | /JPEGImages/2008_004609.jpg 436 | /JPEGImages/2008_004638.jpg 437 | /JPEGImages/2008_004642.jpg 438 | /JPEGImages/2008_004644.jpg 439 | /JPEGImages/2008_004669.jpg 440 | /JPEGImages/2008_004673.jpg 441 | /JPEGImages/2008_004691.jpg 442 | /JPEGImages/2008_004693.jpg 443 | /JPEGImages/2008_004709.jpg 444 | /JPEGImages/2008_004715.jpg 445 | /JPEGImages/2008_004757.jpg 446 | /JPEGImages/2008_004775.jpg 447 | /JPEGImages/2008_004782.jpg 448 | /JPEGImages/2008_004785.jpg 449 | /JPEGImages/2008_004798.jpg 450 | /JPEGImages/2008_004848.jpg 451 | /JPEGImages/2008_004861.jpg 452 | /JPEGImages/2008_004870.jpg 453 | /JPEGImages/2008_004877.jpg 454 | /JPEGImages/2008_004884.jpg 455 | /JPEGImages/2008_004891.jpg 456 | /JPEGImages/2008_004901.jpg 457 | /JPEGImages/2008_004919.jpg 458 | /JPEGImages/2008_005058.jpg 459 | /JPEGImages/2008_005069.jpg 460 | /JPEGImages/2008_005086.jpg 461 | /JPEGImages/2008_005087.jpg 462 | /JPEGImages/2008_005112.jpg 463 | /JPEGImages/2008_005113.jpg 464 | /JPEGImages/2008_005118.jpg 465 | /JPEGImages/2008_005128.jpg 466 | /JPEGImages/2008_005129.jpg 467 | /JPEGImages/2008_005153.jpg 468 | /JPEGImages/2008_005161.jpg 469 | /JPEGImages/2008_005162.jpg 470 | /JPEGImages/2008_005165.jpg 471 | /JPEGImages/2008_005187.jpg 472 | /JPEGImages/2008_005227.jpg 473 | /JPEGImages/2008_005308.jpg 474 | /JPEGImages/2008_005318.jpg 475 | /JPEGImages/2008_005320.jpg 476 | /JPEGImages/2008_005351.jpg 477 | /JPEGImages/2008_005372.jpg 478 | /JPEGImages/2008_005383.jpg 479 | /JPEGImages/2008_005391.jpg 480 | /JPEGImages/2008_005407.jpg 481 | /JPEGImages/2008_005420.jpg 482 | /JPEGImages/2008_005440.jpg 483 | /JPEGImages/2008_005487.jpg 484 | /JPEGImages/2008_005493.jpg 485 | /JPEGImages/2008_005520.jpg 486 | /JPEGImages/2008_005551.jpg 487 | /JPEGImages/2008_005556.jpg 488 | /JPEGImages/2008_005576.jpg 489 | /JPEGImages/2008_005578.jpg 490 | /JPEGImages/2008_005594.jpg 491 | /JPEGImages/2008_005619.jpg 492 | /JPEGImages/2008_005629.jpg 493 | /JPEGImages/2008_005644.jpg 494 | /JPEGImages/2008_005645.jpg 495 | /JPEGImages/2008_005651.jpg 496 | /JPEGImages/2008_005661.jpg 497 | /JPEGImages/2008_005662.jpg 498 | /JPEGImages/2008_005667.jpg 499 | /JPEGImages/2008_005694.jpg 500 | /JPEGImages/2008_005697.jpg 501 | /JPEGImages/2008_005709.jpg 502 | /JPEGImages/2008_005710.jpg 503 | /JPEGImages/2008_005733.jpg 504 | /JPEGImages/2008_005749.jpg 505 | /JPEGImages/2008_005753.jpg 506 | /JPEGImages/2008_005771.jpg 507 | /JPEGImages/2008_005781.jpg 508 | /JPEGImages/2008_005793.jpg 509 | /JPEGImages/2008_005802.jpg 510 | /JPEGImages/2008_005833.jpg 511 | /JPEGImages/2008_005844.jpg 512 | /JPEGImages/2008_005908.jpg 513 | /JPEGImages/2008_005931.jpg 514 | /JPEGImages/2008_005952.jpg 515 | /JPEGImages/2008_006016.jpg 516 | /JPEGImages/2008_006030.jpg 517 | /JPEGImages/2008_006033.jpg 518 | /JPEGImages/2008_006054.jpg 519 | /JPEGImages/2008_006073.jpg 520 | /JPEGImages/2008_006091.jpg 521 | /JPEGImages/2008_006142.jpg 522 | /JPEGImages/2008_006150.jpg 523 | /JPEGImages/2008_006206.jpg 524 | /JPEGImages/2008_006217.jpg 525 | /JPEGImages/2008_006264.jpg 526 | /JPEGImages/2008_006283.jpg 527 | /JPEGImages/2008_006308.jpg 528 | /JPEGImages/2008_006313.jpg 529 | /JPEGImages/2008_006333.jpg 530 | /JPEGImages/2008_006343.jpg 531 | /JPEGImages/2008_006381.jpg 532 | /JPEGImages/2008_006391.jpg 533 | /JPEGImages/2008_006423.jpg 534 | /JPEGImages/2008_006428.jpg 535 | /JPEGImages/2008_006440.jpg 536 | /JPEGImages/2008_006444.jpg 537 | /JPEGImages/2008_006473.jpg 538 | /JPEGImages/2008_006505.jpg 539 | /JPEGImages/2008_006531.jpg 540 | /JPEGImages/2008_006560.jpg 541 | /JPEGImages/2008_006571.jpg 542 | /JPEGImages/2008_006582.jpg 543 | /JPEGImages/2008_006594.jpg 544 | /JPEGImages/2008_006601.jpg 545 | /JPEGImages/2008_006633.jpg 546 | /JPEGImages/2008_006653.jpg 547 | /JPEGImages/2008_006678.jpg 548 | /JPEGImages/2008_006755.jpg 549 | /JPEGImages/2008_006772.jpg 550 | /JPEGImages/2008_006788.jpg 551 | /JPEGImages/2008_006799.jpg 552 | /JPEGImages/2008_006809.jpg 553 | /JPEGImages/2008_006838.jpg 554 | /JPEGImages/2008_006845.jpg 555 | /JPEGImages/2008_006852.jpg 556 | /JPEGImages/2008_006894.jpg 557 | /JPEGImages/2008_006905.jpg 558 | /JPEGImages/2008_006947.jpg 559 | /JPEGImages/2008_006983.jpg 560 | /JPEGImages/2008_007049.jpg 561 | /JPEGImages/2008_007065.jpg 562 | /JPEGImages/2008_007068.jpg 563 | /JPEGImages/2008_007111.jpg 564 | /JPEGImages/2008_007148.jpg 565 | /JPEGImages/2008_007159.jpg 566 | /JPEGImages/2008_007193.jpg 567 | /JPEGImages/2008_007228.jpg 568 | /JPEGImages/2008_007235.jpg 569 | /JPEGImages/2008_007249.jpg 570 | /JPEGImages/2008_007255.jpg 571 | /JPEGImages/2008_007268.jpg 572 | /JPEGImages/2008_007275.jpg 573 | /JPEGImages/2008_007292.jpg 574 | /JPEGImages/2008_007299.jpg 575 | /JPEGImages/2008_007306.jpg 576 | /JPEGImages/2008_007316.jpg 577 | /JPEGImages/2008_007400.jpg 578 | /JPEGImages/2008_007401.jpg 579 | /JPEGImages/2008_007419.jpg 580 | /JPEGImages/2008_007437.jpg 581 | /JPEGImages/2008_007483.jpg 582 | /JPEGImages/2008_007487.jpg 583 | /JPEGImages/2008_007520.jpg 584 | /JPEGImages/2008_007551.jpg 585 | /JPEGImages/2008_007603.jpg 586 | /JPEGImages/2008_007616.jpg 587 | /JPEGImages/2008_007654.jpg 588 | /JPEGImages/2008_007663.jpg 589 | /JPEGImages/2008_007708.jpg 590 | /JPEGImages/2008_007795.jpg 591 | /JPEGImages/2008_007801.jpg 592 | /JPEGImages/2008_007859.jpg 593 | /JPEGImages/2008_007903.jpg 594 | /JPEGImages/2008_007920.jpg 595 | /JPEGImages/2008_007926.jpg 596 | /JPEGImages/2008_008014.jpg 597 | /JPEGImages/2008_008017.jpg 598 | /JPEGImages/2008_008060.jpg 599 | /JPEGImages/2008_008077.jpg 600 | /JPEGImages/2008_008107.jpg 601 | /JPEGImages/2008_008108.jpg 602 | /JPEGImages/2008_008119.jpg 603 | /JPEGImages/2008_008126.jpg 604 | /JPEGImages/2008_008133.jpg 605 | /JPEGImages/2008_008144.jpg 606 | /JPEGImages/2008_008216.jpg 607 | /JPEGImages/2008_008244.jpg 608 | /JPEGImages/2008_008248.jpg 609 | /JPEGImages/2008_008250.jpg 610 | /JPEGImages/2008_008260.jpg 611 | /JPEGImages/2008_008277.jpg 612 | /JPEGImages/2008_008280.jpg 613 | /JPEGImages/2008_008290.jpg 614 | /JPEGImages/2008_008304.jpg 615 | /JPEGImages/2008_008340.jpg 616 | /JPEGImages/2008_008371.jpg 617 | /JPEGImages/2008_008390.jpg 618 | /JPEGImages/2008_008397.jpg 619 | /JPEGImages/2008_008409.jpg 620 | /JPEGImages/2008_008412.jpg 621 | /JPEGImages/2008_008419.jpg 622 | /JPEGImages/2008_008454.jpg 623 | /JPEGImages/2008_008491.jpg 624 | /JPEGImages/2008_008498.jpg 625 | /JPEGImages/2008_008565.jpg 626 | /JPEGImages/2008_008599.jpg 627 | /JPEGImages/2008_008603.jpg 628 | /JPEGImages/2008_008631.jpg 629 | /JPEGImages/2008_008634.jpg 630 | /JPEGImages/2008_008640.jpg 631 | /JPEGImages/2008_008646.jpg 632 | /JPEGImages/2008_008660.jpg 633 | /JPEGImages/2008_008663.jpg 634 | /JPEGImages/2008_008664.jpg 635 | /JPEGImages/2008_008709.jpg 636 | /JPEGImages/2008_008720.jpg 637 | /JPEGImages/2008_008747.jpg 638 | /JPEGImages/2008_008768.jpg 639 | /JPEGImages/2009_000004.jpg 640 | /JPEGImages/2009_000019.jpg 641 | /JPEGImages/2009_000024.jpg 642 | /JPEGImages/2009_000025.jpg 643 | /JPEGImages/2009_000053.jpg 644 | /JPEGImages/2009_000076.jpg 645 | /JPEGImages/2009_000107.jpg 646 | /JPEGImages/2009_000110.jpg 647 | /JPEGImages/2009_000115.jpg 648 | /JPEGImages/2009_000117.jpg 649 | /JPEGImages/2009_000175.jpg 650 | /JPEGImages/2009_000220.jpg 651 | /JPEGImages/2009_000259.jpg 652 | /JPEGImages/2009_000275.jpg 653 | /JPEGImages/2009_000314.jpg 654 | /JPEGImages/2009_000368.jpg 655 | /JPEGImages/2009_000373.jpg 656 | /JPEGImages/2009_000384.jpg 657 | /JPEGImages/2009_000388.jpg 658 | /JPEGImages/2009_000423.jpg 659 | /JPEGImages/2009_000433.jpg 660 | /JPEGImages/2009_000434.jpg 661 | /JPEGImages/2009_000458.jpg 662 | /JPEGImages/2009_000475.jpg 663 | /JPEGImages/2009_000481.jpg 664 | /JPEGImages/2009_000495.jpg 665 | /JPEGImages/2009_000514.jpg 666 | /JPEGImages/2009_000555.jpg 667 | /JPEGImages/2009_000556.jpg 668 | /JPEGImages/2009_000561.jpg 669 | /JPEGImages/2009_000571.jpg 670 | /JPEGImages/2009_000581.jpg 671 | /JPEGImages/2009_000605.jpg 672 | /JPEGImages/2009_000609.jpg 673 | /JPEGImages/2009_000644.jpg 674 | /JPEGImages/2009_000654.jpg 675 | /JPEGImages/2009_000671.jpg 676 | /JPEGImages/2009_000733.jpg 677 | /JPEGImages/2009_000740.jpg 678 | /JPEGImages/2009_000766.jpg 679 | /JPEGImages/2009_000775.jpg 680 | /JPEGImages/2009_000776.jpg 681 | /JPEGImages/2009_000795.jpg 682 | /JPEGImages/2009_000850.jpg 683 | /JPEGImages/2009_000881.jpg 684 | /JPEGImages/2009_000900.jpg 685 | /JPEGImages/2009_000914.jpg 686 | /JPEGImages/2009_000941.jpg 687 | /JPEGImages/2009_000977.jpg 688 | /JPEGImages/2009_000984.jpg 689 | /JPEGImages/2009_000986.jpg 690 | /JPEGImages/2009_001005.jpg 691 | /JPEGImages/2009_001015.jpg 692 | /JPEGImages/2009_001058.jpg 693 | /JPEGImages/2009_001072.jpg 694 | /JPEGImages/2009_001087.jpg 695 | /JPEGImages/2009_001092.jpg 696 | /JPEGImages/2009_001109.jpg 697 | /JPEGImages/2009_001114.jpg 698 | /JPEGImages/2009_001115.jpg 699 | /JPEGImages/2009_001141.jpg 700 | /JPEGImages/2009_001174.jpg 701 | /JPEGImages/2009_001175.jpg 702 | /JPEGImages/2009_001182.jpg 703 | /JPEGImages/2009_001222.jpg 704 | /JPEGImages/2009_001228.jpg 705 | /JPEGImages/2009_001246.jpg 706 | /JPEGImages/2009_001262.jpg 707 | /JPEGImages/2009_001274.jpg 708 | /JPEGImages/2009_001284.jpg 709 | /JPEGImages/2009_001297.jpg 710 | /JPEGImages/2009_001331.jpg 711 | /JPEGImages/2009_001336.jpg 712 | /JPEGImages/2009_001337.jpg 713 | /JPEGImages/2009_001379.jpg 714 | /JPEGImages/2009_001392.jpg 715 | /JPEGImages/2009_001451.jpg 716 | /JPEGImages/2009_001485.jpg 717 | /JPEGImages/2009_001488.jpg 718 | /JPEGImages/2009_001497.jpg 719 | /JPEGImages/2009_001504.jpg 720 | /JPEGImages/2009_001506.jpg 721 | /JPEGImages/2009_001573.jpg 722 | /JPEGImages/2009_001576.jpg 723 | /JPEGImages/2009_001603.jpg 724 | /JPEGImages/2009_001613.jpg 725 | /JPEGImages/2009_001652.jpg 726 | /JPEGImages/2009_001661.jpg 727 | /JPEGImages/2009_001668.jpg 728 | /JPEGImages/2009_001680.jpg 729 | /JPEGImages/2009_001688.jpg 730 | /JPEGImages/2009_001697.jpg 731 | /JPEGImages/2009_001729.jpg 732 | /JPEGImages/2009_001771.jpg 733 | /JPEGImages/2009_001785.jpg 734 | /JPEGImages/2009_001793.jpg 735 | /JPEGImages/2009_001814.jpg 736 | /JPEGImages/2009_001866.jpg 737 | /JPEGImages/2009_001872.jpg 738 | /JPEGImages/2009_001880.jpg 739 | /JPEGImages/2009_001883.jpg 740 | /JPEGImages/2009_001891.jpg 741 | /JPEGImages/2009_001913.jpg 742 | /JPEGImages/2009_001938.jpg 743 | /JPEGImages/2009_001946.jpg 744 | /JPEGImages/2009_001953.jpg 745 | /JPEGImages/2009_001969.jpg 746 | /JPEGImages/2009_001978.jpg 747 | /JPEGImages/2009_001995.jpg 748 | /JPEGImages/2009_002007.jpg 749 | /JPEGImages/2009_002036.jpg 750 | /JPEGImages/2009_002041.jpg 751 | /JPEGImages/2009_002049.jpg 752 | /JPEGImages/2009_002051.jpg 753 | /JPEGImages/2009_002062.jpg 754 | /JPEGImages/2009_002063.jpg 755 | /JPEGImages/2009_002067.jpg 756 | /JPEGImages/2009_002085.jpg 757 | /JPEGImages/2009_002092.jpg 758 | /JPEGImages/2009_002114.jpg 759 | /JPEGImages/2009_002115.jpg 760 | /JPEGImages/2009_002142.jpg 761 | /JPEGImages/2009_002148.jpg 762 | /JPEGImages/2009_002157.jpg 763 | /JPEGImages/2009_002181.jpg 764 | /JPEGImages/2009_002220.jpg 765 | /JPEGImages/2009_002284.jpg 766 | /JPEGImages/2009_002287.jpg 767 | /JPEGImages/2009_002300.jpg 768 | /JPEGImages/2009_002310.jpg 769 | /JPEGImages/2009_002315.jpg 770 | /JPEGImages/2009_002334.jpg 771 | /JPEGImages/2009_002337.jpg 772 | /JPEGImages/2009_002354.jpg 773 | /JPEGImages/2009_002357.jpg 774 | /JPEGImages/2009_002411.jpg 775 | /JPEGImages/2009_002426.jpg 776 | /JPEGImages/2009_002458.jpg 777 | /JPEGImages/2009_002459.jpg 778 | /JPEGImages/2009_002461.jpg 779 | /JPEGImages/2009_002466.jpg 780 | /JPEGImages/2009_002481.jpg 781 | /JPEGImages/2009_002483.jpg 782 | /JPEGImages/2009_002503.jpg 783 | /JPEGImages/2009_002581.jpg 784 | /JPEGImages/2009_002583.jpg 785 | /JPEGImages/2009_002589.jpg 786 | /JPEGImages/2009_002600.jpg 787 | /JPEGImages/2009_002601.jpg 788 | /JPEGImages/2009_002602.jpg 789 | /JPEGImages/2009_002641.jpg 790 | /JPEGImages/2009_002646.jpg 791 | /JPEGImages/2009_002656.jpg 792 | /JPEGImages/2009_002666.jpg 793 | /JPEGImages/2009_002720.jpg 794 | /JPEGImages/2009_002767.jpg 795 | /JPEGImages/2009_002768.jpg 796 | /JPEGImages/2009_002794.jpg 797 | /JPEGImages/2009_002821.jpg 798 | /JPEGImages/2009_002825.jpg 799 | /JPEGImages/2009_002839.jpg 800 | /JPEGImages/2009_002840.jpg 801 | /JPEGImages/2009_002859.jpg 802 | /JPEGImages/2009_002860.jpg 803 | /JPEGImages/2009_002881.jpg 804 | /JPEGImages/2009_002889.jpg 805 | /JPEGImages/2009_002892.jpg 806 | /JPEGImages/2009_002895.jpg 807 | /JPEGImages/2009_002896.jpg 808 | /JPEGImages/2009_002900.jpg 809 | /JPEGImages/2009_002924.jpg 810 | /JPEGImages/2009_002966.jpg 811 | /JPEGImages/2009_002973.jpg 812 | /JPEGImages/2009_002981.jpg 813 | /JPEGImages/2009_003004.jpg 814 | /JPEGImages/2009_003021.jpg 815 | /JPEGImages/2009_003028.jpg 816 | /JPEGImages/2009_003037.jpg 817 | /JPEGImages/2009_003038.jpg 818 | /JPEGImages/2009_003055.jpg 819 | /JPEGImages/2009_003085.jpg 820 | /JPEGImages/2009_003100.jpg 821 | /JPEGImages/2009_003106.jpg 822 | /JPEGImages/2009_003117.jpg 823 | /JPEGImages/2009_003139.jpg 824 | /JPEGImages/2009_003170.jpg 825 | /JPEGImages/2009_003179.jpg 826 | /JPEGImages/2009_003184.jpg 827 | /JPEGImages/2009_003186.jpg 828 | /JPEGImages/2009_003190.jpg 829 | /JPEGImages/2009_003221.jpg 830 | /JPEGImages/2009_003236.jpg 831 | /JPEGImages/2009_003242.jpg 832 | /JPEGImages/2009_003244.jpg 833 | /JPEGImages/2009_003260.jpg 834 | /JPEGImages/2009_003264.jpg 835 | /JPEGImages/2009_003274.jpg 836 | /JPEGImages/2009_003283.jpg 837 | /JPEGImages/2009_003296.jpg 838 | /JPEGImages/2009_003332.jpg 839 | /JPEGImages/2009_003341.jpg 840 | /JPEGImages/2009_003354.jpg 841 | /JPEGImages/2009_003370.jpg 842 | /JPEGImages/2009_003371.jpg 843 | /JPEGImages/2009_003374.jpg 844 | /JPEGImages/2009_003391.jpg 845 | /JPEGImages/2009_003393.jpg 846 | /JPEGImages/2009_003404.jpg 847 | /JPEGImages/2009_003405.jpg 848 | /JPEGImages/2009_003414.jpg 849 | /JPEGImages/2009_003428.jpg 850 | /JPEGImages/2009_003470.jpg 851 | /JPEGImages/2009_003474.jpg 852 | /JPEGImages/2009_003532.jpg 853 | /JPEGImages/2009_003536.jpg 854 | /JPEGImages/2009_003578.jpg 855 | /JPEGImages/2009_003580.jpg 856 | /JPEGImages/2009_003620.jpg 857 | /JPEGImages/2009_003621.jpg 858 | /JPEGImages/2009_003680.jpg 859 | /JPEGImages/2009_003699.jpg 860 | /JPEGImages/2009_003727.jpg 861 | /JPEGImages/2009_003737.jpg 862 | /JPEGImages/2009_003780.jpg 863 | /JPEGImages/2009_003811.jpg 864 | /JPEGImages/2009_003824.jpg 865 | /JPEGImages/2009_003831.jpg 866 | /JPEGImages/2009_003844.jpg 867 | /JPEGImages/2009_003850.jpg 868 | /JPEGImages/2009_003851.jpg 869 | /JPEGImages/2009_003864.jpg 870 | /JPEGImages/2009_003868.jpg 871 | /JPEGImages/2009_003869.jpg 872 | /JPEGImages/2009_003893.jpg 873 | /JPEGImages/2009_003909.jpg 874 | /JPEGImages/2009_003924.jpg 875 | /JPEGImages/2009_003925.jpg 876 | /JPEGImages/2009_003960.jpg 877 | /JPEGImages/2009_003979.jpg 878 | /JPEGImages/2009_003990.jpg 879 | /JPEGImages/2009_003997.jpg 880 | /JPEGImages/2009_004006.jpg 881 | /JPEGImages/2009_004010.jpg 882 | /JPEGImages/2009_004066.jpg 883 | /JPEGImages/2009_004077.jpg 884 | /JPEGImages/2009_004081.jpg 885 | /JPEGImages/2009_004097.jpg 886 | /JPEGImages/2009_004098.jpg 887 | /JPEGImages/2009_004136.jpg 888 | /JPEGImages/2009_004216.jpg 889 | /JPEGImages/2009_004220.jpg 890 | /JPEGImages/2009_004266.jpg 891 | /JPEGImages/2009_004269.jpg 892 | /JPEGImages/2009_004286.jpg 893 | /JPEGImages/2009_004296.jpg 894 | /JPEGImages/2009_004321.jpg 895 | /JPEGImages/2009_004342.jpg 896 | /JPEGImages/2009_004343.jpg 897 | /JPEGImages/2009_004344.jpg 898 | /JPEGImages/2009_004385.jpg 899 | /JPEGImages/2009_004408.jpg 900 | /JPEGImages/2009_004420.jpg 901 | /JPEGImages/2009_004441.jpg 902 | /JPEGImages/2009_004447.jpg 903 | /JPEGImages/2009_004461.jpg 904 | /JPEGImages/2009_004467.jpg 905 | /JPEGImages/2009_004485.jpg 906 | /JPEGImages/2009_004488.jpg 907 | /JPEGImages/2009_004516.jpg 908 | /JPEGImages/2009_004521.jpg 909 | /JPEGImages/2009_004544.jpg 910 | /JPEGImages/2009_004596.jpg 911 | /JPEGImages/2009_004613.jpg 912 | /JPEGImages/2009_004615.jpg 913 | /JPEGImages/2009_004618.jpg 914 | /JPEGImages/2009_004621.jpg 915 | /JPEGImages/2009_004646.jpg 916 | /JPEGImages/2009_004659.jpg 917 | /JPEGImages/2009_004663.jpg 918 | /JPEGImages/2009_004666.jpg 919 | /JPEGImages/2009_004691.jpg 920 | /JPEGImages/2009_004715.jpg 921 | /JPEGImages/2009_004726.jpg 922 | /JPEGImages/2009_004753.jpg 923 | /JPEGImages/2009_004776.jpg 924 | /JPEGImages/2009_004811.jpg 925 | /JPEGImages/2009_004814.jpg 926 | /JPEGImages/2009_004818.jpg 927 | /JPEGImages/2009_004835.jpg 928 | /JPEGImages/2009_004863.jpg 929 | /JPEGImages/2009_004894.jpg 930 | /JPEGImages/2009_004909.jpg 931 | /JPEGImages/2009_004928.jpg 932 | /JPEGImages/2009_004937.jpg 933 | /JPEGImages/2009_004954.jpg 934 | /JPEGImages/2009_004966.jpg 935 | /JPEGImages/2009_004970.jpg 936 | /JPEGImages/2009_004976.jpg 937 | /JPEGImages/2009_005004.jpg 938 | /JPEGImages/2009_005011.jpg 939 | /JPEGImages/2009_005053.jpg 940 | /JPEGImages/2009_005072.jpg 941 | /JPEGImages/2009_005115.jpg 942 | /JPEGImages/2009_005146.jpg 943 | /JPEGImages/2009_005151.jpg 944 | /JPEGImages/2009_005164.jpg 945 | /JPEGImages/2009_005179.jpg 946 | /JPEGImages/2009_005224.jpg 947 | /JPEGImages/2009_005243.jpg 948 | /JPEGImages/2009_005249.jpg 949 | /JPEGImages/2009_005252.jpg 950 | /JPEGImages/2009_005254.jpg 951 | /JPEGImages/2009_005258.jpg 952 | /JPEGImages/2009_005264.jpg 953 | /JPEGImages/2009_005266.jpg 954 | /JPEGImages/2009_005276.jpg 955 | /JPEGImages/2009_005290.jpg 956 | /JPEGImages/2009_005295.jpg 957 | /JPEGImages/2010_000004.jpg 958 | /JPEGImages/2010_000005.jpg 959 | /JPEGImages/2010_000006.jpg 960 | /JPEGImages/2010_000032.jpg 961 | /JPEGImages/2010_000062.jpg 962 | /JPEGImages/2010_000093.jpg 963 | /JPEGImages/2010_000094.jpg 964 | /JPEGImages/2010_000161.jpg 965 | /JPEGImages/2010_000176.jpg 966 | /JPEGImages/2010_000223.jpg 967 | /JPEGImages/2010_000226.jpg 968 | /JPEGImages/2010_000236.jpg 969 | /JPEGImages/2010_000239.jpg 970 | /JPEGImages/2010_000287.jpg 971 | /JPEGImages/2010_000300.jpg 972 | /JPEGImages/2010_000301.jpg 973 | /JPEGImages/2010_000328.jpg 974 | /JPEGImages/2010_000378.jpg 975 | /JPEGImages/2010_000405.jpg 976 | /JPEGImages/2010_000407.jpg 977 | /JPEGImages/2010_000472.jpg 978 | /JPEGImages/2010_000479.jpg 979 | /JPEGImages/2010_000491.jpg 980 | /JPEGImages/2010_000533.jpg 981 | /JPEGImages/2010_000535.jpg 982 | /JPEGImages/2010_000542.jpg 983 | /JPEGImages/2010_000554.jpg 984 | /JPEGImages/2010_000580.jpg 985 | /JPEGImages/2010_000594.jpg 986 | /JPEGImages/2010_000596.jpg 987 | /JPEGImages/2010_000599.jpg 988 | /JPEGImages/2010_000606.jpg 989 | /JPEGImages/2010_000615.jpg 990 | /JPEGImages/2010_000654.jpg 991 | /JPEGImages/2010_000659.jpg 992 | /JPEGImages/2010_000693.jpg 993 | /JPEGImages/2010_000698.jpg 994 | /JPEGImages/2010_000730.jpg 995 | /JPEGImages/2010_000734.jpg 996 | /JPEGImages/2010_000741.jpg 997 | /JPEGImages/2010_000755.jpg 998 | /JPEGImages/2010_000768.jpg 999 | /JPEGImages/2010_000794.jpg 1000 | /JPEGImages/2010_000813.jpg 1001 | /JPEGImages/2010_000817.jpg 1002 | /JPEGImages/2010_000834.jpg 1003 | /JPEGImages/2010_000839.jpg 1004 | /JPEGImages/2010_000848.jpg 1005 | /JPEGImages/2010_000881.jpg 1006 | /JPEGImages/2010_000888.jpg 1007 | /JPEGImages/2010_000900.jpg 1008 | /JPEGImages/2010_000903.jpg 1009 | /JPEGImages/2010_000924.jpg 1010 | /JPEGImages/2010_000946.jpg 1011 | /JPEGImages/2010_000953.jpg 1012 | /JPEGImages/2010_000957.jpg 1013 | /JPEGImages/2010_000967.jpg 1014 | /JPEGImages/2010_000992.jpg 1015 | /JPEGImages/2010_000998.jpg 1016 | /JPEGImages/2010_001053.jpg 1017 | /JPEGImages/2010_001067.jpg 1018 | /JPEGImages/2010_001114.jpg 1019 | /JPEGImages/2010_001132.jpg 1020 | /JPEGImages/2010_001138.jpg 1021 | /JPEGImages/2010_001169.jpg 1022 | /JPEGImages/2010_001171.jpg 1023 | /JPEGImages/2010_001228.jpg 1024 | /JPEGImages/2010_001260.jpg 1025 | /JPEGImages/2010_001268.jpg 1026 | /JPEGImages/2010_001280.jpg 1027 | /JPEGImages/2010_001298.jpg 1028 | /JPEGImages/2010_001302.jpg 1029 | /JPEGImages/2010_001308.jpg 1030 | /JPEGImages/2010_001324.jpg 1031 | /JPEGImages/2010_001332.jpg 1032 | /JPEGImages/2010_001335.jpg 1033 | /JPEGImages/2010_001345.jpg 1034 | /JPEGImages/2010_001346.jpg 1035 | /JPEGImages/2010_001349.jpg 1036 | /JPEGImages/2010_001373.jpg 1037 | /JPEGImages/2010_001381.jpg 1038 | /JPEGImages/2010_001392.jpg 1039 | /JPEGImages/2010_001396.jpg 1040 | /JPEGImages/2010_001420.jpg 1041 | /JPEGImages/2010_001500.jpg 1042 | /JPEGImages/2010_001506.jpg 1043 | /JPEGImages/2010_001521.jpg 1044 | /JPEGImages/2010_001532.jpg 1045 | /JPEGImages/2010_001558.jpg 1046 | /JPEGImages/2010_001598.jpg 1047 | /JPEGImages/2010_001611.jpg 1048 | /JPEGImages/2010_001631.jpg 1049 | /JPEGImages/2010_001639.jpg 1050 | /JPEGImages/2010_001651.jpg 1051 | /JPEGImages/2010_001663.jpg 1052 | /JPEGImages/2010_001664.jpg 1053 | /JPEGImages/2010_001728.jpg 1054 | /JPEGImages/2010_001778.jpg 1055 | /JPEGImages/2010_001861.jpg 1056 | /JPEGImages/2010_001874.jpg 1057 | /JPEGImages/2010_001900.jpg 1058 | /JPEGImages/2010_001905.jpg 1059 | /JPEGImages/2010_001969.jpg 1060 | /JPEGImages/2010_002008.jpg 1061 | /JPEGImages/2010_002014.jpg 1062 | /JPEGImages/2010_002049.jpg 1063 | /JPEGImages/2010_002052.jpg 1064 | /JPEGImages/2010_002091.jpg 1065 | /JPEGImages/2010_002115.jpg 1066 | /JPEGImages/2010_002119.jpg 1067 | /JPEGImages/2010_002134.jpg 1068 | /JPEGImages/2010_002156.jpg 1069 | /JPEGImages/2010_002160.jpg 1070 | /JPEGImages/2010_002186.jpg 1071 | /JPEGImages/2010_002210.jpg 1072 | /JPEGImages/2010_002241.jpg 1073 | /JPEGImages/2010_002252.jpg 1074 | /JPEGImages/2010_002258.jpg 1075 | /JPEGImages/2010_002262.jpg 1076 | /JPEGImages/2010_002273.jpg 1077 | /JPEGImages/2010_002290.jpg 1078 | /JPEGImages/2010_002292.jpg 1079 | /JPEGImages/2010_002347.jpg 1080 | /JPEGImages/2010_002358.jpg 1081 | /JPEGImages/2010_002360.jpg 1082 | /JPEGImages/2010_002367.jpg 1083 | /JPEGImages/2010_002416.jpg 1084 | /JPEGImages/2010_002451.jpg 1085 | /JPEGImages/2010_002481.jpg 1086 | /JPEGImages/2010_002490.jpg 1087 | /JPEGImages/2010_002495.jpg 1088 | /JPEGImages/2010_002588.jpg 1089 | /JPEGImages/2010_002607.jpg 1090 | /JPEGImages/2010_002609.jpg 1091 | /JPEGImages/2010_002610.jpg 1092 | /JPEGImages/2010_002641.jpg 1093 | /JPEGImages/2010_002685.jpg 1094 | /JPEGImages/2010_002699.jpg 1095 | /JPEGImages/2010_002719.jpg 1096 | /JPEGImages/2010_002735.jpg 1097 | /JPEGImages/2010_002751.jpg 1098 | /JPEGImages/2010_002804.jpg 1099 | /JPEGImages/2010_002835.jpg 1100 | /JPEGImages/2010_002852.jpg 1101 | /JPEGImages/2010_002885.jpg 1102 | /JPEGImages/2010_002889.jpg 1103 | /JPEGImages/2010_002904.jpg 1104 | /JPEGImages/2010_002908.jpg 1105 | /JPEGImages/2010_002916.jpg 1106 | /JPEGImages/2010_002974.jpg 1107 | /JPEGImages/2010_002977.jpg 1108 | /JPEGImages/2010_003005.jpg 1109 | /JPEGImages/2010_003021.jpg 1110 | /JPEGImages/2010_003030.jpg 1111 | /JPEGImages/2010_003038.jpg 1112 | /JPEGImages/2010_003046.jpg 1113 | /JPEGImages/2010_003052.jpg 1114 | /JPEGImages/2010_003089.jpg 1115 | /JPEGImages/2010_003110.jpg 1116 | /JPEGImages/2010_003118.jpg 1117 | /JPEGImages/2010_003171.jpg 1118 | /JPEGImages/2010_003217.jpg 1119 | /JPEGImages/2010_003221.jpg 1120 | /JPEGImages/2010_003228.jpg 1121 | /JPEGImages/2010_003243.jpg 1122 | /JPEGImages/2010_003271.jpg 1123 | /JPEGImages/2010_003295.jpg 1124 | /JPEGImages/2010_003306.jpg 1125 | /JPEGImages/2010_003324.jpg 1126 | /JPEGImages/2010_003363.jpg 1127 | /JPEGImages/2010_003382.jpg 1128 | /JPEGImages/2010_003388.jpg 1129 | /JPEGImages/2010_003389.jpg 1130 | /JPEGImages/2010_003392.jpg 1131 | /JPEGImages/2010_003430.jpg 1132 | /JPEGImages/2010_003442.jpg 1133 | /JPEGImages/2010_003459.jpg 1134 | /JPEGImages/2010_003485.jpg 1135 | /JPEGImages/2010_003486.jpg 1136 | /JPEGImages/2010_003500.jpg 1137 | /JPEGImages/2010_003523.jpg 1138 | /JPEGImages/2010_003542.jpg 1139 | /JPEGImages/2010_003552.jpg 1140 | /JPEGImages/2010_003570.jpg 1141 | /JPEGImages/2010_003572.jpg 1142 | /JPEGImages/2010_003586.jpg 1143 | /JPEGImages/2010_003615.jpg 1144 | /JPEGImages/2010_003623.jpg 1145 | /JPEGImages/2010_003657.jpg 1146 | /JPEGImages/2010_003666.jpg 1147 | /JPEGImages/2010_003705.jpg 1148 | /JPEGImages/2010_003710.jpg 1149 | /JPEGImages/2010_003720.jpg 1150 | /JPEGImages/2010_003733.jpg 1151 | /JPEGImages/2010_003750.jpg 1152 | /JPEGImages/2010_003767.jpg 1153 | /JPEGImages/2010_003802.jpg 1154 | /JPEGImages/2010_003809.jpg 1155 | /JPEGImages/2010_003830.jpg 1156 | /JPEGImages/2010_003832.jpg 1157 | /JPEGImages/2010_003836.jpg 1158 | /JPEGImages/2010_003838.jpg 1159 | /JPEGImages/2010_003850.jpg 1160 | /JPEGImages/2010_003867.jpg 1161 | /JPEGImages/2010_003882.jpg 1162 | /JPEGImages/2010_003909.jpg 1163 | /JPEGImages/2010_003922.jpg 1164 | /JPEGImages/2010_003923.jpg 1165 | /JPEGImages/2010_003978.jpg 1166 | /JPEGImages/2010_003989.jpg 1167 | /JPEGImages/2010_003990.jpg 1168 | /JPEGImages/2010_004000.jpg 1169 | /JPEGImages/2010_004003.jpg 1170 | /JPEGImages/2010_004068.jpg 1171 | /JPEGImages/2010_004076.jpg 1172 | /JPEGImages/2010_004117.jpg 1173 | /JPEGImages/2010_004136.jpg 1174 | /JPEGImages/2010_004142.jpg 1175 | /JPEGImages/2010_004195.jpg 1176 | /JPEGImages/2010_004200.jpg 1177 | /JPEGImages/2010_004202.jpg 1178 | /JPEGImages/2010_004232.jpg 1179 | /JPEGImages/2010_004261.jpg 1180 | /JPEGImages/2010_004266.jpg 1181 | /JPEGImages/2010_004273.jpg 1182 | /JPEGImages/2010_004305.jpg 1183 | /JPEGImages/2010_004403.jpg 1184 | /JPEGImages/2010_004433.jpg 1185 | /JPEGImages/2010_004434.jpg 1186 | /JPEGImages/2010_004435.jpg 1187 | /JPEGImages/2010_004438.jpg 1188 | /JPEGImages/2010_004442.jpg 1189 | /JPEGImages/2010_004473.jpg 1190 | /JPEGImages/2010_004482.jpg 1191 | /JPEGImages/2010_004487.jpg 1192 | /JPEGImages/2010_004489.jpg 1193 | /JPEGImages/2010_004512.jpg 1194 | /JPEGImages/2010_004525.jpg 1195 | /JPEGImages/2010_004527.jpg 1196 | /JPEGImages/2010_004532.jpg 1197 | /JPEGImages/2010_004566.jpg 1198 | /JPEGImages/2010_004568.jpg 1199 | /JPEGImages/2010_004579.jpg 1200 | /JPEGImages/2010_004611.jpg 1201 | /JPEGImages/2010_004641.jpg 1202 | /JPEGImages/2010_004688.jpg 1203 | /JPEGImages/2010_004699.jpg 1204 | /JPEGImages/2010_004702.jpg 1205 | /JPEGImages/2010_004716.jpg 1206 | /JPEGImages/2010_004754.jpg 1207 | /JPEGImages/2010_004767.jpg 1208 | /JPEGImages/2010_004776.jpg 1209 | /JPEGImages/2010_004811.jpg 1210 | /JPEGImages/2010_004837.jpg 1211 | /JPEGImages/2010_004839.jpg 1212 | /JPEGImages/2010_004845.jpg 1213 | /JPEGImages/2010_004860.jpg 1214 | /JPEGImages/2010_004867.jpg 1215 | /JPEGImages/2010_004881.jpg 1216 | /JPEGImages/2010_004939.jpg 1217 | /JPEGImages/2010_005001.jpg 1218 | /JPEGImages/2010_005047.jpg 1219 | /JPEGImages/2010_005051.jpg 1220 | /JPEGImages/2010_005091.jpg 1221 | /JPEGImages/2010_005095.jpg 1222 | /JPEGImages/2010_005125.jpg 1223 | /JPEGImages/2010_005140.jpg 1224 | /JPEGImages/2010_005177.jpg 1225 | /JPEGImages/2010_005178.jpg 1226 | /JPEGImages/2010_005194.jpg 1227 | /JPEGImages/2010_005197.jpg 1228 | /JPEGImages/2010_005200.jpg 1229 | /JPEGImages/2010_005205.jpg 1230 | /JPEGImages/2010_005212.jpg 1231 | /JPEGImages/2010_005248.jpg 1232 | /JPEGImages/2010_005294.jpg 1233 | /JPEGImages/2010_005298.jpg 1234 | /JPEGImages/2010_005313.jpg 1235 | /JPEGImages/2010_005324.jpg 1236 | /JPEGImages/2010_005328.jpg 1237 | /JPEGImages/2010_005329.jpg 1238 | /JPEGImages/2010_005380.jpg 1239 | /JPEGImages/2010_005404.jpg 1240 | /JPEGImages/2010_005407.jpg 1241 | /JPEGImages/2010_005411.jpg 1242 | /JPEGImages/2010_005423.jpg 1243 | /JPEGImages/2010_005499.jpg 1244 | /JPEGImages/2010_005509.jpg 1245 | /JPEGImages/2010_005510.jpg 1246 | /JPEGImages/2010_005544.jpg 1247 | /JPEGImages/2010_005549.jpg 1248 | /JPEGImages/2010_005590.jpg 1249 | /JPEGImages/2010_005639.jpg 1250 | /JPEGImages/2010_005699.jpg 1251 | /JPEGImages/2010_005704.jpg 1252 | /JPEGImages/2010_005707.jpg 1253 | /JPEGImages/2010_005711.jpg 1254 | /JPEGImages/2010_005726.jpg 1255 | /JPEGImages/2010_005741.jpg 1256 | /JPEGImages/2010_005765.jpg 1257 | /JPEGImages/2010_005790.jpg 1258 | /JPEGImages/2010_005792.jpg 1259 | /JPEGImages/2010_005797.jpg 1260 | /JPEGImages/2010_005812.jpg 1261 | /JPEGImages/2010_005850.jpg 1262 | /JPEGImages/2010_005861.jpg 1263 | /JPEGImages/2010_005869.jpg 1264 | /JPEGImages/2010_005908.jpg 1265 | /JPEGImages/2010_005915.jpg 1266 | /JPEGImages/2010_005946.jpg 1267 | /JPEGImages/2010_005965.jpg 1268 | /JPEGImages/2010_006044.jpg 1269 | /JPEGImages/2010_006047.jpg 1270 | /JPEGImages/2010_006052.jpg 1271 | /JPEGImages/2010_006081.jpg 1272 | /JPEGImages/2011_000001.jpg 1273 | /JPEGImages/2011_000013.jpg 1274 | /JPEGImages/2011_000014.jpg 1275 | /JPEGImages/2011_000020.jpg 1276 | /JPEGImages/2011_000032.jpg 1277 | /JPEGImages/2011_000042.jpg 1278 | /JPEGImages/2011_000063.jpg 1279 | /JPEGImages/2011_000115.jpg 1280 | /JPEGImages/2011_000120.jpg 1281 | /JPEGImages/2011_000240.jpg 1282 | /JPEGImages/2011_000244.jpg 1283 | /JPEGImages/2011_000254.jpg 1284 | /JPEGImages/2011_000261.jpg 1285 | /JPEGImages/2011_000262.jpg 1286 | /JPEGImages/2011_000271.jpg 1287 | /JPEGImages/2011_000274.jpg 1288 | /JPEGImages/2011_000306.jpg 1289 | /JPEGImages/2011_000311.jpg 1290 | /JPEGImages/2011_000316.jpg 1291 | /JPEGImages/2011_000328.jpg 1292 | /JPEGImages/2011_000351.jpg 1293 | /JPEGImages/2011_000352.jpg 1294 | /JPEGImages/2011_000406.jpg 1295 | /JPEGImages/2011_000414.jpg 1296 | /JPEGImages/2011_000448.jpg 1297 | /JPEGImages/2011_000451.jpg 1298 | /JPEGImages/2011_000470.jpg 1299 | /JPEGImages/2011_000473.jpg 1300 | /JPEGImages/2011_000515.jpg 1301 | /JPEGImages/2011_000537.jpg 1302 | /JPEGImages/2011_000576.jpg 1303 | /JPEGImages/2011_000603.jpg 1304 | /JPEGImages/2011_000616.jpg 1305 | /JPEGImages/2011_000636.jpg 1306 | /JPEGImages/2011_000639.jpg 1307 | /JPEGImages/2011_000654.jpg 1308 | /JPEGImages/2011_000660.jpg 1309 | /JPEGImages/2011_000664.jpg 1310 | /JPEGImages/2011_000667.jpg 1311 | /JPEGImages/2011_000670.jpg 1312 | /JPEGImages/2011_000676.jpg 1313 | /JPEGImages/2011_000721.jpg 1314 | /JPEGImages/2011_000723.jpg 1315 | /JPEGImages/2011_000762.jpg 1316 | /JPEGImages/2011_000766.jpg 1317 | /JPEGImages/2011_000786.jpg 1318 | /JPEGImages/2011_000802.jpg 1319 | /JPEGImages/2011_000810.jpg 1320 | /JPEGImages/2011_000821.jpg 1321 | /JPEGImages/2011_000841.jpg 1322 | /JPEGImages/2011_000844.jpg 1323 | /JPEGImages/2011_000846.jpg 1324 | /JPEGImages/2011_000869.jpg 1325 | /JPEGImages/2011_000890.jpg 1326 | /JPEGImages/2011_000915.jpg 1327 | /JPEGImages/2011_000924.jpg 1328 | /JPEGImages/2011_000937.jpg 1329 | /JPEGImages/2011_000939.jpg 1330 | /JPEGImages/2011_000952.jpg 1331 | /JPEGImages/2011_000968.jpg 1332 | /JPEGImages/2011_000974.jpg 1333 | /JPEGImages/2011_001037.jpg 1334 | /JPEGImages/2011_001072.jpg 1335 | /JPEGImages/2011_001085.jpg 1336 | /JPEGImages/2011_001089.jpg 1337 | /JPEGImages/2011_001090.jpg 1338 | /JPEGImages/2011_001099.jpg 1339 | /JPEGImages/2011_001104.jpg 1340 | /JPEGImages/2011_001112.jpg 1341 | /JPEGImages/2011_001120.jpg 1342 | /JPEGImages/2011_001132.jpg 1343 | /JPEGImages/2011_001151.jpg 1344 | /JPEGImages/2011_001194.jpg 1345 | /JPEGImages/2011_001258.jpg 1346 | /JPEGImages/2011_001274.jpg 1347 | /JPEGImages/2011_001314.jpg 1348 | /JPEGImages/2011_001317.jpg 1349 | /JPEGImages/2011_001321.jpg 1350 | /JPEGImages/2011_001379.jpg 1351 | /JPEGImages/2011_001425.jpg 1352 | /JPEGImages/2011_001431.jpg 1353 | /JPEGImages/2011_001443.jpg 1354 | /JPEGImages/2011_001446.jpg 1355 | /JPEGImages/2011_001452.jpg 1356 | /JPEGImages/2011_001454.jpg 1357 | /JPEGImages/2011_001477.jpg 1358 | /JPEGImages/2011_001509.jpg 1359 | /JPEGImages/2011_001512.jpg 1360 | /JPEGImages/2011_001515.jpg 1361 | /JPEGImages/2011_001528.jpg 1362 | /JPEGImages/2011_001554.jpg 1363 | /JPEGImages/2011_001561.jpg 1364 | /JPEGImages/2011_001580.jpg 1365 | /JPEGImages/2011_001587.jpg 1366 | /JPEGImages/2011_001623.jpg 1367 | /JPEGImages/2011_001648.jpg 1368 | /JPEGImages/2011_001651.jpg 1369 | /JPEGImages/2011_001654.jpg 1370 | /JPEGImages/2011_001684.jpg 1371 | /JPEGImages/2011_001696.jpg 1372 | /JPEGImages/2011_001697.jpg 1373 | /JPEGImages/2011_001760.jpg 1374 | /JPEGImages/2011_001761.jpg 1375 | /JPEGImages/2011_001798.jpg 1376 | /JPEGImages/2011_001807.jpg 1377 | /JPEGImages/2011_001851.jpg 1378 | /JPEGImages/2011_001852.jpg 1379 | /JPEGImages/2011_001853.jpg 1380 | /JPEGImages/2011_001888.jpg 1381 | /JPEGImages/2011_001940.jpg 1382 | /JPEGImages/2011_002014.jpg 1383 | /JPEGImages/2011_002028.jpg 1384 | /JPEGImages/2011_002056.jpg 1385 | /JPEGImages/2011_002061.jpg 1386 | /JPEGImages/2011_002068.jpg 1387 | /JPEGImages/2011_002076.jpg 1388 | /JPEGImages/2011_002090.jpg 1389 | /JPEGImages/2011_002095.jpg 1390 | /JPEGImages/2011_002104.jpg 1391 | /JPEGImages/2011_002136.jpg 1392 | /JPEGImages/2011_002138.jpg 1393 | /JPEGImages/2011_002151.jpg 1394 | /JPEGImages/2011_002153.jpg 1395 | /JPEGImages/2011_002155.jpg 1396 | /JPEGImages/2011_002197.jpg 1397 | /JPEGImages/2011_002198.jpg 1398 | /JPEGImages/2011_002243.jpg 1399 | /JPEGImages/2011_002250.jpg 1400 | /JPEGImages/2011_002257.jpg 1401 | /JPEGImages/2011_002262.jpg 1402 | /JPEGImages/2011_002264.jpg 1403 | /JPEGImages/2011_002296.jpg 1404 | /JPEGImages/2011_002314.jpg 1405 | /JPEGImages/2011_002331.jpg 1406 | /JPEGImages/2011_002333.jpg 1407 | /JPEGImages/2011_002411.jpg 1408 | /JPEGImages/2011_002417.jpg 1409 | /JPEGImages/2011_002425.jpg 1410 | /JPEGImages/2011_002437.jpg 1411 | /JPEGImages/2011_002444.jpg 1412 | /JPEGImages/2011_002445.jpg 1413 | /JPEGImages/2011_002449.jpg 1414 | /JPEGImages/2011_002468.jpg 1415 | /JPEGImages/2011_002469.jpg 1416 | /JPEGImages/2011_002473.jpg 1417 | /JPEGImages/2011_002508.jpg 1418 | /JPEGImages/2011_002523.jpg 1419 | /JPEGImages/2011_002534.jpg 1420 | /JPEGImages/2011_002557.jpg 1421 | /JPEGImages/2011_002564.jpg 1422 | /JPEGImages/2011_002572.jpg 1423 | /JPEGImages/2011_002597.jpg 1424 | /JPEGImages/2011_002622.jpg 1425 | /JPEGImages/2011_002632.jpg 1426 | /JPEGImages/2011_002635.jpg 1427 | /JPEGImages/2011_002643.jpg 1428 | /JPEGImages/2011_002653.jpg 1429 | /JPEGImages/2011_002667.jpg 1430 | /JPEGImages/2011_002681.jpg 1431 | /JPEGImages/2011_002707.jpg 1432 | /JPEGImages/2011_002736.jpg 1433 | /JPEGImages/2011_002759.jpg 1434 | /JPEGImages/2011_002783.jpg 1435 | /JPEGImages/2011_002792.jpg 1436 | /JPEGImages/2011_002799.jpg 1437 | /JPEGImages/2011_002824.jpg 1438 | /JPEGImages/2011_002835.jpg 1439 | /JPEGImages/2011_002866.jpg 1440 | /JPEGImages/2011_002876.jpg 1441 | /JPEGImages/2011_002888.jpg 1442 | /JPEGImages/2011_002894.jpg 1443 | /JPEGImages/2011_002903.jpg 1444 | /JPEGImages/2011_002905.jpg 1445 | /JPEGImages/2011_002986.jpg 1446 | /JPEGImages/2011_003045.jpg 1447 | /JPEGImages/2011_003064.jpg 1448 | /JPEGImages/2011_003070.jpg 1449 | /JPEGImages/2011_003083.jpg 1450 | /JPEGImages/2011_003093.jpg 1451 | /JPEGImages/2011_003096.jpg 1452 | /JPEGImages/2011_003102.jpg 1453 | /JPEGImages/2011_003156.jpg 1454 | /JPEGImages/2011_003170.jpg 1455 | /JPEGImages/2011_003178.jpg 1456 | /JPEGImages/2011_003231.jpg 1457 | --------------------------------------------------------------------------------