unbiased teacher for semi-supervised object detection 配环境复现
配pytorch环境
-
搭建名为ubteachers的虚拟环境
conda create -n ubteachers python=3.7
-
激活虚拟环境
source activate ubteachers
-
安装符合要求的pytorch(按照自己的cuda版本进行选择,在可选的torch版本中找到可以匹配detectron的torch版本)
按照下图选择torch版本:detectron官网
conda install pytorch==1.9.0 torchvision==0.10.0 torchaudio==0.9.0 cudatoolkit=10.2 -c pytorch
安装detectron2
-
首先安装一些支持包。因为我的服务器网络时好时坏,故而有些包只能下载到本地、上传服务器进行安装,如果你的服务器可以联网,可以使用其他安装方式。需要安装的包有opencv,fvcore,Cython,pycocotools。
pip install opencv-python
conda install -c fvcore fvcore 或 pip install fvcore
pip install -U Cython
先下载pycocotools在本地,然后cd到cocoapi-master/PythonAPI下
python setup.py build
python setup.py install
如果出现报错
No module named 'pycocotools._mask'
,可参考https://blog.csdn.net/hesongzefairy/article/details/105343439,执行make命令。 -
再来安装detectron2。先从官网把detectron2下载到本地,不用进入子文件夹:
python -m pip install -e detectron2
到此为止,detectron和环境搭建基本完成。
在输入上面detectron2命令的时候,我出现了报错 could not find a version that satisfies the requirement timm
解决方法:安装timmpip install timm
跑代码
-
下载官方代码和数据集coco2017,我的文件目录为
-
输入命令:
我只有一块GPU,故而num-gups 1
python train_net.py \ --num-gpus 8 \ --config configs/coco_supervision/faster_rcnn_R_50_FPN_sup1_run1.yaml \ SOLVER.IMG_PER_BATCH_LABEL 16 SOLVER.IMG_PER_BATCH_UNLABEL 16
-
出现报错及解决方案
报错一:module 'distutuils' has no attribute 'version'
解决方法,
pip uninstall setuptools
pip install setuptools==59.5.0
报错二:descriptors cannot not be created directly
解决方法:pip install protobuf==3.19.0
报错三(常见):cannot import name 'FastRCNNOutputs'
参考链接ImportError: cannot import name ‘FastRCNNOutputs’ #44
-
将FastRCNNOutputs这个class复制到ubteacher/modeling/roi_heads/fast_rcnn.py
class FastRCNNOutputs: """ An internal implementation that stores information about outputs of a Fast R-CNN head, and provides methods that are used to decode the outputs of a Fast R-CNN head. """ def __init__( self, box2box_transform, pred_class_logits, pred_proposal_deltas, proposals, smooth_l1_beta=0.0, box_reg_loss_type="smooth_l1", ): """ Args: box2box_transform (Box2BoxTransform/Box2BoxTransformRotated): box2box transform instance for proposal-to-detection transformations. pred_class_logits (Tensor): A tensor of shape (R, K + 1) storing the predicted class logits for all R predicted object instances. Each row corresponds to a predicted object instance. pred_proposal_deltas (Tensor): A tensor of shape (R, K * B) or (R, B) for class-specific or class-agnostic regression. It stores the predicted deltas that transform proposals into final box detections. B is the box dimension (4 or 5). When B is 4, each row is [dx, dy, dw, dh (, ....)]. When B is 5, each row is [dx, dy, dw, dh, da (, ....)]. proposals (list[Instances]): A list of N Instances, where Instances i stores the proposals for image i, in the field "proposal_boxes". When training, each Instances must have ground-truth labels stored in the field "gt_classes" and "gt_boxes". The total number of all instances must be equal to R. smooth_l1_beta (float): The transition point between L1 and L2 loss in the smooth L1 loss function. When set to 0, the loss becomes L1. When set to +inf, the loss becomes constant 0. box_reg_loss_type (str): Box regression loss type. One of: "smooth_l1", "giou" """ self.box2box_transform = box2box_transform self.num_preds_per_image = [len(p) for p in proposals] self.pred_class_logits = pred_class_logits self.pred_proposal_deltas = pred_proposal_deltas self.smooth_l1_beta = smooth_l1_beta self.box_reg_loss_type = box_reg_loss_type self.image_shapes = [x.image_size for x in proposals] if len(proposals): box_type = type(proposals[0].proposal_boxes) # cat(..., dim=0) concatenates over all images in the batch self.proposals = box_type.cat([p.proposal_boxes for p in proposals]) assert ( not self.proposals.tensor.requires_grad ), "Proposals should not require gradients!" # "gt_classes" exists if and only if training. But other gt fields may # not necessarily exist in training for images that have no groundtruth. if proposals[0].has("gt_classes"): self.gt_classes = cat([p.gt_classes for p in proposals], dim=0) # If "gt_boxes" does not exist, the proposals must be all negative and # should not be included in regression loss computation. # Here we just use proposal_boxes as an arbitrary placeholder because its # value won't be used in self.box_reg_loss(). gt_boxes = [ p.gt_boxes if p.has("gt_boxes") else p.proposal_boxes for p in proposals ] self.gt_boxes = box_type.cat(gt_boxes) else: self.proposals = Boxes(torch.zeros(0, 4, device=self.pred_proposal_deltas.device)) self._no_instances = len(self.proposals) == 0 # no instances found def softmax_cross_entropy_loss(self): """ Deprecated """ _log_classification_stats(self.pred_class_logits, self.gt_classes) return cross_entropy(self.pred_class_logits, self.gt_classes, reduction="mean") def box_reg_loss(self): """ Deprecated """ if self._no_instances: return 0.0 * self.pred_proposal_deltas.sum() box_dim = self.proposals.tensor.size(1) # 4 or 5 cls_agnostic_bbox_reg = self.pred_proposal_deltas.size(1) == box_dim device = self.pred_proposal_deltas.device bg_class_ind = self.pred_class_logits.shape[1] - 1 # Box delta loss is only computed between the prediction for the gt class k # (if 0 <= k < bg_class_ind) and the target; there is no loss defined on predictions # for non-gt classes and background. # Empty fg_inds should produce a valid loss of zero because reduction=sum. fg_inds = nonzero_tuple((self.gt_classes >= 0) & (self.gt_classes < bg_class_ind))[0] if cls_agnostic_bbox_reg: # pred_proposal_deltas only corresponds to foreground class for agnostic gt_class_cols = torch.arange(box_dim, device=device) else: # pred_proposal_deltas for class k are located in columns [b * k : b * k + b], # where b is the dimension of box representation (4 or 5) # Note that compared to Detectron1, # we do not perform bounding box regression for background classes. gt_class_cols = box_dim * self.gt_classes[fg_inds, None] + torch.arange( box_dim, device=device ) if self.box_reg_loss_type == "smooth_l1": gt_proposal_deltas = self.box2box_transform.get_deltas( self.proposals.tensor, self.gt_boxes.tensor ) loss_box_reg = smooth_l1_loss( self.pred_proposal_deltas[fg_inds[:, None], gt_class_cols], gt_proposal_deltas[fg_inds], self.smooth_l1_beta, reduction="sum", ) elif self.box_reg_loss_type == "giou": fg_pred_boxes = self.box2box_transform.apply_deltas( self.pred_proposal_deltas[fg_inds[:, None], gt_class_cols], self.proposals.tensor[fg_inds], ) loss_box_reg = giou_loss( fg_pred_boxes, self.gt_boxes.tensor[fg_inds], reduction="sum", ) else: raise ValueError(f"Invalid bbox reg loss type '{self.box_reg_loss_type}'") loss_box_reg = loss_box_reg / self.gt_classes.numel() return loss_box_reg def losses(self): """ Deprecated """ return {"loss_cls": self.softmax_cross_entropy_loss(), "loss_box_reg": self.box_reg_loss()} def predict_boxes(self): """ Deprecated """ pred = self.box2box_transform.apply_deltas(self.pred_proposal_deltas, self.proposals.tensor) return pred.split(self.num_preds_per_image, dim=0) def predict_probs(self): """ Deprecated """ probs = F.softmax(self.pred_class_logits, dim=-1) return probs.split(self.num_preds_per_image, dim=0)
-
在这个py文件里添加
from detectron2.layers import ShapeSpec, batched_nms, cat, cross_entropy, nonzero_tuple from fvcore.nn import giou_loss, smooth_l1_loss from detectron2.modeling.box_regression import Box2BoxTransform from detectron2.structures import Boxes
-
注释掉py文件里的这里
至此,程序可以跑通。希望该文章对您所有帮助!