Kā izveidot attēlu klasifikatoru ar lielāku nekā 97% precizitāti

Skaidrs un pilnīgs panākumu plāns

Kā iemācīt datoru aplūkot attēlu un pareizi identificēt to kā ziedu? Kā iemācīt datoru redzēt zieda attēlu un tad precīzi pateikt, kāda ziedu suga tas ir, pat ja jūs pat nezināt, kāda suga tas ir?

Ļaujiet man jums parādīt!

Šis raksts iepazīstinās jūs ar attēlu klasifikatora izveides pamatiem, izmantojot PyTorch. Varat iedomāties, ka kaut ko līdzīgu izmantojat tālruņa lietotnē, kurā tiek pateikts zieda nosaukums, uz kuru kamera skatās. Ja vēlaties, jūs varētu apmācīt šo klasifikatoru un pēc tam eksportēt to izmantošanai savā lietojumprogrammā.

Tas, ko jūs darāt no šejienes, pilnībā atkarīgs no jums un jūsu iztēles.

Es saliku šo rakstu visiem, kas tur ir pilnīgi jauni un meklē vietu, kur sākt. Jūsu pienākums ir ņemt šo informāciju, uzlabot to un padarīt to par savu!

Ja vēlaties apskatīt piezīmju grāmatiņu, to varat atrast šeit.

Tā kā šis PyTorch attēlu klasifikators tika izveidots kā Udacity programmas galīgais projekts, kods balstās uz Udacity kodu, kas savukārt balstās uz oficiālo PyTorch dokumentāciju. Udacity arī nodrošināja JSON failu etiķešu kartēšanai. Šis fails ir atrodams šajā GitHub repo.

Informāciju par ziedu datu kopu var atrast šeit. Datu kopā ir atsevišķa mape katrai no 102 ziedu klasēm. Katrs zieds ir apzīmēts kā skaitlis, un katrā no numurētajiem direktorijiem ir vairāki .jpg faili.

Sāksim!

Annijas Sprattas foto vietnē Unsplash

Tā kā šis ir neironu tīkls, kas izmanto lielāku datu kopu, nekā mans centrālais procesors varētu rīkoties saprātīgā laika posmā, es devos uz priekšu un izveidoju savu attēlu klasifikatoru Google Colab. Colab ir patiesi satriecošs, jo tas nodrošina bezmaksas GPU. (Ja esat iesācējs Colab, iepazīstieties ar šo rakstu par darba sākšanu ar Google Colab!)

Tā kā es izmantoju Colab, man vispirms vajadzēja importēt PyTorch. Tas nav jādara, ja nelietojat Colab.

*** ATJAUNINĀT! (01/29) *** Colab tagad atbalsta vietējo PyTorch !!! Jums nevajadzētu darbināt zemāk esošo kodu, bet es to atstāju tikai gadījumam, ja kādam rodas kādas problēmas!

# Ja izmantojat Google Colab, importējiet PyTorch
# http://pytorch.org/
no os.path imports pastāv
no wheel.pep425tags importa get_abbr_impl, get_impl_ver, get_abi_tag
platforma = '{} {} - {}'. formāts (get_abbr_impl (), get_impl_ver (), get_abi_tag ())
cuda_output =! ldconfig -p | grep cudart.so | sed -e's /.* \. \ ([0-9] * \) \. \ ([0-9] * \) $ / cu \ 1 \ 2 / '
paātrinātājs = cuda_output [0], ja tāds pastāv ('/ dev / nvidia0') cits 'cpu'
! pip install -q http://download.pytorch.org/whl/{accelerator}/torch-0.4.1-{platform}-linux_x86_64.whl torchvision
importa lāpa

Pēc tam, kad man bija dažas problēmas ar Spilvenu (tas ir buggy Colab!), Es vienkārši devos uz priekšu un skrēju šādi:

importēt PIL
drukāt (PIL.PILLOW_VERSION)

