python?pytorch圖像識(shí)別基礎(chǔ)介紹
一、數(shù)據(jù)集爬取
現(xiàn)在的深度學(xué)習(xí)對(duì)數(shù)據(jù)集量的需求越來(lái)越大了,也有了許多現(xiàn)成的數(shù)據(jù)集可供大家查找下載,但是如果你只是想要做一下深度學(xué)習(xí)的實(shí)例以此熟練一下或者找不到好的數(shù)據(jù)集,那么你也可以嘗試自己制作數(shù)據(jù)集——自己從網(wǎng)上爬取圖片,下面是通過(guò)百度圖片爬取數(shù)據(jù)的示例。
import os
import time
import requests
import re
def imgdata_set(save_path,word,epoch):
q=0 #停止爬取圖片條件
a=0 #圖片名稱
while(True):
time.sleep(1)
url="https://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word={}&pn={}&ct=&ic=0&lm=-1&width=0&height=0".format(word,q)
#word=需要搜索的名字
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.56'
}
response=requests.get(url,headers=headers)
# print(response.request.headers)
html=response.text
# print(html)
urls=re.findall('"objURL":"(.*?)"',html)
# print(urls)
for url in urls:
print(a) #圖片的名字
response = requests.get(url, headers=headers)
image=response.content
with open(os.path.join(save_path,"{}.jpg".format(a)),'wb') as f:
f.write(image)
a=a+1
q=q+20
if (q/20)>=int(epoch):
break
if __name__=="__main__":
save_path = input('你想保存的路徑:')
word = input('你想要下載什么圖片?請(qǐng)輸入:')
epoch = input('你想要下載幾輪圖片?請(qǐng)輸入(一輪為60張左右圖片):') # 需要迭代幾次圖片
imgdata_set(save_path, word, epoch)
通過(guò)上述的代碼可以自行選擇自己需要保存的圖片路徑、圖片種類(lèi)和圖片數(shù)目。如我下面做的幾種常見(jiàn)的盆栽植物的圖片爬取,只需要執(zhí)行六次代碼,改變相應(yīng)的盆栽植物的名稱就可以了。下面是爬取盆栽蘆薈的輸入示例,輸入完成后按Enter執(zhí)行即可,會(huì)自動(dòng)爬取圖片保存到指定文件夾,

如圖即為爬取后的圖片。

可以看到圖片中出現(xiàn)了一些無(wú)法打開(kāi)的圖片,同時(shí)因?yàn)槭侵苯优廊〉木W(wǎng)絡(luò)上的圖片,可能會(huì)出現(xiàn)一些相同的圖片,這些都需要進(jìn)行刪除,這就需要我們進(jìn)行第二步處理了。
二、數(shù)據(jù)處理
由于上面直接爬取到的圖片有一些瑕疵,這就需要對(duì)圖片進(jìn)行進(jìn)一步的處理了,對(duì)圖片進(jìn)行去重處理
通過(guò)重復(fù)圖片去重處理,將自己需要的數(shù)據(jù)集按照種類(lèi)分別保存在各自的文件夾里。同樣,由于數(shù)據(jù)集可能存在無(wú)法打開(kāi)的圖片,這就需要對(duì)數(shù)據(jù)集進(jìn)行下一步處理了。
首先將上面去重處理后的文件夾統(tǒng)一保存在同一個(gè)文件夾里面,如下圖所示。

