Sdílet prostřednictvím


Vytvoření vlastního klasifikátoru obrázků pomocí nástroje Transfer Učení

Obsah

Souhrn

imageimageimageimage

Výše uvedené obrázky jsou testovací obrázky použité v druhé části tohoto kurzu. Úkolem je vytrénovat klasifikátor, který dokáže rozlišovat různé kategorie obrázků (v našem příkladu ovce a vlku) úpravou existujícího klasifikátoru, základního modelu. Tady používáme ResNet_18 model, který byl natrénován na korpusu ImageNet. Během několika sekund trénujeme pouze 15 obrázků na třídu a správně předpovídáme všech 10 testovacích obrázků (všimněte si několika zrn soli).

Toto jsou hlavní zdroje pro kurz pro transferové učení:

Recept TransferLearning.py a TransferLearning_Extended.py (viz příklady, obrázky nebo přenosVyučování).
předem natrénované modely Jako základní model pro předávací učení používáme předem natrénovaný ResNet_18 model.
Data Datová sada Květiny s 102 kategoriemi a ukázkovými obrázky ovčích a vlků (viz Nastavení).
Jak spustit Postupujte podle následujícího popisu.

Nastavení

Ke spuštění kódu v tomto příkladu potřebujete CNTK prostředí Pythonu (nápovědu k nastavení najdete tady).

Pokud chcete stáhnout požadovaná data a předem vytrénovaný model, spusťte následující příkaz ve složce Příklady/Image/TransferLearning :

python install_data_and_model.py

Spuštění ukázky

imageimageimageimage

V této části vytvoříme klasifikátor pro sadu dat Květiny. Datovou sadu vytvořila skupina Visual Geometry Group na Univerzitě v Oxfordu pro úkoly klasifikace obrázků. Skládá se z 102 různých kategorií květin společných pro Spojené království a obsahuje zhruba 8 000 obrázků, které jsou rozděleny do tří sad jednou 6000 a dvakrát 1000 obrázků. Další podrobnosti najdete na domovské stránce VGG.

Trénování a vyhodnocení modelu učení přenosu na sadě dat Květiny

python TransferLearning.py

Model dosáhne 93% přesnosti datové sady Květiny po trénování pro 20 epoch.

Základní koncept transferového učení

Při použití základního modelu pro přenos učení v podstatě vycházíme z funkcí a konceptů, které jsme se naučili během trénování základního modelu. Pro konvoluční DNN ResNet_18 v našem případě to znamená, že například odřízneme poslední hustou vrstvu, která je zodpovědná za predikci popisků tříd původního základního modelu a nahradí ji novou hustou vrstvou, která předpovídá popisky tříd našeho nového úkolu. Vstup do staré a nové predikční vrstvy je stejný, jednoduše znovu použijeme vytrénované funkce. Pak tuto upravenou síť vytrénujeme, buď jenom nové váhy nové predikční vrstvy, nebo všechny váhy celé sítě.

Následující kód je součástí TransferLearning.py , která vytvoří nový model ze základního modelu:

    # Load the pretrained classification net and find nodes
    base_model   = load_model(base_model_file)
    feature_node = find_by_name(base_model, feature_node_name)
    last_node    = find_by_name(base_model, last_hidden_node_name)

    # Clone the desired layers with fixed weights
    cloned_layers = combine([last_node.owner]).clone(
        CloneMethod.freeze if freeze else CloneMethod.clone,
        {feature_node: Placeholder(name='features')})

    # Add new dense layer for class prediction
    feat_norm  = input_features - Constant(114)
    cloned_out = cloned_layers(feat_norm)
    z          = Dense(num_classes, activation=None, name=new_output_node_name) (cloned_out)

Vytvoření vlastního klasifikátoru obrázků

V předchozí části jsme natrénovali klasifikátor, který rozlišuje 102 různých kategorií květin pomocí zhruba 6000 obrázků pro trénování. V této části použijeme pouze 15 obrázků na kategorii k vytvoření klasifikátoru, který dokáže sdělit vlkovi z ovce. Pro přenos učení používáme stejný ResNet_18 základní model. Trénování a vyhodnocení spuštění modelu

python TransferLearning_Extended.py

Model je testován na pěti obrázcích ovčích a vlků a předpovídá všechny štítky správně. Výstupní soubor obsahuje na řádek reprezentaci výsledků predikce JSON:

