Pytorch图像检索实践-600学习网
600学习网终身会员188,所有资源无秘无压缩-购买会员
随着电子商务和在线网站的出现,图像检索在我们日常生活中的应用越来越多。
亚马逊.阿里巴巴.Myntra等公司一直在广泛使用图像检索技术。当然,只有当通常的信息检索技术失败时,图像检索才能开始工作。
出身背景
图像检索的基本本质是根据所查询图像的特征从集合或数据库中搜索图像。
在大多数情况下,该特征是图像之间的简单视觉相似姓。在一个复杂的问题中,这一特征可能是两幅图像在风格上的相似姓,甚至互补姓。
由于原始图像不会在基于像素的数据中反映这些特征,我们需要将这些像素数据转换为图像表示将反映这些特征的潜在空间。
一般来说,在潜在空间中,任何两个相似的图像都会彼此靠近,而不同的图像则会相距很远。这是我们用来训练模型的基本管理规则。一旦我们这样做了,检索部分只需要搜索潜在空间,并在给定查询图像所表示的潜在空间中拾取最近的图像。在大多数情况下,它是在最近邻居搜索的帮助下完成的。
因此,我们可以将方法分为两部分:
1.图像表示
2.搜索
我们将在牛津102 Flowers数据集上讨论这两个部分。
图像表示
我们将使用一种叫做暹罗模型的东西,它本身不是一种新模型,而是一种训练模型的技术。在大多数情况下,这与三重态损失一起使用。这项技术的基本组成部分是三元组。
Triple是3个独立的数据样本,如A(锚).B(正)和C(负);其中A和B相似或具有相似的特征(可能是相同的类型),而C与A和B不相似。这三个样本一起构成了训练数据的单位-三元组。
注:90%的图像检索任务都体现在创建Siam网络.三重丢失和三重丢失中。如果你成功地完成了这些,整个努力的成功或多或少是有保证的。
首先,我们将创建管道数据的这个组件。接下来,我们将在PyTorch中创建一个自定义数据集和数据加载器,它将从数据集生成三元组。
类TripletData(数据集):
def__init_(自我.路径.变换.分割=”列车”):
self.path=路径
self.split=分裂#列车或有效
self.cats=102#类别数
自变换=变换
定义_ _获取项目_ _(自我,idx):
#我们对三胞胎的肯定
idx=str(idx%self.cats+1)
#选择我们的一对正面图像(im1,im2)
positives=os.listdir(os.path.join(self.path,idx))
im1,im2=随机样本(阳姓,2)
#选择负面类别和负面形象(im3)
负数_猫=〔str(x+1)对于范围内的x(self.cats)〕
负片_猫。移除(idx)
负_猫=str(随机选择(负_猫))
负数=os.listdir(os.path.join(self.path,negative_cat))
im3=随机选择(负数)
im1,im2,im3=os.path.join(self.path,idx,im1),os.path.join
im1=self.transforms(Image.open(im1))
im2=self.transforms(图像打开(im2))
im3=self.transforms(图像打开(im3))
返回〔im1,im2,im3〕
#由于可能有太多的三胞胎,所以我们会把我们想要的价值放在一起
#图像数量/类别数量的倍数是一个不错的选择
def__len_(自我):
返回自我。猫*8
#变换
train_transforms=transforms.Compose(〔
transforms.Resize((224224))
transforms.RandomHorizontalFlip()
transforms.ToTensor()
变换。归一化((0.4914,0.4822,0.4465),(0.2023,0.1994,0.2010))
])
val_transforms=transforms.Compose(〔
变换。调整大小((224.224))
transforms.ToTensor()
变换。归一化((0.4914,0.4822,0.4465),(0.2023,0.1994,0.2010))
])
列车_数据=TripletData(路径_列车,列车_变换)
val_data=TripletData(PATH_VALID,val_transforms)
train_loader=torch.utils.data.DataLoader(数据集=train_data,批次_size=32,shuffle=True,num_workers=4)
val_loader=torch.utils.data.DataLoader(数据集=val_data,批大小=32,shuffle=False,num_workers=4)
现在我们有了数据,让我们切换到暹罗网络。
暹罗网络给人的印象是有两个或三个模型,但它是一个单一的模型。所有这些模型都有重量,也就是说,只有一个模型。
如前所述,组合整个架构的关键因素是三重损失。三重损失产生一个目标函数,它迫使相似输入对(锚和正)之间的距离小于不同输入对(锚点和负)之间的间距,并限制一定的阈值。
现在让我们来看看三重损失和培训管道的实现。
class TripleLoss(nn.模块):
def_init_(self,margin=1.0):
super(TripleLoss,self).__init()
self.margin=margin def calc_欧几里德(self,x1,x2):
return(x1-x2).pow(2).sum(1)#嵌入空间中的距离用欧几里德计算
def forward(自.锚.正.负):
距离_正=自我计算_欧几里德(锚,正)
距离_负=自我计算_欧几里德(锚,负)
损失=火炬relu(距离_正-距离_负+自身余量)
返回损失.mean()
装置=”cuda”
#我们的基本模型
model=models.resnet18().cuda()
优化器=optim.Adam(model.parameters(),lr=0.001)
三重损失=三重损失()
#培训
对于范围内的历元(历元):
模型.train()
历元_损失=0.0
对于tqdm(列车装载机)中的数据:
优化器.zero_grad()
x1,x2,x3=数据
e1=型号(x1.至(设备))
e2=型号(x2.至(设备))
e3=型号(x3.to(设备))
损失=三联体_损失(e1.e2.e3)
时期_损失+=损失
向后损失()
优化器.step()
print(“列车损失:{}”.format(epoch_Loss.item()))
class TripleLoss(nn.模块):
def_init_(self,margin=1.0):
super(TripleLoss,self).__init()
self.margin=margin def calc_欧几里德(self,x1,x2):
return(x1-x2).pow(2).sum(1)#嵌入空间中的距离用欧几里德计算
def forward(自.锚.正.负):
距离_正=自我计算_欧几里德(锚,正)
距离_负=自我计算_欧几里德(锚,负)
损失=火炬relu(距离_正-距离_负+自身余量)
返回损失.mean()
装置=”cuda”
#我们的基本模型
model=models.resnet18().cuda()
优化器=optim.Adam(model.parameters(),lr=0.001)
三重损失=三重损失()
#培训
对于范围内的历元(历元):
模型.train()
历元_损失=0.0
对于tqdm(列车装载机)中的数据:
优化器.zero_grad()
x1,x2,x3=数据
e1=型号(x1.至(设备))
e2=型号(x2.至(设备))
e3=型号(x3.to(设备))
损失=三联体_损失(e1.e2.e3)
时期_损失+=损失
向后损失()
优化器.step()
print(“列车损失:{}”.format(epoch_Loss.item()))
到目前为止,我们的模型已经过训练,可以将图像转换为嵌入式空间。接下来,让我们进入搜索部分。
搜索
我们可以轻松使用Scikit Learn提供的最近邻居搜索。我们将探索新的更好的东西,而不是走一条简单的路线。
我们将使用Faiss。这比最近的邻居快得多。如果我们有大量的图像,速度上的差异将变得更加明显。
接下来,我们将演示当查询给定图像时,如何在存储的图像表示中搜索最近的图像。
#! pip安装faiss-gpu
进口faiss
faiss_index=faiss.IndexFlatL2(1000)#构建索引
#存储图像表示
im_指数=〔〕
带火炬。无_级():
对于glob.glob(os.path.join(path_TRAIN,’*’)中的f:
im=图像打开(f)
im=im.调整大小((224224))
im=torch.张量(〔val〕transforms(im).numpy()〕).cuda()
preds=模型(im)
preds=np.array(〔preds〔0〕.cpu().numpy()〕)
faiss_index.add(preds)#将表示添加到索引
im_indexs.append(f)#存储图像名称,以便以后查找
#使用查询图像检索
带火炬。无_级():
对于os.listdir中的f(路径测试):
#查询/测试图像
im=Image.open(os.path.join(路径测试,f))
im=im.调整大小((224224))
im=torch.张量(〔val〕transforms(im).numpy()〕).cuda()
测试_嵌入=模型(im).cpu().numpy()
_,I=faiss _ index.search(测试_嵌入,5)
print(“检索图像:{}”.format(im索引〔I〔0〕〔0〕〕)
这包括了基于现代深度学习的图像检索,但不会使其过于复杂。大多数检索问题都可以通过这个基本管道解决。
600学习网 » Pytorch图像检索实践-600学习网