日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

孪生网络实验记录

發布時間:2023/12/20 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 孪生网络实验记录 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

孿生網絡檢測人臉和簽名相似度

  • 孿生網絡介紹
  • 實驗結果預覽
  • 實現步驟
    • ==1. 加載數據==
    • ==2. 定義網絡結構==
    • 3. 損失函數
    • 4. 訓練,保存和加載模型
    • 5. 測試

孿生網絡介紹

個人理解:孿生網絡就是一次學習兩張圖片(兩張圖片是一類或者不是一類),從中發現它們的相似或者不同,等網絡學習完成之后,再給網絡輸入兩張圖片即可知道它們是否是一類。

實驗結果預覽

人臉圖片:

人臉圖片

隨機選的人臉圖片:

手寫簽名圖片:


手寫簽名

隨機選的手寫簽名圖片:

達到的效果:
給出兩張圖片的相似度(一個數值,越大越可能相似),并且可以根據該數值設置一個閾值來進行預測,人臉數據集的預測正確率為90%,手寫簽名數據集的預測正確率為84.9%。

Label表示實際上兩張圖片實際是否為同一類

實現步驟

1. 加載數據

1.1 定義自己的數據集

# 自己的數據集 class SiameseDataset(Dataset): #用上了DataSet from torch.utils.data import DataSet# imageFolderDataset是torchvision.datasets.ImageFolder返回的datasets# transform是torchvision.transforms.Compose返回的transformdef __init__(self, imageFolderDataset, transform=None, should_invert=True):self.imageFolderDataset = imageFolderDatasetself.transform = transformself.should_invert = should_invert# 這個函數很重要,要想辦法返回自己需要的圖片和標簽(不同的方法這個不一樣)# 孿生網絡要返回兩張圖片,而且盡可能好好和好壞比例是1:1def __getitem__(self, index):#imageFolderDataset.imgs是所有文件夾下的圖片的路徑+標簽#例如 [('./data/dogcat_2/cat/cat.12484.jpg', 0), ('./data/dogcat_2/cat/cat.12485.jpg', 0),# ('./data/dogcat_2/dog/dog.12498.jpg', 1), ('./data/dogcat_2/dog/dog.12499.jpg', 1)]# random.choice是隨機選出一張img0_tuple = random.choice(self.imageFolderDataset.imgs) #import random# 用隨機數來使好好和好壞的比例大致是1:1,從數字0和1之間隨機返回一個should_get_same_class = random.randint(0, 1)if should_get_same_class:while True:img1_tuple = random.choice(self.imageFolderDataset.imgs)if img0_tuple[1] == img1_tuple[1]:breakelse:while True:img1_tuple = random.choice(self.imageFolderDataset.imgs)if img0_tuple[1] != img1_tuple[1]:break# 打開圖片并變成灰度圖:img0 = Image.open(img0_tuple[0]) # 用到了Imageimg1 = Image.open(img1_tuple[0])img0 = img0.convert('L')img1 = img1.convert('L')# 是否黑白翻轉if self.should_invert:img0 = PIL.ImageOps.invert(img0) #PIL.ImageOpsimg1 = PIL.ImageOps.invert(img1)# 數據增強(img轉換為tensor)if self.transform is not None:img0 = self.transform(img0)img1 = self.transform(img1)# 把label也轉換為tensor,label是1:兩張圖片不是一類return img0, img1, torch.from_numpy(np.array([int(img0_tuple[1] != img1_tuple[1])], dtype=np.float32))def __len__(self):return len(self.imageFolderDataset.imgs)

1.2 用ImageFolder返回一個數據集類別

# 先用ImageFolder返回一個dataset,再把這個數據集送入到自己造的SiameseDataset中去,得到siamese_dataset folder_dataset = datasets.ImageFolder(root=Config.train_dir)transform = transforms.Compose([transforms.Resize((100, 100)),transforms.ToTensor()])siamese_dataset = SiameseDataset(imageFolderDataset=folder_dataset, transform=transform, should_invert=False)

1.3 數據可視化

# Dataset類只負責數據的抽象,一次調用__getitem__一次只返回一個樣本,使用DataLoader一次可以返回一個batch vis_dataset = DataLoader(siamese_dataset, shuffle=True, batch_size=8, num_workers=8) # vis_dataset是可迭代的 dataiter = iter(vis_dataset) # 等價于img0, img1, label = next(dataiter) example_batch = next(dataiter) # 0代表豎著拼接,1代表橫著拼接 concatenate = torch.cat((example_batch[0], example_batch[1]), 0) imshow(torchvision.utils.make_grid(concatenate)) # (0代表是一類,1代表不是一類) print(example_batch[2].numpy())