記住此文件夾路徑,我這里是‘C:\Users\Lenovo\Desktop\data’,將此路徑輸入到下面代碼中。
import os
from PIL import Image
root_path=r"C:\Users\Lenovo\Desktop\data" #待處理文件夾絕對(duì)路徑(可按‘Ctrl+Shift+c'復(fù)制)
root_names=os.listdir(root_path)
for root_name in root_names:
path=os.path.join(root_path,root_name)
print("正在刪除文件夾:",path)
names=os.listdir(path)
names_path=[]
for name in names:
# print(name)
img=Image.open(os.path.join(path,name))
name_path=os.path.join(path,name)
if img==None: #篩選無(wú)法打開(kāi)的圖片
names_path.append(name_path)
print('成功保存錯(cuò)誤圖片路徑:{}'.format(name))
else:
w,h=img.size
if w<50 or h<50: #篩選錯(cuò)誤圖片
names_path.append(name_path)
print('成功保存特小圖片路徑:{}'.format(name))
print("開(kāi)始刪除需刪除的圖片")
for r in names_path:
os.remove(r)
print("已刪除:",r)
經(jīng)過(guò)上述處理即完成了圖片數(shù)據(jù)集的處理。最后,也可以對(duì)圖片數(shù)據(jù)集進(jìn)行圖片名稱的處理,使圖片的名稱重新從零開(kāi)始依次排列,方便計(jì)數(shù)(注意下面代碼中的rename將會(huì)刪除掉原文件夾中的圖片)。
import os
root_dir=r"C:\Users\Lenovo\Desktop\pzlh" #原文件夾路徑
save_path=r"C:\Users\Lenovo\Desktop\pzlh2" #新建文件夾路徑
img_path=os.listdir(root_dir)
a=0
for i in img_path:
a+=1
i= os.path.join(os.path.abspath(root_dir), i)
new_name=os.path.join(os.path.abspath(save_path), str(a) + '_pzlh.jpg') #此處可以修改圖片名稱
os.rename(i,new_name) #特別注意:rename會(huì)刪除原圖
最后,我們可以得到一個(gè)將完整的常見(jiàn)盆栽植物的數(shù)據(jù)集。如果此時(shí)數(shù)據(jù)集的圖片數(shù)量不多,我們還可以采用數(shù)據(jù)增強(qiáng)的方法,如旋轉(zhuǎn),加噪等步驟,都可以在網(wǎng)上找到相應(yīng)的教程。最后,我們可以得到數(shù)據(jù)集如下圖所示。

三、開(kāi)始識(shí)別
首先,先為上面的圖片數(shù)據(jù)集生成對(duì)應(yīng)的標(biāo)簽文件,運(yùn)行下面代碼可以自動(dòng)生成對(duì)應(yīng)的標(biāo)簽文件。
import os
root_path=r"C:\Users\Lenovo\Desktop\data"
save_path=r"C:\Users\Lenovo\Desktop\data_label" #對(duì)應(yīng)的label文件夾下也要建好相應(yīng)的空子文件夾
names=os.listdir(root_path) #得到images文件夾下的子文件夾的名稱
for name in names:
path=os.path.join(root_path,name)
img_names=os.listdir(path) #得到子文件夾下的圖片的名稱
for img_name in img_names:
save_name = img_name.split(".jpg")[0]+'.txt' #得到相應(yīng)的lable名稱
txt_path=os.path.join(save_path,name) #得到label的子文件夾的路徑
with open(os.path.join(txt_path,save_name), "w") as f: #結(jié)合子文件夾路徑和相應(yīng)子文件夾下圖片的名稱生成相應(yīng)的子文件夾txt文件
f.write(name) #將label寫(xiě)入對(duì)應(yīng)txt文件夾
print(f.name)
然后,將上面已經(jīng)準(zhǔn)備好的數(shù)據(jù)集按照7:3(其他比例也可以)分為訓(xùn)練數(shù)據(jù)集和驗(yàn)證數(shù)據(jù)集(圖片和標(biāo)簽一定要完全對(duì)應(yīng)即對(duì)應(yīng)圖片和標(biāo)簽應(yīng)該都處于訓(xùn)練集或者數(shù)據(jù)集),并如下圖所示放置。