Ja rodas kaut kas zemāks par 5.3.0, izmantojiet nolaižamo izvēlni sadaļā “Runtime”, lai “Restart runtime” un atkal palaistu šo šūnu. Jums vajadzētu būt labam, lai dotos!

Jūs vēlēsities izmantot GPU šim projektam, kuru ir neticami vienkārši uzstādīt Colab. Jūs vienkārši ejat uz nolaižamo izvēlni “izpildlaika”, atlasiet “mainīt izpildlaika veidu” un pēc tam aparatūras paātrinātāja nolaižamajā izvēlnē atlasiet “GPU”!

Tad man patīk skriet

train_on_gpu = torch.cuda.is_avable ()
ja ne vilciena_on_gpu:
    print ('Bummer! Apmācība uz CPU ...')
cits:
    print ('Jums ir labi iet! Apmācība uz GPU ...')

tikai lai pārliecinātos, ka tas darbojas. Tad skrien

ierīce = torch.device ("cuda: 0", ja torch.cuda.is_available () else "cpu")

lai definētu ierīci.

Pēc tam importējiet failus. Ir daudz veidu, kā to izdarīt, ieskaitot Google diska pievienošanu, ja datu krājums tur ir saglabāts, kas patiesībā ir patiešām vienkāršs. Lai arī es neticēju secināt, ka tas ir visnoderīgākais risinājums, es to iekļauju zemāk tikai tāpēc, ka tas ir tik vienkārši un noderīgi.

no vietnes google.colab importēšanas diska
drive.mount ('/ content / gdrive')

Tad jūs redzēsit saiti, noklikšķiniet uz tās, atļaujiet piekļuvi, nokopējiet uznirstošo kodu, ielīmējiet to lodziņā, nospiediet taustiņu enter, un jums ir labi doties! Ja kreisajā pusē sānu lodziņā neredzat savu disku, vienkārši nospiediet “atsvaidzināt”, un tam vajadzētu parādīties.

(Palaidiet šūnu, noklikšķiniet uz saites, nokopējiet kodu lapā, ielīmējiet to lodziņā, nospiediet taustiņu enter un tas tiks parādīts, kad esat veiksmīgi uzstādījis disku):

Tas tiešām ir ļoti vienkārši!

Tomēr, ja jūs labprātāk lejupielādētu koplietota zip faila saiti (šī projekta likvidēšana ir vienkāršāka un ātrāka), varat izmantot:

! wget
! unzip

Piemēram:

! wget -cq https://s3.amazonaws.com/content.udacity-data.com/courses/nd188/flower_data.zip
! unzip -qq flower_data.zip

Tas ļaus jums iegūt Udacity ziedu datus dažu sekunžu laikā!

(Ja augšupielādējat mazus failus, varat tos vienkārši augšupielādēt, izmantojot vienkāršu kodu. Tomēr, ja vēlaties, varat arī doties uz ekrāna kreiso pusi un noklikšķināt uz “augšupielādēt failus”, ja neveicat justies kā palaižot vienkāršu kodu, lai sagrābtu vietējo failu.)

Pēc datu ielādes es importēju bibliotēkas, kuras vēlējos izmantot:

% ievietota matplotlib
% config InlineBackend.figure_format = 'tīklene'
importa laiks
importa json
importa kopija
importēt matplotlib.pyplot kā plt
ievest jūradzimis kā sns
importēt nervozs kā np
importēt PIL
no PIL importa attēla
no kolekcijām importē
importa lāpa
no lāpas importa nn, optim
no torch.optim import lr_scheduler
no lāpas.autograd imports Mainīgs
importēt torchvision
no torchvision importa datu kopām, modeļiem, pārveidēm
no torch.utils.data.sampler importēt SubsetRandomSampler
importa lāpa.nn kā nn
importa lodlampa.nn.funkcionāls kā F

