CV看圖說故事_Phase1.COCO資料集載入與劃分
COCO 是一個大規模的物件偵測、分割與影像描述資料集。COCO 有幾項特色:
- Object segmentation
- Recognition in context
- Superpixel stuff segmentation
- 330K images (>200K labeled)
- 1.5 million object instances
- 80 object categories
- 91 stuff categories
- 5 captions per image
- 250,000 people with keypoints
COCO數據集資料LINK
http://images.cocodataset.org/zips/train2014.zip
http://images.cocodataset.org/zips/val2014.zip
http://images.cocodataset.org/annotations/annotations_trainval2014.zip
下載解壓後存放至Jupyter Notebook專案之下,檔案大小依序分別如下(過程要等一段時間)
val2014.zip 大小6.18GB
train2014.zip 大小12.5GB
annotations_trainval2014.zip 大小241MB
記得解壓縮存放到./data相對目錄下
captions_train2014.json 或 captions_val2014.json JSON 檔中找到,而所有影像都放在 train2014 或 val2014 資料夾中。
關於JSON檔案格式基本上
可以使用如下程式碼,先觀察到有以下四個主要KEY值
info、image、license 和 annotation
import json valcaptions = json.load(open( './data/annotations/captions_val2014.json', 'r')) trcaptions = json.load(open( './data/annotations/captions_train2014.json', 'r')) # inspect the annotations print(trcaptions.keys())
起初目標就是先產生一個簡單的單一檔,包含兩
一欄是影像檔名,另一欄則為該檔案的描述(caption)。
而根據論文 Deep Visual-Semantic Alignments for Generating Image Descriptions
一篇關於影像描述的論文,提出一個可為影像及其區域產生自然語言描述的模型。
這篇論文方法利用影像及其句子描述的資料集,學習語言與視覺資料之間的跨模態對應關係。
該論文實驗是拿 5,000 張圖片拿來做 validation 集,此外建議對所有訓練與驗證影像一起進行訓練。而COCO資料集特點是每張影像都有5段描述,因此驗證集不能根據描述資料來切分。
以下是後半部程式處理
prefix = "./data/" val_prefix = prefix + 'val2014/' train_prefix = prefix + 'train2014/' # training images,前面用 json.load 讀進來的 captions_train2014.json #裡面的 images 是一個 list,根據id,file_name來組對應key-value pair的dict #對 images 裡的每一個 x #key:x['id'](圖片的數字 ID) #value:x['file_name'](那張圖的檔名) trimages = {x['id']: x['file_name'] for x in trcaptions['images']} # validation images # take half images from validation - karpathy split #valcaptions['images']是 captions_val2014.json 裡的 images list,包含 COCO 的 全部 val2014 圖片資訊。 #這邊保留後面5000張影像留著作為後續驗證測試用途,前面全部拿來訓練。 valset = len(valcaptions['images']) - 5000 # leave last 5k valimages = {x['id']: x['file_name'] for x in valcaptions['images'][:valset]} #從 index 0 到 valset - 1 truevalimg = {x['id']: x['file_name'] for x in valcaptions['images'][valset:]} #從 valset 一直到最後 #Flatten to (caption, image_path) structure data = list() #放「訓練用」的資料:每一筆都是 (caption, image_path) errors = list() #放「保留做驗證/測試」的資料 validation = list() #放「有問題的標註」,例如找不到對應圖片 id 的 annotation for item in trcaptions['annotations']: if int(item['image_id']) in trimages: fpath = train_prefix + trimages[int(item['image_id'])] caption = item['caption'] data.append((caption, fpath)) else: errors.append(item) for item in valcaptions['annotations']: caption = item['caption'] if int(item['image_id']) in valimages: fpath = val_prefix + valimages[int(item['image_id'])] data.append((caption, fpath)) elif int(item['image_id']) in truevalimg: # reserved fpath = val_prefix + truevalimg[int(item['image_id'])] validation.append((caption, fpath)) else: errors.append(item)
接續將訓練資料集進行隨機打亂以利訓練
在此準備額外另存寫出 CSV ,用於將訓練和測試資料各自保存為兩個 CSV 檔案。
import random import os import time import datetime import csv random.seed(42) # for reproducibility # lets shuffle the list in place print("Before Shuffling: ", data[:5]) random.shuffle(data) print("Post-shuffling: ", data[:5]) # persist for future use with open(prefix + 'data.csv', 'w') as file: writer = csv.writer(file, quoting=csv.QUOTE_ALL) writer.writerows(data) # persist for future use with open(prefix + 'validation.csv', 'w') as file: writer = csv.writer(file, quoting=csv.QUOTE_ALL) writer.writerows(validation) print("TRAINING: Total Number of Captions: {}, Total Number of Images: {}".format( len(data), len(trimages) + len(valimages))) print("VALIDATION/TESTING: Total Number of Captions: {}, Total Number of Images: {}".format( len(validation), len(truevalimg))) print("Errors: ", errors)
TRAINING:
Total Number of Captions: 591751, Total Number of Images: 118287
VALIDATION/TESTING:
Total Number of Captions: 25016, Total Number of Images: 5000
# 顯示圖片 + 對應 caption 做肉眼驗證用 from PIL import Image import matplotlib.pyplot as plt def show_random_samples(pairs, n=3): """ pairs: list[(caption, image_path)] n: 要顯示幾筆 """ for i in range(n): caption, img_path = random.choice(pairs) # 隨機抽一筆 # 印出文字資訊 print(f"Sample {i+1}") print(f"Image path: {img_path}") print(f"Caption : {caption}") print("-" * 80) # 開啟圖片並顯示 img = Image.open(img_path) plt.imshow(img) plt.axis("off") plt.show() # 從 training data 抽幾張來看 show_random_samples(data, n=3)
from collections import defaultdict def build_imgid_to_file(captions_json): """從 JSON 建 image_id -> 檔名""" return {img["id"]: img["file_name"] for img in captions_json["images"]} def build_imgid_to_captions(captions_json): """從 JSON 建 image_id -> [caption1, caption2, ...]""" mapping = defaultdict(list) for ann in captions_json["annotations"]: mapping[ann["image_id"]].append(ann["caption"]) return mapping # 建 mapping(只要跑一次就可以重複使用) tr_imgid2file = build_imgid_to_file(trcaptions) tr_imgid2caps = build_imgid_to_captions(trcaptions) val_imgid2file = build_imgid_to_file(valcaptions) val_imgid2caps = build_imgid_to_captions(valcaptions) def show_image_with_all_captions(imgid2file, imgid2caps, prefix, n=1): """ 隨機挑 n 張圖,每張圖顯示一次 + 印出該圖所有 caption """ img_ids = list(imgid2file.keys()) for _ in range(n): img_id = random.choice(img_ids) file_name = imgid2file[img_id] fpath = prefix + file_name caps = imgid2caps[img_id] print("=" * 80) print(f"Image ID : {img_id}") print(f"Image path: {fpath}") print("Captions:") for i, c in enumerate(caps, 1): print(f" {i}. {c}") # 顯示圖片 img = Image.open(fpath) plt.imshow(img) plt.axis("off") plt.show() # 看幾張 training 圖片 + 5 個 caption show_image_with_all_captions(tr_imgid2file, tr_imgid2caps, train_prefix, n=3)
呈現出來發掘微軟等參與研究的團隊,當時收集的資料集真的是千奇百怪....
留言
張貼留言