Kjo punë është pjesë e projektit të Shkencës së të Dhënave të Udacity.

Përmbledhje:

Ju mund të mendoni se njohja e racës së një qeni në një imazh është një detyrë e lehtë për ju. Keni të drejtë! Mund të mos jetë e vështirë të gjesh çifte të racave të qenve me variacione minimale ndër-klasore, për shembull, Retrievers me Veshje Kaçurrel dhe Spaniel Ujor Amerikan.

Por, si thua për këta të dy?!

Epo, jo aq e lehtë!

Në dekadën e fundit, është shumë më e lehtë të përdorësh teknika të të mësuarit të thellë me disa rreshta kodi python për të dalluar midis racave të qenve në imazhe. Në këtë blog, unë do t'ju tregoj se si të krijoni Rrjetet Neurale Convolutional (CNN) nga e para dhe të shfrytëzoni teknikat më të fundit të klasifikimit të imazheve në ImageNet. Ky model mund të përdoret si pjesë e një aplikacioni celular ose ueb për botën reale dhe imazhet e ofruara nga përdoruesi. Duke i dhënë një imazh modelit, ai përcakton nëse një qen është i pranishëm dhe kthen racën e vlerësuar. Nëse imazhi është njerëzor, ai do të kthejë racën më të ngjashme të qenve. Ju mund ta gjeni kodin në "repo" time GitHub.

Detektori i njeriut

Kam përdorur zbatimin e "OpenCV" të klasifikuesit të objekteve kaskadë të bazuar në veçori Haar për të zbuluar fytyrat e njerëzve. Funksioni i kaskadës është një qasje e bazuar në mësimin e makinerive e trajnuar në shumë imazhe me etiketa pozitive (me fytyrë) dhe negative (pa asnjë fytyrë). DetektMultiScale merr koordinatat e të gjitha fytyrave dhe i kthen ato si një listë drejtkëndëshash. Por mos harroni të konvertoni imazhin RGB në shkallë gri përpara se ta përdorni.

Funksioni i mëposhtëm face_detector numëron sa fytyra njerëzore janë në foto:

def face_detector(img_path):
    img = cv2.imread(img_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray)
    return len(faces) > 0

Performanca e face_detector u vlerësua në 100 mostra të imazheve të njerëzve dhe qenit. Ky detektor njeh të gjitha fytyrat e njeriut nga të dhënat e njeriut, por nuk funksionoi mirë në grupin e të dhënave të qenve. Kishte rreth 11% false pozitive.

Detektori i qenve

Është koha për të përdorur një detektor tjetër që funksionon më mirë në grupin e të dhënave të qenve. Kam përdorur peshat e para-trajnuara ResNet50 në ImageNet në Keras, i cili është trajnuar në mbi 10 milionë imazhe që përmbajnë 1000 etiketa.

Në kodin e mëposhtëm, paths_to_tensor merr shtegun drejt një imazhi dhe kthen një tensor 4D gati për ResNet50. Por, të gjitha modelet e para-trajnuara në Keras kanë nevojë për përpunim shtesë si normalizimi që mund të bëhet duke përdorur preprocess_input. Funksioni dog_detector kthen "True" nëse një qen zbulohet në imazhin e ruajtur në img_path.