[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":0.997, "Wolf":0.003}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "unknown", "predictions": {"Sheep":0.994, "Wolf":0.006}, "image": "..."}]
[{"class": "unknown", "predictions": {"Sheep":0.614, "Wolf":0.386}, "image": "..."}]
[{"class": "unknown", "predictions": {"Wolf":0.980, "Sheep":0.020}, "image": "..."}]

Všimněte si, že poslední tři obrázky nemají přiřazenou základní třídu pravdy, což je samozřejmě platný scénář, například pro vyhodnocování nezoznaných obrázků ve webové službě. Skutečné obrázky jsou tři obrázky ptáků zobrazené níže. Základní třída pravdy pro tyto ve výstupu JSON je nastavena na unknown. Všimněte si, že predikce konceptů, na které byl klasifikátor natrénován, jsou poměrně dobré i přes několik trénovacích obrázků. Jedná se o velké části z důvodu předtrénovaného základního modelu. Předpovědi pro neviditelné koncepty, například obrázky ptáků, jsou samozřejmě velmi smysluplné, protože klasifikátor zná pouze ovce a vlk. Další informace o tom najdete později.

imageimageimage

Struktura složek pro vlastní sady imagí

Skript můžete použít TransferLearning_Extended.py s vlastními obrázky. Tady je to, co potřebujete:

  1. class_mapping - Pole obsahující názvy kategorií, např. ['wolf', 'sheep']
  2. train_map_file - Textový soubor, který obsahuje každou čáru, nejprve adresu URL obrázku a kartu oddělenou odpovídající index kategorií, například 0 pro vlk nebo 1 ovce:
  3. test_map_file - Textový soubor mapuje testovací obrázky do odpovídající kategorie. Pro neznámé kategorie v testovacích obrázcích se používají -1 jako index kategorií.

Skript může vygenerovat všechny tři položky výše, pokud obrázky strukturujete následujícím způsobem:

<image root folder>
    Train
        Sheep
        Wolf
    Test
        Sheep
        Wolf
        <optional: image files with unknown label directly here>

Podívejte se <cntk root>/Examples/Image/DataSets/Animals/ jako na příklad. Každá podsložka ve Train složce bude považována za jednu kategorii (pouze jedna úroveň bez rekurze). Pro trénování jednotlivých obrázků v Train kořenové složce se ignorují, protože nemají přiřazenou kategorii. Další podsložky ve Test složce, ke kterým ve složce nedojde Train , se ignorují. Pro testování jednotlivých nezařazených obrázků se používají také pro vyhodnocování, tj. obrázky, které jsou uložené přímo ve Test složce, jako jsou tři obrázky ptáků v našem příkladu.

Pokud chcete použít vlastní složky obrázků, musíte nastavit train_image_folder a test_image_folder v horní části TransferLearning_Extended.py skriptu:

# define data location and characteristics
train_image_folder = "<your_image_root_folder>/Train"
test_image_folder = "<your_image_root_folder>/Test"

Pak jednoduše spusťte python TransferLearning_Extended.py. Postup použití jiného základního modelu je popsaný níže.

Pro bodování nemusíte používat test_map_filenapříklad jeden obrázek o jeden po druhém. Jednoduše načtěte natrénovaný model učení přenosu jednou a pak zavolejte eval_single_image pokaždé, když chcete získat předpovědi pro nový obrázek:

    # once:
    # load the trained transfer learning model
    trained_model = load_model(new_model_file)

    # for every new image:
    # get predictions for a single image
    probs = eval_single_image(trained_model, img_file, image_width, image_height)

Několik zrn soli

Vaše trénovací obrázky by měly obsahovat dostatečně scénáře, které chcete později vyhodnocovat. Pokud klasifikátor vidí zcela nové koncepty nebo kontexty, pravděpodobně bude fungovat špatně. Jen několik příkladů:

  • Trénujete jenom na obrázcích z omezeného prostředí (například v interiéru) a pokusíte se obrázky z jiného prostředí (venku).
  • Vytrénujete jenom na obrázcích určitého výsledku a pokusíte se o skóre ostatních.
  • Vaše testovací obrázky mají z velké části různé charakteristiky, například s ohledem na osvětlení, pozadí, barvu, velikost, pozici atd.
  • Vaše testovací obrázky obsahují zcela nové koncepty.

Přidání kategorie catch-all může být dobrý nápad, ale pouze v případě, že trénovací data pro danou kategorii obsahují obrázky, které jsou znovu dostatečně podobné obrázkům, které očekáváte při vyhodnocování času. Stejně jako v předchozím příkladu, pokud vytrénujeme klasifikátor s obrázky ovčích a vlků a použijeme ho k hodnocení obrázku ptáka, klasifikátor může stále přiřadit pouze ovčí nebo vlkový popisek, protože nezná žádné jiné kategorie. Pokud bychom do ní přidali kategorii catch-all a přidali do ní trénovací obrázky ptáků, klasifikátor může správně předpovědět třídu pro obrázek ptáka. Pokud ho však prezentujeme, například obrázek auta, čelí stejnému problému jako předtím, jak ví jen ovce, vlk a pták (což jsme se právě stalo voláním catch-all). Proto vaše trénovací data, také pro zachytávání, musí pokrýt dostatečně tyto koncepty a obrázky, které očekáváte později v bodovací době.

Dalším aspektem, který je třeba mít na paměti, je, že konkrétní základní model může velmi dobře fungovat pro některé úkoly přenosu učení, a ne tak dobré pro ostatní. Například výše uvedený ResNet_18 model byl předem natrénován na korpusu ImageNet, který obsahuje mnoho obrázků zvířat, lidí, aut a mnoho dalších objektů každý den. Použití tohoto základního modelu při přenosu učení k vytvoření klasifikátoru pro podobné objekty každý den může dobře fungovat. Použití stejného modelu jako základní model k vytvoření klasifikátoru pro obrázky bakterií nebo kresby tužky může přinést pouze průměrné výsledky.

Použití jiného základního modelu

Pokud chcete jako základní model použít jiný model, musíte přizpůsobit následující parametry TransferLearning.py (totéž pro TransferLearning_Extended.py):

# define base model location and characteristics
_base_model_file = os.path.join(base_folder, "..", "..", "..", "PretrainedModels", "ResNet_18.model")
_feature_node_name = "features"
_last_hidden_node_name = "z.x"
_image_height = 224
_image_width = 224
_num_channels = 3

Pokud chcete zjistit, jaké názvy uzlů jsou ve vašem modelu a které z nich můžete vybrat, jak last_hidden_node můžete vytisknout všechny názvy uzlů a obrazce uzlů pomocí následujících řádků (viz __main__ metoda v TransferLearning.py):

    # You can use the following to inspect the base model and determine the desired node names
    node_outputs = get_node_outputs(load_model(_base_model_file))
    for out in node_outputs: print("{0} {1}".format(out.name, out.shape))