作者|Kenichi Nakanishi
編譯|VK
來源|Towards Data Science

我有一個愛買植物的未婚妻,還有一只愛啃植物的貓——我想,有什么比把一個能告訴我植物是否安全的分類器更好呢!
需要注意的一點是,這里所做的所有作業都是在google colabs上完成的,使用的notebook可以在我的Github上找到:https://github.com/kenichinakanishi/houseplant_classifier
步驟1-獲取資料
不幸的是,我找不到一個適合我在Kaggle上或使用Google的資料集搜索的預先制作的影像資料集,所以,我準備建立我自己的!
我決定使用ASPCA的《貓和狗的植物毒性清單》,我已經用了好幾次了,這給了我們一個很好的核心作業,為了從網站上獲取這些文本資料,我們可以求助于BeautifulSoup,這是一個Python庫,用于從HTML和XML檔案中提取資料,
from urllib.request import Request, urlopen
from bs4 import BeautifulSoup
def getHTMLContent(link):
html = urlopen(link)
soup = BeautifulSoup(html, 'html.parser')
return soup
然而,當查看他們的網站時,該表并不是一個易于訪問的html表,而是將資料存盤為面板中的行,幸運的是,beauthulsoup為我們提供了一種簡單的方法來搜索決議樹,以找到我們想要的資料,例如:
req = Request('https://www.aspca.org/pet-care/animal-poison-control/cats-plant-list', headers={'User-Agent': 'Mozilla/5.0'})
webpage = urlopen(req).read()
# 爬取資料
soup = BeautifulSoup(webpage, 'lxml')
# 搜索決議樹以從表中獲得所有內容
content_list = soup.find_all('span')[7:-4]
# 將其放入一個dataframe中進行進一步處理
df_cats = pd.DataFrame(content_list)
在收集完原始資料后,我們需要將其分為多個列,并進行一些拆分:
# 清理字串
df_cats[0] = df_cats[0].apply(lambda x: str(x).split('>')[1][:-3])
df_cats[4] = df_cats[4].apply(lambda x: str(x).split('>')[1][:-3])
df_cats[1] = df_cats[1].apply(lambda x: str(x).split('(')[1][0:-4])
# 洗掉無用的列并重命名列
df_cats = df_cats.drop(columns=[2,3,5,6]).rename(columns = {0:'Name',1:'Alternative Names',4:'Scientific Name',7:'Family'})
# 將有毒和無毒植物分開
df_cats['Toxic to Cats'] = True
first_nontoxic_cats = [index for index in df_cats[df_cats['Name'].str.startswith('A')].index if index>100][0]
df_cats.loc[first_nontoxic_cats:,'Toxic to Cats'] = False
然后,我們可以對特定于狗的串列重復此程序,然后合并資料幀并清理nan:
# 合并資料框架到一個,用于保留只存在于一邊的值
df_catsdogs = df_dogs.merge(df_cats, how='outer', on=['Name','Alternative Names','Scientific Name','Family'])
df_catsdogs = df_catsdogs.fillna('Unknown')
aspca_df = df_catsdogs.copy()
# 假設對貓和狗有相同的毒性
aspca_df['Toxic to Cats'] = aspca_df.apply(lambda x: x['Toxic to Dogs'] if (x['Toxic to Cats'] == 'Unknown') else x['Toxic to Cats'], axis=1)
aspca_df['Toxic to Dogs'] = aspca_df.apply(lambda x: x['Toxic to Cats'] if (x['Toxic to Dogs'] == 'Unknown') else x['Toxic to Dogs'], axis=1)

步驟2-淺度清理
接下來,我們可以開始進行淺度清理,包括查看資料集,決定要使用哪些關鍵特征,并標準化它們的格式,

我們目前有名字,替代名稱,學名,家族以及毒性列,所有這些都是從用BeautifulSoup在ASPCA網站上爬來的,
由于我們將使用谷歌影像搜索收集影像,因此我們決定根據每種植物的確切學名進行搜索,以獲得盡可能具體的影像,像“珍珠點”、“大象耳朵”、“蓬松褶邊”和“粉紅珍珠”這樣的名字會很快回傳我們所尋找的植物之外的結果,

