Udostępnij przez


Tworzenie własnego klasyfikatora obrazów przy użyciu usługi Transfer Edukacja

Spis treści

Podsumowanie

imageimageimageimage

Powyższe obrazy to obrazy testowe używane w drugiej części tego samouczka. Zadaniem jest wytrenowanie klasyfikatora, który może odróżnić różne kategorie obrazów (w naszym przykładzie owiec i wilka), modyfikując istniejący model klasyfikatora , model podstawowy. W tym miejscu używamy modelu ResNet_18, który został wytrenowany w korpusie imagenet. Trenujemy tylko 15 obrazów na klasę w ciągu kilku sekund i prawidłowo przewidujemy wszystkie 10 obrazów testowych (zwróć uwagę na kilka ziaren soli).

Poniżej przedstawiono główne zasoby samouczka dotyczącego uczenia transferowego:

Przepis TransferLearning.py i TransferLearning_Extended.py (zobacz Przykłady/Obraz/TransferLearning).
wstępnie wytrenowane modele Jako podstawowy model uczenia transferowego używamy wstępnie wytrenowanego modelu ResNet_18.
Dane Zestaw danych Flowers z 102 kategoriami i przykładowymi obrazami owiec i wilków (zobacz Konfiguracja).
Jak uruchomić Postępuj zgodnie z poniższym opisem.

Konfigurowanie

Aby uruchomić kod w tym przykładzie, potrzebujesz CNTK środowiska języka Python (zobacz tutaj, aby uzyskać pomoc dotyczącą konfiguracji).

Aby pobrać wymagane dane i wstępnie wytrenowany model, uruchom następujące polecenie w folderze Examples/Image/TransferLearning :

python install_data_and_model.py

Uruchamianie przykładu

imageimageimageimage

W tej sekcji utworzymy klasyfikator dla zestawu danych Flowers. Zestaw danych został utworzony przez grupę Visual Geometry Group na Uniwersytecie Oksfordzkim na potrzeby zadań klasyfikacji obrazów. Składa się z 102 różnych kategorii kwiatów wspólnych dla Wielkiej Brytanii i zawiera około 8000 obrazów, które są podzielone na trzy zestawy raz 6000 i dwa razy 1000 obrazów. Aby uzyskać więcej informacji, zobacz stronę główną VGG.

Aby wytrenować i ocenić model uczenia transferowego na przebiegu zestawu danych Flowers

python TransferLearning.py

Model osiąga dokładność 93% w zestawie danych Flowers po trenowaniu w 20 epokach.

Podstawowa koncepcja uczenia transferowego

Kiedy używamy podstawowego modelu do uczenia transferowego, zasadniczo opieramy się na funkcjach i koncepcji, które zostały poznane podczas trenowania modelu podstawowego. W przypadku splotowej nazwy sieci rozproszonej, ResNet_18 w naszym przypadku, oznacza to na przykład, że odcięliśmy ostatnią gęstą warstwę, która jest odpowiedzialna za przewidywanie etykiet klas oryginalnego modelu bazowego i zastąpienie jej nową warstwą gęstą, która będzie przewidywać etykiety klas naszego nowego zadania. Dane wejściowe do starej i nowej warstwy przewidywania są takie same, po prostu ponownie używamy wytrenowanych funkcji. Następnie trenujemy tę zmodyfikowaną sieć— tylko nowe wagi nowej warstwy przewidywania lub wszystkie wagi całej sieci.

Poniższy kod jest częścią TransferLearning.py , która tworzy nowy model na podstawie modelu podstawowego:

    # 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)

Tworzenie własnego niestandardowego klasyfikatora obrazów

W poprzedniej sekcji wyszkoliliśmy klasyfikator, który rozróżnia 102 różne kategorie kwiatów przy użyciu około 6000 obrazów do trenowania. W tej sekcji użyjemy tylko 15 obrazów na kategorię do utworzenia klasyfikatora, który może powiedzieć wilkowi z owiec. Do uczenia transferowego używamy tego samego ResNet_18 modelu podstawowego. Aby wytrenować i ocenić przebieg modelu

python TransferLearning_Extended.py

Model jest testowany na pięciu obrazach owiec i wilków i przewiduje wszystkie etykiety prawidłowo. Plik wyjściowy zawiera w wierszu reprezentację wyników przewidywania w formacie 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": "..."}]

Należy pamiętać, że trzy ostatnie obrazy nie mają przypisanej podstawowej klasy prawdy, która jest oczywiście prawidłowym scenariuszem, np. w przypadku oceniania niewidocznych obrazów w usłudze internetowej. Rzeczywiste obrazy to trzy obrazy ptaków pokazane poniżej. Klasa podstawowej prawdy dla tych elementów w danych wyjściowych JSON jest ustawiona na unknownwartość . Należy pamiętać, że przewidywania dotyczące koncepcji, na których trenowano klasyfikator, są całkiem dobre pomimo kilku obrazów szkoleniowych. Jest to w dużych częściach ze względu na wstępnie wytrenowany model podstawowy. Przewidywania dotyczące niewidocznych pojęć, np. obrazów ptaków, są oczywiście nie bardzo znaczące, ponieważ klasyfikator zna tylko owce i wilka. Więcej informacji na ten temat później.

imageimageimage

