我有一些用 LabelMe 标记的图像数据集,它生成的 xml 文件包含每个文件中存在的各种对象的边界框信息(Pascal voc 格式)。
我已经提取了边界框信息并为所有图像中存在的所有对象生成了一个 csv 文件。 csv 文件中的每一行都包含类似这种格式的信息(filename, x_min, y_min, x_max, y_max, class)。
然后,我实施了一些增强技术并调整了增加 csv 文件大小的边界框信息。该文件分为 80% 的训练数据和 20% 的验证数据。属于 train 或 test 的每个图像文件都移动到相应的文件夹(train/val)。
现在,我正在努力实现更快的 rcnn,其中平均精度指标将与损失函数一起计算,其他性能指标将有所帮助但不是强制性的。我检查了许多 github 存储库,但它们似乎都令人困惑。
我已经实现并运行(google colab)以下代码,该代码仅给出损失结果而不是平均精度(mAP)、准确度。如何计算 mAP 和准确度?
DIR_INPUT = '../'
DIR_TRAIN = DIR_INPUT + 'Model Dataset/train/'
DIR_TEST = DIR_INPUT + 'Model Dataset/test/'
if not os.path.exists(DIR_TRAIN):
os.makedirs(DIR_TRAIN)
if not os.path.exists(DIR_TEST):
os.makedirs(DIR_TEST)
annotation_file = pd.read_csv(DIR_INPUT+'data files/annotation_all_with_augmented.csv')
all_image = DIR_INPUT+"/topics_in_wind_engineering_final/All images/"
split = int(len(os.listdir(all_image)) * .8)
count = 1
for i in os.listdir(all_image):
if count < split:
if not os.path.exists(DIR_TRAIN+i):
shutil.copy(all_image+i, DIR_TRAIN)
else:
if not os.path.exists(DIR_TEST+i):
shutil.copy(all_image+i, DIR_TEST)
count = count + 1
train_df = pd.DataFrame(columns = annotation_file.columns)
valid_df = pd.DataFrame(columns = annotation_file.columns)
for f_name in os.listdir(DIR_TRAIN):
r = annotation_file.loc[annotation_file['image_id'] == f_name]
train_df = train_df.append(r)
for f_name in os.listdir(DIR_TEST):
r = annotation_file.loc[annotation_file['image_id'] == f_name]
valid_df = valid_df.append(r)
train_df['image_id'] = "E:/Wind_Engineering/Model Dataset/train/" + train_df['image_id']
train_df.to_csv('../../frcnn-from-scratch-with-keras-master/dataset.txt', index=False, header = False)
class AerialDataset(Dataset):
def __init__(self, dataframe, image_dir, transforms=None):
super().__init__()
self.image_ids = dataframe['image_id'].unique()
self.df = dataframe
self.image_dir = image_dir
self.transforms = transforms
def __getitem__(self, index: int):
image_id = self.image_ids[index]
records = self.df[self.df['image_id'] == image_id]
image = cv2.imread(f'{self.image_dir}/{image_id}', cv2.IMREAD_COLOR)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)
image /= 255.0
boxes = records[['xmin', 'ymin', 'xmax', 'ymax']].values
area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])
area = torch.as_tensor(area, dtype=torch.float32)
# there is only one class
labels = torch.ones((records.shape[0],), dtype=torch.int64)
# suppose all instances are not crowd
iscrowd = torch.zeros((records.shape[0],), dtype=torch.int64)
target = {}
target['boxes'] = boxes
target['labels'] = labels
target['image_id'] = torch.tensor([index])
target['area'] = area
target['iscrowd'] = iscrowd
if self.transforms:
sample = {
'image': image,
'bboxes': target['boxes'],
'labels': labels
}
sample = self.transforms(**sample)
image = sample['image']
target['boxes'] = torch.stack(tuple(map(torch.tensor, zip(*sample['bboxes'])))).permute(1, 0)
return image, target, image_id
def __len__(self) -> int:
return self.image_ids.shape[0]
def get_train_transform():
return A.Compose([
ToTensorV2(p=1.0)
], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})
def get_valid_transform():
return A.Compose([
ToTensorV2(p=1.0)
], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
num_classes = 2 # 1 class (wheat) + background
# get number of input features for the classifier
in_features = model.roi_heads.box_predictor.cls_score.in_features
# replace the pre-trained head with a new one
model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)
class Averager:
def __init__(self):
self.current_total = 0.0
self.iterations = 0.0
def send(self, value):
self.current_total += value
self.iterations += 1
@property
def value(self):
if self.iterations == 0:
return 0
else:
return 1.0 * self.current_total / self.iterations
def reset(self):
self.current_total = 0.0
self.iterations = 0.0
def collate_fn(batch):
return tuple(zip(*batch))
train_dataset = AerialDataset(train_df, DIR_TRAIN, get_train_transform())
valid_dataset = AerialDataset(valid_df, DIR_TEST, get_valid_transform())
# split the dataset in train and test set
indices = torch.randperm(len(train_dataset)).tolist()
train_data_loader = DataLoader(
train_dataset,
batch_size=16,
shuffle=False,
num_workers=4,
collate_fn=collate_fn
)
valid_data_loader = DataLoader(
valid_dataset,
batch_size=16,
shuffle=False,
num_workers=4,
collate_fn=collate_fn
)
device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
images, targets, image_ids = next(iter(train_data_loader))
images = list(image.to(device) for image in images)
targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
boxes = targets[2]['boxes'].cpu().numpy().astype(np.int32)
sample = images[2].permute(1,2,0).cpu().numpy()
model.to(device)
params = [p for p in model.parameters() if p.requires_grad]
optimizer = torch.optim.SGD(params, lr=0.005, momentum=0.9, weight_decay=0.0005)
# lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=3, gamma=0.1)
lr_scheduler = None
num_epochs = 5
loss_hist = Averager()
itr = 1
loss_track = []
epoch_loss = []
for epoch in range(num_epochs):
loss_hist.reset()
for images, targets, image_ids in train_data_loader:
images = list(image.to(device) for image in images)
targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
loss_dict = model(images, targets)
losses = sum(loss for loss in loss_dict.values())
loss_value = losses.item()
loss_hist.send(loss_value)
optimizer.zero_grad()
losses.backward()
optimizer.step()
loss_track.append(loss_value)
if itr % 50 == 0:
print(f"Iteration #{itr} loss: {loss_value}")
itr += 1
# update the learning rate
if lr_scheduler is not None:
lr_scheduler.step()
print(f"Epoch #{epoch} loss: {loss_hist.value}")
epoch_loss.append(loss_hist.value)
images, targets, image_ids = next(iter(valid_data_loader))
images = list(img.to(device) for img in images)
targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
boxes = targets[1]['boxes'].cpu().numpy().astype(np.int32)
sample = images[1].permute(1,2,0).cpu().numpy()
model.eval()
cpu_device = torch.device("cpu")
outputs = model(images)
outputs = [{k: v.to(cpu_device) for k, v in t.items()} for t in outputs]