最后,數(shù)據(jù)集準(zhǔn)備好后,即可導(dǎo)入到模型開(kāi)始訓(xùn)練,運(yùn)行下列代碼
import time
from torch.utils.tensorboard import SummaryWriter
from torchvision.datasets import ImageFolder
from torchvision import transforms
from torch.utils.data import DataLoader
import torchvision.models as models
import torch.nn as nn
import torch
print("是否使用GPU訓(xùn)練:{}".format(torch.cuda.is_available())) #打印是否采用gpu訓(xùn)練
if torch.cuda.is_available:
print("GPU名稱為:{}".format(torch.cuda.get_device_name())) #打印相應(yīng)的gpu信息
#數(shù)據(jù)增強(qiáng)太多也可能造成訓(xùn)練出不好的結(jié)果,而且耗時(shí)長(zhǎng),宜增強(qiáng)兩三倍即可。
normalize=transforms.Normalize(mean=[.5,.5,.5],std=[.5,.5,.5]) #規(guī)范化
transform=transforms.Compose([ #數(shù)據(jù)處理
transforms.Resize((64,64)),
transforms.ToTensor(),
normalize
])
dataset_train=ImageFolder('data/train',transform=transform) #訓(xùn)練數(shù)據(jù)集
# print(dataset_tran[0])
dataset_valid=ImageFolder('data/valid',transform=transform) #驗(yàn)證或測(cè)試數(shù)據(jù)集
# print(dataset_train.classer)#返回類(lèi)別
print(dataset_train.class_to_idx) #返回類(lèi)別及其索引
# print(dataset_train.imgs)#返回圖片路徑
print(dataset_valid.class_to_idx)
train_data_size=len(dataset_train) #放回?cái)?shù)據(jù)集長(zhǎng)度
test_data_size=len(dataset_valid)
print("訓(xùn)練數(shù)據(jù)集的長(zhǎng)度為:{}".format(train_data_size))
print("測(cè)試數(shù)據(jù)集的長(zhǎng)度為:{}".format(test_data_size))
#torch自帶的標(biāo)準(zhǔn)數(shù)據(jù)集加載函數(shù)
dataloader_train=DataLoader(dataset_train,batch_size=4,shuffle=True,num_workers=0,drop_last=True)
dataloader_test=DataLoader(dataset_valid,batch_size=4,shuffle=True,num_workers=0,drop_last=True)
#2.模型加載
model_ft=models.resnet18(pretrained=True)#使用遷移學(xué)習(xí),加載預(yù)訓(xùn)練權(quán)重
# print(model_ft)
in_features=model_ft.fc.in_features
model_ft.fc=nn.Sequential(nn.Linear(in_features,36),
nn.Linear(36,6))#將最后的全連接改為(36,6),使輸出為六個(gè)小數(shù),對(duì)應(yīng)六種植物的置信度
#凍結(jié)卷積層函數(shù)
# for i,para in enumerate(model_ft.parameters()):
# if i<18:
# para.requires_grad=False
# print(model_ft)
# model_ft.half()#可改為半精度,加快訓(xùn)練速度,在這里不適用
model_ft=model_ft.cuda()#將模型遷移到gpu
#3.優(yōu)化器
loss_fn=nn.CrossEntropyLoss()
loss_fn=loss_fn.cuda() #將loss遷移到gpu
learn_rate=0.01 #設(shè)置學(xué)習(xí)率
optimizer=torch.optim.SGD(model_ft.parameters(),lr=learn_rate,momentum=0.01)#可調(diào)超參數(shù)
total_train_step=0
total_test_step=0
epoch=50 #迭代次數(shù)
writer=SummaryWriter("logs_train_yaopian")
best_acc=-1
ss_time=time.time()
for i in range(epoch):
start_time = time.time()
print("--------第{}輪訓(xùn)練開(kāi)始---------".format(i+1))
model_ft.train()
for data in dataloader_train:
imgs,targets=data
# if torch.cuda.is_available():
# imgs.float()
# imgs=imgs.float()#為上述改為半精度操作,在這里不適用
imgs=imgs.cuda()
targets=targets.cuda()
# imgs=imgs.half()
outputs=model_ft(imgs)
loss=loss_fn(outputs,targets)
optimizer.zero_grad() #梯度歸零
loss.backward() #反向傳播計(jì)算梯度
optimizer.step() #梯度優(yōu)化
total_train_step=total_train_step+1
if total_train_step%100==0:#一輪時(shí)間過(guò)長(zhǎng)可以考慮加一個(gè)
end_time=time.time()
print("使用GPU訓(xùn)練100次的時(shí)間為:{}".format(end_time-start_time))
print("訓(xùn)練次數(shù):{},loss:{}".format(total_train_step,loss.item()))
# writer.add_scalar("valid_loss",loss.item(),total_train_step)
model_ft.eval()
total_test_loss=0
total_accuracy=0
with torch.no_grad(): #驗(yàn)證數(shù)據(jù)集時(shí)禁止反向傳播優(yōu)化權(quán)重
for data in dataloader_test:
imgs,targets=data
# if torch.cuda.is_available():
# imgs.float()
# imgs=imgs.float()
imgs = imgs.cuda()
targets = targets.cuda()
# imgs=imgs.half()
outputs=model_ft(imgs)
loss=loss_fn(outputs,targets)
total_test_loss=total_test_loss+loss.item()
accuracy=(outputs.argmax(1)==targets).sum()
total_accuracy=total_accuracy+accuracy
print("整體測(cè)試集上的loss:{}(越小越好,與上面的loss無(wú)關(guān)此為測(cè)試集的總loss)".format(total_test_loss))
print("整體測(cè)試集上的正確率:{}(越大越好)".format(total_accuracy / len(dataset_valid)))
writer.add_scalar("valid_loss",(total_accuracy/len(dataset_valid)),(i+1))#選擇性使用哪一個(gè)
total_test_step = total_test_step + 1
if total_accuracy > best_acc: #保存迭代次數(shù)中最好的模型
print("已修改模型")
best_acc = total_accuracy
torch.save(model_ft, "best_model_yaopian.pth")
ee_time=time.time()
zong_time=ee_time-ss_time
print("訓(xùn)練總共用時(shí):{}h:{}m:{}s".format(int(zong_time//3600),int((zong_time%3600)//60),int(zong_time%60))) #打印訓(xùn)練總耗時(shí)
writer.close()
上述采用的遷移學(xué)習(xí)直接使用resnet18的模型進(jìn)行訓(xùn)練,只對(duì)全連接的輸出進(jìn)行修改,是一種十分方便且實(shí)用的方法,同樣,你也可以自己編寫(xiě)模型,然后使用自己的模型進(jìn)行訓(xùn)練,但是這種方法顯然需要訓(xùn)練更長(zhǎng)的時(shí)間才能達(dá)到擬合。如圖所示,只需要修改矩形框內(nèi)部分,將‘model_ft=models.resnet18(pretrained=True)'改為自己的模型‘model_ft=model’即可。

四、模型測(cè)試
經(jīng)過(guò)上述的步驟后,我們將會(huì)得到一個(gè)‘best_model_yaopian.pth’的模型權(quán)重文件,最后運(yùn)行下列代碼就可以對(duì)圖片進(jìn)行識(shí)別了
import os
import torch
import torchvision
from PIL import Image
from torch import nn
i=0 #識(shí)別圖片計(jì)數(shù)
root_path="測(cè)試_data" #待測(cè)試文件夾
names=os.listdir(root_path)
for name in names:
print(name)
i=i+1
data_class=['滴水觀音','發(fā)財(cái)樹(shù)','非洲茉莉','君子蘭','盆栽蘆薈','文竹'] #按文件索引順序排列
image_path=os.path.join(root_path,name)
image=Image.open(image_path)
print(image)
transforms=torchvision.transforms.Compose([torchvision.transforms.Resize((64,64)),
torchvision.transforms.ToTensor()])
image=transforms(image)
print(image.shape)
model_ft=torchvision.models.resnet18() #需要使用訓(xùn)練時(shí)的相同模型
# print(model_ft)
in_features=model_ft.fc.in_features
model_ft.fc=nn.Sequential(nn.Linear(in_features,36),
nn.Linear(36,6)) #此處也要與訓(xùn)練模型一致
model=torch.load("best_model_yaopian.pth",map_location=torch.device("cpu")) #選擇訓(xùn)練后得到的模型文件
# print(model)
image=torch.reshape(image,(1,3,64,64)) #修改待預(yù)測(cè)圖片尺寸,需要與訓(xùn)練時(shí)一致
model.eval()
with torch.no_grad():
output=model(image)
print(output) #輸出預(yù)測(cè)結(jié)果
# print(int(output.argmax(1)))
print("第{}張圖片預(yù)測(cè)為:{}".format(i,data_class[int(output.argmax(1))])) #對(duì)結(jié)果進(jìn)行處理,使直接顯示出預(yù)測(cè)的植物種類(lèi)
最后,通過(guò)上述步驟我們可以得到一個(gè)簡(jiǎn)單的盆栽植物智能識(shí)別程序,對(duì)盆栽植物進(jìn)行識(shí)別,如下圖是識(shí)別結(jié)果說(shuō)明。

到這里,我們就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的深度學(xué)習(xí)圖像識(shí)別示例了。
總結(jié)
到此這篇關(guān)于python pytorch圖像識(shí)別基礎(chǔ)介紹的文章就介紹到這了,更多相關(guān)python pytorch圖像識(shí)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- pytorch繪制并顯示loss曲線和acc曲線,LeNet5識(shí)別圖像準(zhǔn)確率
- pytorch實(shí)現(xiàn)圖像識(shí)別(實(shí)戰(zhàn))
- Pytorch實(shí)現(xiàn)圖像識(shí)別之?dāng)?shù)字識(shí)別(附詳細(xì)注釋)
- 使用pytorch完成kaggle貓狗圖像識(shí)別方式
- PyTorch一小時(shí)掌握之圖像識(shí)別實(shí)戰(zhàn)篇
- PyTorch實(shí)現(xiàn)圖像識(shí)別實(shí)戰(zhàn)指南
- 圖文詳解如何利用PyTorch實(shí)現(xiàn)圖像識(shí)別
相關(guān)文章
Python快速進(jìn)修指南之向量數(shù)據(jù)庫(kù)文本搜索
這篇文章主要為大家介紹了Java開(kāi)發(fā)快速進(jìn)修Python指南之向量數(shù)據(jù)庫(kù)文本搜索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
Django使用Profile擴(kuò)展User模塊方式
這篇文章主要介紹了Django使用Profile擴(kuò)展User模塊方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-05-05
pycharm + django跨域無(wú)提示的解決方法
這篇文章主要給大家介紹了關(guān)于pycharm + django跨域無(wú)提示的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
Python程序自動(dòng)以管理員權(quán)限運(yùn)行的實(shí)現(xiàn)方法
Windows上為了安全起見(jiàn),python語(yǔ)言啟動(dòng)的應(yīng)用程序默認(rèn)都不會(huì)使用admin管理員權(quán)限,但是在有些情況下我們又需要使用管理員權(quán)限啟動(dòng)應(yīng)用,這篇文章主要給大家介紹了關(guān)于Python程序自動(dòng)以管理員權(quán)限運(yùn)行的實(shí)現(xiàn)方法,需要的朋友可以參考下2023-11-11
Python中基本數(shù)據(jù)類(lèi)型和常用語(yǔ)法歸納分享
這篇文章主要為大家整理記錄了Python中基本數(shù)據(jù)類(lèi)型和常用語(yǔ)法的使用,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-04-04
python數(shù)學(xué)建模是加深Numpy和Pandas學(xué)習(xí)
這篇文章主要介紹了python數(shù)學(xué)建模是加深Numpy和Pandas學(xué)習(xí),緊接上一篇學(xué)習(xí)內(nèi)容展開(kāi)Numpy更多相關(guān)內(nèi)容,需要的小伙伴可以參考一下2022-07-07
Jupyter Notebook切換conda虛擬環(huán)境的實(shí)現(xiàn)步驟
本文主要介紹了Jupyter Notebook切換conda虛擬環(huán)境的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
詳解python路徑拼接os.path.join()函數(shù)的用法
os.path.join()函數(shù):連接兩個(gè)或更多的路徑名組件。這篇文章主要介紹了python路徑拼接os.path.join()函數(shù)的用法,需要的朋友可以參考下2019-10-10
python json.dumps中文亂碼問(wèn)題解決
這篇文章主要介紹了如何解決python中中文亂碼問(wèn)題和json.dumps中文亂碼問(wèn)題,需要的朋友可以參考下2021-05-05

