The code mainly refers to bubbliiing’s Github YOLOv3 code: github.com/bubbliiiing…

Interpretation of source code

Training section

Yolo_training. Py files

class YOLOLoss(nn.Module) :
    # initialize section,
    # parameter anchors = [[10,16],[16,30],..  num_class:voc 20
    # input_shape = [416,416],cuda: indicates whether to use the GPU
    def __init__(self, anchors, num_classes, input_shape, cuda, anchors_mask = [[6.7.8], [3.4.5], [0.1.2]]) :
        super(YOLOLoss, self).__init__()
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        The anchor corresponding to the feature layer of # 13x13 is [116,90],[156,198],[373,326]
        The anchor corresponding to the feature layer of # 26x26 is [30,61],[62,45],[59,119]
        The anchor corresponding to the feature layer of # 52x52 is [10,13],[16,30],[33,23]
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        16, 30 # [16th [10], [],..]
        self.anchors        = anchors
        # voc:20
        self.num_classes    = num_classes
        # (x,y,w,h,conf,20) = 25
        self.bbox_attrs     = 5 + num_classes
        # [416416]
        self.input_shape    = input_shape
        # Index subscript of the box
        self.anchors_mask   = anchors_mask

        # We use giou's calculation method, which is explained in detail below
        self.giou           = True
        # 
        self.balance        = [0.4.1.0.4]
        self.box_ratio      = 0.05
        self.obj_ratio      = 5 * (input_shape[0] * input_shape[1)/(416 ** 2)
        self.cls_ratio      = 1 * (num_classes / 80)
        
        # conf threshold used by the NMS to reduce the number of boxes
        self.ignore_threshold = 0.5
        # Whether to use GPU for computing
        self.cuda           = cuda
        
    def forward(self, l, input, targets=None) :
        # The calculation of loss is between the predicted value output from model and label. Since we have three layers, L represents the number of feature map. Take the feature map of 13 * 13 for example, input = [BS,13,13,75], and our target is the normalized coordinate of [[[, Class_num],[normalized coordinates, class_num]],[[normalized coordinates, class_num]],[[normalized coordinates, class_num],[[normalized coordinates, class_num]],... Batch_size Label information (multiple [normalized coordinates, list of category numbers])
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # l represents the number of valid feature layers currently entered
        # input shape is bs, 3*(5+num_classes), 13, 13
        # bs, 3*(5+num_classes), 26, 26
        # bs, 3*(5+num_classes), 52, 52
        # targets indicates the actual box.
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Get the number of images, height and width of the feature layer
        # 13 and 13
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        # batch_size 16
        bs      = input.size(0)
        
        # Width and height of the feature map (mainly to calculate the multiple of reduction and convert our real box into the feature map)
        # in_h 13
        # in_w 13
        in_h    = input.size(2)
        in_w    = input.size(3)
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Calculate the step size
        # How many pixels per feature point corresponds to the original image
        # If the feature layer is 13x13, one feature point corresponds to 32 pixels on the original image
        # If the feature layer is 26x26, one feature point corresponds to 16 pixels on the original image
        # If the feature layer is 52x52, one feature point corresponds to 8 pixels on the original image
        Stride_h = stride_w = 32, 16, 8
        # stride_h and stride_w are both 32.
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        Stride_h = STRIde_w = 32
        stride_h = self.input_shape[0] / in_h
        stride_w = self.input_shape[1] / in_w
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # The scaled_anchors size obtained at this time is relative to the feature layer
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        
        # We reduced all three boxes of our corresponding feature graph to equal scale of feature graph
        scaled_anchors  = [(a_w / stride_w, a_h / stride_h) for a_w, a_h in self.anchors]
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        The shape of the input is
        # bs, 3*(5+num_classes), 13, 13 => batch_size, 3, 13, 13, 5 + num_classes
        # batch_size, 3, 26, 26, 5 + num_classes
        # batch_size, 3, 52, 52, 5 + num_classes
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        # consolidate our input into [batch_size, 3,13,13,25]
        # self. Bbox_attrs box attributes (quad-coordinate + confidence + 20 classification)
        prediction = input.view(bs, len(self.anchors_mask[l]), self.bbox_attrs, in_h, in_w).permute(0.1.3.4.2).contiguous()
        
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Prior box center position adjustment parameters
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        The x,y offsets and w, H width and height adjustment parameters of the validation box are collated to obtain the actual box data (this is important to understand)
        # SigmoID calculation was performed for the predicted center offset x and y
        x = torch.sigmoid(prediction[..., 0])
        y = torch.sigmoid(prediction[..., 1])
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Prior frame width and height adjustment parameters
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        Adjust width and height
        w = prediction[..., 2]
        h = prediction[..., 3]
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Get confidence if there is an object
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        # confidence is there an object
        conf = torch.sigmoid(prediction[..., 4])
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Category confidence
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        Get vector information about the type of object
        pred_cls = torch.sigmoid(prediction[..., 5:)# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Get the predicted results the network should have
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        [16,3,13,13,4] note that this is where the last dimension is 4
        y_true, noobj_mask, box_loss_scale = self.get_target(l, targets, scaled_anchors, in_h, in_w)

        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
        # Decode the predicted results and judge the degree of coincidence between the predicted results and the real value
        # If the degree of overlap is too large, it will be ignored, because these feature points belong to the feature points with relatively accurate prediction
        # Not suitable as a negative sample
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        # call get_ignore to assume that there are no objects in the predicted 507 boxes that are smaller than the specified threshold, and update noobj_mask
        The width and height of the 4-dimensional position matrix of box[16,3,13,13,4] is also obtained
        # Used for subsequent loss calculation
        noobj_mask, pred_boxes = self.get_ignore(l, x, y, h, w, targets, scaled_anchors, in_h, in_w, noobj_mask)
        
        # With gpu enabled, all data will be stored on the GPU
        if self.cuda:
            y_true          = y_true.cuda()
            noobj_mask      = noobj_mask.cuda()
            box_loss_scale  = box_loss_scale.cuda()
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # box_loss_scale is the product of the width and height of the real box, which are between 0 and 1, so the product is also between 0 and 1.
        # 2- The product of width and height means that the larger the real box is, the smaller the specific gravity is, and the smaller box is more specific.
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        
        Give more weight to smaller targets, give less weight to larger targets, and pay more attention to smaller targets
        box_loss_scale = 2 - box_loss_scale
            
        loss        = 0
        Get the mask matrix of the real object
        obj_mask    = y_true[..., 4] = =1
        # Count how many objects there are. 0 means no objects
        n           = torch.sum(obj_mask)
        ifn ! =0:
            # If there are objects
            # Assuming that our giou is true, then we use the GIou method to calculate the position loss. If false, we use the MSE and BCE error to calculate the position loss. That's why we use two ways to build y_true
            if self.giou:
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                Calculate the GIOU of the predicted and real results
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
                giou        = self.box_giou(pred_boxes, y_true[..., :4])
                loss_loc    = torch.mean((1 - giou)[obj_mask])
            else:
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
                # To calculate the loss of center offset, BCELoss is better
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
                loss_x      = torch.mean(self.BCELoss(x[obj_mask], y_true[..., 0][obj_mask]) * box_loss_scale)
                loss_y      = torch.mean(self.BCELoss(y[obj_mask], y_true[..., 1][obj_mask]) * box_loss_scale)
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
                # Calculate the loss of the width and height adjustment
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
                loss_w      = torch.mean(self.MSELoss(w[obj_mask], y_true[..., 2][obj_mask]) * box_loss_scale)
                loss_h      = torch.mean(self.MSELoss(h[obj_mask], y_true[..., 3][obj_mask]) * box_loss_scale)
                loss_loc    = (loss_x + loss_y + loss_h + loss_w) * 0.1
            
            # When we calculate class loss, we directly use BCE to calculate
            loss_cls    = torch.mean(self.BCELoss(pred_cls[obj_mask], y_true[..., 5:][obj_mask]))
            # We give corresponding weights to box loss and class loss respectively to get the addition and loss
            loss        += loss_loc * self.box_ratio + loss_cls * self.cls_ratio
        
        # We are calculating the loss of confidence, still using BCE
        loss_conf   = torch.mean(self.BCELoss(conf, obj_mask.type_as(conf))[noobj_mask.bool() | obj_mask])
        Finally, multiply the confidence by the corresponding weight and add the previously calculated loss value to get the final loss
        loss        += loss_conf * self.balance[l] * self.obj_ratio
        # if n ! = 0:
        # print(loss_loc * self.box_ratio, loss_cls * self.cls_ratio, loss_conf * self.balance[l] * self.obj_ratio)
        # Return the loss at last
        return loss
Copy the code
  • Read the function referenced in detail

    • rightget_targetDetailed interpretation of
    def get_target(self, l, targets, anchors, in_h, in_w) :
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
        # Count how many images there are
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
        # batch_size = 16
        bs = len(targets)
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
        # Select which prior boxes do not contain objects
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
        # The purpose of this container is to record where there is no object (one of the three most important points in Loss)
        The size of the container is [batch_size,3,13,13] without gradient descent
        noobj_mask = torch.ones(bs, len(self.anchors_mask[l]), in_h, in_w, requires_grad=False)
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
        # Make the web more focused on small goals
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
        
        # The purpose of this container is to record the weight of the position of the object (one of the three most important points in Loss)
        [batch_size,3,13,13] does not need gradient descent. [batch_size,3,13,13
        box_loss_scale = torch.zeros(bs, len(self.anchors_mask[l]), in_h, in_w, requires_grad=False)
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
        # batch_size, 3, 13, 13, 5 + num_classes
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
        The purpose of this container is to record real data information (one of the three most important points in Loss).
        # y_true has the size [batch_size,3,13,13,25] and does not require gradient descent
        y_true = torch.zeros(bs, len(self.anchors_mask[l]), in_h, in_w, self.bbox_attrs, requires_grad=False)
    
        # We loop through each image
        for b in range(bs):
            # Suppose we have a picture, but there is no target in the picture
            if len(targets[b]) == 0:
                continue
    
            # targets is a list
            # targets[b] Tensor ([[0.8798, 0.1526, 0.1490, 0.2524, 8.0000],[0.6178, 0.0998, 0.1106, 0.1562, 14.0000],[0.7007, 0.3149, 0.3149, 0.4231, 11.0000]]) size is 3 * 5, data are center point x, Y, W, H,class_num respectively
            We are constructing a data container for calculation. Size is the same as the current target
            batch_target = torch.zeros_like(targets[b])
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
            # Calculate the center point of the positive sample on the feature layer
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
            Tensor ([[11.4375, 1.9844, 1.9375, 3.2812, 8.0000],[8.0312, 1.2969, 1.4375, 2.0312, 14.0000],[9.1094, 4.0937, 4.0938, 5.5000, 11.0000]])
            # Because we used x1,y1,x2,y2/416 to get the normalized coordinates, and then we used lower-right - upper-left to get the width and height, (lower-right + upper-left)/2 = the center coordinates
            The following part is the height restoration of the relative coordinates in the feature graph of 13 * 13, or the form of the center point x,y, W, H, class_num
            batch_target[:, [0.2]] = targets[b][:, [0.2]] * in_w
            batch_target[:, [1.3]] = targets[b][:, [1.3]] * in_h
            batch_target[:, 4] = targets[b][:, 4]
            batch_target = batch_target.cpu()
    
            # (gT_box, the heart of anchors_Shapes' calculations) The heart of this next place actually wants to see ours
            # The degree of coincidence between the real box and the 9 prior boxes, so there is no need for the real center point, we will carry out its center point
            So the first two dimensions are 0 when we construct the tensor down here
            
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
            # Convert the real box to a form
            # num_true_box, 4
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
            # We build a new data container according to how many real boxes there are in this picture, and splice the width and height into the last two dimensions of this container
            Example: 2 real boxes, tensor([[0.0000, 0.0000, 3.2812, 7.1875],[0.0000, 0.0000, 2.7500, 8.6875]])
            gt_box = torch.FloatTensor(torch.cat((torch.zeros((batch_target.size(0), 2)), batch_target[:, 2:4]), 1))
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
            # Convert the prior box to a form
            # 9, 4
            # 9 prior boxes, 4
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
            # We will perform the same operation on the 9 prior boxes as above
            # tensor([[0.0000, 0.0000, 0.3125, 0.4062],[0.0000, 0.0000, 0.5000, 0.9375],[0.0000, 0.0000, 1.0312, 0.7188], [0.0000, 0.0000, 0.9375, 1.9062], [0.0000, 0.0000, 1.9375, 1.4062], [0.0000, 0.0000, 1.8438, 3.7188], [0.0000, 0.0000, 3.6250, 2.8125],[0.0000, 0.0000, 4.8750, 6.1875],[0.0000, 0.0000, 11.6562, 10.1875]])
            anchor_shapes = torch.FloatTensor(torch.cat((torch.zeros((len(anchors), 2)), torch.FloatTensor(anchors)), 1))
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
            # Calculate intersection ratio
            # self.calculate_iou(gt_box, anchor_SHAPES) = [num_true_box, 9] Overlap of each real box and nine prior boxes
            # best_ns:
            # [Max_iou, the maximum coincidence degree of each real box, the serial number of the priori box with the most coincidence of each real box]
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
            # [maximum coincidence degree of each real frame max_iou, serial number of the most overlapping prior frame of each real frame] [7,7] indicates that our two real frames are the most consistent with our prior frame 7
            best_ns = torch.argmax(self.calculate_iou(gt_box, anchor_shapes), dim=-1)
    
            for t, best_n in enumerate(best_ns):
    
                # First of all, we will judge the feature layer. We will directly skip the non-feature layer, which shows that the prediction is wrong
                if best_n not in self.anchors_mask[l]:
                    continue
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                # Determine which prior box of the current feature point this prior box is
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
                # k = 1 < class 'list' > : [[6, 7, 8], [3, 4, 5], [0, 1, 2]] we know first to pick up the characteristics of the layer (June)
                # and then we get index which is 1
                k = self.anchors_mask[l].index(best_n)
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                Get which grid point the real box belongs to
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
                The object landed in the grid, we want the upper-left coordinates
                # I = 11, j = 6
                i = torch.floor(batch_target[t, 0]).long()
                j = torch.floor(batch_target[t, 1]).long()
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                # Fetch the type of real box
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
                # Extract the real category
                c = batch_target[t, 4].long()
    
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                # noobj_mask represents feature points without targets
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
                # this represents the matrix with no target. We have checked the real object in (11,6) above, so the corresponding position in our matrix with no target is set to 0
                noobj_mask[b, k, j, i] = 0
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                # tx and TY are the real values of the center adjustment parameters
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
                # self.giou = True 
                if not self.giou:
                    Construct y_true if giou's method is not applicable
                    # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                    # tx and TY are the real values of the center adjustment parameters
                    # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                    # Where we get the true value on the 13 * 13 feature graph, minus the coordinate of the upper left corner of the grid, which is actually the adjustment quantity
                    y_true[b, k, j, i, 0] = batch_target[t, 0] - i.float()
                    y_true[b, k, j, i, 1] = batch_target[t, 1] - j.float(a)# Similarly, we can obtain the w and H factors by reversing the previous formula to obtain the true width and height through w and H width and height factors
                    y_true[b, k, j, i, 2] = math.log(batch_target[t, 2] / anchors[best_n][0])
                    y_true[b, k, j, i, 3] = math.log(batch_target[t, 3] / anchors[best_n][1])
                    # There is an object in the confidence box, confidence is 1
                    y_true[b, k, j, i, 4] = 1
                    # Set the specified position (category) in the category tag to 1
                    y_true[b, k, j, i, c + 5] = 1
                else:
                    If we use giou's method, we construct y_true
                    # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                    # tx and TY are the real values of the center adjustment parameters
                    # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
                    # We put real numbers in real tensor that we've constructed
                    The data put in is the real width and height in the feature map
                    y_true[b, k, j, i, 0] = batch_target[t, 0]
                    y_true[b, k, j, i, 1] = batch_target[t, 1]
                    y_true[b, k, j, i, 2] = batch_target[t, 2]
                    y_true[b, k, j, i, 3] = batch_target[t, 3]
                    y_true[b, k, j, i, 4] = 1
                    y_true[b, k, j, i, c + 5] = 1
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                # Ratio used to obtain XYWh
                # Large target loss weight is small, small target loss weight is significant
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
                # We give our object's box a weight at the same position as y_true. The larger the width and height of the box, the greater the value calculated
                # But we use 2-box_loss_scale in the later calculation, that is, ~ large target loss weight is small, small target loss weight is significant
                box_loss_scale[b, k, j, i] = batch_target[t, 2] * batch_target[t, 3] / in_w / in_h
    
        # Finally, we construct y_true, the targetless matrix and the weight matrix for the specified box
        return y_true, noobj_mask, box_loss_scale
    Copy the code

    The data display of y_true, because we use GIou, the first four dimensions are the true width and height of the relative feature graph (13 * 13)

    • callcalculate_iouBreak down
    The only thing that needs to be noted is that the 4 dimensions are respectively the relative feature graph [non-normalized center point coordinates X, non-normalized center point coordinates Y, non-normalized width W, and non-normalized height H].
    def calculate_iou(self, _box_a, _box_b) :
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Calculate the upper left and lower right corner of the real box
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
    
        b1_x1, b1_x2 = _box_a[:, 0] - _box_a[:, 2] / 2, _box_a[:, 0] + _box_a[:, 2] / 2
        b1_y1, b1_y2 = _box_a[:, 1] - _box_a[:, 3] / 2, _box_a[:, 1] + _box_a[:, 3] / 2
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Calculate the upper left and lower right corner of the prediction box obtained by the prior box
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        b2_x1, b2_x2 = _box_b[:, 0] - _box_b[:, 2] / 2, _box_b[:, 0] + _box_b[:, 2] / 2
        b2_y1, b2_y2 = _box_b[:, 1] - _box_b[:, 3] / 2, _box_b[:, 1] + _box_b[:, 3] / 2
    
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Convert both the real box and the prediction box to the upper left corner and lower right corner
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        box_a = torch.zeros_like(_box_a)
        box_b = torch.zeros_like(_box_b)
        box_a[:, 0], box_a[:, 1], box_a[:, 2], box_a[:, 3] = b1_x1, b1_y1, b1_x2, b1_y2
        box_b[:, 0], box_b[:, 1], box_b[:, 2], box_b[:, 3] = b2_x1, b2_y1, b2_x2, b2_y2
    
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # A is the number of real boxes, B is the number of prior boxes
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        A = box_a.size(0)
        B = box_b.size(0)
    
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Calculate the area of the intersection
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2), box_b[:, 2:].unsqueeze(0).expand(A, B, 2))
        min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2), box_b[:, :2].unsqueeze(0).expand(A, B, 2))
        inter = torch.clamp((max_xy - min_xy), min=0)
        inter = inter[:, :, 0] * inter[:, :, 1]
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Calculate the respective areas of the prediction box and the real box
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        area_a = ((box_a[:, 2] - box_a[:, 0]) * (box_a[:, 3] - box_a[:, 1])).unsqueeze(1).expand_as(inter)  # [A,B]
        area_b = ((box_b[:, 2] - box_b[:, 0]) * (box_b[:, 3] - box_b[:, 1])).unsqueeze(0).expand_as(inter)  # [A,B]
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # for IOU
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        union = area_a + area_b - inter
        return inter / union  # [A,B]
    Copy the code
    • rightget_ignoredDetailed interpretation of
    # This method mainly ignores the predicted data
    def get_ignore(self, l, x, y, h, w, targets, scaled_anchors, in_h, in_w, noobj_mask) :
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
        # Count how many images there are
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
        # batch_size
        bs = len(targets)
    
        FloatTensor = torch.cuda.FloatTensor if x.is_cuda else torch.FloatTensor
        LongTensor = torch.cuda.LongTensor if x.is_cuda else torch.LongTensor
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
        Generate grid, prior box center, upper left corner of grid
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
        # This section is built in the same way as the predicted grid points, mainly to get the specified grid
        grid_x = torch.linspace(0, in_w - 1, in_w).repeat(in_h, 1).repeat(
            int(bs * len(self.anchors_mask[l])), 1.1).view(x.shape).type(FloatTensor)
        grid_y = torch.linspace(0, in_h - 1, in_h).repeat(in_w, 1).t().repeat(
            int(bs * len(self.anchors_mask[l])), 1.1).view(y.shape).type(FloatTensor)
    
        Generate the width and height of the prior box
        # we get the prior box to extract according to the ordinal number ([6,7,8])
        scaled_anchors_l = np.array(scaled_anchors)[self.anchors_mask[l]]
        # We've got a wide tensor of three boxes, and a high tensor of three boxes
        anchor_w = FloatTensor(scaled_anchors_l).index_select(1, LongTensor([0]))
        anchor_h = FloatTensor(scaled_anchors_l).index_select(1, LongTensor([1]))
    
        # we will expand to the size of [16,3(boxes),13,13]
        anchor_w = anchor_w.repeat(bs, 1).repeat(1.1, in_h * in_w).view(w.shape)
        anchor_h = anchor_h.repeat(bs, 1).repeat(1.1, in_h * in_w).view(h.shape)
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
        # Calculate the adjusted center and width of the prediction box
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
        # We get the adjusted coordinates, width and height
        pred_boxes_x = torch.unsqueeze(x + grid_x, -1)
        pred_boxes_y = torch.unsqueeze(y + grid_y, -1)
        pred_boxes_w = torch.unsqueeze(torch.exp(w) * anchor_w, -1)
        pred_boxes_h = torch.unsqueeze(torch.exp(h) * anchor_h, -1)
        [x,y,w,h] [16,3,13,13,4]
        pred_boxes = torch.cat([pred_boxes_x, pred_boxes_y, pred_boxes_w, pred_boxes_h], dim=-1)
        
        # Take out a single picture
        for b in range(bs):
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
            # Convert the prediction into a form
            # pred_boxes_for_ignore num_anchors, 4
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
            Batch_size traverses each image
            # in this part we get [507,4] which is for a picture we merge the boxes, and the last dimension is x,y,w,h
            pred_boxes_for_ignore = pred_boxes[b].view(-1.4)
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
            Calculate the real box and convert the real box to the size relative to the feature layer
            # gt_box num_true_box, 4
            # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
            # Assuming we have a box in our image
            if len(targets[b]) > 0:
                # We made one
                batch_target = torch.zeros_like(targets[b])
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                # Calculate the center point of the positive sample on the feature layer
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
                We can get the center point, width and height, and class_num
                batch_target[:, [0.2]] = targets[b][:, [0.2]] * in_w
                batch_target[:, [1.3]] = targets[b][:, [1.3]] * in_h
                batch_target = batch_target[:, :4]
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                # Calculate intersection ratio
                # anch_ious num_true_box, num_anchors
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
                # Then we calculate the IOU, we can get a [2,507], is that we have two real boxes in the picture, and we have 507 boxes, each of which calculates the IOU with the real box
                anch_ious = self.calculate_iou(batch_target, pred_boxes_for_ignore)
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
                # Each prior box corresponds to the maximum coincidence of the real box
                # anch_ious_max num_anchors
                # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
    
                Size = [507]
                anch_ious_max, _ = torch.max(anch_ious, dim=0)
    
                # pred_boxes [b] the size () [3] : =,13,13 [3]
                anch_ious_max = anch_ious_max.view(pred_boxes[b].size()[:3])
    
                # Assuming that the value calculated by our IOU is greater than the threshold we set, we assume that our box has objects in it, so we set the corresponding position in the matrix without objects to 0
                noobj_mask[b][anch_ious_max > self.ignore_threshold] = 0
        # finally return our predicted box[16,3,13,13,4] and objectless matrix back
        return noobj_mask, pred_boxes
    Copy the code
    • rightbox_giouTo interpret
    def box_giou(self, b1, b2) :
        "" "input is: -- -- -- -- -- -- -- -- -- - b1: tensor, shape = (batch, feat_w feat_h, anchor_num, 4), xywh b2: Tensor, shape=(Batch, feat_w, feat_h, anchor_num, 4), xywh = ------- giou: tensor, shape=(batch, feat_w, feat_h, anchor_num, 1) """
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        Find the top left and bottom right corner of the prediction box
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
    
        # From the input x,y,w,h we can get the coordinates of the upper left and lower right corner
        b1_xy = b1[..., :2]
        b1_wh = b1[..., 2:4]
        b1_wh_half = b1_wh / 2.
        b1_mins = b1_xy - b1_wh_half
        b1_maxes = b1_xy + b1_wh_half
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        Find the upper left and lower right corner of the real box
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
    
        # From the input x,y,w,h we can get the coordinates of the upper left and lower right corner
        b2_xy = b2[..., :2]
        b2_wh = b2[..., 2:4]
        b2_wh_half = b2_wh / 2.
        b2_mins = b2_xy - b2_wh_half
        b2_maxes = b2_xy + b2_wh_half
    
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        Find all iOu of real box and forecast box
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
    
        # We take the greatest of the minimum values of the above two coordinate groups as the minimum coordinate
        intersect_mins = torch.max(b1_mins, b2_mins)
        # We take the smallest of the maximum values of the above two coordinate groups as the maximum coordinates
        intersect_maxes = torch.min(b1_maxes, b2_maxes)
        # We complete the subtraction of the maximum coordinate and the minimum coordinate, compare with 0, save the value if there is an IOU, save the value less than 0
        intersect_wh = torch.max(intersect_maxes - intersect_mins, torch.zeros_like(intersect_maxes))
        # Calculate intersection IOU area
        intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1]
    
        # Calculate the area of both
        b1_area = b1_wh[..., 0] * b1_wh[..., 1]
        b2_area = b2_wh[..., 0] * b2_wh[..., 1]
    
        # Calculate the area of the union
        union_area = b1_area + b2_area - intersect_area
        # get iou
        iou = intersect_area / union_area
    
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        Find the top left and bottom right corner of the smallest box that wraps both boxes
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
    
        # We complete the subtraction of the maximum coordinate and the minimum coordinate, compare with 0, save the value if there is an IOU, save the value less than 0
        enclose_mins = torch.min(b1_mins, b2_mins)
        enclose_maxes = torch.max(b1_maxes, b2_maxes)
        enclose_wh = torch.max(enclose_maxes - enclose_mins, torch.zeros_like(intersect_maxes))
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Calculate the diagonal distance
        # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #
        # Calculate the area of the intersection
        enclose_area = enclose_wh[..., 0] * enclose_wh[..., 1]
        # first
        giou = iou - (enclose_area - union_area) / enclose_area
    
        return giou
    Copy the code

    Giou’s calculation formula is shown below :(with the diagram, it is easier to understand the program)

    • rightBCELossTo interpret
    # target.size = pred.size = [16,20]
    def BCELoss(self, pred, target) :
        epsilon = 1e-7
        pred    = self.clip_by_tensor(pred, epsilon, 1.0 - epsilon)
        output  = - target * torch.log(pred) - (1.0 - target) * torch.log(1.0 - pred)
        return output
    Copy the code
    • rightMSELossTo interpret
    So # is essentially the square error of the position
    def MSELoss(self, pred, target) :
        return torch.pow(pred - target, 2)
    Copy the code
    • rightclip_by_tensorTo interpret
    def clip_by_tensor(self, t, t_min, t_max) :
        t = t.float()
        result = (t >= t_min).float() * t + (t < t_min).float() * t_min
        result = (result <= t_max).float() * result + (result > t_max).float() * t_max
        return result
    Copy the code

