Strona korzysta z plików cookies w celu realizacji usług i zgodnie z Polityką Plików Cookies.



24.05.2022

Nowe możliwości w zakresie...

VMware rozszerza ofertę zabezpieczeń end-to-end dla obciążeń cloud-native poprzez ochronę...
24.05.2022

Zarządzanie kluczami

IBM przedstawił nowe rozwiązanie do zarządzania kluczami w wielu chmurach, oferowane jako...
24.05.2022

Ochrona przed zagrożeniami

ESET wprowadził nowe wersje swoich produktów biznesowych do ochrony stacji roboczych,...
24.05.2022

Value Stream Management

Micro Focus zaprezentował nową platformę do zarządzania strumieniem wartości VSM (ang....
24.05.2022

Unijna decyzja Value Stream...

Komisja rynku wewnętrznego i ochrony konsumentów Parlamentu Europejskiego poparła...
24.05.2022

Nowy laptop Dynabooka

Sprzęt waży 1,45 kg, a jego grubość to 17,8 mm. Jest odporny na czynniki zewnętrzne, gdyż...
24.05.2022

Przepływ pracy

QNAP oferuje model TS-435XeU wykorzystujący procesor Marvell OCTEON TX2 CN9131 2,2 GHz z...
24.05.2022

Wideo bez wstrząsów

Kamera stałopozycyjna firmy Axis Communications służy do monitoringu miejsc zagrożonych...
24.05.2022

Akceleratory dla naukowców

Firma AMD ogłosiła wprowadzenie do sprzedaży opartych na architekturze AMD CDNA 2...

Analiza obrazów z Azure Cognitive Services

Data publikacji: 03-02-2022 Autor: Marcin Szeliga

Analiza obrazów jest jednym z najpopularniejszych zastosowań sztucznej inteligencji. Dzięki wykorzystaniu głębokich sieci neuronowych maszyny zyskały zdolność rozpoznawania obrazów, np. identyfikowania obiektów i postaci widzianych zarówno na obrazach statycznych (zdjęciach), jak i dynamicznych (nagraniach wideo).

 

Celem artykułu jest przedstawienie zasady działania używanych w tym celu głębokich sieci neuronowych oraz wyjaśnienie, dlaczego w praktyce nie uczy się takich sieci od podstaw, i wskazanie alternatywnego rozwiązania.

 

Sztuczne sieci neuronowe składają się z neuronów – prostych jednostek obliczeniowych, które obliczają sumę ważoną sygnałów wejściowych, modyfikują ją za pomocą nieliniowej funkcji aktywacyjnej i zwracają tak obliczoną wartość na wyjściu.

 

Neurony umieszczane są w warstwach. W sieciach sekwencyjnych – do których należą używane do analizy obrazów sieci konwolucyjne – neurony z jednej warstwy połączone są z wyjściami neuronów z poprzedniej warstwy. W takich sieciach dane są przesyłane od warstwy wejściowej, poprzez kolejne warstwy ukryte, aż do warstwy wyjściowej.

 

Poszczególne warstwy sieci neuronowych pełnią różne funkcje: warstwy konwolucyjne (splatające) uczą się rozpoznawania coraz bardziej złożonych kształtów, warstwy wybierające redukują pewną liczbę zmiennych, zastępując je jedną, warstwy wyłączające zapobiegają nadmiernemu dopasowaniu się sieci do danych treningowych, a warstwy w pełni połączone uczą się lokalizować i rozpoznawać widoczne na obrazach obiekty na podstawie ich cech charakterystycznych rozpoznanych przez warstwy konwolucyjne.

 

Przeprowadzane przez neurony operacje, takie jak sumowanie, muszą być wykonywane na liczbach. Dlatego dane wejściowe (obrazy) należy przekształcić do postaci wielowymiarowych macierzy (tensorów). Każdy piksel kolorowego obrazu jest reprezentowany przez trzy liczby odpowiadające jego wartościom kanałów R, G, B. Czwartym wymiarem tensora jest liczba jednocześnie analizowanych obrazów. Warto podkreślić, że nawet dla niewielkich obrazów liczba zmiennych wejściowych jest ogromna, np. dla kolorowego zdjęcia o rozdzielczości Full HD wynosi ona 1920×1080×3 = 6 220 800 zmiennych.

 

> Warstwy sieci konwolucyjnych

 

Warstwa wyjściowa sieci konwolucyjnej klasyfikującej obrazy zawiera tyle neuronów, do ilu klas mogą należeć rozpoznane na tych obrazach obiekty. Każdy z tych neuronów zwraca prawdopodobieństwo, z którym na analizowanym obrazie znajduje się reprezentowany przez ten neuron obiekt. Obiekt, dla którego prawdopodobieństwo jest najwyższe, zwracany jest jako wynik zapytania predykcyjnego.


Podczas uczenia sieć porównuje wyniki predykcji z prawdziwymi danymi, oznacza to, że każde zdjęcie musi zostać wcześniej opisane. Oblicza się dwa rodzaje błędów – treningowy, obliczony dla danych użytych podczas uczenia, i walidacyjny, obliczony dla zdjęć, na których sieć się nie uczy. Błąd treningowy jest używany do zmiany wag połączeń między neuronami. Wagi są zmieniane (zwiększane lub zmniejszane) tak, aby zmniejszyć błąd treningowy. Procedura analizy wszystkich danych treningowych jest wielokrotnie powtarzana. Po zakończeniu każdego powtórzenia (epoki) obliczany jest błąd walidacyjny, który reprezentuje postępy uczenia sieci.

 

Choć sam proces jest matematycznie bardzo zaawansowany (dzięki takim bibliotekom głębokiego uczenia maszynowego jak Tensorflow i Keras), jego zaimplementowanie nie jest trudne. Potrzebować jednak do tego będziemy akceleratora GPU – uczenie głębokich sieci neuronowych z wykorzystaniem procesorów CPU jest zbyt wolne. W tym wypadku użyta została karta Nvidia GeForce GTX 1050 Ti, czyli bardzo prosty akcelerator GPU:

 

import tensorflow as tf
gpus = tf.config.experimental.list_physical_devices('GPU')
tf.config.experimental.set_memory_growth(gpus[0], True)
 

W pierwszej kolejności należy przygotować dane treningowe i walidacyjne. Z reguły zapisuje się je w osobnych folderach, których nazwy odpowiadają widocznym na zdjęciach obiektom (wykorzystane przeze mnie dane dostępne są pod adresem bit.ly/3qijP92):
 

train_dir = './Simpsons/train/'
test_dir = './Simpsons/val/'

 

Do przygotowania danych użyłem obiektu ImageDataGenerator, ograniczając przygotowanie danych do przeskalowania wartości R, G, B do zakresu 0–1:

 

from tensorflow.keras.preprocessing.image import ImageDataGenerator
train_image_generator = ImageDataGenerator(rescale=1./255)
test_image_generator = ImageDataGenerator(rescale=1./255)

 

Następnie podzieliłem dane na bloki liczące osiem losowo wybranych zdjęć i przeskalowałem te zdjęcia do wielkości 128 ×128 pikseli – większe nie zmieściłyby się w pamięci użytej karty graficznej:

 

batch_size = 8
train_data_gen = `
train_image_generator.flow_from_directory(batch_size=batch_size, `
directory=train_dir, shuffle=True, target_size=(128, 128))
Found 435 images belonging to 10 classes.
test_data_gen = test_image_generator.flow_from_directory(batch_size=batch_size,
directory=test_dir, shuffle=True, target_size=(128, 128))
Found 100 images belonging to 10 classes.

 