我們撰寫了幾個快速函式來應用于該系列,以嘗試將資料標準化以便進一步清理,
# 確保每個學名的標點符號正確
def normalize_capitalization(x):
first_word, rest = x.split()[0], x.split()[1:]
first_word = [first_word.capitalize()]
rest = [word.lower() for word in rest]
return ' '.join(first_word+rest)
# 清理那些名字不同的重復物種
def species_normalizer(word):
if word.split()[-1] in ['sp','species','spp','sp.','spp.']:
word = ''.join(word.split()[:-1])
return word
# 從名稱中洗掉cv,因為這是一種過時的表示品種的方式
def cv_remover(word):
if 'cv' in word:
word = word.replace(' cv ',' ')
return word
# 從名稱中洗掉var
def var_remover(word):
if 'var' in word:
word = word.replace(' var. ',' ')
return word
# 應用每個函式
aspca_df['Scientific Name'] = aspca_df['Scientific Name'].apply(normalize_capitalization)
aspca_df['Scientific Name'] = aspca_df['Scientific Name'].apply(species_normalizer)
aspca_df['Scientific Name'] = aspca_df['Scientific Name'].apply(cv_remover)
aspca_df['Scientific Name'] = aspca_df['Scientific Name'].apply(var_remover)
# 洗掉特殊字符
aspca_df['Scientific Name'] = aspca_df['Scientific Name'].apply(lambda x: ''.join([character for character in x if character.isalnum() or character.isspace()]))
# 進一步處理重置資料
aspca_df = aspca_df.sort_values('Scientific Name').drop_duplicates('Scientific Name')
aspca_df = aspca_df.reset_index(drop=True).sort_index()
步驟3-通過交叉參考進行深度清理
仔細研究一下我們的資料里的學名(Scientific Name),我們發現很多名稱是物種的過時同義詞,或者拼寫錯誤,這將在影像采集和以后的訓練模型識別具有不同標簽的相同影像時引起問題,
一個谷歌之后,我們發現了世界植物在線資料庫,一個開放存取的,基于網路的世界植物物種簡編(http://www.worldfloraonline.org/),它們列出了同義詞和公認的物種名稱,并由“分類學專家網路”定期更新,非常適合交叉參考我們不可靠的學名,這個資料庫以一個.txt檔案提供了它們的資料,我們可以讀入該檔案并與從ASPCA植物毒性資料庫中獲取的資料庫進行比較,
# 讀取WFO資料,只保留有用的列
use_cols = ['scientificName','taxonRank','family','genus','taxonomicStatus','taxonID', 'acceptedNameUsageID']
wfo_df = pd.read_csv('/content/drive/My Drive/Houseplant Classifier/classification.txt', sep='\t', lineterminator='\n', usecols=use_cols)
wfo_df = wfo_df.sort_values('taxonomicStatus')

作為第一步,我們將對來自ASPCA的資料進行左合并,保留我們的所有類,并添加與我們當前擁有的確切學名匹配的任何資料,我們的目標是將資料庫中的所有植物更新為最新的可接受的學名,
# 不需要這個列,我們更信任WFO資料庫
aspca_df.drop('Family', axis=1, inplace=True)
# 合并資料檔案以獲得可信資訊
aspca_df = aspca_df.merge(wfo_df, how = 'left', left_on = ['Scientific Name'], right_on = ['scientificName'])
# 按taxonomicStatus進行排序,并洗掉重復項,保持優先級為被接受的名稱
aspca_df = aspca_df.sort_values('taxonomicStatus').drop_duplicates('Scientific Name', keep='first').reset_index(drop=True)
# 用Unknown來填滿NaN
aspca_df = aspca_df.fillna('Unknown')
步驟3.1-用字串匹配修復印刷錯誤
許多學名指的是同一物種,但由于在ASPCA資料庫中的打字錯誤,有幾個字母被刪掉了,讓我們使用difflib中的SequenceMatcher來量化字串距離,通過比較WFO資料庫中不匹配的條目來發現這些錯誤,
我們可以對資料幀進行排序,只與以同一字母開頭的學名進行比較,以節省時間,如果名稱足夠相似,我們將保留它并最侄訓傳最接近的匹配項,這里我們將閾值設定為0.9,以避免任何不正確的匹配,
def get_closest_name(unknown_name, name_df = wfo_df, name_col = 'scientificName', threshold=0.9, verbose=False):
""" 將'unknown_name'與'name_df'中接受的名稱進行匹配,將回傳超過接近的“threshold”的名字.
Parameters
----------
unknown_name: str
我們希望與該名稱進行匹配.
name_df: DataFrame
包含名稱的資料框.
name_col: str, name of name_df column
包含可接受名稱的列
threshold: int
unknown_name需要在多大程度上與接受的名稱匹配
如果超過這個閾值,名稱將被添加到可能的名稱字典中
verbose: bool
函式是否列印整個串列
Returns:
----------
str
與‘unknown_name’最接近的、高于給定‘閾值’的名稱,
"""
import operator
from difflib import SequenceMatcher
def similar(a, b):
return SequenceMatcher(None, a, b).ratio()
poss_names = {}
# 為了節省時間,只看第一個字母相同的條目
for true_sciname in name_df[name_df[name_col].str.startswith(unknown_name[0])][name_col].values:
similar_score = similar(unknown_name, true_sciname)
if similar_score>threshold:
poss_names[true_sciname]=similar_score
# 如果dict為空
if verbose == True:
print(poss_names)
if not bool(poss_names):
print(f'No names close enough to {unknown_name}.')
return ''
else:
print(f'{unknown_name} is closest to {max(poss_names.items(), key=operator.itemgetter(1))[0]}, with a score of {max(poss_names.items(), key=operator.itemgetter(1))[1]:.2f}')
return max(poss_names.items(), key=operator.itemgetter(1))[0]
我們還定義了一個函式來修復資料中的問題條目,它將把它們的學名、科、屬和分類狀態更新為WFO資料庫中的(正確的)相應條目,
def fix_name(unknown_name, true_name):
""" 根據已接受的wfo_df條目修復aspca_df條目.
Parameters
----------
unknown_name: str
我們想要修復的名字.
true_name: DataFrame
修復的名稱.
"""
#得到我們想要改變的列
unknown_data = https://www.cnblogs.com/panchuangai/p/aspca_df[aspca_df['Scientific Name'] == unknown_name]
# 根據ID查找從wfo資料庫中獲取已接受的資料
true_data = https://www.cnblogs.com/panchuangai/p/wfo_df[wfo_df['scientificName'] == true_name]
true_sciname = true_data.loc[:,'scientificName'].values[0]
true_family = true_data.loc[:,'family'].values[0]
true_genus = true_data.loc[:,'genus'].values[0]
true_taxonomicStatus = true_data.loc[:,'taxonomicStatus'].values[0]
# 更改學名、科、屬和分類學地位為可接受的版本
aspca_df.iloc[unknown_data.index,2] = true_sciname
aspca_df.iloc[unknown_data.index,8] = true_family
aspca_df.iloc[unknown_data.index,9] = true_genus
aspca_df.iloc[unknown_data.index,10] = true_taxonomicStatus
現在,我們可以遍歷我們的資料,搜索匹配的名稱并當場更正它們對應的資料幀條目,
unknown_idx = aspca_df[aspca_df.taxonomicStatus == 'Unknown'].index
print(f'{len(unknown_idx)} plants currently cannot be matched.')
from tqdm.notebook import tqdm
for i in tqdm(unknown_idx):
unknown_name = aspca_df.iloc[i,2]
closest_name = get_closest_name(unknown_name)
if closest_name == '':
continue
fix_name(unknown_name,closest_name)
此程序有助于我們發現錯誤,否則需要進行深入的檢查

步驟3.2-人工清理不明物種
不幸的是,許多未被確認的物種在資料庫中沒有一個足夠接近的條目,因此,我們對剩余的未知項進行一些手動修復,謝天謝地,上面的代碼將需要手動關注的樣本數量減少到了50個左右,我們可以重新使用之前的fix_name函式,根據我們在Google上找到的正確條目來修復這些條目,

步驟3.3-匹配同義學名
既然學名已經全部更正,我們仍然需要對它們進行標準化,因為隨著研究的更新,學名可能會隨著時間的推移而改變(導致在“分類狀態”列中出現同義詞標簽),如果一個學名是一個公認的名字的同義詞,我們希望在將來的谷歌影像搜索中使用這個被接受的名字,

# 更新剩下的已接受的學名的同義詞學名
aspca_df = aspca_df.sort_values('taxonomicStatus').drop_duplicates('Scientific Name', keep='first').reset_index(drop=True)
synonym_idx = aspca_df[aspca_df['taxonomicStatus'].values == 'Synonym'].index
for i in synonym_idx:
# 得到我們想要改變的列
synonym_data = https://www.cnblogs.com/panchuangai/p/aspca_df.iloc[i,:]
synonym_name = synonym_data.loc['Scientific Name']
# 根據ID查找從wfo資料庫中獲取已接受的資料
true_data = https://www.cnblogs.com/panchuangai/p/wfo_df[wfo_df['taxonID'] == synonym_data.loc['acceptedNameUsageID']]
true_sciname = true_data.iloc[:,1].values[0]
fix_name(synonym_name,true_sciname)
幸運的是,WFO資料庫包含一個acceptedNameUsageID欄位,該欄位包含給定同義學名的可接受名稱,我們可以利用該欄位查找接受的學名并將其傳遞到fix_name函式中,
步驟3.4-結束
現在,我們已經糾正了拼寫錯誤(自動和手動),并將發回的同義詞與最新的已接受名稱進行了匹配,剩下的就是清理影像下載的資料幀,
# 再次排序并洗掉
aspca_df = aspca_df.sort_values('taxonomicStatus').drop_duplicates('Scientific Name', keep='first')
aspca_df = aspca_df.sort_values('Scientific Name').reset_index(drop=True).sort_index()
# 設定一個單詞名稱的屬作為名稱,而不是NaN
aspca_df.loc[aspca_df.fillna('Unknown')['genus']=='Unknown', 'genus'] = aspca_df.loc[aspca_df.fillna('Unknown')['genus']=='Unknown', 'Scientific Name']
# 洗掉我們不再需要的行
aspca_df = aspca_df.drop(['taxonID', 'scientificName', 'taxonomicStatus', 'acceptedNameUsageID', 'taxonRank'], axis=1)
# 標準化列名
aspca_df.rename(columns = {'genus':'Genus', 'family':'Family'}, inplace=True)
# 重新排序
cols = ['Name', 'Scientific Name', 'Genus', 'Family', 'Alternative Names', 'Toxic to Dogs', 'Toxic to Cats']
aspca_df = aspca_df[cols]
這個程序需要多次迭代才能使方法正確,然而,在我們建立影像資料庫之前,確保我們有干凈的資料可以作業,這在花費時間訓練模型之前是至關重要的,
從最終的寵物植物毒性資料框架中得出一些有趣的結論:
-
110個植物家族中有33個并非完全有毒或無毒,
-
350個植物屬中有7個并非完全有毒或無毒,
-
只有兩種植物表現出物種特異性毒性,莉莉花對貓和核桃對狗!
步驟4-下載影像
下載影像的第一步是獲取我們想要獲取的每個影像的url,為此,我們根據fabianbosler的一篇文章,采用了一種基于Selenium的方法,
Selenium是一個用于測驗web應用程式的可移植框架,Selenium webdriver充當我們的虛擬瀏覽器,可以通過python命令進行控制,
這里使用一個腳本來搜索Google圖片,我們給它一個查詢,只查找和下載縮略圖的網址,因為我們要抓取很多圖片,一個問題是,谷歌的許多影像縮略圖存盤為base64編碼的影像,我們還想抓取這些圖片,這樣我們就不會錯過任何具有高度相關性的圖片,因為我們在搜索結果中走的越遠,這些圖片就越不適合用于訓練目的,
# 如果運行在Colab
!pip install selenium -q
!apt-get update # to update ubuntu to correctly run apt install
!apt install chromium-chromedriver -q
!cp /usr/lib/chromium-browser/chromedriver /usr/bin
import sys
sys.path.insert(0,'/usr/lib/chromium-browser/chromedriver')
# 匯入并設定Selenium webdriver
from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
wd = webdriver.Chrome('chromedriver',chrome_options=chrome_options)
import requests
import time
def fetch_thumbnail_urls(query:str, max_links_to_fetch:int, wd:webdriver, sleep_between_interactions:int=1, non_commercial=False, shuffle=False):
""" 使用Selenium webdriver (wd)根據查詢從谷歌影像中收集url
可以將sleep_between_interactions更改為適應較慢的計算機,
如果shuffle為真,則回傳的url串列將被打亂為隨機順序
Parameters
----------
query: str
傳遞給谷歌影像,
max_links_to_fetch: int
要獲取的url數目,
wd: Selenium webdriver
要使用的webdriver實體,
sleep_between_interactions: int
在webdriver互動之間等待的時間(秒),
non_commercial: bool
標記僅為非商業用途,
shuffle: bool
回傳的url順序是否打亂,
Returns:
----------
List
url的串列,
"""
def scroll_to_end(wd):
wd.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(sleep_between_interactions)
# 構建谷歌查詢
if non_commercial == True:
search_url = 'https://www.google.com/search?as_st=y&source=hp&safe=off&tbm=isch&as_epq={q}&gs_l=img&tbs=sur%3Af'
else:
search_url = "https://www.google.com/search?as_st=y&source=hp&safe=off&tbm=isch&as_epq={q}&gs_l=img"
# 加載頁面
wd.get(search_url.format(q=query))
image_urls = []
image_count = 0
results_start = 0
while image_count < max_links_to_fetch:
scroll_to_end(wd)
# 獲得所有影像縮略圖結果
thumbnail_results = wd.find_elements_by_css_selector("img.Q4LuWd")
number_results = len(thumbnail_results)
for img in thumbnail_results:
# 提取影像url,如果它們是可用的地址
if img.get_attribute('src') and 'http' in img.get_attribute('src'):
image_urls.append(img.get_attribute('src'))
# 還獲取了谷歌使用的編碼影像
elif img.get_attribute('src') and 'data' in img.get_attribute('src'):
image_urls.append(img.get_attribute('src'))
image_count = len(image_urls)
# 如果我們達到指定的配額就中斷
if len(image_urls) >= max_links_to_fetch:
break
# 如果我們需要更多的圖片,點擊加載更多圖片按鈕
else:
time.sleep(30)
load_more_button = wd.find_element_by_css_selector(".mye4qd")
if load_more_button:
wd.execute_script("document.querySelector('.mye4qd').click();")
# 移動指標
results_start = len(thumbnail_results)
if shuffle==True:
random.shuffle(image_urls)
return image_urls
太好了!現在我們有了一種從谷歌圖片中獲取圖片的方法!為了下載我們的圖片,我們將利用fast.ai v2,然而,我們將深入研究源代碼并對其進行一點升級,以便在影像進入時對其進行哈希處理,并忽略/洗掉任何重復項,以便最終得到一致的唯一影像集,我們還將允許它解碼和下載編碼的.jpg和.png影像,這是谷歌影像用來存盤縮略圖的格式,
# 每個會話運行一次
!pip install fastai==2.0.14 -q
from fastai.vision.all import *
import io
from PIL import Image
import base64
import hashlib
def download_images(dest, url_file=None, urls=None, max_pics=150, n_workers=1, timeout=4):
"""
下載文本檔案' url_file '中列出的圖片到路徑' dest ',最多下載' max_pics '個
下載影像后,在保存之前將哈希與其他影像哈希進行比較,
如果哈希已經存在,則嘗試下一個url,
Parameters
----------
dest: Path or str
下載目標檔案夾,
url_file:
URL檔案,\n作為分隔符
urls:
url的串列,
max_pics: int
要下載的影像數量,
n_workers: int
要并行使用的內核數量,
Returns:
----------
從給定的url下載影像到dest目錄,
"""
hash_keys = dict()
# 設定哈希以防止復制影像下載
if urls is None: urls = url_file.read().strip().split("\n")
dest = Path(dest)
dest.mkdir(exist_ok=True)
# n_workers必須是1,因為我們在下載程序中檢查唯一的影像
parallel(partial(_download_image_inner, dest, timeout=timeout, max_pics=max_pics), list(enumerate(urls)), n_workers=1)
def _download_image_inner(dest, inp, timeout=4, max_pics=150):
# 輸入是一個列舉物件
i,url = inp
suffix = re.findall(r'\.\w+?(?=(?:\?|$))', url)
suffix = suffix[0] if len(suffix)>0 else '.jpg'
# 如果我們有足夠的圖片,什么都不用做,直到url用完
if len(dest.ls()) >= max_pics:
return
# 函式處理base64編碼的影像
# 如果抓取的url是已編碼的jpg格式,將其解碼并與其他格式一起保存
try:
if url[:15] == 'data:image/jpeg':
encoded_image = url[url.find('/9'):]
im = Image.open(io.BytesIO(base64.b64decode(encoded_image)))
filehash = hashlib.md5(im.tobytes()).hexdigest()
if filehash not in hash_keys:
hash_keys[filehash] = i
im.save(dest/f"{i:08d}{suffix}")
else:
pass
except:
pass
# 函式處理base64編碼的影像
# 如果抓取的url是已編碼的png,將其解碼并將其與其余內容一起行內保存
try:
if url[:14] == 'data:image/png':
encoded_image = url[url.find('iVBOR'):]
im = Image.open(io.BytesIO(base64.standard_b64decode(encoded_image))).convert('RGB')
filehash = hashlib.md5(im.tobytes()).hexdigest()
if filehash not in hash_keys:
hash_keys[filehash] = i
im.save(dest/f"{i:08d}{suffix}")
else:
pass
except:
pass
# 如果抓取的url是一個http站點,下載它,并檢查我們還沒有得到相同的影像,
try:
download_url(url, dest/f"{i:08d}{suffix}", overwrite=True, show_progress=True, timeout=timeout)
im = Image.open(dest/f"{i:08d}{suffix}")
filehash = hashlib.md5(im.tobytes()).hexdigest()
if filehash not in hash_keys:
hash_keys[filehash] = i
else:
(dest/f"{i:08d}{suffix}").unlink()
except Exception as e: f"Couldn't download {url}."
現在,我們可以遍歷我們的每一個科學植物名稱,收集它們的網址,然后下載這些圖片,同時驗證這些圖片是否是唯一的,每一組影像都下載到Colabs上我的鏈接驅動器中自己的檔案夾中,需要注意的一點是,由于google images上存在大量重復的圖片,要抓取的url數量必須遠遠大于你最終想要的圖片數量,
# 實體化webdriver
wd = webdriver.Chrome('chromedriver',options=options)
from tqdm.notebook import tqdm
import itertools
scientific_names = aspca_df['Scientific Name']
# 回圈所有室內植物的名字,抓取url并下載到我的谷歌驅動器
for name in tqdm(scientific_names):
try:
path = Path('/content/drive/My Drive/Houseplant Classifier/plant_images_deepest');
folder = name
dest = path/folder
dest.mkdir(parents=True, exist_ok=True)
if len(dest.ls())<150:
print(f'{name} has {len(dest.ls())} images.')
url_science = fetch_thumbnail_urls(f'{name}', max_links_to_fetch = 600, wd=wd, non_commercial = False, shuffle = False)
dest = path/folder
# 強制重繪hash_key—在函式中作為全域變數存盤,這里清空
hash_keys = dict()
download_images(path/folder, urls = url_science, max_pics=150)
print(f'Finished downloading images of {name} : {len(dest.ls())} images downloaded.')
else:
print(f'{name} already has sufficient images.')
except Exception as e:
print(f'Error with {name}. {e}')
下載后,我們將采取步驟確保每個檔案夾包含正確數量的唯一影像,
因此,在這個階段,這些圖片被整齊地分到各自的檔案夾中,并直接放在我們的谷歌硬碟上,需要注意的是,如果你想用這些圖片來訓練CNN,如果你在使用它們之前把這些圖片帶到本地的Colab環境中,但這將在下一篇文章中進一步討論,
最后
從零開始構建資料庫影像分類專案對于簡單的玩具示例來說很簡單,參見fast.ai v2一個棕色/黑色/泰迪熊分類器的好例子(https://github.com/fastai/fastbook/blob/master/02_production.ipynb),對于這個專案,我想擴展相同的方法,但將其應用到更大的類集合中,這個程序實際上可以分為幾個步驟:
- 獲取類串列
由于beauthulsoup,從web頁面中獲取表格或文本資料非常簡單,通常只需要通過正則運算式或內置python方法進行更多處理,
清理和驗證下載資料的準確性是這一步中最大的挑戰,當我們有10個類和領域知識時,在繼續之前很容易發現錯誤并修復它們,當我們有500個類,事情就變得更難了,一個獨立的資料源是至關重要的,我們可以根據它來驗證我們的資料,在這種情況下,我們信任ASPCA資料中的毒性資訊,但不信任它們提供的學名,因此必須使用WFO資料庫對其進行更正,后者提供了最新的分類資訊,
- 獲取每個類的影像url串列
我們可以執行搜索,找到縮略圖并下載,甚至可以下載得到更大解析度的影像,
- 將每個影像下載到帶標簽的檔案夾中
用于下載影像的fastai函式運行良好,但是一個主要的絆腳石是下載重復的影像,如果你想要更多的圖片(10-15張),并且你下載了谷歌圖片搜索的所有結果,你很快就會得到大量的圖片副本,此外,該函式無法處理base64編碼的影像,值得慶幸的是,fastai提供了它們的源代碼,可以對其進行修改,以解釋編碼的影像以及下載http鏈接,下載后對它們進行哈希處理,并且只保留唯一的影像,
原文鏈接:https://towardsdatascience.com/creating-a-plant-pet-toxicity-classifier-a29587f3f04c
歡迎關注磐創AI博客站:
http://panchuang.net/
sklearn機器學習中文官方檔案:
http://sklearn123.com/
歡迎關注磐創博客資源匯總站:
http://docs.panchuang.net/
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/211579.html
標籤:其他
上一篇:使用NLP創建摘要