輸出:
[[1.]
[1.]
[1.]
[1.]
[1.]
[1.]
[1.]
[0.]

2. 定義網絡結構

# 定義網絡 # 這里有一個計算每次卷積輸出大小的問題 # 網絡只要管forward的參數即可 # 網絡最終輸出兩個img經過網絡計算后的5個維度的表示 class SiameseNet(nn.Module):def __init__(self):super(SiameseNet, self).__init__()self.cnn = nn.Sequential(nn.Conv2d(1, 4, kernel_size=3, padding=1),nn.BatchNorm2d(4),nn.ReLU(inplace=True),nn.Conv2d(4, 8, kernel_size=3, padding=1),nn.BatchNorm2d(8),nn.ReLU(inplace=True),nn.Conv2d(8, 8, kernel_size=3, padding=1),nn.BatchNorm2d(8),nn.ReLU(inplace=True),)self.fc = nn.Sequential(nn.Linear(8 * 100 * 100, 500), # nn.BatchNorm2d(500),nn.ReLU(inplace=True),nn.Dropout(0.2),nn.Linear(500, 500), # nn.BatchNorm2d(500),nn.ReLU(inplace=True),nn.Dropout(0.2),nn.Linear(500, 5))def forward_once(self, x):output = self.cnn(x)output = output.view(output.size()[0], -1)output = self.fc(output)return outputdef forward(self, img0, img1):output1 = self.forward_once(img0)output2 = self.forward_once(img1)return output1, output2

3. 損失函數

# 損失函數,也是只用管forward里面的參數 class ContrastiveLoss(nn.Module):def __init__(self, margin=2.0):super(ContrastiveLoss, self).__init__()self.margin = margindef forward(self, output1, output2, label):distance = F.pairwise_distance(output1, output2, keepdim=True)loss = torch.mean((1-label) * torch.pow(distance, 2) +(label) * torch.pow(torch.clamp(self.margin - distance, min=0.0), 2))return loss

4. 訓練,保存和加載模型

4.1 定義訓練函數

# 數據集,網絡,損失函數,優化器 # 數據集就是先通過ImageFolder得到(按文件夾分類的)dataset,再傳進SiameseDataset類得到自己要的(每次返回img0,img1,label)數據類型, 最后傳入DataLoader得到batch # 訓練 train_dataloader = DataLoader(siamese_dataset,shuffle=True,num_workers=8,batch_size=Config.train_batch_size) net = SiameseNet().cuda() criterion = ContrastiveLoss() optimizer = optim.Adam(net.parameters(), lr=0.0005)#from torch import optim # 定義兩個列表畫loss曲線 # 把loss添加到loss_history中,把iteration添加到counter中def train():counter = []loss_history = []iteration_number = 0for epoch in range(0, Config.train_epoch):for i, data in enumerate(train_dataloader, 0):img0, img1, label = dataimg0, img1, label = img0.cuda(), img1.cuda(), label.cuda()# 每次梯度都先要清零optimizer.zero_grad()output1, output2 = net(img0, img1)loss = criterion(output1, output2, label)# 計算梯度loss.backward()# 優化optimizer.step()if i % 10 == 0:print('Epoch number {}\n Current loss {}\n'.format(epoch, loss.item()))iteration_number += 10counter.append(iteration_number)loss_history.append(loss.item())show_loss(counter, loss_history)return net

4.2 訓練和保存

model = train() torch.save(model.state_dict(), './model/model.pt') print('Model saved successfully')

訓練誤差曲線圖:

200個epoch后的loss為:

4.3 加載保存的模型

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = SiameseNet().to(device) model.load_state_dict(torch.load('./model/model.pt'))

5. 測試

5.1 載入數據

folder_dataset_test = datasets.ImageFolder(root=Config.test_dir) siamese_dataset_test = SiameseDataset(imageFolderDataset=folder_dataset_test,transform=transform,should_invert=False) test_dataloader = DataLoader(siamese_dataset_test, num_workers=6, batch_size=1, shuffle=True) dataiter = iter(test_dataloader)

5.2 抽樣測試

# Print the sample outputs to view its dissimilarity counter=0 list_0 = torch.FloatTensor([[0]]) list_1 = torch.FloatTensor([[1]]) for i, data in enumerate(test_dataloader,0): x0, x1 , label = dataconcatenated = torch.cat((x0,x1),0)output1,output2 = model(x0.to(device),x1.to(device))distance = F.pairwise_distance(output1, output2)if label==list_0:label="Same"else:label="Not same"imshow(torchvision.utils.make_grid(concatenated),'Similarity: {:.2f} Label: {}'.format(1/distance.item(),label))counter=counter+1if counter ==20:break

5.3 整體準確率測試

# 1.item() 返回此張量的值作為標準Python數。這僅適用于具有一個元素的張量。 # 2.tolist() 將張量作為(嵌套)列表返回。可定位到矩陣的具體位置。 # test_dataloader = DataLoader(test_dataloader,num_workers=6,batch_size=1,shuffle=True) accuracy=0 counter=0 correct=0 for i, data in enumerate(test_dataloader,0):x0, x1 , label = dataoutput1,output2 = model(x0.to(device),x1.to(device))res=F.pairwise_distance(output1.cuda(), output2.cuda())res = 1/reslabel=label[0].tolist()label=int(label[0]) # result=torch.max(res,1)[1][0]if res > 1:result = 0else:result = 1if label == result:correct=correct+1counter=counter+1accuracy=(correct/len(test_dataloader))*100 print("Accuracy:{}%".format(accuracy))

參考鏈接:
[1]: https://innovationincubator.com/siamese-neural-network-with-pytorch-code-example/
[2]: https://github.com/harveyslash/Facial-Similarity-with-Siamese-Networks-in-Pytorch

總結

以上是生活随笔為你收集整理的孪生网络实验记录的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。