Klasyfikacja obrazu przy użyciu wstępnie wytrenowanego modelu
W tej lekcji nauczysz się używać wstępnie wytrenowanego modelu do wykrywania obiektów na danym obrazie. Będziesz używaćsqueezenet wstępnie wyszkolony moduł, który z dużą dokładnością wykrywa i klasyfikuje obiekty na danym obrazie.
Otwórz nowy Juypter notebook i postępuj zgodnie z instrukcjami, aby opracować tę aplikację do klasyfikacji obrazów.
Importowanie bibliotek
Najpierw importujemy wymagane pakiety za pomocą poniższego kodu -
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
Następnie skonfigurowaliśmy kilka variables -
INPUT_IMAGE_SIZE = 227
mean = 128
Obrazy używane do treningu będą oczywiście miały różne rozmiary. Wszystkie te obrazy muszą zostać przekonwertowane na stały rozmiar, aby zapewnić dokładne szkolenie. Podobnie obrazy testowe i obraz, który chcesz przewidzieć w środowisku produkcyjnym, również muszą zostać przekonwertowane na rozmiar, taki sam jak używany podczas szkolenia. W ten sposób tworzymy zmienną o nazwieINPUT_IMAGE_SIZE mający wartość 227. Dlatego przekonwertujemy wszystkie nasze obrazy do rozmiaru227x227 przed użyciem w naszym klasyfikatorze.
Deklarujemy również zmienną o nazwie mean mający wartość 128, który jest później używany do poprawy wyników klasyfikacji.
Następnie opracujemy dwie funkcje do przetwarzania obrazu.
Przetwarzanie obrazu
Przetwarzanie obrazu składa się z dwóch etapów. Pierwsza to zmiana rozmiaru obrazu, a druga to centralne przycięcie obrazu. W tych dwóch krokach napiszemy dwie funkcje do zmiany rozmiaru i kadrowania.
Zmiana rozmiaru obrazu
Najpierw napiszemy funkcję do zmiany rozmiaru obrazu. Jak wspomniano wcześniej, zmienimy rozmiar obrazu na227x227. Zdefiniujmy więc funkcjęresize w następujący sposób -
def resize(img, input_height, input_width):
Współczynnik kształtu obrazu uzyskujemy, dzieląc szerokość przez wysokość.
original_aspect = img.shape[1]/float(img.shape[0])
Jeśli współczynnik proporcji jest większy niż 1, oznacza to, że obraz jest szeroki, to znaczy w trybie poziomym. Teraz dostosowujemy wysokość obrazu i zwracamy obraz o zmienionym rozmiarze, używając następującego kodu -
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)
Jeśli współczynnik proporcji to less than 1, to wskazuje portrait mode. Teraz dostosowujemy szerokość za pomocą następującego kodu -
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)
Jeśli współczynnik proporcji jest równy 1, nie dokonujemy żadnych regulacji wysokości / szerokości.
if(original_aspect == 1):
return skimage.transform.resize(img, (input_width,
input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
Pełny kod funkcji jest podany poniżej w celu szybkiego odniesienia -
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)
Napiszemy teraz funkcję przycinania obrazu wokół jego środka.
Kadrowanie obrazu
Deklarujemy crop_image działają w następujący sposób -
def crop_image(img,cropx,cropy):
Wyodrębniamy wymiary obrazu za pomocą następującego stwierdzenia -
y,x,c = img.shape
Tworzymy nowy punkt początkowy dla obrazu, używając następujących dwóch wierszy kodu -
startx = x//2-(cropx//2)
starty = y//2-(cropy//2)
Na koniec zwracamy przycięty obraz, tworząc obiekt obrazu o nowych wymiarach -
return img[starty:starty+cropy,startx:startx+cropx]
Cały kod funkcji jest podany poniżej w celu szybkiego odniesienia -
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]
Teraz napiszemy kod do testowania tych funkcji.
Przetwarzanie obrazu
Najpierw skopiuj plik obrazu do images podfolder w katalogu projektu. tree.jpgplik jest kopiowany w projekcie. Poniższy kod Pythona ładuje obraz i wyświetla go na konsoli -
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')
Dane wyjściowe są następujące -
Zwróć uwagę, że rozmiar oryginalnego obrazu to 600 x 960. Musimy zmienić rozmiar tego do naszej specyfikacji227 x 227. Wołanie naszego wcześniej zdefiniowanegoresizefunkcja wykonuje tę pracę.
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')
Wynik jest taki, jak podano poniżej -
Zwróć uwagę, że teraz rozmiar obrazu to 227 x 363. Musimy to przyciąć227 x 227dla końcowego kanału do naszego algorytmu. W tym celu nazywamy wcześniej zdefiniowaną funkcję crop.
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')
Poniżej wymienione jest wyjście kodu -
W tym momencie obraz ma rozmiar 227 x 227i jest gotowy do dalszej obróbki. Teraz zamieniamy osie obrazu, aby wyodrębnić trzy kolory do trzech różnych stref.
img = img.swapaxes(1, 2).swapaxes(0, 1)
print("CHW Image Shape: " , img.shape)
Poniżej podano wynik -
CHW Image Shape: (3, 227, 227)
Zauważ, że ostatnia oś stała się teraz pierwszym wymiarem w szyku. Teraz wykreślimy trzy kanały za pomocą następującego kodu -
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))
Dane wyjściowe podano poniżej -
Na koniec wykonujemy dodatkowe przetwarzanie obrazu, takie jak konwersja Red Green Blue do Blue Green Red (RGB to BGR), usuwając średnią dla lepszych wyników i dodając oś wielkości partii za pomocą następujących trzech linii kodu -
# 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)
W tym momencie Twój obraz jest w formacie NCHW formati jest gotowy do wprowadzenia do naszej sieci. Następnie załadujemy nasze wstępnie wytrenowane pliki modelu i przekażemy do niego powyższy obraz w celu przewidywania.
Przewidywanie obiektów w przetworzonym obrazie
Najpierw konfigurujemy ścieżki dla init i predict sieci zdefiniowane we wstępnie wytrenowanych modelach Caffe.
Ustawianie ścieżek do plików modelu
Pamiętaj z naszej wcześniejszej dyskusji, że wszystkie wstępnie wyszkolone modele są zainstalowane w modelsteczka. Skonfigurowaliśmy ścieżkę do tego folderu w następujący sposób -
CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
Ustanowiliśmy ścieżkę do init_net protobuf pliku squeezenet model w następujący sposób -
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
W podobny sposób utworzyliśmy ścieżkę do predict_net protobuf w następujący sposób -
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
Drukujemy dwie ścieżki do celów diagnostycznych -
print(INIT_NET)
print(PREDICT_NET)
Powyższy kod wraz z danymi wyjściowymi jest podany tutaj w celu szybkiego odniesienia -
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)
Dane wyjściowe są wymienione poniżej -
/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
Następnie utworzymy predyktor.
Tworzenie Predictora
Czytamy pliki modelu, korzystając z następujących dwóch instrukcji -
with open(INIT_NET, "rb") as f:
init_net = f.read()
with open(PREDICT_NET, "rb") as f:
predict_net = f.read()
Predykator jest tworzony przez przekazanie wskaźników do dwóch plików jako parametrów do pliku Predictor funkcjonować.
p = workspace.Predictor(init_net, predict_net)
Plik pobiekt jest predyktorem używanym do przewidywania obiektów na dowolnym podanym obrazie. Zauważ, że każdy obraz wejściowy musi być w formacie NCHW, tak jak to zrobiliśmy wcześniej w naszymtree.jpg plik.
Przewidywanie obiektów
Przewidywanie obiektów na danym obrazku jest trywialne - wystarczy wykonać jedną linię polecenia. Nazywamyrun metoda na predictor obiekt do wykrycia obiektu na danym obrazie.
results = p.run({'data': img})
Wyniki prognozy są teraz dostępne w results obiekt, który konwertujemy na tablicę dla naszej czytelności.
results = np.asarray(results)
Wydrukuj wymiary tablicy dla zrozumienia, używając następującej instrukcji -
print("results shape: ", results.shape)
Wyjście jest jak pokazano poniżej -
results shape: (1, 1, 1000, 1, 1)
Teraz usuniemy niepotrzebną oś -
preds = np.squeeze(results)
Najwyższe orzeczenie można teraz pobrać, biorąc rozszerzenie max wartość w preds szyk.
curr_pred, curr_conf = max(enumerate(preds), key=operator.itemgetter(1))
print("Prediction: ", curr_pred)
print("Confidence: ", curr_conf)
Dane wyjściowe są następujące -
Prediction: 984
Confidence: 0.89235985
Jak widać, model przewidział obiekt z wartością indeksu 984 z 89%pewność siebie. Indeks 984 nie ma dla nas większego sensu w zrozumieniu, jaki rodzaj obiektu jest wykrywany. Musimy uzyskać ujednoliconą nazwę obiektu za pomocą jego wartości indeksu. Rodzaj obiektów, które model rozpoznaje wraz z odpowiadającymi im wartościami indeksu, jest dostępny w repozytorium github.
Teraz zobaczymy, jak pobrać nazwę naszego obiektu o wartości indeksu 984.
Wynik usztywniający
Tworzymy obiekt URL do repozytorium github w następujący sposób -
codes = "https://gist.githubusercontent.com/aaronmarkham/cd3a6b6ac0
71eca6f7b4a6e40e6038aa/raw/9edb4038a37da6b5a44c3b5bc52e448ff09bfe5b/alexnet_codes"
Przeczytaliśmy zawartość adresu URL -
response = urllib2.urlopen(codes)
Odpowiedź będzie zawierała listę wszystkich kodów i ich opisy. Poniżej przedstawiono kilka wierszy odpowiedzi, aby zrozumieć, co zawiera -
5: 'electric ray, crampfish, numbfish, torpedo',
6: 'stingray',
7: 'cock',
8: 'hen',
9: 'ostrich, Struthio camelus',
10: 'brambling, Fringilla montifringilla',
Teraz iterujemy całą tablicę, aby zlokalizować nasz pożądany kod 984 za pomocą pliku for pętla w następujący sposób -
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")
Po uruchomieniu kodu zobaczysz następujące dane wyjściowe -
Model predicts rapeseed with 0.89235985 confidence
Możesz teraz wypróbować model na innym zdjęciu.
Przewidywanie innego obrazu
Aby przewidzieć inny obraz, po prostu skopiuj plik obrazu do pliku imagesfolder katalogu twojego projektu. To jest katalog, w którym nasz wcześniejszy pliktree.jpgplik jest przechowywany. Zmień nazwę pliku obrazu w kodzie. Wymagana jest tylko jedna zmiana, jak pokazano poniżej
img = skimage.img_as_float(skimage.io.imread("images/pretzel.jpg")).astype(np.float32)
Oryginalny obraz i wynik prognozy pokazano poniżej -
Dane wyjściowe są wymienione poniżej -
Model predicts pretzel with 0.99999976 confidence
Jak widać, wstępnie wytrenowany model jest w stanie wykryć obiekty na danym obrazie z dużą dokładnością.
Pełne źródło
Pełne źródło powyższego kodu, które używa wstępnie wytrenowanego modelu do wykrywania obiektów na danym obrazie, jest wymienione tutaj dla szybkiego odniesienia -
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")
W tym czasie wiesz, jak używać wstępnie wytrenowanego modelu do wykonywania prognoz w zbiorze danych.
Następnie dowiesz się, jak zdefiniować swój neural network (NN) architektury w Caffe2i trenuj je na swoim zbiorze danych. Dowiemy się teraz, jak utworzyć trywialny jednowarstwowy NN.