conclusion

Get_target gets the label function, we need to construct three variables, the first variable,noobj_maskThat is, we construct a matrix [bs,3,13,13] where there is no object 1 and there is an object 0; The second variable,box_loss_scaleIs that we want to give the small box more weight, for example, 13 * 13 we are identifying the large object, 52 * 52 is identifying the small object,box_loss_scale[b, k, j, i] = batch_target[t, 2] * batch_target[t, 3] / in_w / in_hBy dividing by in_W and in_h, we see that 52 * 52 is going to be smaller than 13 * 13. When we use it later, it’s 2-box_loss_scale, so 52 * 52 is going to be bigger than 13 * 13. That’s why we give small weights to big things, and big weights to small things, and we want to pay more attention to small things; The third variable,y_trueIs our real value (x,y,w,h,conf,num_class=20) set at the specified position in the matrix. Have two judgment is more important, the first is that we use real box high wide and 9 wide width ratio of the transcendental box, take out the most like that, assuming that the and l layer is corresponding to us, is the construction of data, or it is not match, just skip to the cause of the first two dimensional structure are 0 is we want real boxes and prior to box in the same center; The second judgment is whether to use GIou or not. Use GIou, y_true to store the real width and height data of the relative feature graph. If giou is not used, the first four bits of y_true will still store the values of offsets X,y, width and height change factors w and h.

The get_ignore function is mainly based on the IOU_ threshold, through the calculation of the IOU between our prediction box and our real box, the obtained IOU value is less than the iOU_ threshold, we consider that there is no object. So we still need to update our noobj_mask to consider the positions above the iou_ threshold as objects, and this function also returns the predicted position of the box[16,3,13,13,4] relative to the real position of the center point of the feature graph, the width and height of the 4-dimensional position matrix.

Our loss actually contains three parts, there are objects: box_loss. There are two calculation methods: one uses GIou to calculate, and the other uses original MSE and BCE to calculate. In this part, we will integrate our position loss weight box_LOss_scale; Cls_loss: uses BCE to calculate the loss of classified labels. Conf_loss: confidence loss, which can be calculated using BCE; There is no object: only Conf_Loss is computed; In the end, the total loss is the sum of the product of all the above-mentioned loss and corresponding weight.