Jak łatwo sprawdzić, każdy blok tak przygotowanych danych jest czterowymiarowym tensorem, którego pierwszym wymiarem jest numer zdjęcia, drugim i trzecim – pozycja piksela, a czwartym – numer kanału:

 

sample_batch = next(train_data_gen)
sample_batch[0].shape
(8, 128, 128, 3)

 

Model, w tym wypadku konwolucyjna sieć neuronowa, też jest bardzo prosty. Składa się zaledwie z dwóch bloków konwolucyjnych, z których każdy zawiera dwie warstwy splatające. Każda z tych warstw nakłada na dane wejściowe filtry o wielkości 3×3 piksele, przy czym liczba tych filtrów jest podwajana w każdej kolejnej warstwie. Funkcją aktywacyjną jest powszechnie używana w głębokich sieciach neuronowych funkcja ReLu.

 

Po każdym bloku konwolucyjnym dodany został blok zawierający warstwę wybierającą i wyłączającą. Pierwsza z nich zastępuje cztery sąsiednie wartości ich wartością maksymalną, druga wyłącza podczas uczenia 25% losowo wybranych neuronów.

 

Następnie dane zostały przekształcone do jednowymiarowego tensora wymaganego przez warstwy w pełni połączone (każdy neuron takiej warstwy jest połączony z wyjściami wszystkich neuronów z poprzedniej warstwy). Pierwsza z tych warstw liczy 512, druga 256 neuronów. Ostatnia warstwa jest warstwą wyjściową – ponieważ na przykładowych zdjęciach widać 10 postaci z serialu „Simpsonowie”, zawiera ona 10 neuronów:

 