Tālāk seko datu pārvērtības! Jūs vēlaties pārliecināties, ka treniņu komplektā izmantojat vairāku veidu pārvērtības, lai palīdzētu jūsu programmai iemācīties tik daudz, cik vien iespējams. Varat izveidot stabilāku modeli, apmācot to uz apvērstiem, pagrieztiem un apgrieztiem attēliem.

Tas nozīmē, ka tiek nodrošinātas standarta novirzes, lai normalizētu attēla vērtības, pirms tās tiek nodotas mūsu tīklam, bet tās var atrast arī, aplūkojot attēla sensoru dažādo izmēru vidējās un standarta novirzes vērtības. Oficiālā dokumentācija šeit ir neticami noderīga!

Savam attēlu klasifikatoram es to darīju vienkāršu:

data_transforms = {
    'vilciens': pārveido.Komponēt ([
        pārveido.RandomRotation (30),
        pārveido.RandomResizedCrop (224),
        transforms.RandomHorizontalFlip (),
        pārveido.ToTensor (),
        pārveido.Normalizēt ([0,455, 0,456, 0,406],
                             [0.229, 0.224, 0.225])
    ]),
    “derīgs”: pārveido.Komponēt ([
        pārveido.Resize (256),
        pārveido.CenterCrop (224),
        pārveido.ToTensor (),
        pārveido.Normalizēt ([0,455, 0,456, 0,406],
                             [0.229, 0.224, 0.225])
    ])
}
# Ievietojiet datu kopas, izmantojot ImageFolder
image_datasets = {x: datasets.ImageFolder (os.path.join (data_dir, x),
                                          datu_transformācijas [x])
                  x x ['vilcienā', 'derīgs']}
# Izmantojot attēlu datu kopas un vilciena formas, definējiet datu meklētājus
batch_size = 64
dataloaders = {x: torch.utils.data.DataLoader (image_datasets [x], batch_size = batch_size,
                                             shuffle = True, num_workers = 4)
              x x ['vilcienā', 'derīgs']}
klases_vārdi = image_datasets ['vilciens']
dataset_sizes = {x: len (image_datasets [x]) for x in ['vilciens', 'derīgs']}
klases_vārdi = image_datasets ['vilciens']

Kā redzat iepriekš, arī iepriekš norādītajā kodā es definēju partijas lielumu, datu ielādētājus un klases nosaukumus.

Lai ļoti ātri apskatītu datus un pārbaudītu savu ierīci, es skrēju:

drukāt (datu kopas izmēri)
drukāt (ierīce)
{'vilciens': 6552, 'derīgs': 818}
cuda: 0

Tālāk mums jāveic kartēšana no etiķetes numura un faktiskā zieda nosaukuma. Udacity sniedza JSON failu, lai šo kartēšanu varētu veikt vienkārši.

ar atvērtu ('cat_to_name.json', 'r') kā f:
    cat_to_name = json.load (f)

Lai pārbaudītu datu ielādētāju, izpildiet:

attēli, etiķetes = nākamais (iter (dataloaders ['train']))
rand_idx = np.random.randint (len (attēli))
# Drukāt (rand_idx)
drukāt ("etiķete: {}, klase: {}, nosaukums: {}". formāts) (etiķetes [rand_idx] .item (),
                                               klases_vārdi [etiķetes [rand_idx] .item ()],
                                               cat_to_name [klases_vārdi [iezīmes [rand_idx] .item ()]]))

Tagad tas sāk kļūt vēl aizraujošāks! Vairākus modeļus pēdējo gadu laikā cilvēki ir izveidojuši tālu, daudz vairāk kvalificēti, nekā vairumam no mums, atkārtotai izmantošanai datoru redzes problēmu risināšanā. PyTorch ļauj ērti ielādēt iepriekš apmācītus modeļus un uz tiem balstīties, un tieši to mēs gatavojamies darīt šajā projektā. Modeļa izvēle ir pilnībā jūsu ziņā!

