1、dcnv2的实现测试了两种,一种是官方版dcnv2,git链接:https://github.com/CharlesShang/DCNv2.git,编译直接cd到DCNv2,然后./make.sh即可,第二种是mmcv.ops.modulated_deform_conv.ModulatedDeformConv2dPack
2、实验以resnet50、mnist训练为例
from torch_op.common import init_seed
from torchvision.datasets import MNIST
from torchvision import transforms
from torch.utils.data import DataLoader
from torchvision.models.resnet import resnet50
from torch import nn,optim
import torch
with_dcn = True
if with_dcn:
#两种dcn导入方法
# from dcn_v2 import DCN
from mmcv.ops.modulated_deform_conv import ModulatedDeformConv2dPack as DCN
init_seed(0)
batch_size =64
num_workers = 16
epochs = 20
lr = 0.1
train_dataset = MNIST('torch_op/mnist/data',train=True,download=True,
transform=transforms.Compose([
transforms.ToTensor(),
# transforms.Normalize((0.1307,),(0.3081))
])
)
test_dataset = MNIST('torch_op/mnist/data',train=False,download=True,
transform=transforms.Compose([
transforms.ToTensor(),
# transforms.Normalize((0.1307,),(0.3081))
])
)
train_loader = DataLoader(train_dataset,batch_size=batch_size,shuffle=True,num_workers=num_workers)
test_loader = DataLoader(test_dataset,batch_size=batch_size,shuffle=False,num_workers=num_workers)
#替换原网络中每个bottleneck中第二个conv为dcn
def replace(layers):
for name,module in layers.named_children():
if isinstance(module,torch.nn.Conv2d):
if 'conv2' in name:
new_module = DCN(module.in_channels, module.out_channels, module.kernel_size, module.stride, module.padding,
module.dilation, 1)
layers.add_module(name,new_module)
else:
replace(module)
model = resnet50(False,num_classes=10)
#需要将conv替换成dcn的module列表
if with_dcn:
replace_list = ['layer2','layer3','layer4']
for name,module in model.named_children():
if name not in replace_list:
continue
# print(module)
replace(module)
# print('*'*20)
# print(module)
# print('-'*20)
print(model)
model = model.cuda()
optimizer = optim.SGD(model.parameters(),lr=lr)
criterion = nn.CrossEntropyLoss()
def train():
model.train()
for batch_idx,(data,target) in enumerate(train_loader):
if data.size(1)==1:
data = torch.cat([data,data,data],dim=1)
# print('start_train')
data = data.cuda()
target = target.cuda()
optimizer.zero_grad()
output = model(data)
loss = criterion(output,target)
loss.backward()
optimizer.step()
if batch_idx % 100 == 0:
print('loss:{}'.format(loss.item()))
def test(e):
model.eval()
total_right = 0
total_wrong = 0
with torch.no_grad():
for batch_idx,(data,target) in enumerate(test_loader):
if data.size(1) == 1:
data = torch.cat([data, data, data], dim=1)
data = data.cuda()
target = target.cuda()
output = model(data)
output = output.max(dim=1)[1]
right = torch.sum(output==target).item()
wrong = len(data) - right
total_right += right
total_wrong += wrong
print('epoch-{} acc:{}/{}={}'.format(e,total_right,total_right+total_wrong,total_right/(total_wrong+total_right)))
for e in range(epochs):
train()
test(e)
3、总结
当把layer2、3、4的conv全部替换为dcn时,训练特别慢,而且acc一直很低,大概只有10%左右