model = tf.keras.models.Sequential([
layers.Conv2D(16, (3, 3), padding='same', activation='relu',
input_shape=sample_batch[0].shape[1:]),
layers.Conv2D(32, (3, 3), padding='same', activation='relu'),
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Dropout(0.25),
layers.Conv2D(64, (3, 3), padding='same', activation='relu'),
layers.Conv2D(128, (3, 3), padding='same', activation='relu'),
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Dropout(0.25),
layers.Flatten(),
layers.Dense(512, activation='relu'),
layers.Dropout(0.25),
layers.Dense(256, activation='relu'),
layers.Dense(10, activation='softmax')
])

 

Do uczenia modelu użyty został algorytm Adam, a na funkcję kosztu wybrałem funkcję entropii krzyżowej (ta funkcja pozwala porównać rozkład dwóch zmiennych kategorycznych, w tym wypadku wynik predykcji z opisem zdjęcia):

 

model.compile(optimizer='adam',
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])

 

Nasz miniaturowy model liczy zaledwie 67 340 714 parametrów, których wartości zostaną znalezione podczas uczenia. Powszechnie używane sieci konwolucyjne są znacznie bardziej złożone. Na przykład liczba parametrów sieci Inception v4 wynosi 43 mln, sieci ImageNet – 60 mln, a sieci VGG16 – 143 mln.

 

Tak zdefiniowana sieć konwolucyjna została nauczona na danych treningowych. Liczbę cykli uczenia ustawiłem na 40:

 

training_hist = model.fit(train_data_gen, epochs=40,
steps_per_epoch=435//batch_size, validation_data=test_data_gen,
validation_steps=100//batch_size)
Epoch 1/40 54/54 [==============================] – 4s 68ms/step – loss: 3.3013 –
accuracy: 0.1047 – val_loss: 2.1654 – val_accuracy: 0.1250
Epoch 2/40 54/54 [==============================] – 4s 68ms/step – loss: 1.7357 –
accuracy: 0.3540 – val_loss: 1.1956 – val_accuracy: 0.6354
Epoch 3/40 54/54 [==============================] – 4s 64ms/step – loss: 0.8825 –
accuracy: 0.7370 – val_loss: 0.5385 – val_accuracy: 0.8333

Epoch 39/40 54/54 [==============================] – 3s 58ms/step – loss: 0.0079 –
accuracy: 0.9973 – val_loss: 0.9307 – val_accuracy: 0.8646
Epoch 40/40 54/54 [==============================] – 4s 69ms/step – loss: 0.0241 –
accuracy: 0.9959 – val_loss: 0.7729 – val_accuracy: 0.8646

 

Nasz model początkowo uczył się bardzo szybko, ale pomimo kontynuacji uczenia nie był w stanie poprawnie sklasyfikować 90% zdjęć walidacyjnych – trafność zmierzona dla tych danych wahała się w kolejnych cyklach w okolicach osiemdziesięciu paru procent (rys. 1).

 

Nauczonego modelu możemy użyć do identyfikacji widocznej na zdjęciu postaci (rys. 2):

 

lookup = [
'Bart-Simpson', 'Chief-Wiggum', 'Dr-Hibbert', 'Homer-Simpsons',
'Krusty-the-Clown', 'Lisa-Simpson', 'Marge-Simpsons', 'Milhouse-van-Houten',
'Mr-Burns', 'Ned-Flanders'
]
import PIL
from PIL import Image
import requests
from io import BytesIO
url = 'https://raw.githubusercontent.com/hnky/dataset-lego-figures/`
master/_test/ Lisa.jpg'
response = requests.get(url)
image = PIL.Image.open(BytesIO(response.content)).resize([128,128])
image

 

Chociaż model nie jest idealny, to niektóre postacie rozpoznaje prawidłowo:

 

input_array = np.array(image, dtype=np.float32)[np.newaxis, :, :, :]
outputs = model.predict(input_array.astype(np.float32))
print('Predicted label: ', lookup[np.argmax(outputs)])
Predicted label: Lisa-Simpson

 

Model prawidłowo rozpoznał Lisę. Niestety z niektórymi innymi postaciami nie poszło mu już tak dobrze.

 

[...]

 

Pracownik naukowy Wyższej Szkoły Bankowej w Poznaniu Wydział Zamiejscowy w Chorzowie, jest autorem książek poświęconych analizie danych i posiada tytuł Microsoft Most Valuable Professional.

Pełna treść artykułu jest dostępna w papierowym wydaniu pisma.

prenumerata Numer niedostępny Spis treści

.

Transmisje online zapewnia: StreamOnline

All rights reserved © 2019 Presscom / Miesięcznik "IT Professional"