SiamMAE复现记录,训练我们自己的数据集。AI学习从复现开始!

现着手于一个预训练任务,看了MAE论文的,又看到今年的SiamMAE,但是作者未开源,但是结构并不负责,尝试复现。

SiamMAE是在MAE上做的优化,本人就再MAE基础上做复现任务。

先看下这两个网络结构如下图:

 

 

 由架构可以看出,SiamMAE相较于MAE在第二分支非常接近,只是Decoder方式有变化。论文中使用的是cross_decoder。接下来,我们就开始吧

1.首先MAE  git下来。

2.论文中第一分支和第二分支为视频中两帧前后照片,第一分支和第二分支都采取vit的套路,先patch_embed,MAE代码中也是比较清晰

 def forward_features(self, x, mask):
        x = self.patch_embed(x)
        # cls_tokens = self.cls_token.expand(batch_size, -1, -1)
        # x = torch.cat((cls_tokens, x), dim=1)
        x = x + self.pos_embed.type_as(x).to(x.device).clone().detach()

        B, _, C = x.shape
        x_vis = x[~mask].reshape(B, -1, C) # ~mask means visible

        for blk in self.blocks:
            x_vis = blk(x_vis)

        x_vis = self.norm(x_vis)
        return x_vis

    def forward(self, x, mask):
        x = self.forward_features(x, mask)
        x = self.head(x)
        return x

论文中提到使用的是共享权值的encoder,所以此处可直接使用MAE的encoder,由于MAE是单分支的,这里需要更改modeling_pretraining.py代码,将网络中间稍作修改。

 def forward(self, m, m_mask, x, mask):

        # x_after进入encoder,再线性层拉伸维度
        x_after = self.encoder(x, mask) # [B, N_vis, C_e]
        x_after = self.encoder_to_decoder(x_after) # [B, N_vis, C_d]
        # m_before进入encoder, 再线性层拉伸维度
        m_before = self.encoder(m, m_mask)
        m_before = self.encoder_to_decoder(m_before)

此处带入一个实例,假设我的图片输入为[1, 3, 512, 512],则在encoder后,第一分支输出即为[1, 1024, 768]

我的切窗大小为16*16,即划分32*32=1024个patch, c为16*16*3=768

而第二个分支encoder的输入为未被掩码的patch,这里我没有按照论文的95%掩码率,使用的仍是MAE原始的75%掩码率,即输入256个patch,输出不变,即[1, 256, 768]

3.decoder

在双分支都encoder后,就准备decoder,MAE在进入decoder之前做了线性层改变维度,因为decoder中的输入为384维度,我们之前encoder的输出为768维度。

self.encoder_to_decoder = nn.Linear(encoder_embed_dim, decoder_embed_dim, bias=False)
x_after = self.encoder_to_decoder(x_after)

论文中这里的decoder跟mae中的不一样,使用的是cross_self decoder

 此处找到了一篇关于这样的文章,并找到了相关代码

self.transformer_decoder = TransformerDecoder(dim=decoder_embed_dim, depth=decoder_depth,
                            heads=decoder_num_heads, dim_head=decoder_num_heads, mlp_dim=4*decoder_embed_dim, dropout=0,
                                                      softmax=True)
x_full = self.transformer_decoder(x_full, m_before)
class TransformerDecoder(nn.Module):
    def __init__(self, dim, depth, heads, dim_head, mlp_dim, dropout, softmax=True):
        super().__init__()
        self.layers = nn.ModuleList([])
        for _ in range(depth):
            self.layers.append(nn.ModuleList([
                Residual2(PreNorm2(dim, Cross_Attention(dim, heads = heads,
                                                        dim_head = dim_head, dropout = dropout,
                                                        softmax=softmax))),
                Residual(PreNorm(dim, FeedForward(dim, mlp_dim, dropout = dropout)))
            ]))
    def forward(self, x, m, mask = None):
        """target(query), memory"""
        m = nn.Linear()
        for attn, ff in self.layers:
            x = attn(x, m, mask = mask)
            x = ff(x)
        return x

这里decoder后会产生[1, 1024, 384]维度的输出,这里我们跟原图label求一下损失,论文中使用的不是MAE的MSE损失函数,改成了L1损失,那么我们也改一下。

loss_func1 = nn.L1Loss()


with torch.cuda.amp.autocast():
  # 模型中传入两条路径的两个输入图片,batch_image1为before,batch_image2为after
  # bool_pos为before的掩码率为0,bool_masked_pos为after的掩码率为0.75
  outputs = model(batch_image1, bool_pos, batch_image2, bool_masked_pos)
  loss = loss_func(input=outputs, target=labels)

最后我们要训练我们自己的数据集,文章中是图像重建任务,与MAE不同,输入端是两张图片,所以,dataset这边也需要改一下。

在dataset_folder.py中我们新建一个class,继承自ImageFolder,重写get_item方法,这就不多说啦,代码如下:

class customImageFolder(ImageFolder):
    #复写image_folder, 返回两张图像
    def __init__(self, root, transform=None):
        super(customImageFolder, self).__init__(root, transform)

    def __getitem__(self, index1):

        path1 = self.imgs[index1][0]  # 此时的self.imgs等于self.samples,即内容为[(图像路径, 该图像对应的类别索引值),(),...]
        label1 = self.imgs[index1][1]
        path_name = path1.split('/')
        path2 = os.path.join(path_name[0], path_name[1], 'after', path_name[-1])

        img1 = self.loader(path1)
        img2 = self.loader(path2)
        if self.transform is not None:
            img1 = self.transform(img1)
            img2 = self.transform(img2)
        #print(img1, img2, label1, '11111111111111111')
        return img1, label1, img2

    def __len__(self) -> int:
        return len(self.imgs)

OK,大功告成,我们就开始训练我们的数据集啦

python run_mae_pretraining.py --data_path data/train/before --mask_ratio 0.75 --model pretrain_mae_base_patch16_224 --batch_size 10 --opt adamw --opt_betas 0.9 0.95 --warmup_epochs 5 --epochs 150 --output_dir  output/pretrain_mae_base_patch16_224

data_path就是数据集地址,mask_ratio就是掩码率,model就使用了默认的,就先跑个150轮吧,每5轮改变学习率策略。

 

这就开始训练了! 

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值