from keras.preprocessing import image                  
from tqdm import tqdm
from keras.applications.resnet50 import preprocess_input, decode_predictions
def path_to_tensor(img_path):
    img = image.load_img(img_path, target_size=(224, 224)
    return np.expand_dims(x, axis=0)
def paths_to_tensor(img_paths):
    list_of_tensors = [path_to_tensor(img_path) for img_path in       tqdm(img_paths)]
    return np.vstack(list_of_tensors)
def ResNet50_predict_labels(img_path):
    img = preprocess_input(path_to_tensor(img_path))
    return np.argmax(ResNet50_model.predict(img))
def dog_detector(img_path):
    prediction = ResNet50_predict_labels(img_path)
    return ((prediction <= 268) & (prediction >= 151))

Për të vlerësuar detektorin e qenve, kontrollova nëse klasa e parashikuar e RestNet50 në ImageNet bie në kategoritë e racave të qenve. Detektori i qenve funksionon mirë pa asnjë negativ negativ.

Tani që njohëm qentë në imazhe, është koha për të parashikuar racat. Por së pari ne duhet të analizojmë të dhënat e trenit pak më në detaje:

Grupi i të dhënave

Ky grup i të dhënave ka 8,351 imazhe gjithsej me 133 raca të ndryshme. Numri i imazheve të disponueshme nga të cilat modeli mund të mësojë është rreth 62 për lloj, gjë që mund të mos jetë e mjaftueshme për CNN. Në këtë mjedis të botës reale, imazhet kanë rezolucione, madhësi, kushte ndriçimi të ndryshme, gjithashtu disa imazhe kanë më shumë se një qen. Duke krahasuar shpërndarjen e intensitetit të pikselit të imazheve të njëjta të etiketuara, vura re, për shembull, fotot për American_staffordshire_terrier ndryshojnë në kontrast, madhësi dhe shkëlqim. Vlerat e intensitetit të kanaleve të kuqe, jeshile dhe blu të gjetura në këto dy imazhe shpërndahen ndryshe. Ky ndryshim në të dhëna e bën detyrën e caktimit të racës për qentë edhe më sfiduese.

Shpërndarja e etiketave të racave në të dhënat e trajnimit tregon se të dhënat janë paksa të çekuilibruara, me, mesatarisht, 53 mostra për klasë. Shumica e racave kanë pothuajse të njëjtën shpërndarje në grupet e të dhënave të trenave, të vlefshme dhe testuese.

Gjithashtu, si pjesë e përpunimit të të dhënave, kam hequr shkallët e imazheve duke e ndarë çdo piksel në çdo imazh me 255.

Metrika

Meqenëse këtu kemi të bëjmë me një problem të shumë-klasifikimit dhe të dhënat janë paksa të çekuilibruara, unë përdora metrikën e vlerësimit të saktësisë dhe funksionin e kostos categorical_crossentropy. Por, së pari, etiketat duhet të jenë në një format kategorik. Skedarët e synuar janë lista e etiketave të koduara të qenve që lidhen me imazhin me këtë format. Kjo humbje e regjistrit me shumë klasa ndëshkon klasifikuesin nëse probabiliteti i parashikuar çon në një emërtim të ndryshëm nga ai aktual dhe shkakton saktësi më të lartë. Një klasifikues i përsosur ka një humbje zero dhe një saktësi prej 100%.

Klasifikoni racat e qenve

Këtu kam krijuar një CNN me 4 shtresa në Keras me funksionin e aktivizimit Relu. Modeli fillon me një imazh hyrës prej 224 *224*3 kanale me ngjyra. Ky imazh hyrës është i madh, por shumë i cekët, vetëm R, G dhe B. Shtresat e konvolucionit shtrydhin imazhet duke reduktuar gjerësinë dhe lartësinë ndërsa rrisin thellësinë shtresë pas shtrese. Duke shtuar më shumë filtra, rrjeti mund të mësojë më shumë veçori domethënëse në foto dhe të përgjithësohet më mirë.

Shtresa ime e parë prodhon një dalje me 16 kanale funksionale që përdoret si hyrje për shtresën tjetër. Filtrat janë koleksioni i 16 matricave katrore, hartave të veçorive dalëse, të cilat janë shuma të ponderuara të veçorive hyrëse dhe kernelit. Peshat e kernelit llogariten gjatë procesit të trajnimit nga të dhënat e ImageNet, dhe ajo që bën është të rrëshqasë nëpër hartat e veçorive hyrëse dhe të prodhojë veçori dalëse. Pra, forma e veçorive të daljes varet nga madhësia e kernelit dhe karakteristikat hyrëse.

Kontrolloni këtë faqe për një kuptim më të mirë se si funksionon CNN.

Mendoj se do të ishte ideale që veçoritë hyrëse dhe dalëse të kishin të njëjtën madhësi. Kështu, vendosa të përdor të njëjtin mbushje për të dalë nga skaji i imazheve me pads zero për të gjitha shtresat me hapin 2. Kam përdorur gjithashtu operacionin max-pooling për të siguruar që nuk po humbas informacionin në foto duke ulur mundësinë e mbipërshtatjes. Maksimumi i bashkimit merr maksimumin e pikselëve rreth një vendndodhjeje.
Pas katër shtresave konvolucionale dhe bashkimit maksimal, të ndjekur nga dy shtresa plotësisht të lidhura, kam trajnuar klasifikuesin. Shtresat Convolutional nxjerrin veçoritë e imazhit dhe klasifikuesi i klasifikon ato në bazë të veçorive të marra më parë. Imazhi më poshtë tregon se si sekuenca e blloqeve të veçorive dhe klasifikuesit në krye transferojnë informacionin nga imazhi i papërpunuar dhe parashikojnë vlerat e synuara të kërkuara.

Arkitektura e modelit të CNN është:

from keras.layers import Conv2D, MaxPooling2D, GlobalAveragePooling2D
from keras.layers import Dropout, Flatten, Dense
from keras.models import Sequential
# Model Architecture
model = Sequential()
model.add(Conv2D(filters=16, kernel_size=2, padding='same', activation='relu', input_shape=(224,224,3)))
model.add(MaxPooling2D(pool_size=2))

model.add(Conv2D(filters=32, kernel_size=2 , padding='same' , activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=64 , kernel_size=2 , padding='same' , activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Dropout(0.4))
model.add(Conv2D(filters=128 , kernel_size=2 , padding='same' , activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Dropout(0.4))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.4))
model.add(Dense(133,activation='softmax'))
model.summary()

Modeli i krijuar nga e para nuk po funksionon mirë, saktësia 12%, për shkak të mungesës së të dhënave të mjaftueshme të imazheve për të trajnuar modelin. Një përmirësim i mundshëm është shtimi i të dhënave për të shtuar më shumë të dhëna. Kjo strategji modifikon imazhet duke mbushur, prerë dhe rrotulluar imazhet në mënyrë të rastësishme. Gjithashtu i mundëson modelit të përgjithësohet më mirë pa u përshtatur më tepër, natyrisht, me parametrat e duhur.

Siç u përmend më parë, trajnimi i një klasifikuesi CNN të bërë nga e para në një të dhënë të vogël si kjo do të çojë në mospërshtatje dhe me kaq shumë shtresa, dhe akordimi i parametrave shpesh shkakton mbipërshtatje. Pra, është koha për të përdorur rrjetet e para-trajnuara të mësimit të transferimit për të krijuar një klasifikues të racës CNN edhe pse këto modele nuk janë krijuar në mënyrë eksplicite për këtë detyrë. Por një avantazh i këtyre rrjeteve është se ato janë trajnuar në grupe të dhënash të mëdha, ImageNet me miliona imazhe të etiketuara dhe kanë arritur saktësinë 90%. Gjithashtu, ata mund të përgjithësohen në imazhe të tjera jashtë ImageNet.

I zbatova modelet e para-trajnuara si VGG, Inception V3 dhe ResNet në Keras dhe krahasova saktësinë e tyre. I përdora ato si nxjerrës të veçorive fikse dhe rregullova mirë shtresën e lidhur plotësisht duke minimizuar funksionin e humbjes së entropisë duke përdorur zbritjen e gradientit stokastik, shkallën e të mësuarit prej 0,001 dhe momentin Nesterov. Gjithashtu, shtresa e fundit e lidhur plotësisht është ndryshuar në numrin e racave të qenve, 133. Më pas, çdo model është trajnuar në 25 epoka me 20 mostra secila grup.

# model Architecture
Xception_model = Sequential()
Xception_model.add(GlobalAveragePooling2D(input_shape=(train_Xception.shape[1:])))
Xception_model.add(Dense(133, activation='softmax'))
checkpointer = ModelCheckpoint(filepath='saved_models/weights.best.Xception.hdf5', verbose = 0, save_best_only=True)
sgd = SGD(lr= 1e-3 , decay=1e-6, momentum=0.9 , nesterov = True)
# compile the model
Xception_model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])
# Training the model 
Xception_model.fit(train_Xception , train_targets, 
               validation_data = (valid_Xception, valid_targets),
               shuffle = True,
               batch_size = 20,
               epochs = 25,
               verbose = 1)