Daži no populārākajiem iepriekš apmācītajiem modeļiem, piemēram, ResNet, AlexNet un VGG, nāk no ImageNet Challenge. Šie iepriekš apmācītie modeļi ļauj citiem ātri sasniegt progresīvus rezultātus datora redzējumā, neprasot tik lielu datora enerģijas daudzumu, pacietību un laiku. Man faktiski bija lieliski rezultāti ar DenseNet, un es nolēmu izmantot DenseNet161, kas man salīdzinoši ātri deva ļoti labus rezultātus.

To var ātri iestatīt, palaižot

modelis = modeļi.densenet161 (iepriekš apmācīts = patiess)

taču varētu būt interesantāk izvēlēties sev modeli, pilnveidotāju un plānotāju. Lai iestatītu izvēli arhitektūrā, palaidiet

modeļa nosaukums = 'densenet' #vgg
ja model_name == 'densenet':
    modelis = modeļi.densenet161 (iepriekš apmācīts = patiess)
    num_in_features = 2208
    drukāt (modelis)
elif model_name == 'vgg':
    modelis = modeļi.vgg19 (iepriekš apmācīts = patiess)
    num_in_features = 25088
    drukāt (modelis.klases)
cits:
    drukāt ("Nezināms modelis, lūdzu, izvēlieties" densenet "vai" vgg ")

kas ļauj ātri iestatīt alternatīvu modeli.

Pēc tam jūs varat sākt veidot savu klasifikatoru, izmantojot parametrus, kas jums vislabāk darbojas. Es gāju uz priekšu un uzcēlu

paramam model.parameters ():
    param.requires_grad = Nepatiess
def būvēšanas klasifikators (num_in_features, hidden_layers, num_out_features):
   
    klasifikators = nn.Sequential ()
    ja hidden_layers == nav:
        klasifikators.add_modulis ('fc0', nn.Linear (num_in_features, 102))
    cits:
        layer_sizes = zip (slēptie slāņi [: - 1], slēptie slāņi [1:])
        classifier.add_module ('fc0', nn.Linear (num_in_features, hidden_layers [0]))
        klasifikators.add_modulis ('relu0', nn.ReLU ())
        klasifikators.add_modulis ('drop0', nn.Dropout (.6))
        klasifikators.add_modulis ('relu1', nn.ReLU ())
        klasifikators.add_modulis ('drop1', nn.Dropout (.5))
        i, (h1, h2) uzskaitījumā (slāņa_izmēri):
            klasifikators.add_modulis ('fc' + str (i + 1), nn.Linear (h1, h2))
            klasifikators.add_modulis ('relu' + str (i + 1), nn.ReLU ())
            klasifikators.add_modulis ('piliens' + str (i + 1), nn.propout (.5))
        classifier.add_module ('output', nn.Linear (hidden_layers [-1], num_out_features))
        
    atgriešanās klasifikators

kas ļauj viegli mainīt slēpto slāņu skaitu, ko izmantoju, kā arī ātri pielāgot pamešanas ātrumu. Jūs varat izlemt pievienot papildu ReLU un izstāšanās slāņus, lai smalkāk modelētu.

Pēc tam strādājiet pie klasifikatora parametru apmācības. Es nolēmu pārliecināties, ka šeit apmācīju tikai klasifikatora parametrus, kamēr funkciju parametri ir iesaldēti. Izmantojot optimizētāju, kritēriju un plānotāju, varat kļūt tik radošs, cik vēlaties. Kritērijs ir metode, ko izmanto modeļa piemērotības novērtēšanai, optimizētājs ir optimizācijas metode, ko izmanto svaru atjaunināšanai, un plānotājs nodrošina dažādas metodes, lai pielāgotu optimizācijas laikā izmantoto mācību ātrumu un soļa lielumu.

Izmēģiniet pēc iespējas vairāk iespēju un kombināciju, lai redzētu, kas dod vislabāko rezultātu. Šeit varat redzēt visu oficiālo dokumentāciju. Es iesaku to apskatīt un pats pieņemt lēmumus par to, ko vēlaties izmantot. Jums šeit burtiski nav bezgalīgs skaits iespēju, taču, protams, tas jūtas, tiklīdz sākat spēlēt apkārt!

hidden_layers = Nav
classifier = build_classifier (num_in_features, hidden_layers, 102)
drukāt (klasifikators)
# Apmāciet tikai klasifikatora parametrus, funkciju parametri ir iesaldēti
ja model_name == 'densenet':
    modelis.klasifikators = klasifikators
    kritērijs = nn.CrossEntropyLoss ()
    optimizētājs = optim.Adadelta (model.parameters ())
    sched = optim.lr_scheduler.StepLR (optimizētājs, step_size = 4)
elif model_name == 'vgg':
    modelis.klasifikators = klasifikators
    kritērijs = nn.NLLLoss ()
    optimizētājs = optim.Adam (model.classifier.parameters (), lr = 0,0001)
    sched = lr_scheduler.StepLR (optimizētājs, solis_lielums = 4, gamma = 0,1)
cits:
    caurlaide

Tagad ir pienācis laiks apmācīt savu modeli.

# Adaptēts no https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html
def train_model (modelis, kritērijs, optimizētājs, grafiks, num_epochs = 5):
    kopš = laiks.time ()
best_model_wts = copy.deepcopy (model.state_dict ())
    best_acc = 0,0
par laikmetu diapazonā (num_epochs):
        print ('Laikmets {} / {}'. formāts (laikmets + 1, num_epochs))
        drukāt ('-' * 10)
# Katrā laikmetā ir apmācības un apstiprināšanas posms
        fāzei ['vilcienā', 'derīgi']:
            ja fāze == 'vilciens':
                model.train () # Iestatiet modeli uz apmācības režīmu
            cits:
                model.eval () # Iestatiet modeli, lai novērtētu režīmu
tekošais zaudējums = 0,0
            izpildes_labojumi = 0
# Neveiciet datus.
            ieejām, etiķetēm datu ielādes ierīces [fāze]:
                ieejas = ieejas.to (ierīce)
                labels = labels.to (ierīce)
# Nulles parametru gradienti
                optimizer.zero_grad ()
# Uz priekšu
                # sliežu ceļa vēsture, ja tikai vilcienā
                ar torch.set_grad_enabled (fāze == 'vilciens'):
                    izvades = modelis (ieejas)
                    _, preds = torch.max (izejas, 1)
                    zaudējumi = kritērijs (rezultāti, etiķetes)
# Atpakaļ + optimizēt tikai treniņa fāzē
                    ja fāze == 'vilciens':
                        # sched.step ()
                        loss.backward ()
                        
                        optimizer.step ()
# Statistika
                tekošs zaudējums + = zaudējumi.item () * ieejas lielums (0)
                tekošie_labojumi + = lodlampa.summa (preds == etiķetes.dati)
epoch_loss = tekošs zaudējums / datu kopas izmēri [fāze]
            epoch_acc = running_corrects.double () / dataet_sizes [fāze]
print ('{} Zaudējums: {: .4f} Acc: {: .4f}'. formāts) (
                fāze, epoch_loss, epoch_acc))
