Safetensors
File size: 7,427 Bytes
4d3c316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import itertools
import torch
from models import XVLMBase, load_pretrained

class BBoxCollector:
    # ... [与之前的BBoxCollector定义相同] ...
    # 记得在calculate_loss()返回spatial_loss时,你可能需要进行相应的调整以确保其正确返回。
    def __init__(self):
        self.collect_bbox = []
        self.current_num = None

    def update_bbox(self, bbox_info):
        new_num = bbox_info['num']

        # 情况1
        if not self.collect_bbox:
            self.collect_bbox.append(bbox_info)
            self.current_num = new_num
            return

        # 情况2
        if len(self.collect_bbox) == 1:
            if new_num == self.current_num:
                self.collect_bbox.append(bbox_info)
                return
            else:
                # 排出旧的bbox
                self.collect_bbox = [bbox_info]
                self.current_num = new_num
                return

        if len(self.collect_bbox) == 2:
            if new_num == self.current_num:
                self.calculate_loss(self.collect_bbox)
                self.collect_bbox = []  # 清空
                self.collect_bbox.append(bbox_info)
            else:
                self.calculate_loss(self.collect_bbox)
                self.collect_bbox = []  # 清空
                self.collect_bbox.append(bbox_info)
                self.current_num = new_num

    def calculate_loss(self, bboxes):
        permutations = list(itertools.permutations(bboxes, 2))
        for pair in permutations:
            target_bbox_A = pair[0]['bbox']
            target_bbox_B = pair[1]['bbox']
            
            sen_token_A = pair[0]['text_token']
            sen_embeds_A = pair[0]['text_embeds']
            sen_token_B = pair[1]['text_token']
            sen_embeds_B = pair[1]['text_embeds']
            
            feature_map = pair[0]['image_feature_map']  # 仅使用第一个bbox的feature map,您可能需要进行相应的调整
            
            target_ids = compute_rela(target_bbox_A, target_bbox_B)
            spatial_loss = self.get_spatial_relation_loss(sen_token_A, sen_embeds_A, sen_token_B, sen_embeds_B, target_bbox_A, target_bbox_B, feature_map, target_ids)
            print("Calculated spatial loss:", spatial_loss)

def compute_rela(bbox1, bbox2):
    x1, y1, w1, h1 = bbox1
    x2, y2, w2, h2 = bbox2

    len_x = x1 - x2
    a_len_x = abs(len_x)

    len_y = y1 - y2
    a_len_y = abs(len_y)

    if a_len_x < 0.5 * w1:
        if len_y > 0:
            return torch.tensor([0, -1])
        if len_y < 0:
            return torch.tensor([0, 1])
    
    else:
        if len_x > 0:
            if a_len_y < 0.5 * h1:
                return torch.tensor([-1, 0])
            else:
                if len_y > 0:
                    return torch.tensor([-1, -1])
                else:
                    return torch.tensor([-1, 1])
        
        if len_x < 0:
            if a_len_y < 0.5 * h1:
                return  torch.tensor([1, 0])
            else:
                if len_y > 0:
                    return torch.tensor([1, -1])
                else:
                    return torch.tensor([1, 1])



class XVLM(XVLMBase):
    def __init__(self, config):
        super().__init__(config, load_vision_params=False, load_text_params=False,
                         use_contrastive_loss=True, use_matching_loss=True, use_mlm_loss=False, use_bbox_loss=True)

        self.num_attention_heads = self.text_encoder.config.num_attention_heads
        self.init_params = []

    def load_pretrained(self, ckpt_rpath, config, is_eval=False):
        state_dict = load_pretrained(ckpt_rpath, config, is_eval=is_eval, load_text=True)
        msg = self.load_state_dict(state_dict, strict=False)
        print('load checkpoint from %s' % ckpt_rpath)
        print("missing_keys: ", [p for p in msg.missing_keys if 'vision_encoder' not in p])
        print("unexpected_keys: ", msg.unexpected_keys)

    def forward(self, image, text_ids, text_atts, idx=None, pair=None):
        # print("Note: This part is in the model process!")
        # print(f"Here is the model {idx} image: {image}")
        # print(f'Here is the model {idx} text_ids:{text_ids}')
        # print(f'Here is the model {idx} text_atts:{text_atts}')
        # print(f'Here is the model {idx} pair:{pair}')
        image_embeds, image_atts = self.get_vision_embeds(image)
        # print('Here is the image_embeding size')
        # print(image_embeds.size(0))
        text_embeds = self.get_text_embeds(text_ids, text_atts)
        # output_coord & target_bbox: 64, 4
        image_feat, text_feat = self.get_features(image_embeds, text_embeds)

        loss_itc = self.get_contrastive_loss(image_feat, text_feat, idx=idx)
        loss_itm = self.get_matching_loss(image_embeds, image_atts, image_feat, text_embeds, text_atts, text_feat, idx=idx)

        # print(f'loss_itc is {loss_itc}, loss_itm is {loss_itm}')
        n = len(pair)
        # print(f"the length of the pair is:{n}")
        if n == 0:
            # loss_bb = -100
            return loss_itc, loss_itm
        else:
            total_spatial_loss = 0.0  # 用于累积空间关系损失
            loss_count = 0  # 用于记录计算出的空间关系损失的数量
            for i in range(n):
                loss_bb = 0
                repeat_image = 0
                num = pair[i][0]
                new = image[num].unsqueeze(0)
                image_embeds, _ = self.get_vision_embeds(new)

                vis = self.vision_encoder.forward(new,feature_map=12)
                feature_map = vis.permute(0,3,1,2)
                
                sen_token = pair[i][1]
                sen_embeds = self.get_text_embeds(sen_token.input_ids, sen_token.attention_mask)
                print(f'Here is the number{pair[i][0]}')
                # print(sen_embeds.size(0))
                # print(image_embeds.size(0))
                output_coord = self.predict_bbox(image_embeds, sen_embeds, sen_token.attention_mask)
                # print('let us see the pair')
                # print(pair[i][2])
                # print(pair[i][2].size())
                # print(output_coord)
                # print(output_coord.size())
                loss_bbox, loss_giou = self.get_bbox_loss(output_coord, pair[i][2].unsqueeze(0))
                loss_bb += (loss_bbox + loss_giou)
                # Update the BBoxCollector with the current bbox information from the pair
                bbox_info = {
                    'text_token': pair[i][1],  # assuming this is sen_embeds
                    'text_embeds': pair[i][1],  # assuming this is sen_embeds
                    'bbox': pair[i][2],  # bbox
                    'image_feature_map': feature_map,
                    'num': pair[i][0]  # num
                }
                spatial_loss = self.bbox_collector.update_bbox(bbox_info)

                if spatial_loss is not None:  # 如果计算出了空间关系损失
                    total_spatial_loss += spatial_loss
                    loss_count += 1

            if loss_count > 0:
                average_spatial_loss = total_spatial_loss / loss_count
            else:
                average_spatial_loss = 0.0
                # print(f"loss_bb is {loss_bb}")
            loss_bb = loss_bb/n
            # print(f"loss_bb is {loss_bb}")
            return loss_itc, loss_itm, loss_bb