Modeli Xception tejkalon të gjitha modelet e tjera me një saktësi prej 86% dhe një humbje prej 0,4723 në të dhënat e testimit. Në përgjithësi, modelet e bazuara në Inception tejkalojnë pak VGG dhe ResNet në ImageNet; gjithashtu, është më efikas nga ana llogaritëse. Performanca e modelit mund të përmirësohet duke aplikuar teknika më të përshtatshme akordimi. Për shembull, trajnimi i disa shtresave të sipërme në lidhje me veçori specifike të qenve dhe ngrirja e të tjerave që zbulojnë veçori më të përgjithshme. Sepse ato janë kapur tashmë në peshat ImageNet.

Rezultati

Tani, është koha për të kombinuar detektorët dhe Xception-predict-race, gjithashtu, për t'i testuar ato në disa imazhe me madhësi dhe rezolucione të ndryshme. Siç u përmend më parë, saktësia u zgjodh si një metrikë e vlerësimit të modelit për këtë klasifikues. Ky kod merr një rrugë drejt një imazhi dhe së pari përcakton nëse imazhi është një qen, njeri apo asnjëri prej tyre, më pas e kthen racën e parashikuar të ngjashme:

def Xception_predict_breed (img_path):
    bottleneck_feature = extract_Xception(path_to_tensor(img_path)) 
    predicted_vector = Xception_model.predict(bottleneck_feature) 
    return dog_names[np.argmax(predicted_vector)]
def display_img(img_path):
    img = cv2.imread(img_path)
    cv_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    imgplot = plt.imshow(cv_rgb)
    return imgplot
