การจำแนกภาพโดยใช้โมเดลก่อนการฝึกอบรม
ในบทเรียนนี้คุณจะได้เรียนรู้การใช้แบบจำลองที่ได้รับการฝึกฝนมาก่อนเพื่อตรวจจับวัตถุในภาพที่กำหนด คุณจะใช้squeezenet โมดูลที่ได้รับการฝึกฝนมาแล้วซึ่งตรวจจับและจำแนกวัตถุในภาพที่กำหนดด้วยความแม่นยำสูง
เปิดไฟล์ Juypter notebook และทำตามขั้นตอนเพื่อพัฒนาแอพพลิเคชั่นการจัดประเภทรูปภาพนี้
การนำเข้าไลบรารี
ขั้นแรกเรานำเข้าแพ็คเกจที่ต้องการโดยใช้รหัสด้านล่าง -
from caffe2.proto import caffe2_pb2
from caffe2.python import core, workspace, models
import numpy as np
import skimage.io
import skimage.transform
from matplotlib import pyplot
import os
import urllib.request as urllib2
import operator
ต่อไปเราจะตั้งค่าบางส่วน variables -
INPUT_IMAGE_SIZE = 227
mean = 128
ภาพที่ใช้ในการฝึกจะมีหลายขนาดอย่างเห็นได้ชัด ภาพทั้งหมดนี้ต้องถูกแปลงเป็นขนาดคงที่เพื่อการฝึกที่ถูกต้อง ในทำนองเดียวกันภาพทดสอบและภาพที่คุณต้องการคาดการณ์ในสภาพแวดล้อมการผลิตจะต้องถูกแปลงเป็นขนาดเช่นเดียวกับภาพที่ใช้ในระหว่างการฝึกอบรม ดังนั้นเราจึงสร้างตัวแปรด้านบนที่เรียกว่าINPUT_IMAGE_SIZE มีค่า 227. ดังนั้นเราจะแปลงภาพทั้งหมดของเราให้มีขนาด227x227 ก่อนที่จะใช้ในลักษณนามของเรา
เรายังประกาศตัวแปรที่เรียกว่า mean มีค่า 128ซึ่งใช้ในภายหลังเพื่อปรับปรุงผลการจำแนกประเภท
ต่อไปเราจะพัฒนาสองฟังก์ชั่นสำหรับการประมวลผลภาพ
การประมวลผลภาพ
การประมวลผลภาพประกอบด้วยสองขั้นตอน อันดับแรกคือการปรับขนาดรูปภาพและอันที่สองคือการครอบตัดรูปภาพจากส่วนกลาง สำหรับสองขั้นตอนนี้เราจะเขียนสองฟังก์ชันสำหรับการปรับขนาดและการครอบตัด
การปรับขนาดภาพ
ขั้นแรกเราจะเขียนฟังก์ชันสำหรับปรับขนาดภาพ ดังที่ได้กล่าวไว้ก่อนหน้านี้เราจะปรับขนาดภาพเป็น227x227. ดังนั้นให้เรากำหนดฟังก์ชันresize ดังต่อไปนี้ -
def resize(img, input_height, input_width):
เราได้อัตราส่วนของภาพโดยการหารความกว้างด้วยความสูง
original_aspect = img.shape[1]/float(img.shape[0])
หากอัตราส่วนภาพมากกว่า 1 แสดงว่าภาพมีความกว้างแสดงว่าอยู่ในโหมดแนวนอน ตอนนี้เราปรับความสูงของภาพและส่งคืนภาพที่ปรับขนาดโดยใช้รหัสต่อไปนี้ -
if(original_aspect>1):
new_height = int(original_aspect * input_height)
return skimage.transform.resize(img, (input_width,
new_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
ถ้าอัตราส่วนกว้างยาวคือ less than 1มันบ่งบอกถึง portrait mode. ตอนนี้เราปรับความกว้างโดยใช้รหัสต่อไปนี้ -
if(original_aspect<1):
new_width = int(input_width/original_aspect)
return skimage.transform.resize(img, (new_width,
input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
หากอัตราส่วนภาพเท่ากับ 1เราไม่ได้ทำการปรับความสูง / ความกว้างใด ๆ
if(original_aspect == 1):
return skimage.transform.resize(img, (input_width,
input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
รหัสฟังก์ชันเต็มได้รับด้านล่างสำหรับการอ้างอิงอย่างรวดเร็วของคุณ -
def resize(img, input_height, input_width):
original_aspect = img.shape[1]/float(img.shape[0])
if(original_aspect>1):
new_height = int(original_aspect * input_height)
return skimage.transform.resize(img, (input_width,
new_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
if(original_aspect<1):
new_width = int(input_width/original_aspect)
return skimage.transform.resize(img, (new_width,
input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
if(original_aspect == 1):
return skimage.transform.resize(img, (input_width,
input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
ตอนนี้เราจะเขียนฟังก์ชันสำหรับการครอบตัดรูปภาพรอบ ๆ กึ่งกลาง
การครอบตัดรูปภาพ
เราประกาศ crop_image ฟังก์ชันดังต่อไปนี้ -
def crop_image(img,cropx,cropy):
เราแยกขนาดของภาพโดยใช้ข้อความต่อไปนี้ -
y,x,c = img.shape
เราสร้างจุดเริ่มต้นใหม่สำหรับรูปภาพโดยใช้โค้ดสองบรรทัดต่อไปนี้ -
startx = x//2-(cropx//2)
starty = y//2-(cropy//2)
สุดท้ายเราส่งคืนภาพที่ครอบตัดโดยการสร้างวัตถุภาพที่มีขนาดใหม่ -
return img[starty:starty+cropy,startx:startx+cropx]
รหัสฟังก์ชันทั้งหมดได้รับด้านล่างสำหรับการอ้างอิงอย่างรวดเร็วของคุณ -
def crop_image(img,cropx,cropy):
y,x,c = img.shape
startx = x//2-(cropx//2)
starty = y//2-(cropy//2)
return img[starty:starty+cropy,startx:startx+cropx]
ตอนนี้เราจะเขียนโค้ดเพื่อทดสอบฟังก์ชันเหล่านี้
กำลังประมวลผลภาพ
ขั้นแรกให้คัดลอกไฟล์รูปภาพลงในไฟล์ images โฟลเดอร์ย่อยภายในไดเรกทอรีโครงการของคุณ tree.jpgไฟล์ถูกคัดลอกในโครงการ โค้ด Python ต่อไปนี้จะโหลดรูปภาพและแสดงบนคอนโซล -
img = skimage.img_as_float(skimage.io.imread("images/tree.jpg")).astype(np.float32)
print("Original Image Shape: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Original image')
ผลลัพธ์มีดังนี้ -
โปรดทราบว่าขนาดของภาพต้นฉบับคือ 600 x 960. เราจำเป็นต้องปรับขนาดให้เป็นข้อมูลจำเพาะของเรา227 x 227. โทรหาเราที่กำหนดไว้ก่อนหน้านี้resizeฟังก์ชันทำงานนี้
img = resize(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after resizing: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Resized image')
ผลลัพธ์เป็นไปตามที่ระบุด้านล่าง -
โปรดทราบว่าตอนนี้ขนาดของภาพคือ 227 x 363. เราจำเป็นต้องครอบตัดสิ่งนี้เพื่อ227 x 227สำหรับฟีดสุดท้ายของอัลกอริทึมของเรา เราเรียกฟังก์ชันการครอบตัดที่กำหนดไว้ก่อนหน้านี้เพื่อจุดประสงค์นี้
img = crop_image(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after cropping: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Center Cropped')
ด้านล่างนี้เป็นผลลัพธ์ของรหัส -
ณ จุดนี้ภาพมีขนาด 227 x 227และพร้อมสำหรับการประมวลผลต่อไป ตอนนี้เราสลับแกนภาพเพื่อแยกสีทั้งสามออกเป็นสามโซนที่แตกต่างกัน
img = img.swapaxes(1, 2).swapaxes(0, 1)
print("CHW Image Shape: " , img.shape)
ด้านล่างคือผลลัพธ์ -
CHW Image Shape: (3, 227, 227)
โปรดทราบว่าแกนสุดท้ายกลายเป็นมิติแรกในอาร์เรย์แล้ว ตอนนี้เราจะพล็อตสามช่องโดยใช้รหัสต่อไปนี้ -
pyplot.figure()
for i in range(3):
pyplot.subplot(1, 3, i+1)
pyplot.imshow(img[i])
pyplot.axis('off')
pyplot.title('RGB channel %d' % (i+1))
ผลลัพธ์ระบุไว้ด้านล่าง -
สุดท้ายเราทำการประมวลผลเพิ่มเติมเกี่ยวกับภาพเช่นการแปลง Red Green Blue ถึง Blue Green Red (RGB to BGR)ลบค่าเฉลี่ยเพื่อให้ได้ผลลัพธ์ที่ดีขึ้นและเพิ่มแกนขนาดแบทช์โดยใช้โค้ดสามบรรทัดต่อไปนี้ -
# convert RGB --> BGR
img = img[(2, 1, 0), :, :]
# remove mean
img = img * 255 - mean
# add batch size axis
img = img[np.newaxis, :, :, :].astype(np.float32)
ณ จุดนี้รูปภาพของคุณอยู่ใน NCHW formatและพร้อมที่จะป้อนเข้าสู่เครือข่ายของเรา ต่อไปเราจะโหลดไฟล์โมเดลที่ได้รับการฝึกฝนมาแล้วและฟีดภาพด้านบนลงในไฟล์เพื่อการคาดคะเน
การทำนายวัตถุในภาพที่ประมวลผล
ก่อนอื่นเราตั้งค่าเส้นทางสำหรับไฟล์ init และ predict เครือข่ายที่กำหนดไว้ในแบบจำลองก่อนการฝึกอบรมของ Caffe
การตั้งค่าเส้นทางไฟล์โมเดล
โปรดจำไว้ว่าจากการสนทนาก่อนหน้านี้รุ่นที่ผ่านการฝึกอบรมทั้งหมดได้รับการติดตั้งในไฟล์ modelsโฟลเดอร์ เราตั้งค่าเส้นทางไปยังโฟลเดอร์นี้ดังนี้ -
CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
เราตั้งค่าเส้นทางไปยังไฟล์ init_net protobuf ของไฟล์ squeezenet รุ่นดังนี้ -
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
ในทำนองเดียวกันเราตั้งค่าเส้นทางไปยังไฟล์ predict_net protobuf ดังนี้ -
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
เราพิมพ์สองเส้นทางเพื่อการวินิจฉัย -
print(INIT_NET)
print(PREDICT_NET)
รหัสข้างต้นพร้อมกับผลลัพธ์มีให้ที่นี่สำหรับการอ้างอิงอย่างรวดเร็วของคุณ -
CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
print(INIT_NET)
print(PREDICT_NET)
ผลลัพธ์ดังต่อไปนี้ -
/anaconda3/lib/python3.7/site-packages/caffe2/python/models/squeezenet/init_net.pb
/anaconda3/lib/python3.7/site-packages/caffe2/python/models/squeezenet/predict_net.pb
ต่อไปเราจะสร้างตัวทำนาย
การสร้าง Predictor
เราอ่านไฟล์โมเดลโดยใช้สองคำสั่งต่อไปนี้ -
with open(INIT_NET, "rb") as f:
init_net = f.read()
with open(PREDICT_NET, "rb") as f:
predict_net = f.read()
ตัวทำนายถูกสร้างขึ้นโดยส่งพอยน์เตอร์ไปยังไฟล์สองไฟล์เป็นพารามิเตอร์ไปยังไฟล์ Predictor ฟังก์ชัน
p = workspace.Predictor(init_net, predict_net)
pวัตถุคือตัวทำนายซึ่งใช้สำหรับทำนายวัตถุในภาพใด ๆ โปรดทราบว่าภาพอินพุตแต่ละภาพต้องอยู่ในรูปแบบ NCHW ตามที่เราได้ทำไว้ก่อนหน้านี้กับไฟล์tree.jpg ไฟล์.
ทำนายวัตถุ
ในการทำนายวัตถุในภาพที่กำหนดนั้นเป็นเรื่องเล็กน้อยเพียงแค่ดำเนินการคำสั่งบรรทัดเดียว เราโทรrun วิธีการบน predictor วัตถุสำหรับการตรวจจับวัตถุในภาพที่กำหนด
results = p.run({'data': img})
ขณะนี้ผลการทำนายมีอยู่ในไฟล์ results ซึ่งเราแปลงเป็นอาร์เรย์เพื่อให้อ่านง่าย
results = np.asarray(results)
พิมพ์ขนาดของอาร์เรย์เพื่อความเข้าใจของคุณโดยใช้คำสั่งต่อไปนี้ -
print("results shape: ", results.shape)
ผลลัพธ์ดังแสดงด้านล่าง -
results shape: (1, 1, 1000, 1, 1)
ตอนนี้เราจะลบแกนที่ไม่จำเป็น -
preds = np.squeeze(results)
ตอนนี้สามารถเรียกข้อมูลการคาดการณ์สูงสุดได้โดยการใช้ max ค่าใน preds อาร์เรย์
curr_pred, curr_conf = max(enumerate(preds), key=operator.itemgetter(1))
print("Prediction: ", curr_pred)
print("Confidence: ", curr_conf)
ผลลัพธ์มีดังนี้ -
Prediction: 984
Confidence: 0.89235985
ดังที่คุณเห็นโมเดลได้ทำนายวัตถุที่มีค่าดัชนี 984 ด้วย 89%ความมั่นใจ. ดัชนี 984 ไม่สมเหตุสมผลกับเรามากนักในการทำความเข้าใจประเภทของวัตถุที่ตรวจพบ เราจำเป็นต้องได้รับชื่อสตริงสำหรับวัตถุโดยใช้ค่าดัชนี ชนิดของอ็อบเจ็กต์ที่โมเดลรับรู้พร้อมกับค่าดัชนีที่สอดคล้องกันนั้นมีอยู่ในที่เก็บ github
ตอนนี้เราจะดูวิธีดึงชื่อสำหรับวัตถุของเราที่มีค่าดัชนี 984
ผลสตริง
เราสร้างออบเจ็กต์ URL ไปยังที่เก็บ github ดังนี้ -
codes = "https://gist.githubusercontent.com/aaronmarkham/cd3a6b6ac0
71eca6f7b4a6e40e6038aa/raw/9edb4038a37da6b5a44c3b5bc52e448ff09bfe5b/alexnet_codes"
เราอ่านเนื้อหาของ URL -
response = urllib2.urlopen(codes)
การตอบกลับจะมีรายการรหัสทั้งหมดและคำอธิบาย คำตอบไม่กี่บรรทัดแสดงไว้ด้านล่างเพื่อให้คุณเข้าใจว่ามีอะไรบ้าง -
5: 'electric ray, crampfish, numbfish, torpedo',
6: 'stingray',
7: 'cock',
8: 'hen',
9: 'ostrich, Struthio camelus',
10: 'brambling, Fringilla montifringilla',
ตอนนี้เราทำซ้ำอาร์เรย์ทั้งหมดเพื่อค้นหารหัสที่ต้องการของเราคือ 984 โดยใช้ไฟล์ for วนดังนี้ -
for line in response:
mystring = line.decode('ascii')
code, result = mystring.partition(":")[::2]
code = code.strip()
result = result.replace("'", "")
if (code == str(curr_pred)):
name = result.split(",")[0][1:]
print("Model predicts", name, "with", curr_conf, "confidence")
เมื่อคุณเรียกใช้รหัสคุณจะเห็นผลลัพธ์ต่อไปนี้ -
Model predicts rapeseed with 0.89235985 confidence
ตอนนี้คุณสามารถลองใช้โมเดลกับรูปภาพอื่นได้
การทำนายภาพที่แตกต่างกัน
หากต้องการทำนายภาพอื่นให้คัดลอกไฟล์ภาพลงในไฟล์ imagesโฟลเดอร์ของไดเรกทอรีโครงการของคุณ นี่คือไดเร็กทอรีที่ก่อนหน้านี้ของเราtree.jpgไฟล์ถูกเก็บไว้ เปลี่ยนชื่อไฟล์รูปภาพในโค้ด ต้องทำการเปลี่ยนแปลงเพียงครั้งเดียวดังที่แสดงด้านล่าง
img = skimage.img_as_float(skimage.io.imread("images/pretzel.jpg")).astype(np.float32)
ภาพต้นฉบับและผลการทำนายแสดงไว้ด้านล่าง -
ผลลัพธ์ดังต่อไปนี้ -
Model predicts pretzel with 0.99999976 confidence
อย่างที่คุณเห็นโมเดลที่ได้รับการฝึกฝนมาก่อนนั้นสามารถตรวจจับวัตถุในภาพที่กำหนดได้ด้วยความแม่นยำสูง
แหล่งที่มาแบบเต็ม
แหล่งที่มาแบบเต็มสำหรับโค้ดด้านบนที่ใช้แบบจำลองที่ได้รับการฝึกฝนมาก่อนสำหรับการตรวจจับวัตถุในภาพที่ระบุไว้สำหรับการอ้างอิงอย่างรวดเร็วของคุณ -
def crop_image(img,cropx,cropy):
y,x,c = img.shape
startx = x//2-(cropx//2)
starty = y//2-(cropy//2)
return img[starty:starty+cropy,startx:startx+cropx]
img = skimage.img_as_float(skimage.io.imread("images/pretzel.jpg")).astype(np.float32)
print("Original Image Shape: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Original image')
img = resize(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after resizing: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Resized image')
img = crop_image(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after cropping: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Center Cropped')
img = img.swapaxes(1, 2).swapaxes(0, 1)
print("CHW Image Shape: " , img.shape)
pyplot.figure()
for i in range(3):
pyplot.subplot(1, 3, i+1)
pyplot.imshow(img[i])
pyplot.axis('off')
pyplot.title('RGB channel %d' % (i+1))
# convert RGB --> BGR
img = img[(2, 1, 0), :, :]
# remove mean
img = img * 255 - mean
# add batch size axis
img = img[np.newaxis, :, :, :].astype(np.float32)
CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
print(INIT_NET)
print(PREDICT_NET)
with open(INIT_NET, "rb") as f:
init_net = f.read()
with open(PREDICT_NET, "rb") as f:
predict_net = f.read()
p = workspace.Predictor(init_net, predict_net)
results = p.run({'data': img})
results = np.asarray(results)
print("results shape: ", results.shape)
preds = np.squeeze(results)
curr_pred, curr_conf = max(enumerate(preds), key=operator.itemgetter(1))
print("Prediction: ", curr_pred)
print("Confidence: ", curr_conf)
codes = "https://gist.githubusercontent.com/aaronmarkham/cd3a6b6ac071eca6f7b4a6e40e6038aa/raw/9edb4038a37da6b5a44c3b5bc52e448ff09bfe5b/alexnet_codes"
response = urllib2.urlopen(codes)
for line in response:
mystring = line.decode('ascii')
code, result = mystring.partition(":")[::2]
code = code.strip()
result = result.replace("'", "")
if (code == str(curr_pred)):
name = result.split(",")[0][1:]
print("Model predicts", name, "with", curr_conf, "confidence")
ในตอนนี้คุณจะรู้วิธีใช้แบบจำลองที่ผ่านการฝึกอบรมมาแล้วเพื่อทำการคาดคะเนบนชุดข้อมูลของคุณ
ต่อไปคือเรียนรู้วิธีกำหนดไฟล์ neural network (NN) สถาปัตยกรรมใน Caffe2และฝึกอบรมในชุดข้อมูลของคุณ ตอนนี้เราจะเรียนรู้วิธีสร้าง NN ชั้นเดียวที่ไม่สำคัญ