การจำแนกภาพโดยใช้โมเดลก่อนการฝึกอบรม

ในบทเรียนนี้คุณจะได้เรียนรู้การใช้แบบจำลองที่ได้รับการฝึกฝนมาก่อนเพื่อตรวจจับวัตถุในภาพที่กำหนด คุณจะใช้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 ชั้นเดียวที่ไม่สำคัญ