def breed_identifier(img_path):
    display_img(img_path)
    prediction = Xception_predict_breed(img_path)
    if dog_detector(img_path) == True:
        print('picture is a dog')
        return print (f"This dog is a {prediction}\n")
    
    if face_detector(img_path) == True:
        print('picture is a human')
        return print (f"This person looks like a {prediction}\n")
    
    else:
        return print('The picture is neither dog nor human')

Rezultati tregon se modeli po funksionon mirë. Për shembull, ai mund të parashikonte American_staffordshire_terrier në të dhënat e provës ndërsa ishte trajnuar për imazhe me shkëlqim, madhësi dhe nivele të ndryshme zmadhimi.

Dhe rezultati i mëposhtëm është në imazhet njerëzore:

Matrica e konfuzionit të parashikimeve në të dhënat e testit është dhënë më poshtë. Por, nuk është e lehtë të përfytyrosh se cilat raca janë klasifikuar më keq.

Për një kuptim më të mirë të rasteve të keqklasifikuara, unë çiftova vlerat e parashikuara dhe ato aktuale. Modeli nuk mund të klasifikonte midis Great_pyrenees dhe Kuvasz, të cilat të dyja janë të bardha, të mëdha dhe me gëzof. Gjithashtu nuk mund të dallonte midis Mastiff dhe Bullmastiff, i cili është një përzierje midis një bulldogu dhe një mastifi. Duke shtuar më shumë të dhëna, modeli do të jetë në gjendje të mësojë veçori më specifike dhe të bëjë dallimin midis këtyre racave të ngjashme, gjë që është edhe konfuze për njerëzit.

Përmirësime të mundshme

Saktësia e modelit mund të përmirësohet duke shtuar të dhënat dhe duke shtuar më shumë të dhëna të etiketuara me trajnime pasi modeli ishte pak i çekuilibruar. Me marrjen e më shumë të dhënave, modelet Convnet do të jenë më të afta të mësojnë veçoritë më të rëndësishme dhe specifike të qenve nga imazhet. Por, kërkon një sasi të konsiderueshme kohe dhe përdorim të memories. Një mënyrë tjetër e mundshme për të rritur saktësinë e modelit është mesatarizimi i parashikimeve të disa rrjeteve për të marrë parashikimin përfundimtar të njohur si teknikat e ansamblit. Siç e përmenda më parë, një përmirësim mund të jetë aplikimi i strategjive më të përshtatshme të rregullimit të imët për të rregulluar peshat bazuar në të dhënat. Gjithashtu, një analizë e duhur e modelit përfundimtar do të ishte shtimi i pak zhurmës në imazhe dhe për të parë se si po funksionon.

Përfundim

Në këtë punë, unë kam zbatuar klasifikuesin e kaskadës haar dhe peshat e para-stërvitura ResNet50 për të zbuluar fytyrat e njerëzve dhe qenve. Gjithashtu kalova pak kohë duke eksploruar të dhënat për të gjetur karakteristikat e imazheve, të cilat më ndihmuan të aplikoja teknika më të përshtatshme. Për klasifikimin e racave të qenve, unë kam filluar me disa numra shtresash Convolutional si një rrjet bazë. Modeli performoi më mirë se një supozim i rastësishëm, 1 në 133, por ende nuk përshtatet.

Me kohën dhe fuqinë e dhënë të memories, vendosa të shfrytëzoj disa arkitektura të të mësuarit të transferimit për të përmirësuar performancën e CNN, gjë që rezultoi në një përmirësim të ndjeshëm. Kam përdorur modelet e trajnuara paraprakisht si nxjerrës të veçorive fikse dhe ndryshova shtresën mesatare globale të bashkimit, shtresën e lidhur plotësisht dhe aplikova qasje të tjera të akordimit. Xception dhe ResNet50 prodhuan saktësi më të lartë se të tjerët, rreth 86%. Është mjaft sfiduese për të marrë një saktësi më të lartë për shkak të kompleksitetit të këtyre llojeve të grupeve të të dhënave me disa ngjashmëri midis racave të përziera.

Në fund, e testova modelin në të njëjtat foto të etiketuara me shpërndarje të ndryshme intensiteti dhe performoi mjaft mirë.

Pjesa më emocionuese e këtij projekti ishte se si ConvNets moderne me disa rreshta kodesh na e bënë të lehtë kryerjen e detyrave që edhe njerëzit i konsiderojnë sfiduese. Por është mjaft e vështirë të përmirësohet modeli me kohën e dhënë dhe fuqinë e memories. Kam në plan të eksploroj qasjet e përmendura të përmirësimit dhe do ta përditësoj këtë blog me rezultate më të mira.

ju lutem mos ngurroni të përdorni "kodin tim" nëse ju duket interesant.