SimCLR代码实现

网络编辑求职招聘QQ群 https://m.sojk.net/yinshijj/26323.html

Model:

importtorchimporttorch.nnasnnimporttorch.nn.functionalasFfromtorch.nn.modulesimportbatchnormfromtorchvision.models.resnetimportresnet50classModel(nn.Module):def__init__(self,feature_dim=):super(Model,self).__init__()#修改resnet50作为fself.f=[]forname,moduleinresnet50().named_children():#name=conv1,bn1,relu,maxpool,layer1,layer2,layer3,layer4,avgpool,fcifname==conv1:#原conv1为Conv2d(3,64,kernel_size=(7,7),stride=(2,2),padding=(3,3),bias=False)#现在output=(input-3+2*1)/1+1=inputmodule=nn.Conv2d(3,64,kernel_size=3,stride=1,padding=1,bias=False)#去掉线性层和maxpool层ifnotisinstance(module,nn.Linear)andnotisinstance(module,nn.MaxPool2d):self.f.append(module)#基础编码器fself.f=nn.Sequential(*self.f)#投影头gself.g=nn.Sequential(nn.Linear(,,bias=False),nn.BatchNorm1d(),nn.ReLU(inplace=True),nn.Linear(,feature_dim,bias=True))defforward(self,x):x=self.f(x)#[b,3,64,64]=[b,,1,1]feature=torch.flatten(x,start_dim=1)#[b,,1,1]=[b,]out=self.g(feature)#[b,]=[b,feature_dim]returnF.normalize(feature,dim=-1),F.normalize(out,dim=-1)

其中:

f(·)是CNN,网络结构:

(f):Sequential((0):Conv2d(3,64,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(1):BatchNorm2d(64,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(2):ReLU(inplace=True)(3):Sequential((0):Bottleneck((conv1):Conv2d(64,64,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(64,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(64,64,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(64,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(64,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True)(downsample):Sequential((0):Conv2d(64,,kernel_size=(1,1),stride=(1,1),bias=False)(1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)))(1):Bottleneck((conv1):Conv2d(,64,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(64,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(64,64,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(64,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(64,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True))(2):Bottleneck((conv1):Conv2d(,64,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(64,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(64,64,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(64,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(64,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True)))(4):Sequential((0):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(2,2),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True)(downsample):Sequential((0):Conv2d(,,kernel_size=(1,1),stride=(2,2),bias=False)(1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)))(1):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True))(2):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True))(3):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True)))(5):Sequential((0):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(2,2),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True)(downsample):Sequential((0):Conv2d(,,kernel_size=(1,1),stride=(2,2),bias=False)(1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)))(1):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True))(2):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True))(3):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True))(4):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True))(5):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True)))(6):Sequential((0):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(2,2),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True)(downsample):Sequential((0):Conv2d(,,kernel_size=(1,1),stride=(2,2),bias=False)(1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)))(1):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True))(2):Bottleneck((conv1):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn1):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv2):Conv2d(,,kernel_size=(3,3),stride=(1,1),padding=(1,1),bias=False)(bn2):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(conv3):Conv2d(,,kernel_size=(1,1),stride=(1,1),bias=False)(bn3):BatchNorm2d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(relu):ReLU(inplace=True)))(7):AdaptiveAvgPool2d(output_size=(1,1)))

g(·)是一个多层感知机,网络结构:

(g):Sequential((0):Linear(in_features=,out_features=,bias=False)(1):BatchNorm1d(,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True)(2):ReLU(inplace=True)(3):Linear(in_features=,out_features=,bias=True))

utils:

fromPILimportImagefromtorch.utils.dataimportDatasetfromtorchvisionimporttransformsimporttorch#自定义数据集classMyDataSet(Dataset):def__init__(self,images_path:list,image_class:list,transform=None):self.images_path=images_pathself.image_class=image_classself.transform=transformdef__len__(self):returnlen(self.images_path)def__getitem__(self,index):img=Image.open(self.images_path[index])#RGB为彩色图像,L为灰度图像ifimg.mode!=RGB:raiseValueError("image:{}isntRGBmode.".format(self.images_path[index]))label=self.image_class[index]ifself.transformisnotNone:img1=self.transform(img)img2=self.transform(img)returnimg1,img2,labelimportosdefread_split_data(root:str):#数据集路径和验证集划分比例assertos.path.exists(root),"datasetroot:{}doesnotexist.".format(root)#遍历文件夹,一个文件夹对应一个类别flower_class=[claforclainos.listdir(root)ifos.path.isdir(os.path.join(root,cla))]#排序,保证顺序一致flower_class.sort()#生成类别名称以及对应的数字索引class_indices=dict((k,v)forv,kinenumerate(flower_class))train_images_path=[]#存储训练集的所有图片路径train_images_label=[]#存储训练集图片对应的索引信息every_class_num=[]#存储每个类别的样本总数supported=[".jpg",".JPG",".png",".PNG"]#支持的文件后缀类型#遍历每个类别下的文件forclainflower_class:cla_path=os.path.join(root,cla)#遍历获取该类别supported支持的所有文件路径images=[os.path.join(root,cla,i)foriinos.listdir(cla_path)ifos.path.splitext(i)[-1]insupported]#获取该类别对应的索引image_class=class_indices[cla]#记录该类别的样本数every_class_num.append(len(images))#遍历某个类别的所有文件forimg_pathinimages:train_images_path.append(img_path)train_images_label.append(image_class)returntrain_images_path,train_images_labeldata_transform={"train":transforms.Compose([transforms.RandomResizedCrop(32),transforms.RandomHorizontalFlip(p=0.5),transforms.RandomApply([transforms.ColorJitter(0.4,0.4,0.4,0.1)],p=0.8),transforms.RandomGrayscale(p=0.2),transforms.ToTensor(),transforms.Normalize([0.,0.,0.],[0.,0.,0.])]),"val":transforms.Compose([transforms.Resize([32,32]),transforms.ToTensor(),transforms.Normalize([0.,0.,0.],[0.,0.,0.])])}