Struktura folderów dla niestandardowych zestawów obrazów

Możesz użyć skryptu TransferLearning_Extended.py z własnymi obrazami. Oto, czego potrzebujesz:

  1. class_mapping — Tablica zawierająca nazwy kategorii, np. ['wolf', 'sheep']
  2. train_map_file - Plik tekstowy, który zawiera pierwszy wiersz adresu URL obrazu i kartę rozdzielił odpowiedni indeks kategorii, np. 0 dla wilka lub 1 owiec:
  3. test_map_file - Plik tekstowy mapuje obrazy testowe do odpowiedniej kategorii. W przypadku nieznanych kategorii obrazów testowych użyj -1 jako indeksu kategorii.

Skrypt może wygenerować wszystkie trzy powyższe elementy, jeśli strukturę obrazów jest w następujący sposób:

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

Zobacz <cntk root>/Examples/Image/DataSets/Animals/ jako przykład. Każdy podfolder w folderze Train będzie traktowany jako jedna kategoria (tylko jeden poziom, bez rekursji). W przypadku trenowania pojedynczych obrazów w Train folderze głównym są ignorowane, ponieważ nie mają przypisanej kategorii. Dodatkowe podfoldery w folderze Test , które nie występują w folderze Train , są ignorowane. Do testowania pojedynczych obrazów bez kategorii służą również do oceniania, czyli obrazów przechowywanych bezpośrednio w Test folderze, takim jak trzy obrazy ptaków w naszym przykładzie.

Aby użyć niestandardowych folderów obrazów, należy ustawić train_image_folder i test_image_folder w górnej części skryptu TransferLearning_Extended.py :

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

Następnie po prostu uruchom polecenie python TransferLearning_Extended.py. Sposób korzystania z innego modelu podstawowego opisano poniżej.

W przypadku oceniania nie trzeba używać elementu test_map_file, np. jeśli chcesz ocenić pojedyncze obrazy jeden po drugim. Wystarczy załadować wytrenowany model uczenia transferowego raz, a następnie wywołać eval_single_image je zawsze, gdy chcesz uzyskać przewidywania dla nowego obrazu:

    # 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)

Kilka ziaren soli

Obrazy szkoleniowe powinny obejmować wystarczająco odpowiednie scenariusze, które chcesz zdobyć później. Jeśli klasyfikator widzi w pełni nowe pojęcia lub konteksty, prawdopodobnie będzie działać źle. Wystarczy kilka przykładów:

  • Trenujesz tylko na obrazach ze środowiska ograniczeń (np. wewnątrz) i próbujesz ocenić obrazy z innego środowiska (na zewnątrz).
  • Trenujesz tylko na obrazach pewnego make i próbujesz zdobyć innych.
  • Obrazy testowe mają w dużej mierze różne cechy, np. w odniesieniu do oświetlenia, tła, koloru, rozmiaru, położenia itp.
  • Obrazy testowe zawierają zupełnie nowe koncepcje.

Dodanie kategorii catch-all może być dobrym pomysłem, ale tylko wtedy, gdy dane szkoleniowe dla tej kategorii zawierają obrazy, które są ponownie wystarczająco podobne do obrazów, których oczekujesz podczas oceniania. Jak w powyższym przykładzie, jeśli trenujemy klasyfikator z obrazami owiec i wilków i używamy go do oceny obrazu ptaka, klasyfikator nadal może przypisać tylko etykietę owiec lub wilka, ponieważ nie zna żadnych innych kategorii. Gdybyśmy dodali do niej kategorię catch-all i dodali do niej obrazy treningowe ptaków, klasyfikator może prawidłowo przewidzieć klasę dla obrazu ptaka. Jeśli jednak przedstawimy go, np. obraz samochodu, stoi w obliczu tego samego problemu co wcześniej, ponieważ zna tylko owce, wilka i ptaka (które właśnie przyszło nam nazwać catch-all). W związku z tym dane szkoleniowe, również dla wszystkich, muszą obejmować wystarczająco te pojęcia i obrazy, których oczekujesz później w czasie oceniania.

Innym aspektem, który należy wziąć pod uwagę, jest to, że konkretny model podstawowy może działać bardzo dobrze w przypadku niektórych zadań uczenia transferowego, a nie tak dobrego dla innych. Na przykład powyższy ResNet_18 model został wstępnie wytrenowany w korpusie ImageNet, który zawiera wiele obrazów zwierząt, ludzi, samochodów i wielu innych obiektów każdego dnia. Użycie tego modelu podstawowego w uczeniu transferowym w celu utworzenia klasyfikatora dla podobnych obiektów każdego dnia może się dobrze wypracować. Użycie tego samego modelu co model podstawowy do utworzenia klasyfikatora obrazów rysunków drobnoustrojów lub ołówków może przynieść tylko przeciętne wyniki.

Korzystanie z innego modelu podstawowego

Aby użyć innego modelu jako modelu podstawowego, należy dostosować następujące parametry w TransferLearning.py programie (tak samo jak w przypadku 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

Aby zbadać, jakie nazwy węzłów znajdują się w modelu i które z nich należy wybrać, ponieważ last_hidden_node można wydrukować wszystkie nazwy węzłów i kształty węzłów przy użyciu następujących wierszy (zobacz __main__ metodę w TransferLearning.pypliku ):

    # 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))