├── .gitignore ├── README.md ├── datasets ├── __init__.py ├── fewmodelnet.py ├── modelnet.py └── mvmodelnet.py ├── models ├── __init__.py ├── feature.py ├── mvvoxnet.py └── voxnet.py ├── mvvoxnet └── baseline │ ├── 10_train.sh │ ├── 30_train.sh │ ├── few_10_train.sh │ └── train.py ├── utils ├── __init__.py ├── logger.py ├── npytar.py └── transformer.py └── voxnet ├── baseline ├── 10_train.sh ├── 30_train.sh ├── few_train.py ├── few_train.sh ├── log_best_acc.txt ├── log_last_acc.txt ├── mean_std.py └── train.py ├── finetune ├── 10_train.sh ├── few_train.py ├── few_train.sh └── train.py ├── readval.py ├── readval_few.py ├── svm ├── 10_train.sh ├── few_train.py ├── few_train.sh ├── log_acc.txt ├── mean_std.py └── train.py └── val_acc ├── baseline_fewm10.txt ├── baseline_m10.txt └── baseline_m30.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore all data files 2 | data/* 3 | 4 | # ignore log files 5 | *log*/ 6 | 7 | # ignore saved weight 8 | *.pth.tar 9 | 10 | # ignore .pyc 11 | *.pyc 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VoxNet-Pytorch 2 | Pytorch version of voxnet: https://github.com/dimatura/voxnet 3 | -------------------------------------------------------------------------------- /datasets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxxue/voxnet-pytorch/c3f0d3bdd201792e543b070f574787000712e852/datasets/__init__.py -------------------------------------------------------------------------------- /datasets/fewmodelnet.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.utils.data import Dataset, DataLoader 3 | 4 | import numpy as np 5 | import sys 6 | import os 7 | import re 8 | 9 | sys.path.append(os.path.join("..")) 10 | #from utils import npytar 11 | from utils import npytar 12 | 13 | class fewModelNet(Dataset): 14 | def __init__(self, filedir, filename): 15 | reader = npytar.NpyTarReader(os.path.join(filedir, filename)) 16 | temp_list = [] 17 | for (arr, name) in reader: 18 | temp_list.append((arr, name)) 19 | reader.close() 20 | # in this dataset we have 12 views for each shape 21 | if len(temp_list) % 12 != 0: 22 | # assert is a statement in python2/3, not a function 23 | assert "some shapes might not have 12 views" 24 | # pick all the examples 25 | # b x v x c x d x d x d 26 | temp_data = np.zeros((len(temp_list)//12, 12, 1, 32, 32, 32), dtype=np.float32) 27 | # all view share the same label 28 | temp_label = np.zeros((len(temp_list)//12,), dtype=np.int) 29 | 30 | # sort the file by its name 31 | # format: classnum.classname_idx.viewidx 32 | # exception: 001.2h31k8fak.viewidx 33 | temp_list.sort(key=lambda x: (int(x[1].split(".")[0]), x[1].split(".")[-2].split("_")[-1], int(x[1].split(".")[-1]))) 34 | for idx, (arr, name) in enumerate(temp_list): 35 | temp_data[idx//12, idx%12, 0] = arr 36 | if idx % 12 == 0: 37 | # assign label 38 | # name: class_idx.fname.view_idx 39 | temp_label[idx//12] = int(name.split('.')[0])-1 40 | else: 41 | # check label consistency 42 | assert temp_label[idx//12]==(int(name.split('.')[0])-1), "label is inconsistent among different views for file {}, original label{}".format(name, temp_label[idx//12]) 43 | #finish loading all data 44 | # select 9 shapes for each examples 45 | # quite a stupid method since we can get 90 directly 46 | self.data = np.zeros((90, 12, 1, 32, 32, 32), dtype=np.float32) 47 | self.label = np.zeros((90,), dtype=np.int) 48 | 49 | for i in range(10): 50 | index = (temp_label == i) 51 | temp_class_len = sum(index) 52 | #print(temp_class_len) 53 | temp_class_data = temp_data[index] 54 | rand_idx = np.random.choice(temp_class_len, 9, replace=False) 55 | #print(rand_idx) 56 | self.data[i*9:i*9+9] = temp_class_data[rand_idx] 57 | self.label[i*9:i*9+9] = i 58 | 59 | 60 | def __len__(self): 61 | return self.label.shape[0]*12 62 | 63 | def __getitem__(self, idx): 64 | return self.data[idx//12, idx%12], self.label[idx//12] 65 | 66 | 67 | if __name__ == '__main__': 68 | modelnet30 = fewModelNet("../data", "shapenet10_test.tar") 69 | print(len(modelnet30)) 70 | print(modelnet30[80][0].shape, modelnet30[80][1]) 71 | print(np.mean(modelnet30[80][0][np.where(modelnet30[80][0]!=0)])) 72 | -------------------------------------------------------------------------------- /datasets/modelnet.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.utils.data import Dataset, DataLoader 3 | 4 | import numpy as np 5 | import sys 6 | import os 7 | import re 8 | 9 | sys.path.append(os.path.join(os.path.dirname(__file__), "..")) 10 | #from utils import npytar 11 | from utils import npytar 12 | 13 | class ModelNet(Dataset): 14 | def __init__(self, filedir, filename): 15 | reader = npytar.NpyTarReader(os.path.join(filedir, filename)) 16 | temp_list = [] 17 | for (arr, name) in reader: 18 | temp_list.append((arr, name)) 19 | reader.close() 20 | # in this dataset we have 12 views for each shape 21 | if len(temp_list) % 12 != 0: 22 | # assert is a statement in python2/3, not a function 23 | assert "some shapes might not have 12 views" 24 | # b x v x c x d x d x d 25 | self.data = np.zeros((len(temp_list)//12, 12, 1, 32, 32, 32), dtype=np.float32) 26 | # all view share the same label 27 | self.label = np.zeros((len(temp_list)//12,), dtype=np.int) 28 | # sort the file by its name 29 | # format: classnum.classname_idx.viewidx 30 | # exception: 001.2h31k8fak.viewidx 31 | temp_list.sort(key=lambda x: (int(x[1].split(".")[0]), x[1].split(".")[-2].split("_")[-1], int(x[1].split(".")[-1]))) 32 | for idx, (arr, name) in enumerate(temp_list): 33 | self.data[idx//12, idx%12, 0] = arr 34 | if idx % 12 == 0: 35 | # assign label 36 | # name: class_idx.fname.view_idx 37 | self.label[idx//12] = int(name.split('.')[0])-1 38 | else: 39 | # check label consistency 40 | assert self.label[idx//12]==(int(name.split('.')[0])-1), "label is inconsistent among different views for file {}, original label{}".format(name, self.label[idx//12]) 41 | #finish loading all data 42 | 43 | def __len__(self): 44 | return self.label.shape[0]*12 45 | 46 | def __getitem__(self, idx): 47 | return self.data[idx//12, idx%12], self.label[idx//12] 48 | 49 | 50 | if __name__ == '__main__': 51 | modelnet30 = ModelNet("../data", "shapenet10_test.tar") 52 | print(len(modelnet30)) 53 | print(modelnet30[123][0].shape, modelnet30[123][1]) 54 | print(np.mean(modelnet30[123][0][np.where(modelnet30[123][0]!=0)])) 55 | -------------------------------------------------------------------------------- /datasets/mvmodelnet.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.utils.data import Dataset, DataLoader 3 | 4 | import numpy as np 5 | import sys 6 | import os 7 | import re 8 | 9 | sys.path.append("..") 10 | #sys.path.append(os.path.dirname(os.path.abspath(__file__))) 11 | #print os.path.dirname(os.path.abspath(__file__)) 12 | #from utils import npytar 13 | from utils import npytar 14 | 15 | class MVModelNet(Dataset): 16 | def __init__(self, filedir, filename): 17 | reader = npytar.NpyTarReader(os.path.join(filedir, filename)) 18 | temp_list = [] 19 | for (arr, name) in reader: 20 | temp_list.append((arr, name)) 21 | reader.close() 22 | # in this dataset we have 12 views for each shape 23 | if len(temp_list) % 12 != 0: 24 | # assert is a statement in python2/3, not a function 25 | assert "some shapes might not have 12 views" 26 | # b x v x c x d x d x d 27 | self.data = np.zeros((len(temp_list)//12, 12, 1, 32, 32, 32), dtype=np.float32) 28 | # all view share the same label 29 | self.label = np.zeros((len(temp_list)//12,), dtype=np.int) 30 | # sort the file by its name 31 | # format: classnum.classname_idx.viewidx 32 | # exception: 001.2h31k8fak.viewidx 33 | temp_list.sort(key=lambda x: (int(x[1].split(".")[0]), x[1].split(".")[-2].split("_")[-1], int(x[1].split(".")[-1]))) 34 | for idx, (arr, name) in enumerate(temp_list): 35 | self.data[idx//12, idx%12, 0] = arr 36 | if idx % 12 == 0: 37 | # assign label 38 | # name: class_idx.fname.view_idx 39 | self.label[idx//12] = int(name.split('.')[0])-1 40 | else: 41 | # check label consistency 42 | assert self.label[idx//12]==(int(name.split('.')[0])-1), "label is inconsistent among different views for file {}, original label{}".format(name, self.label[idx//12]) 43 | #finish loading all data 44 | 45 | def __len__(self): 46 | return self.label.shape[0] 47 | 48 | def __getitem__(self, idx): 49 | return self.data[idx], self.label[idx] 50 | 51 | 52 | if __name__ == '__main__': 53 | modelnet30 = MVModelNet("../data", "shapenet30_test.tar") 54 | print(__file__) 55 | print(os.path.dirname(__file__)) 56 | print(len(modelnet30)) 57 | print(modelnet30[123][0].shape, modelnet30[123][1]) 58 | print(np.mean(modelnet30[123][0][np.where(modelnet30[123][0]!=0)])) 59 | -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxxue/voxnet-pytorch/c3f0d3bdd201792e543b070f574787000712e852/models/__init__.py -------------------------------------------------------------------------------- /models/feature.py: -------------------------------------------------------------------------------- 1 | # Code copy from https://github.com/daavoo/pyntcloud/blob/master/pyntcloud/learn/models/voxnet.py 2 | import torch 3 | from collections import OrderedDict 4 | 5 | 6 | class VoxNet(torch.nn.Module): 7 | 8 | def __init__(self, num_classes, input_shape=(32, 32, 32)): 9 | #weights_path=None, 10 | #load_body_weights=True, 11 | #load_head_weights=True): 12 | """ 13 | VoxNet: A 3D Convolutional Neural Network for Real-Time Object Recognition. 14 | 15 | Modified in order to accept different input shapes. 16 | 17 | Parameters 18 | ---------- 19 | num_classes: int, optional 20 | Default: 10 21 | input_shape: (x, y, z) tuple, optional 22 | Default: (32, 32, 32) 23 | weights_path: str or None, optional 24 | Default: None 25 | load_body_weights: bool, optional 26 | Default: True 27 | load_head_weights: bool, optional 28 | Default: True 29 | 30 | Notes 31 | ----- 32 | Weights available at: url to be added 33 | 34 | If you want to finetune with custom classes, set load_head_weights to False. 35 | Default head weights are pretrained with ModelNet10. 36 | """ 37 | super(VoxNet, self).__init__() 38 | self.body = torch.nn.Sequential(OrderedDict([ 39 | ('conv1', torch.nn.Conv3d(in_channels=1, 40 | out_channels=32, kernel_size=5, stride=2)), 41 | ('lkrelu1', torch.nn.LeakyReLU()), 42 | ('drop1', torch.nn.Dropout(p=0.2)), 43 | ('conv2', torch.nn.Conv3d(in_channels=32, out_channels=32, kernel_size=3)), 44 | ('lkrelu2', torch.nn.LeakyReLU()), 45 | ('pool2', torch.nn.MaxPool3d(2)), 46 | ('drop2', torch.nn.Dropout(p=0.3)) 47 | ])) 48 | 49 | # Trick to accept different input shapes 50 | x = self.body(torch.autograd.Variable( 51 | torch.rand((1, 1) + input_shape))) 52 | first_fc_in_features = 1 53 | for n in x.size()[1:]: 54 | first_fc_in_features *= n 55 | 56 | #self.head = torch.nn.Sequential(OrderedDict([ 57 | # ('fc1', torch.nn.Linear(first_fc_in_features, 128)), 58 | # ('relu1', torch.nn.ReLU()), 59 | # ('drop3', torch.nn.Dropout(p=0.4)), 60 | # ('fc2', torch.nn.Linear(128, num_classes)) 61 | #])) 62 | self.head = torch.nn.Sequential(OrderedDict([ 63 | ('fc1', torch.nn.Linear(first_fc_in_features, 128)) 64 | #('relu1', torch.nn.ReLU()) 65 | #('drop3', torch.nn.Dropout(p=0.4)), 66 | #('fc2', torch.nn.Linear(128, num_classes)) 67 | ])) 68 | 69 | 70 | #if weights_path is not None: 71 | # weights = torch.load(weights_path) 72 | # if load_body_weights: 73 | # self.body.load_state_dict(weights["body"]) 74 | # elif load_head_weights: 75 | # self.head.load_state_dict(weights["head"]) 76 | 77 | def forward(self, x): 78 | x = self.body(x) 79 | x = x.view(x.size(0), -1) 80 | x = self.head(x) 81 | return x 82 | -------------------------------------------------------------------------------- /models/mvvoxnet.py: -------------------------------------------------------------------------------- 1 | # Code copy from https://github.com/daavoo/pyntcloud/blob/master/pyntcloud/learn/models/voxnet.py 2 | import torch 3 | from collections import OrderedDict 4 | 5 | 6 | class MVVoxNet(torch.nn.Module): 7 | 8 | def __init__(self, num_classes, input_shape=(32, 32, 32)): 9 | #weights_path=None, 10 | #load_body_weights=True, 11 | #load_head_weights=True): 12 | """ 13 | VoxNet: A 3D Convolutional Neural Network for Real-Time Object Recognition. 14 | 15 | Modified in order to accept different input shapes. 16 | 17 | Parameters 18 | ---------- 19 | num_classes: int, optional 20 | Default: 10 21 | input_shape: (x, y, z) tuple, optional 22 | Default: (32, 32, 32) 23 | weights_path: str or None, optional 24 | Default: None 25 | load_body_weights: bool, optional 26 | Default: True 27 | load_head_weights: bool, optional 28 | Default: True 29 | 30 | Notes 31 | ----- 32 | Weights available at: url to be added 33 | 34 | If you want to finetune with custom classes, set load_head_weights to False. 35 | Default head weights are pretrained with ModelNet10. 36 | """ 37 | super(MVVoxNet, self).__init__() 38 | self.body = torch.nn.Sequential(OrderedDict([ 39 | ('conv1', torch.nn.Conv3d(in_channels=1, 40 | out_channels=32, kernel_size=5, stride=2)), 41 | ('lkrelu1', torch.nn.LeakyReLU()), 42 | ('drop1', torch.nn.Dropout(p=0.2)), 43 | ('conv2', torch.nn.Conv3d(in_channels=32, out_channels=32, kernel_size=3)), 44 | ('lkrelu2', torch.nn.LeakyReLU()), 45 | ('pool2', torch.nn.MaxPool3d(2)), 46 | ('drop2', torch.nn.Dropout(p=0.3)) 47 | ])) 48 | 49 | # Trick to accept different input shapes 50 | x = self.body(torch.autograd.Variable( 51 | torch.rand((1, 1) + input_shape))) 52 | first_fc_in_features = 1 53 | for n in x.size()[1:]: 54 | first_fc_in_features *= n 55 | 56 | self.head = torch.nn.Sequential(OrderedDict([ 57 | ('fc1', torch.nn.Linear(first_fc_in_features, 128)), 58 | ('relu1', torch.nn.ReLU()), 59 | ('drop3', torch.nn.Dropout(p=0.4)), 60 | ('fc2', torch.nn.Linear(128, num_classes)) 61 | ])) 62 | 63 | #if weights_path is not None: 64 | # weights = torch.load(weights_path) 65 | # if load_body_weights: 66 | # self.body.load_state_dict(weights["body"]) 67 | # elif load_head_weights: 68 | # self.head.load_state_dict(weights["head"]) 69 | 70 | def forward(self, x): 71 | # shape x: BxVx1xDxDxD 72 | view_pool = [] 73 | for v_idx in range(x.size(1)): 74 | v = x[:, v_idx] 75 | v = self.body(v) 76 | v = v.view(v.size(0), -1) 77 | view_pool.append(v) 78 | 79 | pooled_view = view_pool[0] 80 | for i in range(1, len(view_pool)): 81 | pooled_view = torch.max(pooled_view, view_pool[i]) 82 | 83 | pooled_view = self.head(pooled_view) 84 | return pooled_view 85 | -------------------------------------------------------------------------------- /models/voxnet.py: -------------------------------------------------------------------------------- 1 | # Code copy from https://github.com/daavoo/pyntcloud/blob/master/pyntcloud/learn/models/voxnet.py 2 | import torch 3 | from collections import OrderedDict 4 | 5 | 6 | class VoxNet(torch.nn.Module): 7 | 8 | def __init__(self, num_classes, input_shape=(32, 32, 32)): 9 | #weights_path=None, 10 | #load_body_weights=True, 11 | #load_head_weights=True): 12 | """ 13 | VoxNet: A 3D Convolutional Neural Network for Real-Time Object Recognition. 14 | 15 | Modified in order to accept different input shapes. 16 | 17 | Parameters 18 | ---------- 19 | num_classes: int, optional 20 | Default: 10 21 | input_shape: (x, y, z) tuple, optional 22 | Default: (32, 32, 32) 23 | weights_path: str or None, optional 24 | Default: None 25 | load_body_weights: bool, optional 26 | Default: True 27 | load_head_weights: bool, optional 28 | Default: True 29 | 30 | Notes 31 | ----- 32 | Weights available at: url to be added 33 | 34 | If you want to finetune with custom classes, set load_head_weights to False. 35 | Default head weights are pretrained with ModelNet10. 36 | """ 37 | super(VoxNet, self).__init__() 38 | self.body = torch.nn.Sequential(OrderedDict([ 39 | ('conv1', torch.nn.Conv3d(in_channels=1, 40 | out_channels=32, kernel_size=5, stride=2)), 41 | ('lkrelu1', torch.nn.LeakyReLU()), 42 | ('drop1', torch.nn.Dropout(p=0.2)), 43 | ('conv2', torch.nn.Conv3d(in_channels=32, out_channels=32, kernel_size=3)), 44 | ('lkrelu2', torch.nn.LeakyReLU()), 45 | ('pool2', torch.nn.MaxPool3d(2)), 46 | ('drop2', torch.nn.Dropout(p=0.3)) 47 | ])) 48 | 49 | # Trick to accept different input shapes 50 | x = self.body(torch.autograd.Variable( 51 | torch.rand((1, 1) + input_shape))) 52 | first_fc_in_features = 1 53 | for n in x.size()[1:]: 54 | first_fc_in_features *= n 55 | 56 | self.head = torch.nn.Sequential(OrderedDict([ 57 | ('fc1', torch.nn.Linear(first_fc_in_features, 128)), 58 | ('relu1', torch.nn.ReLU()), 59 | ('drop3', torch.nn.Dropout(p=0.4)), 60 | ('fc2', torch.nn.Linear(128, num_classes)) 61 | ])) 62 | 63 | #if weights_path is not None: 64 | # weights = torch.load(weights_path) 65 | # if load_body_weights: 66 | # self.body.load_state_dict(weights["body"]) 67 | # elif load_head_weights: 68 | # self.head.load_state_dict(weights["head"]) 69 | 70 | def forward(self, x): 71 | x = self.body(x) 72 | x = x.view(x.size(0), -1) 73 | x = self.head(x) 74 | return x 75 | -------------------------------------------------------------------------------- /mvvoxnet/baseline/10_train.sh: -------------------------------------------------------------------------------- 1 | CUDA_VISIBLE_DEVICES=1 \ 2 | python train.py \ 3 | --training_fname shapenet10_test.tar \ 4 | --testing_fname shapenet10_train.tar \ 5 | --model mvvoxnet \ 6 | --log_dir log_10 \ 7 | --num_classes 10 \ 8 | --max_epoch 32 \ 9 | --batch_size 8 \ 10 | --learning_rate 0.001 \ 11 | --momentum 0.9 \ 12 | --optimizer adam \ 13 | --decay_step 4 \ 14 | --decay_rate 0.8 \ 15 | --saved_fname weight10 \ 16 | #--cont \ 17 | #--ckpt_dir \ 18 | #--ckpt_fname 19 | -------------------------------------------------------------------------------- /mvvoxnet/baseline/30_train.sh: -------------------------------------------------------------------------------- 1 | CUDA_VISIBLE_DEVICES=1 \ 2 | python train.py \ 3 | --training_fname shapenet30_train.tar \ 4 | --testing_fname shapenet30_test.tar \ 5 | --model mvvoxnet \ 6 | --log_dir log_30 \ 7 | --num_classes 30 \ 8 | --max_epoch 32 \ 9 | --batch_size 8 \ 10 | --learning_rate 0.001 \ 11 | --momentum 0.9 \ 12 | --optimizer adam \ 13 | --decay_step 4 \ 14 | --decay_rate 0.8 \ 15 | --saved_fname weight30 \ 16 | #--cont \ 17 | #--ckpt_dir \ 18 | #--ckpt_fname 19 | -------------------------------------------------------------------------------- /mvvoxnet/baseline/few_10_train.sh: -------------------------------------------------------------------------------- 1 | CUDA_VISIBLE_DEVICES=1 \ 2 | python train.py \ 3 | --training_fname few_shapenet10_test.tar \ 4 | --testing_fname few_shapenet10_train.tar \ 5 | --model mvvoxnet \ 6 | --log_dir log_few_10 \ 7 | --num_classes 10 \ 8 | --max_epoch 32 \ 9 | --batch_size 8 \ 10 | --learning_rate 0.001 \ 11 | --momentum 0.9 \ 12 | --optimizer adam \ 13 | --decay_step 4 \ 14 | --decay_rate 0.8 \ 15 | --saved_fname weight10 \ 16 | #--cont \ 17 | #--ckpt_dir \ 18 | #--ckpt_fname 19 | -------------------------------------------------------------------------------- /mvvoxnet/baseline/train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.backends.cudnn as cudnn 4 | from torch.utils.data import DataLoader 5 | from torch.autograd import Variable 6 | import torchvision.transforms as transforms 7 | 8 | import imp 9 | import logging 10 | from path import Path 11 | import numpy as np 12 | import time 13 | import os 14 | import sys 15 | import importlib 16 | import argparse 17 | 18 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 19 | ROOT_DIR = os.path.dirname(os.path.dirname(BASE_DIR)) 20 | sys.path.append(ROOT_DIR) 21 | from datasets.mvmodelnet import MVModelNet 22 | 23 | def main(args): 24 | global LOG_FOUT 25 | LOG_FOUT = open(os.path.join(args.log_dir, 'log.txt'), 'w') 26 | log_string(args) 27 | 28 | # load network 29 | print("loading module") 30 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 31 | module = importlib.import_module("models."+args.model) 32 | model = module.MVVoxNet(num_classes=args.num_classes, input_shape=(32,32,32)) 33 | model.to(device) 34 | 35 | # backup files 36 | if not os.path.exists(args.log_dir): 37 | os.mkdir(args.log_dir) 38 | os.system('cp {} {}'.format(os.path.join(ROOT_DIR, 'models', args.model+'.py'), args.log_dir)) 39 | os.system('cp {} {}'.format(__file__, args.log_dir)) 40 | #logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s| %(message)s') 41 | #logging.info('logs will be saved to {}'.format(args.log_fname)) 42 | #logger = Logger(args.log_fname, reinitialize=True) 43 | print("loading dataset") 44 | dset_train = MVModelNet(os.path.join(ROOT_DIR, "data"), args.training_fname) 45 | dset_test = MVModelNet(os.path.join(ROOT_DIR, "data"), args.testing_fname) 46 | log_string('\ntrain dataset size: {}'.format(len(dset_train))) 47 | log_string('\ntest dataset size: {}'.format(len(dset_test))) 48 | 49 | train_loader = DataLoader(dset_train, batch_size=args.batch_size, shuffle=True, num_workers=4) 50 | test_loader = DataLoader(dset_test, batch_size=args.batch_size, num_workers=4) 51 | 52 | 53 | start_epoch = 0 54 | best_acc = 0. 55 | if args.cont: 56 | start_epoch, best_acc = load_checkpoint(args, model) 57 | 58 | print("set optimizer") 59 | # set optimization methods 60 | criterion = nn.CrossEntropyLoss() 61 | optimizer = torch.optim.Adam(model.parameters(), lr=args.learning_rate) 62 | scheduler = torch.optim.lr_scheduler.StepLR(optimizer, args.decay_step, args.decay_rate) 63 | 64 | for epoch in range(start_epoch, args.max_epoch): 65 | scheduler.step() 66 | log_string('\n-----------------------------------') 67 | log_string('Epoch: [%d/%d]' % (epoch+1, args.max_epoch)) 68 | start = time.time() 69 | 70 | model.train() 71 | train(train_loader, model, criterion, optimizer, device) 72 | log_string('Time taken: %.2f sec.' % (time.time() - start)) 73 | 74 | model.eval() 75 | avg_test_acc, avg_loss = test(test_loader, model, criterion, optimizer, device) 76 | 77 | log_string('\nEvaluation:') 78 | log_string('\tVal Acc: %.2f - Loss: %.4f' % (avg_test_acc, avg_loss)) 79 | log_string('\tCurrent best val acc: %.2f' % best_acc) 80 | 81 | # Log epoch to tensorboard 82 | # See log using: tensorboard --logdir='logs' --port=6006 83 | #util.logEpoch(logger, resnet, epoch + 1, avg_loss, avg_test_acc) 84 | 85 | # Save model 86 | if avg_test_acc > best_acc: 87 | log_string('\tSaving checkpoint - Acc: %.2f' % avg_test_acc) 88 | best_acc = avg_test_acc 89 | best_loss = avg_loss 90 | torch.save({ 91 | 'epoch': epoch + 1, 92 | #'state_dict': resnet.state_dict(), 93 | 'body': model.body.state_dict(), 94 | 'feat': model.head.state_dict(), 95 | 'acc': avg_test_acc, 96 | 'best_acc': best_acc, 97 | 'optimizer': optimizer.state_dict() 98 | }, os.path.join(args.log_dir, args.saved_fname+".pth.tar")) 99 | 100 | LOG_FOUT.close() 101 | return 102 | 103 | 104 | def log_string(out_str): 105 | LOG_FOUT.write(str(out_str)+'\n') 106 | LOG_FOUT.flush() 107 | print(out_str) 108 | 109 | 110 | def load_checkpoint(args, model): 111 | # Load checkpoint. 112 | print('\n==> Loading checkpoint..') 113 | fname = os.path.join(args.ckpt_dir, args.ckpt_fname + '.pth.tar') 114 | assert os.path.isfile(fname), 'Error: no checkpoint file found!' 115 | 116 | checkpoint = torch.load(fname) 117 | best_acc = checkpoint['best_acc'] 118 | start_epoch = checkpoint['epoch'] 119 | model.body.load_state_dict(checkpoint['body']) 120 | model.head.load_state_dict(checkpoint['head']) 121 | 122 | return start_epoch, best_acc 123 | 124 | 125 | def train(loader, model, criterion, optimizer, device): 126 | num_batch = len(loader) 127 | batch_size = loader.batch_size 128 | total = torch.LongTensor([0]) 129 | correct = torch.LongTensor([0]) 130 | total_loss = 0. 131 | 132 | for i, (inputs, targets) in enumerate(loader): 133 | #inputs = torch.from_numpy(inputs) 134 | inputs, targets = inputs.to(device), targets.to(device) 135 | # in 0.4.0 variable and tensor are merged 136 | #inputs, targets = Variable(inputs), Variable(targets) 137 | 138 | # compute output 139 | outputs = model(inputs) 140 | loss = criterion(outputs, targets) 141 | 142 | total_loss += loss.item() 143 | _, predicted = torch.max(outputs.detach(), 1) 144 | total += batch_size 145 | correct += (predicted == targets).cpu().sum() 146 | 147 | # compute gradient and do SGD step 148 | optimizer.zero_grad() 149 | loss.backward() 150 | optimizer.step() 151 | 152 | log_iter = 100 153 | if (i + 1) % log_iter == 0: 154 | log_string("\tIter [%d/%d] Loss: %.4f" % (i + 1, num_batch, total_loss/log_iter)) 155 | total_loss = 0. 156 | 157 | log_string("Train Accuracy %.2f" % (100.0 * correct.item() / total.item())) 158 | return 159 | 160 | 161 | def test(loader, model, criterion, optimizer, device): 162 | # Eval 163 | total = torch.LongTensor([0]) 164 | correct = torch.LongTensor([0]) 165 | 166 | total_loss = 0.0 167 | n = 0 168 | 169 | for i, (inputs, targets) in enumerate(loader): 170 | with torch.no_grad(): 171 | # Convert from list of 3D to 4D 172 | #inputs = torch.from_numpy(inputs) 173 | 174 | inputs, targets = inputs.to(device), targets.to(device) 175 | 176 | # compute output 177 | outputs = model(inputs) 178 | loss = criterion(outputs, targets) 179 | 180 | total_loss += loss.item() 181 | n += 1 182 | 183 | _, predicted = torch.max(outputs.detach(), 1) 184 | total += targets.size(0) 185 | correct += (predicted == targets).cpu().sum() 186 | 187 | avg_test_acc = 100. * correct.item() / total.item() 188 | avg_loss = total_loss / n 189 | 190 | return avg_test_acc, avg_loss 191 | 192 | 193 | if __name__ == "__main__": 194 | parser = argparse.ArgumentParser() 195 | parser.add_argument('--training_fname', type=Path, help='training .tar file') 196 | parser.add_argument('--testing_fname', type=Path, help='testing .tar file') 197 | parser.add_argument('--model', default='voxnet', help='Model name: [default:voxnet]') 198 | parser.add_argument('--log_dir', default='log', help='Log dir [default: log]') 199 | parser.add_argument('--num_classes', type=int, default=40, help='Category Number [10/30/40] [default: 40]') 200 | parser.add_argument('--max_epoch', type=int, default=256, help='Epoch to run [default: 256]') 201 | parser.add_argument('--batch_size', type=int, default=4, help='Batch Size during training [default: 4]') 202 | parser.add_argument('--learning_rate', type=float, default=0.001, help='Initial learning rate [default: 0.001]') 203 | parser.add_argument('--momentum', type=float, default=0.9, help='Initial learning rate [default: 0.9]') 204 | parser.add_argument('--optimizer', default='adam', help='adam or momentum [default: adam]') 205 | parser.add_argument('--decay_step', type=int, default=16, help='Decay step for lr decay [default: 16]') 206 | parser.add_argument('--decay_rate', type=float, default=0.7, help='Decay rate for lr decay [default: 0.8]') 207 | parser.add_argument('--saved_fname', type=Path, default=None, help='name of weight to be saved') 208 | parser.add_argument('--cont', action='store_true', default=False) 209 | parser.add_argument('--ckpt_dir', default='log', help='check point dir [default: log]') 210 | parser.add_argument('--ckpt_fname', default='model', help='check point name [default: model]') 211 | args = parser.parse_args() 212 | 213 | cudnn.benchmark = True 214 | main(args) 215 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxxue/voxnet-pytorch/c3f0d3bdd201792e543b070f574787000712e852/utils/__init__.py -------------------------------------------------------------------------------- /utils/logger.py: -------------------------------------------------------------------------------- 1 | # copy from original voxnet implementation: https://github.com/dimatura/voxnet 2 | import time 3 | import json 4 | import logging 5 | 6 | from path import Path 7 | 8 | class Logger(object): 9 | 10 | def __init__(self, fname, reinitialize=False): 11 | self.fname = Path(fname) 12 | self.reinitialize = reinitialize 13 | if self.fname.exists(): 14 | if self.reinitialize: 15 | logging.warn('{} exists, deleting'.format(self.fname)) 16 | self.fname.remove() 17 | 18 | def log(self, record=None, **kwargs): 19 | """ 20 | Assumption: no newlines in the input. 21 | """ 22 | if record is None: 23 | record = {} 24 | record.update(kwargs) 25 | record['_stamp'] = time.time() 26 | with open(self.fname, 'ab') as f: 27 | f.write(json.dumps(record, ensure_ascii=True)+'\n') 28 | 29 | 30 | def read_records(fname): 31 | """ convenience for reading back. """ 32 | skipped = 0 33 | with open(fname, 'rb') as f: 34 | for line in f: 35 | if not line.endswith('\n'): 36 | skipped += 1 37 | continue 38 | yield json.loads(line.strip()) 39 | if skipped > 0: 40 | logging.warn('skipped {} lines'.format(skipped)) 41 | -------------------------------------------------------------------------------- /utils/npytar.py: -------------------------------------------------------------------------------- 1 | 2 | import cStringIO as StringIO 3 | import tarfile 4 | import time 5 | import zlib 6 | 7 | import numpy as np 8 | 9 | PREFIX = 'data/' 10 | SUFFIX = '.npy.z' 11 | 12 | class NpyTarWriter(object): 13 | def __init__(self, fname): 14 | self.tfile = tarfile.open(fname, 'w|') 15 | 16 | def add(self, arr, name): 17 | 18 | sio = StringIO.StringIO() 19 | np.save(sio, arr) 20 | zbuf = zlib.compress(sio.getvalue()) 21 | sio.close() 22 | 23 | zsio = StringIO.StringIO(zbuf) 24 | tinfo = tarfile.TarInfo('{}{}{}'.format(PREFIX, name, SUFFIX)) 25 | tinfo.size = len(zbuf) 26 | tinfo.mtime = time.time() 27 | zsio.seek(0) 28 | self.tfile.addfile(tinfo, zsio) 29 | zsio.close() 30 | 31 | def close(self): 32 | self.tfile.close() 33 | 34 | 35 | class NpyTarReader(object): 36 | def __init__(self, fname): 37 | self.tfile = tarfile.open(fname, 'r|') 38 | 39 | def __iter__(self): 40 | return self 41 | 42 | def __next__(self): 43 | return self.next() 44 | 45 | def next(self): 46 | entry = self.tfile.next() 47 | if entry is None: 48 | raise StopIteration() 49 | name = entry.name[len(PREFIX):-len(SUFFIX)] 50 | fileobj = self.tfile.extractfile(entry) 51 | buf = zlib.decompress(fileobj.read()) 52 | arr = np.load(StringIO.StringIO(buf)) 53 | return arr, name 54 | 55 | def close(self): 56 | self.tfile.close() 57 | 58 | -------------------------------------------------------------------------------- /utils/transformer.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Jitter(object): 4 | def __init__(self, max_jitter_ij, max_jitter_k): 5 | self.max_ij = max_jitter_ij 6 | self.max_k = max_jitter_k 7 | 8 | 9 | def __call__(self, batch): 10 | # batch x D x D x D 11 | # or batch x nview x D x D xD 12 | dst = src.copy() 13 | rank = len(batch.shape) 14 | # reverse in x/y direction 15 | shitf_ijk = [np.random.randint(-self.max_ij, self.max_ij), 16 | np.random.randint(-self.max_ij, self.max_ij), 17 | np.random.randint(-self.max_k, self.max_k)] 18 | if rank == 4: 19 | if np.random.binomial(1, .2): 20 | dst[:, ::-1, :, :] = dst 21 | if np.random.binomial(1, .2): 22 | dst[:, :, ::-1, :] = dst 23 | for axis, shift in enumerate(shift_ijk): 24 | if shift != 0: 25 | dst = np.roll(dst, shift, axis+1) 26 | elif rank == 5: 27 | if np.random.binomial(1, .2): 28 | dst[:, :, ::-1, :, :] = dst 29 | if np.random.binomial(1, .2): 30 | dst[:, :, :, ::-1, :] = dst 31 | for axis, shift in enumerate(shift_ijk): 32 | if shift != 0: 33 | dst = np.roll(dst, shift, axis+2) 34 | else: 35 | assert "rank of each batch should be 4 or 5 instead of {}".format(rank) 36 | 37 | return dst 38 | 39 | -------------------------------------------------------------------------------- /voxnet/baseline/10_train.sh: -------------------------------------------------------------------------------- 1 | CUDA_VISIBLE_DEVICES=1 \ 2 | python train.py \ 3 | --training_fname shapenet10_test.tar \ 4 | --testing_fname shapenet10_train.tar \ 5 | --model voxnet \ 6 | --log_dir log_10 \ 7 | --num_classes 10 \ 8 | --max_epoch 32 \ 9 | --batch_size 8 \ 10 | --learning_rate 0.001 \ 11 | --momentum 0.9 \ 12 | --optimizer adam \ 13 | --decay_step 4 \ 14 | --decay_rate 0.8 \ 15 | --saved_fname weight10 \ 16 | #--cont \ 17 | #--ckpt_dir \ 18 | #--ckpt_fname 19 | -------------------------------------------------------------------------------- /voxnet/baseline/30_train.sh: -------------------------------------------------------------------------------- 1 | CUDA_VISIBLE_DEVICES=1 \ 2 | python train.py \ 3 | --training_fname shapenet30_train.tar \ 4 | --testing_fname shapenet30_test.tar \ 5 | --model voxnet \ 6 | --log_dir log_30 \ 7 | --num_classes 30 \ 8 | --max_epoch 32 \ 9 | --batch_size 8 \ 10 | --learning_rate 0.001 \ 11 | --momentum 0.9 \ 12 | --optimizer adam \ 13 | --decay_step 4 \ 14 | --decay_rate 0.8 \ 15 | --saved_fname weight30 \ 16 | #--cont \ 17 | #--ckpt_dir \ 18 | #--ckpt_fname 19 | -------------------------------------------------------------------------------- /voxnet/baseline/few_train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.backends.cudnn as cudnn 4 | from torch.utils.data import DataLoader 5 | from torch.autograd import Variable 6 | import torchvision.transforms as transforms 7 | 8 | import imp 9 | import logging 10 | from path import Path 11 | import numpy as np 12 | import time 13 | import os 14 | import sys 15 | import importlib 16 | import argparse 17 | 18 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 19 | ROOT_DIR = os.path.dirname(os.path.dirname(BASE_DIR)) 20 | sys.path.append(ROOT_DIR) 21 | from datasets.modelnet import ModelNet 22 | from datasets.fewmodelnet import fewModelNet 23 | 24 | def main(args): 25 | # load network 26 | print("loading module") 27 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 28 | module = importlib.import_module("models."+args.model) 29 | model = module.VoxNet(num_classes=args.num_classes, input_shape=(32,32,32)) 30 | model.to(device) 31 | 32 | # backup files 33 | if not os.path.exists(args.log_dir): 34 | os.mkdir(args.log_dir) 35 | os.system('cp {} {}'.format(os.path.join(ROOT_DIR, 'models', args.model+'.py'), args.log_dir)) 36 | os.system('cp {} {}'.format(__file__, args.log_dir)) 37 | #logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s| %(message)s') 38 | #logging.info('logs will be saved to {}'.format(args.log_fname)) 39 | #logger = Logger(args.log_fname, reinitialize=True) 40 | print("loading dataset") 41 | dset_train = fewModelNet(os.path.join(ROOT_DIR, "data"), args.training_fname) 42 | dset_test = ModelNet(os.path.join(ROOT_DIR, "data"), args.testing_fname) 43 | print("train dataset size: {}".format(len(dset_train))) 44 | print("test dataset size: {}".format(len(dset_test))) 45 | 46 | train_loader = DataLoader(dset_train, batch_size=args.batch_size, shuffle=True, num_workers=4) 47 | test_loader = DataLoader(dset_test, batch_size=args.batch_size, num_workers=4) 48 | 49 | global LOG_FOUT 50 | LOG_FOUT = open(os.path.join(args.log_dir, 'log.txt'), 'w') 51 | log_string(args) 52 | 53 | start_epoch = 0 54 | best_acc = 0. 55 | if args.cont: 56 | start_epoch, best_acc = load_checkpoint(args, model) 57 | 58 | print("set optimizer") 59 | # set optimization methods 60 | criterion = nn.CrossEntropyLoss() 61 | optimizer = torch.optim.Adam(model.parameters(), lr=args.learning_rate) 62 | scheduler = torch.optim.lr_scheduler.StepLR(optimizer, args.decay_step, args.decay_rate) 63 | 64 | for epoch in range(start_epoch, args.max_epoch): 65 | scheduler.step() 66 | log_string('\n-----------------------------------') 67 | log_string('Epoch: [%d/%d]' % (epoch+1, args.max_epoch)) 68 | start = time.time() 69 | 70 | model.train() 71 | train(train_loader, model, criterion, optimizer, device) 72 | log_string('Time taken: %.2f sec.' % (time.time() - start)) 73 | 74 | model.eval() 75 | avg_test_acc, avg_loss = test(test_loader, model, criterion, optimizer, device) 76 | 77 | log_string('\nEvaluation:') 78 | log_string('\tVal Acc: %.2f - Loss: %.4f' % (avg_test_acc, avg_loss)) 79 | log_string('\tCurrent best val acc: %.2f' % best_acc) 80 | 81 | # Log epoch to tensorboard 82 | # See log using: tensorboard --logdir='logs' --port=6006 83 | #util.logEpoch(logger, resnet, epoch + 1, avg_loss, avg_test_acc) 84 | 85 | # Save model 86 | if avg_test_acc > best_acc: 87 | log_string('\tSaving checkpoint - Acc: %.2f' % avg_test_acc) 88 | best_acc = avg_test_acc 89 | best_loss = avg_loss 90 | torch.save({ 91 | 'epoch': epoch + 1, 92 | #'state_dict': resnet.state_dict(), 93 | 'body': model.body.state_dict(), 94 | 'feat': model.head.state_dict(), 95 | 'acc': avg_test_acc, 96 | 'best_acc': best_acc, 97 | 'optimizer': optimizer.state_dict() 98 | }, os.path.join(args.log_dir, args.saved_fname+".pth.tar")) 99 | 100 | LOG_FOUT.close() 101 | with open("log_best_acc.txt", "a") as f: 102 | f.write("{}\n".format(best_acc)) 103 | with open("log_last_acc.txt", "a") as f: 104 | f.write("{}\n".format(avg_test_acc)) 105 | return 106 | 107 | 108 | def log_string(out_str): 109 | LOG_FOUT.write(str(out_str)+'\n') 110 | LOG_FOUT.flush() 111 | print(out_str) 112 | 113 | 114 | def load_checkpoint(args, model): 115 | # Load checkpoint. 116 | print('\n==> Loading checkpoint..') 117 | fname = os.path.join(args.ckpt_dir, args.ckpt_fname + '.pth.tar') 118 | assert os.path.isfile(fname), 'Error: no checkpoint file found!' 119 | 120 | checkpoint = torch.load(fname) 121 | best_acc = checkpoint['best_acc'] 122 | start_epoch = checkpoint['epoch'] 123 | model.body.load_state_dict(checkpoint['body']) 124 | model.head.load_state_dict(checkpoint['head']) 125 | 126 | return start_epoch, best_acc 127 | 128 | 129 | def train(loader, model, criterion, optimizer, device): 130 | num_batch = len(loader) 131 | batch_size = loader.batch_size 132 | total = torch.LongTensor([0]) 133 | correct = torch.LongTensor([0]) 134 | total_loss = 0. 135 | 136 | for i, (inputs, targets) in enumerate(loader): 137 | #inputs = torch.from_numpy(inputs) 138 | inputs, targets = inputs.to(device), targets.to(device) 139 | # in 0.4.0 variable and tensor are merged 140 | #inputs, targets = Variable(inputs), Variable(targets) 141 | 142 | # compute output 143 | outputs = model(inputs) 144 | loss = criterion(outputs, targets) 145 | 146 | total_loss += loss.item() 147 | _, predicted = torch.max(outputs.detach(), 1) 148 | total += batch_size 149 | correct += (predicted == targets).cpu().sum() 150 | 151 | # compute gradient and do SGD step 152 | optimizer.zero_grad() 153 | loss.backward() 154 | optimizer.step() 155 | 156 | log_iter = 1000 157 | if (i + 1) % log_iter == 0: 158 | log_string("\tIter [%d/%d] Loss: %.4f" % (i + 1, num_batch, total_loss/log_iter)) 159 | total_loss = 0. 160 | 161 | log_string("Train Accuracy %.2f" % (100.0 * correct.item() / total.item())) 162 | return 163 | 164 | 165 | def test(loader, model, criterion, optimizer, device): 166 | # Eval 167 | total = torch.LongTensor([0]) 168 | correct = torch.LongTensor([0]) 169 | 170 | total_loss = 0.0 171 | n = 0 172 | 173 | for i, (inputs, targets) in enumerate(loader): 174 | with torch.no_grad(): 175 | # Convert from list of 3D to 4D 176 | #inputs = torch.from_numpy(inputs) 177 | 178 | inputs, targets = inputs.to(device), targets.to(device) 179 | 180 | # compute output 181 | outputs = model(inputs) 182 | loss = criterion(outputs, targets) 183 | 184 | total_loss += loss.item() 185 | n += 1 186 | 187 | _, predicted = torch.max(outputs.detach(), 1) 188 | total += targets.size(0) 189 | correct += (predicted == targets).cpu().sum() 190 | 191 | avg_test_acc = 100. * correct.item() / total.item() 192 | avg_loss = total_loss / n 193 | 194 | return avg_test_acc, avg_loss 195 | 196 | 197 | if __name__ == "__main__": 198 | parser = argparse.ArgumentParser() 199 | parser.add_argument('--training_fname', type=Path, help='training .tar file') 200 | parser.add_argument('--testing_fname', type=Path, help='testing .tar file') 201 | parser.add_argument('--model', default='voxnet', help='Model name: [default:voxnet]') 202 | parser.add_argument('--log_dir', default='log', help='Log dir [default: log]') 203 | parser.add_argument('--num_classes', type=int, default=40, help='Category Number [10/30/40] [default: 40]') 204 | parser.add_argument('--max_epoch', type=int, default=256, help='Epoch to run [default: 256]') 205 | parser.add_argument('--batch_size', type=int, default=4, help='Batch Size during training [default: 4]') 206 | parser.add_argument('--learning_rate', type=float, default=0.001, help='Initial learning rate [default: 0.001]') 207 | parser.add_argument('--momentum', type=float, default=0.9, help='Initial learning rate [default: 0.9]') 208 | parser.add_argument('--optimizer', default='adam', help='adam or momentum [default: adam]') 209 | parser.add_argument('--decay_step', type=int, default=16, help='Decay step for lr decay [default: 16]') 210 | parser.add_argument('--decay_rate', type=float, default=0.7, help='Decay rate for lr decay [default: 0.8]') 211 | parser.add_argument('--saved_fname', type=Path, default=None, help='name of weight to be saved') 212 | parser.add_argument('--cont', action='store_true', default=False) 213 | parser.add_argument('--ckpt_dir', default='log', help='check point dir [default: log]') 214 | parser.add_argument('--ckpt_fname', default='model', help='check point name [default: model]') 215 | args = parser.parse_args() 216 | 217 | cudnn.benchmark = True 218 | main(args) 219 | -------------------------------------------------------------------------------- /voxnet/baseline/few_train.sh: -------------------------------------------------------------------------------- 1 | CUDA_VISIBLE_DEVICES=0 2 | for i in `seq 1 10` 3 | do 4 | python few_train.py \ 5 | --training_fname shapenet10_test.tar \ 6 | --testing_fname shapenet10_train.tar \ 7 | --model voxnet \ 8 | --log_dir log_few_$i \ 9 | --num_classes 10 \ 10 | --max_epoch 32 \ 11 | --batch_size 8 \ 12 | --learning_rate 0.001 \ 13 | --momentum 0.9 \ 14 | --optimizer adam \ 15 | --decay_step 4 \ 16 | --decay_rate 0.8 \ 17 | --saved_fname weight10 18 | done 19 | #--cont \ 20 | #--ckpt_dir \ 21 | #--ckpt_fname 22 | -------------------------------------------------------------------------------- /voxnet/baseline/log_best_acc.txt: -------------------------------------------------------------------------------- 1 | 74.4612878978 2 | 71.9890587154 3 | 61.7055040508 4 | 79.0841894262 5 | 71.8700409254 6 | 74.1209387789 7 | 73.9079595757 8 | 72.9182326902 9 | 73.2690219661 10 | 68.2681867535 11 | -------------------------------------------------------------------------------- /voxnet/baseline/log_last_acc.txt: -------------------------------------------------------------------------------- 1 | 73.7617973774 2 | 69.4771569364 3 | 59.6738494947 4 | 77.6810323227 5 | 70.400066817 6 | 71.1099974944 7 | 71.7948717949 8 | 72.3106155517 9 | 71.139229934 10 | 67.7482669339 11 | -------------------------------------------------------------------------------- /voxnet/baseline/mean_std.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | acc = [] 4 | with open("./log_last_acc.txt", 'r') as f: 5 | for line in f: 6 | a = float(line.strip('\n')) 7 | print a 8 | acc.append(a) 9 | 10 | acc = np.array(acc) 11 | print "-------" 12 | print np.mean(acc) 13 | print np.var(acc) 14 | print np.std(acc) 15 | -------------------------------------------------------------------------------- /voxnet/baseline/train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.backends.cudnn as cudnn 4 | from torch.utils.data import DataLoader 5 | from torch.autograd import Variable 6 | import torchvision.transforms as transforms 7 | 8 | import imp 9 | import logging 10 | from path import Path 11 | import numpy as np 12 | import time 13 | import os 14 | import sys 15 | import importlib 16 | import argparse 17 | 18 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 19 | ROOT_DIR = os.path.dirname(os.path.dirname(BASE_DIR)) 20 | sys.path.append(ROOT_DIR) 21 | from datasets.modelnet import ModelNet 22 | 23 | def main(args): 24 | # load network 25 | print("loading module") 26 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 27 | module = importlib.import_module("models."+args.model) 28 | model = module.VoxNet(num_classes=args.num_classes, input_shape=(32,32,32)) 29 | model.to(device) 30 | 31 | # backup files 32 | if not os.path.exists(args.log_dir): 33 | os.mkdir(args.log_dir) 34 | os.system('cp {} {}'.format(os.path.join(ROOT_DIR, 'models', args.model+'.py'), args.log_dir)) 35 | os.system('cp {} {}'.format(__file__, args.log_dir)) 36 | #logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s| %(message)s') 37 | #logging.info('logs will be saved to {}'.format(args.log_fname)) 38 | #logger = Logger(args.log_fname, reinitialize=True) 39 | print("loading dataset") 40 | dset_train = ModelNet(os.path.join(ROOT_DIR, "data"), args.training_fname) 41 | dset_test = ModelNet(os.path.join(ROOT_DIR, "data"), args.testing_fname) 42 | 43 | train_loader = DataLoader(dset_train, batch_size=args.batch_size, shuffle=True, num_workers=4) 44 | test_loader = DataLoader(dset_test, batch_size=args.batch_size, num_workers=4) 45 | 46 | global LOG_FOUT 47 | LOG_FOUT = open(os.path.join(args.log_dir, 'log.txt'), 'w') 48 | log_string(args) 49 | 50 | start_epoch = 0 51 | best_acc = 0. 52 | if args.cont: 53 | start_epoch, best_acc = load_checkpoint(args, model) 54 | 55 | print("set optimizer") 56 | # set optimization methods 57 | criterion = nn.CrossEntropyLoss() 58 | optimizer = torch.optim.Adam(model.parameters(), lr=args.learning_rate) 59 | scheduler = torch.optim.lr_scheduler.StepLR(optimizer, args.decay_step, args.decay_rate) 60 | 61 | for epoch in range(start_epoch, args.max_epoch): 62 | scheduler.step() 63 | log_string('\n-----------------------------------') 64 | log_string('Epoch: [%d/%d]' % (epoch+1, args.max_epoch)) 65 | start = time.time() 66 | 67 | model.train() 68 | train(train_loader, model, criterion, optimizer, device) 69 | log_string('Time taken: %.2f sec.' % (time.time() - start)) 70 | 71 | model.eval() 72 | avg_test_acc, avg_loss = test(test_loader, model, criterion, optimizer, device) 73 | 74 | log_string('\nEvaluation:') 75 | log_string('\tVal Acc: %.2f - Loss: %.4f' % (avg_test_acc, avg_loss)) 76 | log_string('\tCurrent best val acc: %.2f' % best_acc) 77 | 78 | # Log epoch to tensorboard 79 | # See log using: tensorboard --logdir='logs' --port=6006 80 | #util.logEpoch(logger, resnet, epoch + 1, avg_loss, avg_test_acc) 81 | 82 | # Save model 83 | if avg_test_acc > best_acc: 84 | log_string('\tSaving checkpoint - Acc: %.2f' % avg_test_acc) 85 | best_acc = avg_test_acc 86 | best_loss = avg_loss 87 | torch.save({ 88 | 'epoch': epoch + 1, 89 | #'state_dict': resnet.state_dict(), 90 | 'body': model.body.state_dict(), 91 | 'feat': model.head.state_dict(), 92 | 'acc': avg_test_acc, 93 | 'best_acc': best_acc, 94 | 'optimizer': optimizer.state_dict() 95 | }, os.path.join(args.log_dir, args.saved_fname+".pth.tar")) 96 | 97 | LOG_FOUT.close() 98 | return 99 | 100 | 101 | def log_string(out_str): 102 | LOG_FOUT.write(str(out_str)+'\n') 103 | LOG_FOUT.flush() 104 | print(out_str) 105 | 106 | 107 | def load_checkpoint(args, model): 108 | # Load checkpoint. 109 | print('\n==> Loading checkpoint..') 110 | fname = os.path.join(args.ckpt_dir, args.ckpt_fname + '.pth.tar') 111 | assert os.path.isfile(fname), 'Error: no checkpoint file found!' 112 | 113 | checkpoint = torch.load(fname) 114 | best_acc = checkpoint['best_acc'] 115 | start_epoch = checkpoint['epoch'] 116 | model.body.load_state_dict(checkpoint['body']) 117 | model.head.load_state_dict(checkpoint['head']) 118 | 119 | return start_epoch, best_acc 120 | 121 | 122 | def train(loader, model, criterion, optimizer, device): 123 | num_batch = len(loader) 124 | batch_size = loader.batch_size 125 | total = torch.LongTensor([0]) 126 | correct = torch.LongTensor([0]) 127 | total_loss = 0. 128 | 129 | for i, (inputs, targets) in enumerate(loader): 130 | #inputs = torch.from_numpy(inputs) 131 | inputs, targets = inputs.to(device), targets.to(device) 132 | # in 0.4.0 variable and tensor are merged 133 | #inputs, targets = Variable(inputs), Variable(targets) 134 | 135 | # compute output 136 | outputs = model(inputs) 137 | loss = criterion(outputs, targets) 138 | 139 | total_loss += loss.item() 140 | _, predicted = torch.max(outputs.detach(), 1) 141 | total += batch_size 142 | correct += (predicted == targets).cpu().sum() 143 | 144 | # compute gradient and do SGD step 145 | optimizer.zero_grad() 146 | loss.backward() 147 | optimizer.step() 148 | 149 | log_iter = 1000 150 | if (i + 1) % log_iter == 0: 151 | log_string("\tIter [%d/%d] Loss: %.4f" % (i + 1, num_batch, total_loss/log_iter)) 152 | total_loss = 0. 153 | 154 | log_string("Train Accuracy %.2f" % (100.0 * correct.item() / total.item())) 155 | return 156 | 157 | 158 | def test(loader, model, criterion, optimizer, device): 159 | # Eval 160 | total = torch.LongTensor([0]) 161 | correct = torch.LongTensor([0]) 162 | 163 | total_loss = 0.0 164 | n = 0 165 | 166 | for i, (inputs, targets) in enumerate(loader): 167 | with torch.no_grad(): 168 | # Convert from list of 3D to 4D 169 | #inputs = torch.from_numpy(inputs) 170 | 171 | inputs, targets = inputs.to(device), targets.to(device) 172 | 173 | # compute output 174 | outputs = model(inputs) 175 | loss = criterion(outputs, targets) 176 | 177 | total_loss += loss.item() 178 | n += 1 179 | 180 | _, predicted = torch.max(outputs.detach(), 1) 181 | total += targets.size(0) 182 | correct += (predicted == targets).cpu().sum() 183 | 184 | avg_test_acc = 100. * correct.item() / total.item() 185 | avg_loss = total_loss / n 186 | 187 | return avg_test_acc, avg_loss 188 | 189 | 190 | if __name__ == "__main__": 191 | parser = argparse.ArgumentParser() 192 | parser.add_argument('--training_fname', type=Path, help='training .tar file') 193 | parser.add_argument('--testing_fname', type=Path, help='testing .tar file') 194 | parser.add_argument('--model', default='voxnet', help='Model name: [default:voxnet]') 195 | parser.add_argument('--log_dir', default='log', help='Log dir [default: log]') 196 | parser.add_argument('--num_classes', type=int, default=40, help='Category Number [10/30/40] [default: 40]') 197 | parser.add_argument('--max_epoch', type=int, default=256, help='Epoch to run [default: 256]') 198 | parser.add_argument('--batch_size', type=int, default=4, help='Batch Size during training [default: 4]') 199 | parser.add_argument('--learning_rate', type=float, default=0.001, help='Initial learning rate [default: 0.001]') 200 | parser.add_argument('--momentum', type=float, default=0.9, help='Initial learning rate [default: 0.9]') 201 | parser.add_argument('--optimizer', default='adam', help='adam or momentum [default: adam]') 202 | parser.add_argument('--decay_step', type=int, default=16, help='Decay step for lr decay [default: 16]') 203 | parser.add_argument('--decay_rate', type=float, default=0.7, help='Decay rate for lr decay [default: 0.8]') 204 | parser.add_argument('--saved_fname', type=Path, default=None, help='name of weight to be saved') 205 | parser.add_argument('--cont', action='store_true', default=False) 206 | parser.add_argument('--ckpt_dir', default='log', help='check point dir [default: log]') 207 | parser.add_argument('--ckpt_fname', default='model', help='check point name [default: model]') 208 | args = parser.parse_args() 209 | 210 | cudnn.benchmark = True 211 | main(args) 212 | -------------------------------------------------------------------------------- /voxnet/finetune/10_train.sh: -------------------------------------------------------------------------------- 1 | CUDA_VISIBLE_DEVICES=3 \ 2 | python train.py \ 3 | --training_fname shapenet10_test.tar \ 4 | --testing_fname shapenet10_train.tar \ 5 | --model feature \ 6 | --log_dir log_10 \ 7 | --num_classes 10 \ 8 | --max_epoch 32 \ 9 | --batch_size 8 \ 10 | --learning_rate 0.001 \ 11 | --momentum 0.9 \ 12 | --optimizer adam \ 13 | --decay_step 4 \ 14 | --decay_rate 0.8 \ 15 | --saved_fname weight10 \ 16 | --cont \ 17 | --ckpt_dir ../baseline/log_30/ \ 18 | --ckpt_fname weight30 19 | -------------------------------------------------------------------------------- /voxnet/finetune/few_train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.backends.cudnn as cudnn 4 | from torch.utils.data import DataLoader 5 | from torch.autograd import Variable 6 | import torchvision.transforms as transforms 7 | 8 | from sklearn.svm import SVC 9 | 10 | import imp 11 | import logging 12 | from path import Path 13 | import numpy as np 14 | import time 15 | import os 16 | import sys 17 | import importlib 18 | import argparse 19 | 20 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 21 | ROOT_DIR = os.path.dirname(os.path.dirname(BASE_DIR)) 22 | sys.path.append(ROOT_DIR) 23 | from datasets.modelnet import ModelNet 24 | from datasets.fewmodelnet import fewModelNet 25 | 26 | def main(args): 27 | # load network 28 | print("loading module") 29 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 30 | module = importlib.import_module("models."+args.model) 31 | model = module.VoxNet(num_classes=args.num_classes, input_shape=(32,32,32)) 32 | model.to(device) 33 | 34 | # backup files 35 | if not os.path.exists(args.log_dir): 36 | os.mkdir(args.log_dir) 37 | os.system('cp {} {}'.format(os.path.join(ROOT_DIR, 'models', args.model+'.py'), args.log_dir)) 38 | os.system('cp {} {}'.format(__file__, args.log_dir)) 39 | #logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s| %(message)s') 40 | #logging.info('logs will be saved to {}'.format(args.log_fname)) 41 | #logger = Logger(args.log_fname, reinitialize=True) 42 | print("loading dataset") 43 | dset_train = fewModelNet(os.path.join(ROOT_DIR, "data"), args.training_fname) 44 | dset_test = ModelNet(os.path.join(ROOT_DIR, "data"), args.testing_fname) 45 | print(len(dset_train)) 46 | print(len(dset_test)) 47 | 48 | train_loader = DataLoader(dset_train, batch_size=args.batch_size, shuffle=True, num_workers=4) 49 | test_loader = DataLoader(dset_test, batch_size=args.batch_size, num_workers=4) 50 | 51 | global LOG_FOUT 52 | LOG_FOUT = open(os.path.join(args.log_dir, 'log.txt'), 'w') 53 | log_string(args) 54 | 55 | start_epoch = 0 56 | best_acc = 0. 57 | if args.cont: 58 | start_epoch, best_acc = load_checkpoint(args, model) 59 | 60 | start_epoch = 0 61 | best_acc = 0. 62 | 63 | print("set optimizer") 64 | # set optimization methods 65 | criterion = nn.CrossEntropyLoss() 66 | optimizer = torch.optim.Adam(model.parameters(), lr=args.learning_rate) 67 | scheduler = torch.optim.lr_scheduler.StepLR(optimizer, args.decay_step, args.decay_rate) 68 | 69 | for epoch in range(start_epoch, args.max_epoch): 70 | scheduler.step() 71 | log_string('\n-----------------------------------') 72 | log_string('Epoch: [%d/%d]' % (epoch+1, args.max_epoch)) 73 | start = time.time() 74 | 75 | model.train() 76 | train(train_loader, model, criterion, optimizer, device) 77 | log_string('Time taken: %.2f sec.' % (time.time() - start)) 78 | 79 | model.eval() 80 | avg_test_acc, avg_loss = test(test_loader, model, criterion, optimizer, device) 81 | 82 | log_string('\nEvaluation:') 83 | log_string('\tVal Acc: %.2f - Loss: %.4f' % (avg_test_acc, avg_loss)) 84 | log_string('\tCurrent best val acc: %.2f' % best_acc) 85 | 86 | # Log epoch to tensorboard 87 | # See log using: tensorboard --logdir='logs' --port=6006 88 | #util.logEpoch(logger, resnet, epoch + 1, avg_loss, avg_test_acc) 89 | 90 | # Save model 91 | if avg_test_acc > best_acc: 92 | log_string('\tSaving checkpoint - Acc: %.2f' % avg_test_acc) 93 | best_acc = avg_test_acc 94 | best_loss = avg_loss 95 | torch.save({ 96 | 'epoch': epoch + 1, 97 | #'state_dict': resnet.state_dict(), 98 | 'body': model.body.state_dict(), 99 | 'feat': model.head.state_dict(), 100 | 'acc': avg_test_acc, 101 | 'best_acc': best_acc, 102 | 'optimizer': optimizer.state_dict() 103 | }, os.path.join(args.log_dir, args.saved_fname+".pth.tar")) 104 | 105 | with open("log_best_acc.txt") as f: 106 | f.write("{}\n".format(best_acc)) 107 | 108 | with open("log_last_acc.txt") as f: 109 | f.write("{}\n".format(avg_test_acc)) 110 | 111 | LOG_FOUT.close() 112 | return 113 | 114 | 115 | def log_string(out_str): 116 | LOG_FOUT.write(str(out_str)+'\n') 117 | LOG_FOUT.flush() 118 | print(out_str) 119 | 120 | 121 | def load_checkpoint(args, model): 122 | # Load checkpoint. 123 | print('\n==> Loading checkpoint..') 124 | fname = os.path.join(args.ckpt_dir, args.ckpt_fname + '.pth.tar') 125 | assert os.path.isfile(fname), 'Error: no checkpoint file found!' 126 | 127 | checkpoint = torch.load(fname) 128 | best_acc = checkpoint['best_acc'] 129 | start_epoch = checkpoint['epoch'] 130 | model.body.load_state_dict(checkpoint['body']) 131 | # not loading all the weight for head 132 | new_head_dict = model.head.state_dict() 133 | 134 | original_head_dict = checkpoint['feat'] 135 | for k in original_head_dict: 136 | if k in new_head_dict: 137 | print("same weight:", k) 138 | else: 139 | print("discarded weight:", k) 140 | 141 | original_head_dict = {k: v for k, v in original_head_dict.items() if k in new_head_dict} 142 | new_head_dict.update(original_head_dict) 143 | model.head.load_state_dict(new_head_dict) 144 | 145 | return start_epoch, best_acc 146 | 147 | 148 | def train(loader, model, criterion, optimizer, device): 149 | num_batch = len(loader) 150 | batch_size = loader.batch_size 151 | total = torch.LongTensor([0]) 152 | correct = torch.LongTensor([0]) 153 | total_loss = 0. 154 | 155 | for i, (inputs, targets) in enumerate(loader): 156 | #inputs = torch.from_numpy(inputs) 157 | inputs, targets = inputs.to(device), targets.to(device) 158 | # in 0.4.0 variable and tensor are merged 159 | #inputs, targets = Variable(inputs), Variable(targets) 160 | 161 | # compute output 162 | outputs = model(inputs) 163 | loss = criterion(outputs, targets) 164 | 165 | total_loss += loss.item() 166 | _, predicted = torch.max(outputs.detach(), 1) 167 | total += batch_size 168 | correct += (predicted == targets).cpu().sum() 169 | 170 | # compute gradient and do SGD step 171 | optimizer.zero_grad() 172 | loss.backward() 173 | optimizer.step() 174 | 175 | log_iter = 1000 176 | if (i + 1) % log_iter == 0: 177 | log_string("\tIter [%d/%d] Loss: %.4f" % (i + 1, num_batch, total_loss/log_iter)) 178 | total_loss = 0. 179 | 180 | log_string("Train Accuracy %.2f" % (100.0 * correct.item() / total.item())) 181 | return 182 | 183 | 184 | def test(loader, model, criterion, optimizer, device): 185 | # Eval 186 | total = torch.LongTensor([0]) 187 | correct = torch.LongTensor([0]) 188 | 189 | total_loss = 0.0 190 | n = 0 191 | 192 | for i, (inputs, targets) in enumerate(loader): 193 | with torch.no_grad(): 194 | # Convert from list of 3D to 4D 195 | #inputs = torch.from_numpy(inputs) 196 | 197 | inputs, targets = inputs.to(device), targets.to(device) 198 | 199 | # compute output 200 | outputs = model(inputs) 201 | loss = criterion(outputs, targets) 202 | 203 | total_loss += loss.item() 204 | n += 1 205 | 206 | _, predicted = torch.max(outputs.detach(), 1) 207 | total += targets.size(0) 208 | correct += (predicted == targets).cpu().sum() 209 | 210 | avg_test_acc = 100. * correct.item() / total.item() 211 | avg_loss = total_loss / n 212 | 213 | return avg_test_acc, avg_loss 214 | 215 | 216 | if __name__ == "__main__": 217 | parser = argparse.ArgumentParser() 218 | parser.add_argument('--training_fname', type=Path, help='training .tar file') 219 | parser.add_argument('--testing_fname', type=Path, help='testing .tar file') 220 | parser.add_argument('--model', default='voxnet', help='Model name: [default:voxnet]') 221 | parser.add_argument('--log_dir', default='log', help='Log dir [default: log]') 222 | parser.add_argument('--num_classes', type=int, default=40, help='Category Number [10/30/40] [default: 40]') 223 | parser.add_argument('--max_epoch', type=int, default=256, help='Epoch to run [default: 256]') 224 | parser.add_argument('--batch_size', type=int, default=4, help='Batch Size during training [default: 4]') 225 | parser.add_argument('--learning_rate', type=float, default=0.001, help='Initial learning rate [default: 0.001]') 226 | parser.add_argument('--momentum', type=float, default=0.9, help='Initial learning rate [default: 0.9]') 227 | parser.add_argument('--optimizer', default='adam', help='adam or momentum [default: adam]') 228 | parser.add_argument('--decay_step', type=int, default=16, help='Decay step for lr decay [default: 16]') 229 | parser.add_argument('--decay_rate', type=float, default=0.7, help='Decay rate for lr decay [default: 0.8]') 230 | parser.add_argument('--saved_fname', type=Path, default=None, help='name of weight to be saved') 231 | parser.add_argument('--cont', action='store_true', default=False) 232 | parser.add_argument('--ckpt_dir', default='log', help='check point dir [default: log]') 233 | parser.add_argument('--ckpt_fname', default='model', help='check point name [default: model]') 234 | args = parser.parse_args() 235 | 236 | cudnn.benchmark = True 237 | main(args) 238 | -------------------------------------------------------------------------------- /voxnet/finetune/few_train.sh: -------------------------------------------------------------------------------- 1 | CUDA_VISIBLE_DEVICES=2 2 | for i in `seq 1 10` 3 | do 4 | python few_train.py \ 5 | --training_fname shapenet10_test.tar \ 6 | --testing_fname shapenet10_train.tar \ 7 | --model feature \ 8 | --log_dir log_few/log_$i \ 9 | --num_classes 10 \ 10 | --max_epoch 32 \ 11 | --batch_size 8 \ 12 | --learning_rate 0.001 \ 13 | --momentum 0.9 \ 14 | --optimizer adam \ 15 | --decay_step 4 \ 16 | --decay_rate 0.8 \ 17 | --saved_fname weight10 \ 18 | --cont \ 19 | --ckpt_dir ../baseline/log_30/ \ 20 | --ckpt_fname weight30 21 | done 22 | -------------------------------------------------------------------------------- /voxnet/finetune/train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.backends.cudnn as cudnn 4 | from torch.utils.data import DataLoader 5 | from torch.autograd import Variable 6 | import torchvision.transforms as transforms 7 | 8 | from sklearn.svm import SVC 9 | 10 | import imp 11 | import logging 12 | from path import Path 13 | import numpy as np 14 | import time 15 | import os 16 | import sys 17 | import importlib 18 | import argparse 19 | 20 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 21 | ROOT_DIR = os.path.dirname(os.path.dirname(BASE_DIR)) 22 | sys.path.append(ROOT_DIR) 23 | from datasets.modelnet import ModelNet 24 | 25 | def main(args): 26 | # load network 27 | print("loading module") 28 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 29 | module = importlib.import_module("models."+args.model) 30 | model = module.VoxNet(num_classes=args.num_classes, input_shape=(32,32,32)) 31 | model.to(device) 32 | 33 | # backup files 34 | if not os.path.exists(args.log_dir): 35 | os.mkdir(args.log_dir) 36 | os.system('cp {} {}'.format(os.path.join(ROOT_DIR, 'models', args.model+'.py'), args.log_dir)) 37 | os.system('cp {} {}'.format(__file__, args.log_dir)) 38 | #logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s| %(message)s') 39 | #logging.info('logs will be saved to {}'.format(args.log_fname)) 40 | #logger = Logger(args.log_fname, reinitialize=True) 41 | print("loading dataset") 42 | dset_train = ModelNet(os.path.join(ROOT_DIR, "data"), args.training_fname) 43 | dset_test = ModelNet(os.path.join(ROOT_DIR, "data"), args.testing_fname) 44 | 45 | train_loader = DataLoader(dset_train, batch_size=args.batch_size, shuffle=True, num_workers=4) 46 | test_loader = DataLoader(dset_test, batch_size=args.batch_size, num_workers=4) 47 | 48 | global LOG_FOUT 49 | LOG_FOUT = open(os.path.join(args.log_dir, 'log.txt'), 'w') 50 | log_string(args) 51 | 52 | start_epoch = 0 53 | best_acc = 0. 54 | if args.cont: 55 | start_epoch, best_acc = load_checkpoint(args, model) 56 | start_epoch = 0 57 | best_acc = 0. 58 | 59 | print("set optimizer") 60 | # set optimization methods 61 | criterion = nn.CrossEntropyLoss() 62 | optimizer = torch.optim.Adam(model.parameters(), lr=args.learning_rate) 63 | scheduler = torch.optim.lr_scheduler.StepLR(optimizer, args.decay_step, args.decay_rate) 64 | 65 | for epoch in range(start_epoch, args.max_epoch): 66 | scheduler.step() 67 | log_string('\n-----------------------------------') 68 | log_string('Epoch: [%d/%d]' % (epoch+1, args.max_epoch)) 69 | start = time.time() 70 | 71 | model.train() 72 | train(train_loader, model, criterion, optimizer, device) 73 | log_string('Time taken: %.2f sec.' % (time.time() - start)) 74 | 75 | model.eval() 76 | avg_test_acc, avg_loss = test(test_loader, model, criterion, optimizer, device) 77 | 78 | log_string('\nEvaluation:') 79 | log_string('\tVal Acc: %.2f - Loss: %.4f' % (avg_test_acc, avg_loss)) 80 | log_string('\tCurrent best val acc: %.2f' % best_acc) 81 | 82 | # Log epoch to tensorboard 83 | # See log using: tensorboard --logdir='logs' --port=6006 84 | #util.logEpoch(logger, resnet, epoch + 1, avg_loss, avg_test_acc) 85 | 86 | # Save model 87 | if avg_test_acc > best_acc: 88 | log_string('\tSaving checkpoint - Acc: %.2f' % avg_test_acc) 89 | best_acc = avg_test_acc 90 | best_loss = avg_loss 91 | torch.save({ 92 | 'epoch': epoch + 1, 93 | #'state_dict': resnet.state_dict(), 94 | 'body': model.body.state_dict(), 95 | 'feat': model.head.state_dict(), 96 | 'acc': avg_test_acc, 97 | 'best_acc': best_acc, 98 | 'optimizer': optimizer.state_dict() 99 | }, os.path.join(args.log_dir, args.saved_fname+".pth.tar")) 100 | 101 | LOG_FOUT.close() 102 | return 103 | 104 | 105 | def log_string(out_str): 106 | LOG_FOUT.write(str(out_str)+'\n') 107 | LOG_FOUT.flush() 108 | print(out_str) 109 | 110 | 111 | def load_checkpoint(args, model): 112 | # Load checkpoint. 113 | print('\n==> Loading checkpoint..') 114 | fname = os.path.join(args.ckpt_dir, args.ckpt_fname + '.pth.tar') 115 | assert os.path.isfile(fname), 'Error: no checkpoint file found!' 116 | 117 | checkpoint = torch.load(fname) 118 | best_acc = checkpoint['best_acc'] 119 | start_epoch = checkpoint['epoch'] 120 | model.body.load_state_dict(checkpoint['body']) 121 | # not loading all the weight for head 122 | new_head_dict = model.head.state_dict() 123 | 124 | original_head_dict = checkpoint['feat'] 125 | for k in original_head_dict: 126 | if k in new_head_dict: 127 | print("same weight:", k) 128 | else: 129 | print("discarded weight:", k) 130 | 131 | original_head_dict = {k: v for k, v in original_head_dict.items() if k in new_head_dict} 132 | new_head_dict.update(original_head_dict) 133 | model.head.load_state_dict(new_head_dict) 134 | 135 | return start_epoch, best_acc 136 | 137 | 138 | def train(loader, model, criterion, optimizer, device): 139 | num_batch = len(loader) 140 | batch_size = loader.batch_size 141 | total = torch.LongTensor([0]) 142 | correct = torch.LongTensor([0]) 143 | total_loss = 0. 144 | 145 | for i, (inputs, targets) in enumerate(loader): 146 | #inputs = torch.from_numpy(inputs) 147 | inputs, targets = inputs.to(device), targets.to(device) 148 | # in 0.4.0 variable and tensor are merged 149 | #inputs, targets = Variable(inputs), Variable(targets) 150 | 151 | # compute output 152 | outputs = model(inputs) 153 | loss = criterion(outputs, targets) 154 | 155 | total_loss += loss.item() 156 | _, predicted = torch.max(outputs.detach(), 1) 157 | total += batch_size 158 | correct += (predicted == targets).cpu().sum() 159 | 160 | # compute gradient and do SGD step 161 | optimizer.zero_grad() 162 | loss.backward() 163 | optimizer.step() 164 | 165 | log_iter = 1000 166 | if (i + 1) % log_iter == 0: 167 | log_string("\tIter [%d/%d] Loss: %.4f" % (i + 1, num_batch, total_loss/log_iter)) 168 | total_loss = 0. 169 | 170 | log_string("Train Accuracy %.2f" % (100.0 * correct.item() / total.item())) 171 | return 172 | 173 | 174 | def test(loader, model, criterion, optimizer, device): 175 | # Eval 176 | total = torch.LongTensor([0]) 177 | correct = torch.LongTensor([0]) 178 | 179 | total_loss = 0.0 180 | n = 0 181 | 182 | for i, (inputs, targets) in enumerate(loader): 183 | with torch.no_grad(): 184 | # Convert from list of 3D to 4D 185 | #inputs = torch.from_numpy(inputs) 186 | 187 | inputs, targets = inputs.to(device), targets.to(device) 188 | 189 | # compute output 190 | outputs = model(inputs) 191 | loss = criterion(outputs, targets) 192 | 193 | total_loss += loss.item() 194 | n += 1 195 | 196 | _, predicted = torch.max(outputs.detach(), 1) 197 | total += targets.size(0) 198 | correct += (predicted == targets).cpu().sum() 199 | 200 | avg_test_acc = 100. * correct.item() / total.item() 201 | avg_loss = total_loss / n 202 | 203 | return avg_test_acc, avg_loss 204 | 205 | 206 | if __name__ == "__main__": 207 | parser = argparse.ArgumentParser() 208 | parser.add_argument('--training_fname', type=Path, help='training .tar file') 209 | parser.add_argument('--testing_fname', type=Path, help='testing .tar file') 210 | parser.add_argument('--model', default='voxnet', help='Model name: [default:voxnet]') 211 | parser.add_argument('--log_dir', default='log', help='Log dir [default: log]') 212 | parser.add_argument('--num_classes', type=int, default=40, help='Category Number [10/30/40] [default: 40]') 213 | parser.add_argument('--max_epoch', type=int, default=256, help='Epoch to run [default: 256]') 214 | parser.add_argument('--batch_size', type=int, default=4, help='Batch Size during training [default: 4]') 215 | parser.add_argument('--learning_rate', type=float, default=0.001, help='Initial learning rate [default: 0.001]') 216 | parser.add_argument('--momentum', type=float, default=0.9, help='Initial learning rate [default: 0.9]') 217 | parser.add_argument('--optimizer', default='adam', help='adam or momentum [default: adam]') 218 | parser.add_argument('--decay_step', type=int, default=16, help='Decay step for lr decay [default: 16]') 219 | parser.add_argument('--decay_rate', type=float, default=0.7, help='Decay rate for lr decay [default: 0.8]') 220 | parser.add_argument('--saved_fname', type=Path, default=None, help='name of weight to be saved') 221 | parser.add_argument('--cont', action='store_true', default=False) 222 | parser.add_argument('--ckpt_dir', default='log', help='check point dir [default: log]') 223 | parser.add_argument('--ckpt_fname', default='model', help='check point name [default: model]') 224 | args = parser.parse_args() 225 | 226 | cudnn.benchmark = True 227 | main(args) 228 | -------------------------------------------------------------------------------- /voxnet/readval.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | parser = argparse.ArgumentParser() 4 | parser.add_argument("rfname") 5 | parser.add_argument("wfname") 6 | args = parser.parse_args() 7 | 8 | rfname = args.rfname 9 | wfname = args.wfname 10 | 11 | val_acc = [] 12 | with open(rfname, "r") as f: 13 | for line in f: 14 | if "Val" in line: 15 | val_acc.append(float(line.split()[2])) 16 | 17 | print(val_acc) 18 | with open(wfname, "w") as f: 19 | for i, acc in enumerate(val_acc): 20 | f.write("{} {}\n".format(i, acc)) 21 | 22 | -------------------------------------------------------------------------------- /voxnet/readval_few.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import argparse 3 | 4 | parser = argparse.ArgumentParser() 5 | parser.add_argument("dir") 6 | parser.add_argument("wfname") 7 | 8 | args = parser.parse_args() 9 | 10 | all_acc = [] 11 | for i in range(1,11): 12 | each_acc = [] 13 | with open(args.dir+"{}/log.txt".format(i), 'r') as f: 14 | for line in f: 15 | if "Val" in line: 16 | each_acc.append(float(line.split()[2])) 17 | all_acc.append(each_acc) 18 | 19 | all_acc = np.array(all_acc) 20 | avg_acc = np.mean(all_acc, axis=0) 21 | print(avg_acc) 22 | 23 | with open(args.wfname,"w") as f: 24 | for i, acc in enumerate(avg_acc): 25 | f.write("{} {}\n".format(i, acc)) 26 | 27 | 28 | -------------------------------------------------------------------------------- /voxnet/svm/10_train.sh: -------------------------------------------------------------------------------- 1 | CUDA_VISIBLE_DEVICES=2 \ 2 | python train.py \ 3 | --training_fname shapenet10_test.tar \ 4 | --testing_fname shapenet10_train.tar \ 5 | --model feature \ 6 | --log_dir log_10 \ 7 | --num_classes 10 \ 8 | --max_epoch 32 \ 9 | --batch_size 1 \ 10 | --learning_rate 0.001 \ 11 | --momentum 0.9 \ 12 | --optimizer adam \ 13 | --decay_step 4 \ 14 | --decay_rate 0.8 \ 15 | --saved_fname weight10 \ 16 | --cont \ 17 | --ckpt_dir ../baseline/log_30/ \ 18 | --ckpt_fname weight30 19 | -------------------------------------------------------------------------------- /voxnet/svm/few_train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.backends.cudnn as cudnn 4 | from torch.utils.data import DataLoader 5 | from torch.autograd import Variable 6 | import torchvision.transforms as transforms 7 | 8 | from sklearn.svm import SVC 9 | 10 | import imp 11 | import logging 12 | from path import Path 13 | import numpy as np 14 | import time 15 | import os 16 | import sys 17 | import importlib 18 | import argparse 19 | 20 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 21 | ROOT_DIR = os.path.dirname(os.path.dirname(BASE_DIR)) 22 | sys.path.append(ROOT_DIR) 23 | from datasets.modelnet import ModelNet 24 | from datasets.fewmodelnet import fewModelNet 25 | 26 | def main(args): 27 | # load network 28 | print("loading module") 29 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 30 | module = importlib.import_module("models."+args.model) 31 | model = module.VoxNet(num_classes=args.num_classes, input_shape=(32,32,32)) 32 | model.to(device) 33 | 34 | # backup files 35 | if not os.path.exists(args.log_dir): 36 | os.mkdir(args.log_dir) 37 | os.system('cp {} {}'.format(os.path.join(ROOT_DIR, 'models', args.model+'.py'), args.log_dir)) 38 | os.system('cp {} {}'.format(__file__, args.log_dir)) 39 | #logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s| %(message)s') 40 | #logging.info('logs will be saved to {}'.format(args.log_fname)) 41 | #logger = Logger(args.log_fname, reinitialize=True) 42 | print("loading dataset") 43 | dset_train = fewModelNet(os.path.join(ROOT_DIR, "data"), args.training_fname) 44 | dset_test = ModelNet(os.path.join(ROOT_DIR, "data"), args.testing_fname) 45 | 46 | # set shuffle to false since the label is not shuffle 47 | # drop_last = False so every instance will be loaded 48 | # batch_size = 1 49 | print(args.batch_size) 50 | train_loader = DataLoader(dset_train, batch_size=args.batch_size, num_workers=4, drop_last=False) 51 | test_loader = DataLoader(dset_test, batch_size=args.batch_size, num_workers=4, drop_last=False) 52 | 53 | global LOG_FOUT 54 | LOG_FOUT = open(os.path.join(args.log_dir, 'log.txt'), 'w') 55 | log_string(args) 56 | 57 | start_epoch = 0 58 | best_acc = 0. 59 | if args.cont: 60 | start_epoch, best_acc = load_checkpoint(args, model) 61 | 62 | train_feature = np.zeros((len(dset_train), 128)) 63 | train_label = np.zeros((len(dset_train),), dtype=np.int) 64 | test_feature = np.zeros((len(dset_test), 128)) 65 | test_label = np.zeros((len(dset_test),), dtype=np.int) 66 | 67 | model.eval() 68 | # make sure batch size = 1 69 | with torch.no_grad(): 70 | for i, (inputs, targets) in enumerate(train_loader): 71 | inputs, targets = inputs.to(device), targets.to(device) 72 | # compute output 73 | outputs = model(inputs) 74 | train_feature[i] = outputs 75 | train_label[i] = targets 76 | 77 | for i, (inputs, targets) in enumerate(test_loader): 78 | inputs, targets = inputs.to(device), targets.to(device) 79 | # compute output 80 | outputs = model(inputs) 81 | test_feature[i] = outputs 82 | test_label[i] = targets 83 | 84 | 85 | #print(train_feature[-1]) 86 | #print(train_label[-1]) 87 | #print(test_feature[-1]) 88 | #print(test_label[-1]) 89 | 90 | np.save(os.path.join(args.log_dir,"train_feature"), train_feature) 91 | np.save(os.path.join(args.log_dir,"train_label"), train_label) 92 | np.save(os.path.join(args.log_dir,"test_feature"), test_feature) 93 | np.save(os.path.join(args.log_dir,"test_label"), test_label) 94 | 95 | svm = SVC(kernel='linear') 96 | svm.fit(train_feature, train_label) 97 | train_pred = svm.predict(train_feature) 98 | test_pred = svm.predict(test_feature) 99 | train_acc = np.sum(train_pred == train_label) * 1.0 / train_feature.shape[0] 100 | test_acc = np.sum(test_pred == test_label) * 1.0 / test_feature.shape[0] 101 | log_string(str(train_acc)) 102 | log_string(str(test_acc)) 103 | 104 | with open("log_acc.txt", "a") as f: 105 | f.write("{}\n".format(test_acc)) 106 | 107 | #print("set optimizer") 108 | # set optimization methods 109 | #criterion = nn.CrossEntropyLoss() 110 | #optimizer = torch.optim.Adam(model.parameters(), lr=args.learning_rate) 111 | #scheduler = torch.optim.lr_scheduler.StepLR(optimizer, args.decay_step, args.decay_rate) 112 | 113 | #for epoch in range(start_epoch, args.max_epoch): 114 | # scheduler.step() 115 | # log_string('\n-----------------------------------') 116 | # log_string('Epoch: [%d/%d]' % (epoch+1, args.max_epoch)) 117 | # start = time.time() 118 | 119 | # model.train() 120 | # train(train_loader, model, criterion, optimizer, device) 121 | # log_string('Time taken: %.2f sec.' % (time.time() - start)) 122 | 123 | # model.eval() 124 | # avg_test_acc, avg_loss = test(test_loader, model, criterion, optimizer, device) 125 | 126 | # log_string('\nEvaluation:') 127 | # log_string('\tVal Acc: %.2f - Loss: %.4f' % (avg_test_acc, avg_loss)) 128 | # log_string('\tCurrent best val acc: %.2f' % best_acc) 129 | 130 | # # Log epoch to tensorboard 131 | # # See log using: tensorboard --logdir='logs' --port=6006 132 | # #util.logEpoch(logger, resnet, epoch + 1, avg_loss, avg_test_acc) 133 | 134 | # # Save model 135 | # if avg_test_acc > best_acc: 136 | # log_string('\tSaving checkpoint - Acc: %.2f' % avg_test_acc) 137 | # best_acc = avg_test_acc 138 | # best_loss = avg_loss 139 | # torch.save({ 140 | # 'epoch': epoch + 1, 141 | # #'state_dict': resnet.state_dict(), 142 | # 'body': model.body.state_dict(), 143 | # 'feat': model.head.state_dict(), 144 | # 'acc': avg_test_acc, 145 | # 'best_acc': best_acc, 146 | # 'optimizer': optimizer.state_dict() 147 | # }, os.path.join(args.log_dir, args.saved_fname+".pth.tar")) 148 | 149 | LOG_FOUT.close() 150 | return 151 | 152 | 153 | def log_string(out_str): 154 | LOG_FOUT.write(str(out_str)+'\n') 155 | LOG_FOUT.flush() 156 | print(out_str) 157 | 158 | 159 | def load_checkpoint(args, model): 160 | # Load checkpoint. 161 | print('\n==> Loading checkpoint..') 162 | fname = os.path.join(args.ckpt_dir, args.ckpt_fname + '.pth.tar') 163 | assert os.path.isfile(fname), 'Error: no checkpoint file found!' 164 | 165 | checkpoint = torch.load(fname) 166 | best_acc = checkpoint['best_acc'] 167 | start_epoch = checkpoint['epoch'] 168 | model.body.load_state_dict(checkpoint['body']) 169 | # not loading all the weight for head 170 | new_head_dict = model.head.state_dict() 171 | 172 | original_head_dict = checkpoint['feat'] 173 | for k in original_head_dict: 174 | if k in new_head_dict: 175 | print("same weight:", k) 176 | else: 177 | print("discarded weight:", k) 178 | 179 | original_head_dict = {k: v for k, v in original_head_dict.items() if k in new_head_dict} 180 | new_head_dict.update(original_head_dict) 181 | model.head.load_state_dict(new_head_dict) 182 | 183 | return start_epoch, best_acc 184 | 185 | 186 | def train(loader, model, criterion, optimizer, device): 187 | num_batch = len(loader) 188 | batch_size = loader.batch_size 189 | total = torch.LongTensor([0]) 190 | correct = torch.LongTensor([0]) 191 | total_loss = 0. 192 | 193 | for i, (inputs, targets) in enumerate(loader): 194 | #inputs = torch.from_numpy(inputs) 195 | inputs, targets = inputs.to(device), targets.to(device) 196 | # in 0.4.0 variable and tensor are merged 197 | #inputs, targets = Variable(inputs), Variable(targets) 198 | 199 | # compute output 200 | outputs = model(inputs) 201 | loss = criterion(outputs, targets) 202 | 203 | total_loss += loss.item() 204 | _, predicted = torch.max(outputs.detach(), 1) 205 | total += batch_size 206 | correct += (predicted == targets).cpu().sum() 207 | 208 | # compute gradient and do SGD step 209 | optimizer.zero_grad() 210 | loss.backward() 211 | optimizer.step() 212 | 213 | log_iter = 1000 214 | if (i + 1) % log_iter == 0: 215 | log_string("\tIter [%d/%d] Loss: %.4f" % (i + 1, num_batch, total_loss/log_iter)) 216 | total_loss = 0. 217 | 218 | log_string("Train Accuracy %.2f" % (100.0 * correct.item() / total.item())) 219 | return 220 | 221 | 222 | def test(loader, model, criterion, optimizer, device): 223 | # Eval 224 | total = torch.LongTensor([0]) 225 | correct = torch.LongTensor([0]) 226 | 227 | total_loss = 0.0 228 | n = 0 229 | 230 | for i, (inputs, targets) in enumerate(loader): 231 | with torch.no_grad(): 232 | # Convert from list of 3D to 4D 233 | #inputs = torch.from_numpy(inputs) 234 | 235 | inputs, targets = inputs.to(device), targets.to(device) 236 | 237 | # compute output 238 | outputs = model(inputs) 239 | loss = criterion(outputs, targets) 240 | 241 | total_loss += loss.item() 242 | n += 1 243 | 244 | _, predicted = torch.max(outputs.detach(), 1) 245 | total += targets.size(0) 246 | correct += (predicted == targets).cpu().sum() 247 | 248 | avg_test_acc = 100. * correct.item() / total.item() 249 | avg_loss = total_loss / n 250 | 251 | return avg_test_acc, avg_loss 252 | 253 | 254 | if __name__ == "__main__": 255 | parser = argparse.ArgumentParser() 256 | parser.add_argument('--training_fname', type=Path, help='training .tar file') 257 | parser.add_argument('--testing_fname', type=Path, help='testing .tar file') 258 | parser.add_argument('--model', default='voxnet', help='Model name: [default:voxnet]') 259 | parser.add_argument('--log_dir', default='log', help='Log dir [default: log]') 260 | parser.add_argument('--num_classes', type=int, default=40, help='Category Number [10/30/40] [default: 40]') 261 | parser.add_argument('--max_epoch', type=int, default=256, help='Epoch to run [default: 256]') 262 | parser.add_argument('--batch_size', type=int, default=4, help='Batch Size during training [default: 4]') 263 | parser.add_argument('--learning_rate', type=float, default=0.001, help='Initial learning rate [default: 0.001]') 264 | parser.add_argument('--momentum', type=float, default=0.9, help='Initial learning rate [default: 0.9]') 265 | parser.add_argument('--optimizer', default='adam', help='adam or momentum [default: adam]') 266 | parser.add_argument('--decay_step', type=int, default=16, help='Decay step for lr decay [default: 16]') 267 | parser.add_argument('--decay_rate', type=float, default=0.7, help='Decay rate for lr decay [default: 0.8]') 268 | parser.add_argument('--saved_fname', type=Path, default=None, help='name of weight to be saved') 269 | parser.add_argument('--cont', action='store_true', default=False) 270 | parser.add_argument('--ckpt_dir', default='log', help='check point dir [default: log]') 271 | parser.add_argument('--ckpt_fname', default='model', help='check point name [default: model]') 272 | args = parser.parse_args() 273 | 274 | cudnn.benchmark = True 275 | main(args) 276 | -------------------------------------------------------------------------------- /voxnet/svm/few_train.sh: -------------------------------------------------------------------------------- 1 | CUDA_VISIBLE_DEVICES=1 2 | for i in `seq 1 10` 3 | do 4 | python few_train.py \ 5 | --training_fname shapenet10_test.tar \ 6 | --testing_fname shapenet10_train.tar \ 7 | --model feature \ 8 | --log_dir log_few/log_$i \ 9 | --num_classes 10 \ 10 | --max_epoch 32 \ 11 | --batch_size 1 \ 12 | --learning_rate 0.001 \ 13 | --momentum 0.9 \ 14 | --optimizer adam \ 15 | --decay_step 4 \ 16 | --decay_rate 0.8 \ 17 | --saved_fname weight10 \ 18 | --cont \ 19 | --ckpt_dir ../baseline/log_30/ \ 20 | --ckpt_fname weight30 21 | done 22 | -------------------------------------------------------------------------------- /voxnet/svm/log_acc.txt: -------------------------------------------------------------------------------- 1 | 0.753762848752 2 | 0.718979441997 3 | 0.714115271659 4 | 0.734581497797 5 | 0.719805433186 6 | 0.799008810573 7 | 0.749541116006 8 | 0.778542584435 9 | 0.739720998532 10 | 0.730359765051 11 | -------------------------------------------------------------------------------- /voxnet/svm/mean_std.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | acc = [] 4 | with open("./log_acc.txt", 'r') as f: 5 | for line in f: 6 | a = float(line.strip('\n')) 7 | print a 8 | acc.append(a) 9 | 10 | acc = np.array(acc) 11 | print "-------" 12 | print np.mean(acc) 13 | print np.var(acc) 14 | print np.std(acc) 15 | -------------------------------------------------------------------------------- /voxnet/svm/train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.backends.cudnn as cudnn 4 | from torch.utils.data import DataLoader 5 | from torch.autograd import Variable 6 | import torchvision.transforms as transforms 7 | 8 | from sklearn.svm import SVC 9 | 10 | import imp 11 | import logging 12 | from path import Path 13 | import numpy as np 14 | import time 15 | import os 16 | import sys 17 | import importlib 18 | import argparse 19 | 20 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 21 | ROOT_DIR = os.path.dirname(os.path.dirname(BASE_DIR)) 22 | sys.path.append(ROOT_DIR) 23 | from datasets.modelnet import ModelNet 24 | 25 | def main(args): 26 | # load network 27 | print("loading module") 28 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 29 | module = importlib.import_module("models."+args.model) 30 | model = module.VoxNet(num_classes=args.num_classes, input_shape=(32,32,32)) 31 | model.to(device) 32 | 33 | # backup files 34 | if not os.path.exists(args.log_dir): 35 | os.mkdir(args.log_dir) 36 | os.system('cp {} {}'.format(os.path.join(ROOT_DIR, 'models', args.model+'.py'), args.log_dir)) 37 | os.system('cp {} {}'.format(__file__, args.log_dir)) 38 | #logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s| %(message)s') 39 | #logging.info('logs will be saved to {}'.format(args.log_fname)) 40 | #logger = Logger(args.log_fname, reinitialize=True) 41 | print("loading dataset") 42 | dset_train = ModelNet(os.path.join(ROOT_DIR, "data"), args.training_fname) 43 | dset_test = ModelNet(os.path.join(ROOT_DIR, "data"), args.testing_fname) 44 | print(len(dset_train)) 45 | print(len(dset_test)) 46 | 47 | # set shuffle to false since the label is not shuffle 48 | # drop_last = False so every instance will be loaded 49 | # batch_size = 1 50 | print(args.batch_size) 51 | train_loader = DataLoader(dset_train, batch_size=args.batch_size, num_workers=4, drop_last=False) 52 | test_loader = DataLoader(dset_test, batch_size=args.batch_size, num_workers=4, drop_last=False) 53 | 54 | global LOG_FOUT 55 | LOG_FOUT = open(os.path.join(args.log_dir, 'log.txt'), 'w') 56 | log_string(args) 57 | 58 | start_epoch = 0 59 | best_acc = 0. 60 | if args.cont: 61 | start_epoch, best_acc = load_checkpoint(args, model) 62 | 63 | train_feature = np.zeros((len(dset_train), 128)) 64 | train_label = np.zeros((len(dset_train),), dtype=np.int) 65 | test_feature = np.zeros((len(dset_test), 128)) 66 | test_label = np.zeros((len(dset_test),), dtype=np.int) 67 | 68 | model.eval() 69 | # make sure batch size = 1 70 | with torch.no_grad(): 71 | for i, (inputs, targets) in enumerate(train_loader): 72 | inputs, targets = inputs.to(device), targets.to(device) 73 | # compute output 74 | outputs = model(inputs) 75 | train_feature[i] = outputs 76 | train_label[i] = targets 77 | 78 | for i, (inputs, targets) in enumerate(test_loader): 79 | inputs, targets = inputs.to(device), targets.to(device) 80 | # compute output 81 | outputs = model(inputs) 82 | test_feature[i] = outputs 83 | test_label[i] = targets 84 | 85 | 86 | print(train_feature[-1]) 87 | print(train_label[-1]) 88 | print(test_feature[-1]) 89 | print(test_label[-1]) 90 | 91 | np.save(os.path.join(args.log_dir,"train_feature"), train_feature) 92 | np.save(os.path.join(args.log_dir,"train_label"), train_label) 93 | np.save(os.path.join(args.log_dir,"test_feature"), test_feature) 94 | np.save(os.path.join(args.log_dir,"test_label"), test_label) 95 | 96 | svm = SVC(kernel='linear') 97 | svm.fit(train_feature, train_label) 98 | train_pred = svm.predict(train_feature) 99 | test_pred = svm.predict(test_feature) 100 | print(str(np.sum(train_pred == train_label) * 1.0 / train_feature.shape[0])) 101 | print(str(np.sum(test_pred == test_label) * 1.0 / test_feature.shape[0])) 102 | #print("set optimizer") 103 | # set optimization methods 104 | #criterion = nn.CrossEntropyLoss() 105 | #optimizer = torch.optim.Adam(model.parameters(), lr=args.learning_rate) 106 | #scheduler = torch.optim.lr_scheduler.StepLR(optimizer, args.decay_step, args.decay_rate) 107 | 108 | #for epoch in range(start_epoch, args.max_epoch): 109 | # scheduler.step() 110 | # log_string('\n-----------------------------------') 111 | # log_string('Epoch: [%d/%d]' % (epoch+1, args.max_epoch)) 112 | # start = time.time() 113 | 114 | # model.train() 115 | # train(train_loader, model, criterion, optimizer, device) 116 | # log_string('Time taken: %.2f sec.' % (time.time() - start)) 117 | 118 | # model.eval() 119 | # avg_test_acc, avg_loss = test(test_loader, model, criterion, optimizer, device) 120 | 121 | # log_string('\nEvaluation:') 122 | # log_string('\tVal Acc: %.2f - Loss: %.4f' % (avg_test_acc, avg_loss)) 123 | # log_string('\tCurrent best val acc: %.2f' % best_acc) 124 | 125 | # # Log epoch to tensorboard 126 | # # See log using: tensorboard --logdir='logs' --port=6006 127 | # #util.logEpoch(logger, resnet, epoch + 1, avg_loss, avg_test_acc) 128 | 129 | # # Save model 130 | # if avg_test_acc > best_acc: 131 | # log_string('\tSaving checkpoint - Acc: %.2f' % avg_test_acc) 132 | # best_acc = avg_test_acc 133 | # best_loss = avg_loss 134 | # torch.save({ 135 | # 'epoch': epoch + 1, 136 | # #'state_dict': resnet.state_dict(), 137 | # 'body': model.body.state_dict(), 138 | # 'feat': model.head.state_dict(), 139 | # 'acc': avg_test_acc, 140 | # 'best_acc': best_acc, 141 | # 'optimizer': optimizer.state_dict() 142 | # }, os.path.join(args.log_dir, args.saved_fname+".pth.tar")) 143 | 144 | LOG_FOUT.close() 145 | return 146 | 147 | 148 | def log_string(out_str): 149 | LOG_FOUT.write(str(out_str)+'\n') 150 | LOG_FOUT.flush() 151 | print(out_str) 152 | 153 | 154 | def load_checkpoint(args, model): 155 | # Load checkpoint. 156 | print('\n==> Loading checkpoint..') 157 | fname = os.path.join(args.ckpt_dir, args.ckpt_fname + '.pth.tar') 158 | assert os.path.isfile(fname), 'Error: no checkpoint file found!' 159 | 160 | checkpoint = torch.load(fname) 161 | best_acc = checkpoint['best_acc'] 162 | start_epoch = checkpoint['epoch'] 163 | model.body.load_state_dict(checkpoint['body']) 164 | # not loading all the weight for head 165 | new_head_dict = model.head.state_dict() 166 | 167 | original_head_dict = checkpoint['feat'] 168 | for k in original_head_dict: 169 | if k in new_head_dict: 170 | print("same weight:", k) 171 | else: 172 | print("discarded weight:", k) 173 | 174 | original_head_dict = {k: v for k, v in original_head_dict.items() if k in new_head_dict} 175 | new_head_dict.update(original_head_dict) 176 | model.head.load_state_dict(new_head_dict) 177 | 178 | return start_epoch, best_acc 179 | 180 | 181 | def train(loader, model, criterion, optimizer, device): 182 | num_batch = len(loader) 183 | batch_size = loader.batch_size 184 | total = torch.LongTensor([0]) 185 | correct = torch.LongTensor([0]) 186 | total_loss = 0. 187 | 188 | for i, (inputs, targets) in enumerate(loader): 189 | #inputs = torch.from_numpy(inputs) 190 | inputs, targets = inputs.to(device), targets.to(device) 191 | # in 0.4.0 variable and tensor are merged 192 | #inputs, targets = Variable(inputs), Variable(targets) 193 | 194 | # compute output 195 | outputs = model(inputs) 196 | loss = criterion(outputs, targets) 197 | 198 | total_loss += loss.item() 199 | _, predicted = torch.max(outputs.detach(), 1) 200 | total += batch_size 201 | correct += (predicted == targets).cpu().sum() 202 | 203 | # compute gradient and do SGD step 204 | optimizer.zero_grad() 205 | loss.backward() 206 | optimizer.step() 207 | 208 | log_iter = 1000 209 | if (i + 1) % log_iter == 0: 210 | log_string("\tIter [%d/%d] Loss: %.4f" % (i + 1, num_batch, total_loss/log_iter)) 211 | total_loss = 0. 212 | 213 | log_string("Train Accuracy %.2f" % (100.0 * correct.item() / total.item())) 214 | return 215 | 216 | 217 | def test(loader, model, criterion, optimizer, device): 218 | # Eval 219 | total = torch.LongTensor([0]) 220 | correct = torch.LongTensor([0]) 221 | 222 | total_loss = 0.0 223 | n = 0 224 | 225 | for i, (inputs, targets) in enumerate(loader): 226 | with torch.no_grad(): 227 | # Convert from list of 3D to 4D 228 | #inputs = torch.from_numpy(inputs) 229 | 230 | inputs, targets = inputs.to(device), targets.to(device) 231 | 232 | # compute output 233 | outputs = model(inputs) 234 | loss = criterion(outputs, targets) 235 | 236 | total_loss += loss.item() 237 | n += 1 238 | 239 | _, predicted = torch.max(outputs.detach(), 1) 240 | total += targets.size(0) 241 | correct += (predicted == targets).cpu().sum() 242 | 243 | avg_test_acc = 100. * correct.item() / total.item() 244 | avg_loss = total_loss / n 245 | 246 | return avg_test_acc, avg_loss 247 | 248 | 249 | if __name__ == "__main__": 250 | parser = argparse.ArgumentParser() 251 | parser.add_argument('--training_fname', type=Path, help='training .tar file') 252 | parser.add_argument('--testing_fname', type=Path, help='testing .tar file') 253 | parser.add_argument('--model', default='voxnet', help='Model name: [default:voxnet]') 254 | parser.add_argument('--log_dir', default='log', help='Log dir [default: log]') 255 | parser.add_argument('--num_classes', type=int, default=40, help='Category Number [10/30/40] [default: 40]') 256 | parser.add_argument('--max_epoch', type=int, default=256, help='Epoch to run [default: 256]') 257 | parser.add_argument('--batch_size', type=int, default=4, help='Batch Size during training [default: 4]') 258 | parser.add_argument('--learning_rate', type=float, default=0.001, help='Initial learning rate [default: 0.001]') 259 | parser.add_argument('--momentum', type=float, default=0.9, help='Initial learning rate [default: 0.9]') 260 | parser.add_argument('--optimizer', default='adam', help='adam or momentum [default: adam]') 261 | parser.add_argument('--decay_step', type=int, default=16, help='Decay step for lr decay [default: 16]') 262 | parser.add_argument('--decay_rate', type=float, default=0.7, help='Decay rate for lr decay [default: 0.8]') 263 | parser.add_argument('--saved_fname', type=Path, default=None, help='name of weight to be saved') 264 | parser.add_argument('--cont', action='store_true', default=False) 265 | parser.add_argument('--ckpt_dir', default='log', help='check point dir [default: log]') 266 | parser.add_argument('--ckpt_fname', default='model', help='check point name [default: model]') 267 | args = parser.parse_args() 268 | 269 | cudnn.benchmark = True 270 | main(args) 271 | -------------------------------------------------------------------------------- /voxnet/val_acc/baseline_fewm10.txt: -------------------------------------------------------------------------------- 1 | 0 61.564 2 | 1 65.713 3 | 2 66.083 4 | 3 68.6 5 | 4 68.378 6 | 5 68.918 7 | 6 69.515 8 | 7 69.68 9 | 8 70.24 10 | 9 69.744 11 | 10 69.911 12 | 11 69.227 13 | 12 69.004 14 | 13 70.295 15 | 14 70.247 16 | 15 69.844 17 | 16 70.445 18 | 17 69.83 19 | 18 70.011 20 | 19 70.331 21 | 20 69.836 22 | 21 70.745 23 | 22 70.454 24 | 23 70.052 25 | 24 70.829 26 | 25 70.873 27 | 26 70.658 28 | 27 70.822 29 | 28 71.055 30 | 29 70.647 31 | 30 70.583 32 | 31 70.509 33 | -------------------------------------------------------------------------------- /voxnet/val_acc/baseline_m10.txt: -------------------------------------------------------------------------------- 1 | 0 85.65 2 | 1 87.69 3 | 2 87.25 4 | 3 86.93 5 | 4 89.09 6 | 5 88.69 7 | 6 89.56 8 | 7 89.04 9 | 8 88.05 10 | 9 88.41 11 | 10 88.56 12 | 11 88.2 13 | 12 87.37 14 | 13 89.65 15 | 14 87.46 16 | 15 88.02 17 | 16 87.66 18 | 17 85.59 19 | 18 87.18 20 | 19 86.91 21 | 20 89.07 22 | 21 87.78 23 | 22 88.84 24 | 23 89.02 25 | 24 88.58 26 | 25 88.4 27 | 26 89.77 28 | 27 87.33 29 | 28 88.21 30 | 29 88.27 31 | 30 88.0 32 | 31 88.34 33 | -------------------------------------------------------------------------------- /voxnet/val_acc/baseline_m30.txt: -------------------------------------------------------------------------------- 1 | 0 85.06 2 | 1 86.03 3 | 2 84.5 4 | 3 86.04 5 | 4 86.06 6 | 5 85.52 7 | 6 86.69 8 | 7 84.83 9 | 8 85.93 10 | 9 84.45 11 | 10 83.16 12 | 11 85.58 13 | 12 85.51 14 | 13 86.55 15 | 14 86.16 16 | 15 84.89 17 | 16 83.93 18 | 17 84.46 19 | 18 85.12 20 | 19 83.84 21 | 20 83.23 22 | 21 84.85 23 | 22 84.53 24 | 23 84.91 25 | 24 83.38 26 | 25 86.3 27 | 26 86.65 28 | 27 83.32 29 | 28 85.52 30 | 29 85.22 31 | 30 82.71 32 | 31 83.87 33 | --------------------------------------------------------------------------------