训练:

importtorchimporttorch.optimasoptimfromtorch.utils.dataimportDataLoaderimportutilsfrommodelimportModeldevice=torch.device("cuda"iftorch.cuda.is_available()else"cpu")print("using{}device.".format(device))batch_size=32class_num=5root_train="C:\\Users\\Arthur\\Desktop\\Data\\flower\\flower_train"root_val="C:\\Users\\Arthur\\Desktop\\Data\\flower\\flower_val"train_images_path,train_images_label=utils.read_split_data(root_train)val_images_path,val_images_label=utils.read_split_data(root_val)train_data_set=utils.MyDataSet(images_path=train_images_path,image_class=train_images_label,transform=utils.data_transform["train"])train_loader=DataLoader(train_data_set,batch_size=batch_size,shuffle=True,num_workers=0,drop_last=True)train_num=len(train_data_set)memory_data_set=utils.MyDataSet(images_path=train_images_path,image_class=train_images_label,transform=utils.data_transform["val"])memory_loader=DataLoader(memory_data_set,batch_size=batch_size,shuffle=False,num_workers=0,drop_last=True)validate_data_set=utils.MyDataSet(images_path=val_images_path,image_class=val_images_label,transform=utils.data_transform["val"])validate_loader=DataLoader(validate_data_set,batch_size=batch_size,shuffle=False,num_workers=0,drop_last=True)val_num=len(validate_data_set)print("using{}imagesfortraining,{}imagesforvalidation.".format(train_num,val_num))epochs=temperature=0.5best_acc=0.0save_path=./SimCLR.pthtrain_steps=len(train_loader)model=Model().to(device)optimizer=optim.Adam(model.parameters(),lr=0.)forepochinrange(epochs):#训练model.train()running_loss=0.0fori,(imgs_1,imgs_2,labels)inenumerate(train_loader):imgs_1=imgs_1.to(device)imgs_2=imgs_2.to(device)labels=labels.to(device)optimizer.zero_grad()#out_1=out2=[b,]#共享权重,使用同一个网络进行输出feature_1,out_1=model(imgs_1)feature_2,out_2=model(imgs_2)#out=[2b,]out=torch.cat([out_1,out_2],dim=0)#sim_matrix=[2b,2b]sim_matrix=torch.exp(torch.mm(out,out.t().contiguous())/temperature)#mask=[2b,2b],除了对角线为False,其余地方为Truemask=(torch.ones_like(sim_matrix)-torch.eye(2*batch_size,device=sim_matrix.device)).bool()#删除掉对角线元素,用来做softmax的分母,因为对角线元素相当于自己与自己对比,sim_matrix=[2b,2b-1]sim_matrix=sim_matrix.masked_select(mask).view(2*batch_size,-1)#计算exp(si,sj)/temperature,si和sj是来自相同的图像的变换,img_sim_positive=[b]img_sim=torch.exp(torch.sum(out_1*out_2,dim=-1)/temperature)#在图像位置互换的情况下,再次计算同一对图像的损失img_sim=torch.cat([img_sim,img_sim],dim=0)#损失函数loss=(-torch.log(img_sim/sim_matrix.sum(dim=-1))).mean()loss.backward()optimizer.step()running_loss+=loss.item()print("trainepoch[{}/{}]loss:{:.3f}".format(epoch+1,epochs,running_loss/train_steps))#验证model.eval()acc=0.0total_num=0feature_bank=[]labels_bank=[]withtorch.no_grad():#memory_loader返回两批相同的imgsfori,(imgs,_,labels)inenumerate(memory_loader):imgs=imgs.to(device)labels=labels.to(device)#feature=[b,feature_dim]feature,out=model(imgs)feature_bank.append(feature)labels_bank.append(labels)#将验证集所有feature在0维上拼接起来,再进行转置,feature_bank=[feature_dim,N]feature_bank=torch.cat(feature_bank,dim=0).t().contiguous()#feature_labels=[N]feature_labels=torch.cat(labels_bank,dim=0).to(device)#用验证集的feature与memory_loader的feature_bank做对比fori,(imgs,_,labels)inenumerate(validate_loader):imgs=imgs.to(device)labels=labels.to(device)#feature=[b,feature_dim]feature,out=model(imgs)total_num+=imgs.size(0)#sim_matrix=[b,N]sim_matrix=torch.mm(feature,feature_bank)#sim_indices=[b,1]_,sim_indices=sim_matrix.max(dim=-1)predicate_labels=feature_labels[sim_indices]acc+=torch.eq(predicate_labels,labels).sum().item()val_accurate=acc/total_numprint("valepoch[{}/{}]accuracy:{:.3f}".format(epoch+1,epochs,val_accurate))ifval_accuratebest_acc:best_acc=val_accuratetorch.save(model.state_dict(),save_path)print(FinishedTraining)

运行结果:

预览时标签不可点收录于话题#个上一篇下一篇



转载请注明地址:http://www.sanbaicaoasb.com/scls/7723.html
  • 上一篇文章:
  • 下一篇文章:
  • 热点文章

    • 没有热点文章

    推荐文章

    • 没有推荐文章