乐趣区

关于人工智能:建立一个植物毒性分类器数据准备和清理

作者 |Kenichi Nakanishi
编译 |VK
起源 |Towards Data Science

我有一个爱买动物的未婚妻,还有一只爱啃动物的猫——我想,有什么比把一个能通知我动物是否平安的分类器更好呢!

须要留神的一点是,这里所做的所有工作都是在 google colabs 上实现的,应用的 notebook 能够在我的 Github 上找到:https://github.com/kenichinak…


步骤 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 = aspca_df[aspca_df['Scientific Name'] == unknown_name]

  # 依据 ID 查找从 wfo 数据库中获取已承受的数据
  true_data = 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 = aspca_df.iloc[i,:]
  synonym_name = synonym_data.loc['Scientific Name']

  # 依据 ID 查找从 wfo 数据库中获取已承受的数据
  true_data = 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/fas…。对于这个我的项目,我想扩大雷同的办法,但将其利用到更大的类汇合中。这个过程实际上能够分为几个步骤:

  1. 获取类列表

因为 beauthulsoup,从 web 页面中获取表格或文本数据非常简单,通常只须要通过正则表达式或内置 python 办法进行更多解决。

清理和验证下载数据的准确性是这一步中最大的挑战。当咱们有 10 个类和畛域常识时,在持续之前很容易发现错误并修复它们。当咱们有 500 个类,事件就变得更难了。一个独立的数据源是至关重要的,咱们能够依据它来验证咱们的数据。在这种状况下,咱们信赖 ASPCA 数据中的毒性信息,但不信赖它们提供的学名,因而必须应用 WFO 数据库对其进行更正,后者提供了最新的分类信息。

  1. 获取每个类的图像 url 列表

咱们能够执行搜寻,找到缩略图并下载,甚至能够下载失去更大分辨率的图像。

  1. 将每个图像下载到带标签的文件夹中

用于下载图像的 fastai 函数运行良好,然而一个次要的绊脚石是下载反复的图像。如果你想要更多的图片(10-15 张),并且你下载了谷歌图片搜寻的所有后果,你很快就会失去大量的图片正本。此外,该函数无奈解决 base64 编码的图像。值得庆幸的是,fastai 提供了它们的源代码,能够对其进行批改,以解释编码的图像以及下载 http 链接,下载后对它们进行哈希解决,并且只保留惟一的图像。

原文链接:https://towardsdatascience.co…

欢送关注磐创 AI 博客站:
http://panchuang.net/

sklearn 机器学习中文官网文档:
http://sklearn123.com/

欢送关注磐创博客资源汇总站:
http://docs.panchuang.net/

退出移动版