# Dziļi nokopējiet modeli
            ja fāze == “derīga” un epoch_acc> best_acc:
                best_acc = epoch_acc
                best_model_wts = copy.deepcopy (model.state_dict ())
drukāt ()
laiks_laps = laiks.time () - kopš
    print ('Apmācība pabeigta {: .0f} m {: .0f} s'.format (
        time_elapsed // 60, time_elapsed% 60))
    print ('Best val Acc: {: 4f}'. formāts (best_acc))
# Ielādēt labāko modeļa svaru
    model.load_state_dict (labākais_modele_wts)
    
    atgriešanās modelis
laikmets = 30
modelis.to (ierīce)
modelis = vilciena modelis (modelis, kritērijs, optimizētājs, grafiks, laikmets)

Es gribēju, lai varētu viegli pārraudzīt savas epopejas, kā arī sekot līdzi laikam, kas pagājis, kamēr mans modelis darbojās. Iepriekš minētais kods satur abus, un rezultāti ir diezgan labi! Var redzēt, ka modelis ātri mācās un validācijas komplekta precizitāte līdz 7. epopejai ātri sasniedza vairāk nekā 95%!

Laikmets 1/30
----------
vilciena zaudējumi: 2.4793 Acc: 0.4791
derīgi zaudējumi: 0.9688 Acc: 0.8191

Laikmets 2/30
----------
vilciena zaudējumi: 0.8288 Acc: 0.8378
derīgi zaudējumi: 0,4714 Acc: 0,9010

Laikmets 3/30
----------
vilciena zaudējumi: 0.5191 Acc: 0.8890
derīgi zaudējumi: 0,3197 Acc: 0,9181

Laikmets 4/30
----------
vilciena zaudējumi: 0.4064 Acc: 0.9095
derīgi zaudējumi: 0,2975 Acc: 0,9169

Laikmets 5/30
----------
vilciena zaudējumi: 0.3401 Acc: 0.9214
derīgi zaudējumi: 0,2486 Acc: 0,9401

Laikmets 6/30
----------
vilciena zaudējumi: 0.3111 Acc: 0.9303
derīgi zaudējumi: 0,2153 Acc: 0,9487

Laikmets 7/30
----------
vilciena zaudējumi: 0,2987 Acc: 0,9298
derīgi zaudējumi: 0.1969 Acc: 0.9584
...
Treniņš pabeigts 67m 43s
Labākais val Acc: 0.973105

Var redzēt, ka šī koda palaišana pakalpojumā Google Colab ar GPU aizņēma nedaudz vairāk par stundu.

Tagad ir pienācis laiks novērtēšanai

model.eval ()
precizitāte = 0
izejmateriāliem, etiķetēm datu atjaunošanas ierīcēs ['derīgi']:
    ieejas, etiķetes = ieejas.to (ierīce), etiķetes.to (ierīce)
    izvades = modelis (ieejas)
    
    # Klase ar visaugstāko varbūtību ir mūsu paredzētā klase
    vienādība = (labels.data == outputs.max (1) [1])
# Precizitāte = pareizo prognožu skaits, dalīts ar visām prognozēm
    precizitāte + = vienlīdzība.tipa_as (lāpa.FloatTensor ()). vidējā ()
    
print ("Testa precizitāte: {: .3f}". formāts (precizitāte / len (datu vākšanas rīki ['derīgi'])))
Testa precizitāte: 0.973

Ir svarīgi saglabāt savu kontrolpunktu

model.class_to_idx = image_datasets ['vilciens']. class_to_idx
kontrolpunkts = {'input_size': 2208,
              'output_size': 102,
              “laikmets”: laikmets,
              “partijas_izmērs”: 64,
              'modelis': models.densenet161 (iepriekš apmācīts = patiess),
              'klasifikators': klasifikators,
              “plānotājs”: grafiks,
              “optimizētājs”: optimizer.state_dict (),
              'state_dict': model.state_dict (),
              'class_to_idx': model.class_to_idx
             }
   
torch.save (kontrolpunkts, 'checkpoint.pth')

Jums nav jāsaglabā visi parametri, bet es tos šeit iekļauju kā piemēru. Šis kontrolpunkts īpaši ietaupa modeli ar iepriekš apmācītu densenet161 arhitektūru, bet, ja vēlaties saglabāt savu kontrolpunktu ar divu izvēles iespēju, to var absolūti izdarīt. Vienkārši pielāgojiet ievades lielumu un modeli.

Tagad jūs varat ielādēt savu kontrolpunktu. Ja iesniedzat projektu Udacity darbvietā, viss var nedaudz sarežģīt. Šeit ir sniegta neliela palīdzība kontrolpunkta ielādes traucējummeklēšanā.

Jūs varat pārbaudīt savas atslēgas, palaižot

ckpt = torch.load ('checkpoint.pth')
ckpt.keys ()

Pēc tam ielādējiet un atjaunojiet modeli!

def load_checkpoint (faila ceļš):
    kontrolpunkts = torch.load (faila ceļš)
    modelis = kontrolpunkts ['modelis']
    model.classifier = kontrolpunkts ['klasifikators']
    model.load_state_dict (kontrolpunkts ['state_dict'])
    model.class_to_idx = kontrolpunkts ['class_to_idx']
    optimizētājs = kontrolpunkts ['optimizētājs']
    laikmets = kontrolpunkts ['laikmets']
    
    paramam model.parameters ():
        param.requires_grad = Nepatiess
        
    atgriešanās modelis, kontrolpunkts ['class_to_idx']
modelis, class_to_idx = load_checkpoint ('checkpoint.pth')

Vai vēlaties turpināt? Ir laba ideja veikt attēlu sākotnēju apstrādi un secinājumus par klasifikāciju. Iet uz priekšu un definējiet savu attēla ceļu un atveriet attēlu:

image_path = 'ziedu_dati / derīgs / 102 / image_08006.jpg'
img = Image.open (image_path)

Apstrādājiet savu attēlu un apskatiet apstrādāto attēlu:

def process_image (attēls):
    '' 'Mērogo, apgriež un normalizē PyTorch modeļa PIL attēlu,
        atgriež Numpy masīvu
    '' '
    # Apstrādājiet PIL attēlu izmantošanai PyTorch modelī
    # tensor.numpy (). transponēt (1, 2, 0)
    preprocess = transforms.Compose ([
        pārveido.Resize (256),
        pārveido.CenterCrop (224),
        pārveido.ToTensor (),
        pārveido.Normalizē (vidējais = [0,455, 0,456, 0,406],
                             std = [0,229, 0,224, 0,225])
    ])
    attēls = priekšapstrāde (attēls)
    atgriezt attēlu
def imshow (attēls, cirvis = nav, nosaukums = nav):
    "" "Imshow for Tensor." ""
    ja cirvis nav:
        vīģe, cirvis = plt.subplots ()
    
    # PyTorch sensori pieņem, ka krāsu kanāls ir pirmā dimensija
    #, bet matplotlib pieņem, ka tā ir trešā dimensija
    attēls = attēls.numpy (). transponēt ((1, 2, 0))
    
    # Atcelt atsaukšanu
    vidējais = np.array ([0,455, 0,456, 0,406])
    std = np.array ([0,229, 0,224, 0,225])
    attēls = std * attēls + vidējais
    
    # Attēlam jābūt apcirptam no 0 līdz 1, pretējā gadījumā tas tiek parādīts kā troksnis
    attēls = np.clip (attēls, 0, 1)
    
    ax.imshow (attēls)
    
    atpakaļ cirvis
ar attēlu.open ('ziedu_dati / derīgs / 102 / attēls_08006.jpg') kā attēlu:
    plt.imshow (attēls)
model.class_to_idx = image_datasets ['vilciens']. class_to_idx

Izveidojiet funkciju paredzēšanai:

def prognozēt2 (attēla ceļš, modelis, topk = 5):
    '' 'Paredziet attēla klasi (vai klases), izmantojot apmācītu dziļās mācīšanās modeli.
    '' '
    
    # Ieviesiet kodu, lai paredzētu klasi no attēla faila
    img = Image.open (image_path)
    img = process_image (img)
    
    # Pārveidojiet 2D attēlu 1D vektorā
    img = np.expand_dims (img, 0)
    
    
    img = torch.from_numpy (img)
    
    model.eval ()
    ieejas = mainīgs (img) .to (ierīce)
    logits = model.forward (ieejas)
    
    ps = F.softmax (logits, dim = 1)
    topk = ps.cpu (). topk (topk)
    
    atgriešanās (e.data.numpy (). squeeze (). tolist () for e in topk)

Kad attēli ir pareizā formātā, varat uzrakstīt funkciju, lai prognozētu ar savu modeli. Viena no izplatītākajām praksēm ir paredzēt iespējamās 5 labākās klases (parasti tās sauc par top-KK). Jūs vēlaties aprēķināt klases varbūtības, pēc tam atrodiet KK lielākās vērtības.

Lai iegūtu tenzorā lielākās KK lielākās vērtības, izmantojiet k.topk (). Ar šo metodi iegūst gan augstākās k varbūtības, gan to varbūtību indeksus, kas atbilst klasēm. No šiem indeksiem jāpārveido par faktiskajām klases etiķetēm, izmantojot class_to_idx, ko pievienojāt modelim vai no attēlu mapes, kuru izmantojāt, lai ielādētu datus. Pārliecinieties, ka vārdnīca ir apgriezta, lai iegūtu kartējumu no indeksa uz klasi.

Šai metodei vajadzētu būt ceļam uz attēlu un modeļa kontrolpunktu, pēc tam atdodot varbūtības un klases.

img_path = 'ziedu_dati / derīgs / 18 / image_04252.jpg'
zondes, klases = prognozēt2 (img_path, model.to (ierīce))
drukāt (zondes)
drukāt (klases)
flower_names = [cat_to_name [klases_vārdi [e]] e klasēs]
print (ziedu_vārdi)

Es biju diezgan apmierināta ar to, kā uzstājās mans modelis!

[0.9999195337295532, 1.4087702766119037e-05, 1.3897360986447893e-05, 1.1400215043977369e-05, 6.098791800468462e-06]
[12, 86, 7, 88, 40]
['Peru lilija', 'tuksneša roze', 'king protea', 'magnolija', 'zobenlilija']

Būtībā gandrīz 100% iespējams, ka manis norādītais attēls ir Peru lilija. Vai vēlaties to apskatīt? Mēģiniet izmantot matplotlib, lai diagrammā parādītu piecu labāko klašu varbūtības joslu diagrammā kopā ar ieejas attēlu:

def skats_klasificēt (img_path, prob, klases, kartēšana):
    '' 'Funkcija attēla apskatei un tās prognozējamās klases.
    '' '
    attēls = attēls.atvērts (img_path)
fig, (ax1, ax2) = plt.subplots (figsize = (6,10), ncols = 1, nrows = 2)
    ziedu_vārds = kartēšana [img_path.split ('/') [- 2]]
    ax1.set_title (zieda_vārds)
    ax1.imshow (attēls)
    ax1.axis ('izslēgts')
    
    y_pos = np.arange (len (prob))
    ax2.barh (y_pos, prob, align = 'centrs')
    ax2.set_yticks (y_pos)
    ax2.set_yticklabels (ziedu vārdi)
    ax2.invert_yaxis () # etiķetes lasāmas no augšas uz leju
    ax2.set_title ('klases varbūtība')
skats_klasificēt (img_path, probs, klases, cat_to_name)

Jums vajadzētu redzēt kaut ko līdzīgu:

Man jāsaka, ka esmu diezgan apmierināts ar to! Es iesaku pārbaudīt dažus citus attēlus, lai redzētu, cik tuvu jūsu prognozes ir dažādiem attēliem.

Tagad ir laiks izveidot savu modeli un paziņot man, kā tas darbojas, atbildēs zemāk!

Peza Gonzaleza fotoattēls vietnē Unsplash

Vai esat pabeidzis dziļo mācīšanos vai mašīnmācības modeli, bet nezināt, ko ar to darīt tālāk? Kāpēc to neizvietot internetā?

Izņemiet savu modeli, lai visi to redzētu!

Iepazīstieties ar šo rakstu, lai uzzinātu, kā izvietot savu mašīnmācīšanās modeli, izmantojot Flask!