def test_knn(self): print 'knn_test' knn = KNNClassifier(k_neighbors=3, metric='cityblock') knn.estimate(self.__train_samples, self.__train_labels) result_labels = knn.classify(self.__test_samples) result_labels_ref = np.array([['C', 'C', 'C', 'A', 'C']]).T self.assertEqual(result_labels_ref.shape, result_labels.shape) self.assertEqual(result_labels_ref.dtype, result_labels.dtype) np.testing.assert_equal(result_labels, result_labels_ref)
def test_data_dict_to_points_and_labels_returns_expected_values_and_labels(): given = { (1, "Jogging"): ((70, 12), ), (1, "Downstairs"): ( (85, 12), (81, 12), (70, 12), ), (2, "Jogging"): (), (3, "Jogging"): ((150, 30), ) } points = ( (70, 12), (85, 12), (81, 12), (70, 12), (150, 30), ) labels = ( "Jogging", "Downstairs", "Downstairs", "Downstairs", "Jogging", ) expected = points, labels result = KNNClassifier.data_dict_to_points_and_labels(given) assert result == expected
def test_sort_distances_and_labels_returns_expected(): distances = (110.1, 5.1, 5.2, 17, 10.1, 10.2) labels = ('a', 'b', 'c', 'd', 'e', 'f') sorted_distances = (5.1, 5.2, 10.1, 10.2, 17, 110.1) sorted_labels = ('b', 'c', 'e', 'f', 'd', 'a') expected = (sorted_distances, sorted_labels) result = KNNClassifier.sort_distances_and_labels(distances, labels) assert result == expected
def evaluate(self, images, labels): print('Evaluate dataset on pre-trained model') pairData, pairLabels = None, None outputs = [] outputs_probs = [] for illum in config.illuminantTypes: for desc in self.descriptors: clfPath = config.classification_folder + 'model_' + illum + '_' + desc.lower( ) + '.pkl' if os.path.isfile(clfPath): clf = KNNClassifier.load(clfPath) testData, testLabels, _ = self.getTrainingData(images, desc, illum=illum) if len(testData) > 0: pairData, pairLabels = testData, testLabels prediction = clf.predict( testData, False) * config.descriptors_weights[desc] outputs.append(prediction) prediction = clf.predict( testData, True) * config.descriptors_weights[desc] outputs_probs.append(prediction) if pairData is not None: output = np.zeros(len(pairData)) output_prob = np.zeros(len(pairData)) for i in range(len(outputs)): predictions = outputs[i] output += predictions predictions_prob = outputs_probs[i] for j in range(len(predictions)): output_prob[j] += predictions_prob[j][1] # If voting is majority, classify as fake counter = 0 misclassified = 0 scipy.io.savemat('classification_output.mat', dict(labels=pairLabels, scores=output_prob)) totalModels = len(outputs) for val in np.nditer(output): if val > totalModels / 2: if pairLabels[counter] != 1: misclassified += 1 else: if pairLabels[counter] != 0: misclassified += 1 counter += 1 print('Number of classifiers: ' + str(totalModels)) totalSamples = len(pairData) print('Misclassified: ' + str(misclassified) + '/' + str(totalSamples)) accuracy = (totalSamples - misclassified) / totalSamples print('Accuracy: ' + str(accuracy))
def test_knn(self): print 'knn_test' knn = KNNClassifier(k_neighbors=1, metric='cityblock') knn.estimate(self.__train_samples, self.__train_labels) result_labels = knn.classify(self.__test_samples) result_labels_ref = np.array([['A', 'A', 'C', 'A', 'C' ]]).T self.assertEqual(result_labels_ref.shape, result_labels.shape) self.assertEqual(result_labels_ref.dtype, result_labels.dtype) np.testing.assert_equal(result_labels, result_labels_ref) knn = KNNClassifier(k_neighbors=3, metric='cityblock') knn.estimate(self.__train_samples, self.__train_labels) result_labels = knn.classify(self.__test_samples) result_labels_ref = np.array([['C', 'C', 'C', 'A', 'C' ]]).T np.testing.assert_equal(result_labels, result_labels_ref)
def fit(self): # initializing the classifier self.__classifier = KNNClassifier(self.__nn, self.__metric) # relative bow-matrices by category (weighted) rel_category_bow_dict = { cat: self.__wght(self.category_bow_dict[cat]) for cat in self.category_bow_dict } # initializing the cross-validator (5 folds as in main) n_folds = 4 self.__cross_validator = CrossValidation( category_bow_dict=rel_category_bow_dict, n_folds=n_folds)
def _test_ocr(self, train_file, test_file): # get data from images ground_truth = test_file.ground.classes test_file.remove_ground() # create OCR segmenter = ContourSegmenter(blur_y=5, blur_x=5) extractor = SimpleFeatureExtractor() classifier = KNNClassifier() ocr = OCR(segmenter, extractor, classifier) # train and test ocr.train(train_file) chars, classes, _ = ocr.ocr(test_file, show_steps=False) print chars print reconstruct_chars(ground_truth) self.assertEqual(chars, reconstruct_chars(ground_truth)) self.assertEqual(list(classes), list(ground_truth))
def test_ocr_digits(self): # get data from images img1 = ImageFile('digits1') img2 = ImageFile('digits2') ground_truth = img2.ground.classes img2.remove_ground() # create OCR segmenter = ContourSegmenter() extractor = SimpleFeatureExtractor() classifier = KNNClassifier() ocr = OCR(segmenter, extractor, classifier) # train and test ocr.train(img1) chars, classes, _ = ocr.ocr(img2, show_steps=False) self.assertEqual(list(classes), list(ground_truth)) self.assertEqual(chars, reconstruct_chars(ground_truth))
def test_distances_to_points_returns_expected_values(): point = (10, 10) points = ( (-100.1, 10), (13, 14), (13, 6), (18, 25), (20, 10), (10, 20), ) expected = ( 110.1, 5, 5, 17, 10, 10, ) result = KNNClassifier.distances_to_points(point, points) assert result == expected
from unittest import TestCase from classification import DocumentCollection, KNNClassifier, TextDocument dir_train = "../data/20news-bydate/20news-bydate-train/" dir_test = "../data/20news-bydate/20news-bydate-test/" doc_collection_train = DocumentCollection.from_dir(dir_train) classifier = KNNClassifier(n_neighbors=4) classifier.fit(doc_collection_train) train_docs = doc_collection_train.docid_to_doc.values() vectorsOfTrainDocs = [(doc, doc_collection_train.tfidf(doc.token_counts)) for doc in train_docs] test_doc = TextDocument.from_file(dir_test + 'alt.atheism/53068', 'alt.atheism') vecTestDoc = doc_collection_train.tfidf(test_doc.token_counts) #2.1 dist = classifier.calculate_similarities(vecTestDoc, vectorsOfTrainDocs) #2.2 ordered = classifier.order_nearest_to_farthest(dist) #2.3 k_nearest_labels = classifier.labels_k_closest(ordered) #2.4 label = classifier.choose_one(k_nearest_labels) class ClassificationTest(TestCase): def test_01_calc_sims(self): sorted_dist = sorted(dist) self.assertEqual(sorted_dist[-1][1], 'alt.atheism')
def aufgabe2(): # Laden des Brown Corpus CorpusLoader.load() brown = CorpusLoader.brown_corpus() brown_categories = brown.categories() # In dieser Aufgabe sollen unbekannte Dokumente zu bekannten Kategorien # automatisch zugeordnet werden. # # Die dabei erforderlichen numerischen Berechnungen lassen sich im Vergleich # zu einer direkten Implementierung in Python erheblich einfacher mit # NumPy / SciPy durchfuehren. Die folgende Aufgabe soll Ihnen die Unterschiede # anhand eines kleinen Beispiels verdeutlichen. # # Geben Sie fuer jede Katgorie des Brown Corpus die durchschnittliche Anzahl # von Woertern pro Dokument aus. Bestimmen Sie auch die Standardabweichung. # Stellen Sie diese Statistik mit einem bar plot dar. Verwenden Sie dabei # auch Fehlerbalken (siehe visualization.hbar_plot) # # Berechnen Sie Mittelwert und Standardabweichung jeweils: # # - nur mit Python Funktion # hilfreiche Funktionen: sum, float, math.sqrt, math.pow # # - mit NumPy # hilfreiche Funktionen: np.array, np.mean, np.std # # http://docs.python.org/2/library/math.html # http://wiki.scipy.org/Tentative_NumPy_Tutorial # http://docs.scipy.org/doc/numpy/reference/generated/numpy.mean.html # http://docs.scipy.org/doc/numpy/reference/generated/numpy.std.html ####### +++++ Python Implementierung ++++ print 'Python Implementierung' liste = [] for i in brown_categories: a = len(brown.words(categories=i))/len(brown.fileids(categories=i)) print i print a liste.append(a) mittelwert = sum(liste)/len(brown_categories) print 'Mittelwert:' + str(mittelwert) summe = 0 for i in liste: summe +=math.pow(i-mittelwert,2) standard = math.sqrt(summe/len(brown_categories)) #standard = math.sqrt(sum(list)/len(brown_categories)) print 'Standardabweichung:'+str(standard) ####### +++++ Numpy Implementierung ++++ print 'NumPy Implementierung' liste2 = np.array(liste) mittelwert2 = np.mean(liste2, axis=0) print 'Mittelwert:' + str(mittelwert2) standard2 = np.std(liste2, axis=0) print 'Standardabweichung:'+ str(standard2) hbar_plot(liste2, brown_categories, x_err=standard2, title="Words per document") # ********************************** ACHTUNG ************************************** # Die nun zu implementierenden Funktionen spielen eine zentrale Rolle im weiteren # Verlauf des Fachprojekts. Achten Sie auf eine effiziente und 'saubere' Umsetzung. # Verwenden Sie geeignete Datenstrukturen und passende Python Funktionen. # Wenn Ihnen Ihr Ansatz sehr aufwaendig vorkommt, haben Sie vermutlich nicht die # passenden Datenstrukturen / Algorithmen / (highlevel) Python / NumPy Funktionen # verwendet. Fragen Sie in diesem Fall! # # Schauen Sie sich jetzt schon gruendlich die Klassen und deren Interfaces in den # mitgelieferten Modulen an. Wenn Sie Ihre Datenstrukturen von Anfang an dazu # passend waehlen, erleichtert dies deren spaetere Benutzung. Zusaetzlich bieten # diese Klassen bereits etwas Inspiration fuer Python-typisches Design, wie zum # Beispiel Duck-Typing. # # Zu einigen der vorgebenen Intefaces finden Sie Unit Tests in dem Paket 'test'. # Diese sind sehr hilfreich um zu ueberpruefen, ob ihre Implementierung zusammen # mit anderen mitgelieferten Implementierungen / Interfaces funktionieren wird. # Stellen Sie immer sicher, dass die Unit tests fuer die von Ihnen verwendeten # Funktionen erfolgreich sind. # Hinweis: Im Verlauf des Fachprojekts werden die Unit Tests nach und nach erfolg- # reich sein. Falls es sie zu Beginn stoert, wenn einzelne Unit Tests fehlschlagen # koennen Sie diese durch einen 'decorator' vor der Methodendefinition voruebergehend # abschalten: @unittest.skip('') # https://docs.python.org/2/library/unittest.html#skipping-tests-and-expected-failures # Denken Sie aber daran sie spaeter wieder zu aktivieren. # # Wenn etwas unklar ist, fragen Sie! # ********************************************************************************* # # Klassifikation von Dokumenten # # Nachdem Sie sich nun mit der Struktur und den Eigenschaften des Brown # Corpus vertraut gemacht haben, soll er die Datengrundlage fuer die # Evaluierung von Algorithmen zur automatischen Klassifikation von # Dokumenten bilden. # In der Regel bestehen diese Algorithmen aus drei Schritten: # - Vorverarbeitung # - Merkmalsberechnung # - Klassifikation # # Bei der Anwendung auf Dokumente (Texte) werden diese Schritte wie folgt # umgesetzt: # - Vorverarbeitung: Filterung von stopwords und Abbildung von Woertern auf # Wortstaemme. # - Merkmalsberechnung: Jedes Dokument wird numerisch durch einen Vektor # repraesentiert (--> NumPy), der moeglichst die # bzgl. der Klassifikation bedeutungsunterscheidenden # Informationen enthaehlt. # - Klassifikation: Jedem Merkmalsvektor (Dokument) wird ein Klassenindex # (Kategorie) zugeordnet. # # Details finden Sie zum Beispiel in: # http://www5.informatik.uni-erlangen.de/fileadmin/Persons/NiemannHeinrich/klassifikation-von-mustern/m00-www.pdf (section 1.3) # # Eine sehr verbreitete Merkmalsrepraesentation fuer (textuelle) Dokumente sind # sogenannte Bag-of-Words. # Dabei wird jedes Dokument durch ein Histogram (Verteilung) ueber Wortfrequenzen # repraesentiert. Man betrachtet dazu das Vorkommen von 'typischen' Woertern, die # durch ein Vokabular gegeben sind. # # Bestimmen Sie ein Vokabular, also die typischen Woerter, fuer den Brown Corpus. # Berechnen Sie dazu die 500 haeufigsten Woerter (nach stemming und Filterung von # stopwords und Satzzeichen) normalized_words = WordListNormalizer().normalize_words(brown.words())[1] vocab = BagOfWords.most_freq_words(normalized_words, 500) # Berechnen Sie Bag-of-Words Repraesentationen fuer jedes Dokument des Brown Corpus. # Verwenden Sie absolute Frequenzen. # Speichern Sie die Bag-of-Word Repraesentationen fuer jede Kategorie in einem # 2-D NumPy Array. Speichern Sie den Bag-of-Words Vektor fuer jedes Dokument in # einer Zeile, so dass das Array (ndarray) folgende Dimension hat: # |Dokument_kat| X |Vokabular| # # |Dokument_kat| entspricht der Anzahl Dokumente einer Kategorie. # |Vokabular| entspricht der Anzahl Woerter im Vokabular (hier 500). # # Eine einfache Zuordnung von Kategorie und Bag-of-Words Matrix ist durch ein # Dictionary moeglich. # # Implementieren Sie die Funktion BagOfWords.category_bow_dict im Modul features. bow_list = {} for cat in brown_categories: bow_list[cat] = [WordListNormalizer().normalize_words(brown.words(fileids=doc))[1] for doc in brown.fileids(categories=cat)] a = BagOfWords(vocab) print "Merkmalsvektoren erstellt" # Um einen Klassifikator statistisch zu evaluieren, benoetigt man eine Trainingsstichprobe # und eine Teststichprobe der Daten die klassifiziert werden sollen. # Die Trainingsstichprobe benoetigt man zum Erstellen oder Trainieren des Klassifikators. # Dabei werden in der Regel die Modellparameter des Klassifikators statistisch aus den # Daten der Traingingsstichprobe geschaetzt. Die Klassenzugehoerigkeiten sind fuer die # Beispiele aus der Trainingsstichprobe durch so genannte Klassenlabels gegeben. # # Nachdem man den Klassifikator trainiert hat, interessiert man sich normalerweise dafuer # wie gut er sich unter realen Bedingung verhaelt. Das heisst, dass der Klassifikator bei # der Klassifikation zuvor unbekannter Daten moeglichst wenige Fehler machen soll. # Dies simuliert man mit der Teststichprobe. Da auch fuer jedes Beispiel aus der Teststichprobe # die Klassenzugehoerigkeit bekannt ist, kann man am Ende die Klassifikationsergebnisse mit # den wahren Klassenlabels (aus der Teststichprobe) vergleichen und eine Fehlerrate angeben. # In dem gegebenen Brown Corpus ist keine Aufteilung in Trainings und Testdaten vorgegeben. # # Waehlen Sie daher die ersten 80% der Dokumente UEBER ALLE KATEGORIEN als Trainingstichprobe # und die letzten 20% der Dokumente UEBER ALLE KATEGORIEN als Teststichprobe. # # Erklaeren Sie, warum Sie die Stichproben ueber alle Kategorien zusammenstellen MUESSEN. # # Bitte beachten Sie, dass wir im Rahmen des Fachprojekts keinen Test auf unbekannten Testdaten # simulieren. Wir haben ja bereits fuer die Erstellung der Vokabulars (haeufigste Woerter, # siehe oben) den kompletten Datensatz verwendet. # Stattdessen betrachten wir hier ein so genanntes Validierungsszenario, in dem wir die # Klassifikationsleistung auf dem Brown Corpus optimieren. Die Ergebnisse lassen sich somit # nur sehr bedingt auf unbekannte Daten uebertragen. # # Erstellen Sie nun die NumPy Arrays train_samples, train_labels, test_samples und test_labels, # so dass diese mit den estimate und classify Methoden der Klassen im classificaton Modul # verwendet werden koennen. Teilen Sie die Daten wie oben angegeben zu 80% in # Trainingsdaten und 20% in Testdaten auf. # # Hinweis: Vollziehen Sie nach, wie die Klasse CrossValidation im evaluation Modul # funktioniert. Wenn Sie moechten, koennen die Klasse zur Aufteilung der Daten # verwenden. print "Arrays sind generiert" train_labels = np.array(brown_categories).reshape(len(brown_categories), 1) test_labels =np.array(brown_categories).reshape(len(brown_categories), 1) print "Reshaped" cv = CrossValidation(a.category_bow_dict(bow_list), 5) cv2 = cv.corpus_fold(1) train_samples = cv2[0] test_samples = cv2[2] train_labels = cv2[1] test_labels = cv2[3] # Klassifizieren Sie nun alle Dokumente der Teststichprobe nach dem Prinzip des k-naechste- # Nachbarn Klassifikators. Dabei wird die Distanz zwischen dem Merkmalsvektors eines # Testbeispiels und allen Merkmalsvektoren aus der Trainingstichprobe berechnet. Das # Klassenlabel des Testbeispiels wird dann ueber einen Mehrheitsentscheid der Klassenlabels # der k aehnlichsten Merkmalsvektoren aus der Trainingsstichprobe bestimmt. # http://www5.informatik.uni-erlangen.de/fileadmin/Persons/NiemannHeinrich/klassifikation-von-mustern/m00-www.pdf (Abschnitt 4.2.7) # # Verwenden Sie die Euklidische Distanz und betrachten Sie nur den naechsten Nachbarn (k=1). # http://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html # # Implementieren Sie die Funktionen estimate und classify in der Klasse KNNClassifier # im Modul classification. classification = KNNClassifier(1, 'euclidean') classification.estimate(train_samples, train_labels) result_knnk = classification.classify(test_samples) # Nachdem Sie mit dem KNNClassifier fuer jedes Testbeispiel ein Klassenlabel geschaetzt haben, # koennen Sie dieses mit dem tatsaechlichen Klassenlabel vergleichen. Dieses koennen Sie wie # bei den Traingingsdaten dem Corpus entnehmen. # # Ermitteln Sie eine Gesamtfehlerrate und je eine Fehlerrate pro Kategorie. # Implementieren Sie dazu die Klasse ClassificationEvaluator im evaluation Modul. # # Warum ist diese Aufteilung der Daten in Training und Test problematisch? Was sagen die Ergebnisse aus? eval = ClassificationEvaluator(result_knnk, test_labels) error_overall = eval.error_rate()[0] error_cat_list = eval.category_error_rates() print "Error Overall" print error_overall print "Error Catlist" print error_cat_list
from files import ImageFile from segmentation import ContourSegmenter from feature_extraction import SimpleFeatureExtractor from classification import KNNClassifier from ocr import OCR, accuracy, show_differences segmenter = ContourSegmenter(blur_y=5, blur_x=5, block_size=11, c=10) extractor = SimpleFeatureExtractor(feature_size=10, stretch=False) classifier = KNNClassifier() ocr = OCR(segmenter, extractor, classifier) ocr.train(ImageFile('digits1')) test_image = ImageFile('digits2') test_chars, test_classes, test_segments = ocr.ocr(test_image, show_steps=True) print("accuracy:", accuracy(test_image.ground.classes, test_classes)) print("OCRed text:\n", test_chars)
def test_resolve_ties_handles_all_tied_case(): labels = ('a', 'b', 'c', 'd', 'e', 'a', 'b') expected = 'a' result = KNNClassifier.resolve_ties(labels, 5) assert result == expected
def aufgabe2(): # Laden des Brown Corpus CorpusLoader.load() brown = CorpusLoader.brown_corpus() brown_categories = brown.categories() # In dieser Aufgabe sollen unbekannte Dokumente zu bekannten Kategorien # automatisch zugeordnet werden. # # Die dabei erforderlichen numerischen Berechnungen lassen sich im Vergleich # zu einer direkten Implementierung in Python erheblich einfacher mit # NumPy / SciPy durchfuehren. Die folgende Aufgabe soll Ihnen die Unterschiede # anhand eines kleinen Beispiels verdeutlichen. # # Geben Sie fuer jede Katgorie des Brown Corpus die durchschnittliche Anzahl # von Woertern pro Dokument aus. Bestimmen Sie auch die Standardabweichung. # Stellen Sie diese Statistik mit einem bar plot dar. Verwenden Sie dabei # auch Fehlerbalken (siehe visualization.hbar_plot) # # Berechnen Sie Mittelwert und Standardabweichung jeweils: # # - nur mit Python Funktion # hilfreiche Funktionen: sum, float, math.sqrt, math.pow # # - mit NumPy # hilfreiche Funktionen: np.array, np.mean, np.std # # http://docs.python.org/2/library/math.html # http://wiki.scipy.org/Tentative_NumPy_Tutorial # http://docs.scipy.org/doc/numpy/reference/generated/numpy.mean.html # http://docs.scipy.org/doc/numpy/reference/generated/numpy.std.html for cat in brown_categories: # python standard libs only # calculating the mean doc_words = 0 docs = brown.fileids(categories=cat) n = float(len(docs)) for doc in docs: doc_words += len(brown.words(doc)) mean = float(doc_words) / n # claculating the std std = 0. for doc in docs: std += math.pow(float(len(brown.words(doc))) - mean, 2) std = math.sqrt(std / n) # using numpy arr_doc_words = np.array([ len(brown.words(doc)) for doc in brown.fileids(categories=cat) ]).astype(float) np_std = np.std(arr_doc_words) # printing the std for each category print("{}\npython: {}, mean={}\nnp:{}, mean={}".format( cat, std, mean, np_std, np.mean(arr_doc_words))) # ********************************** ACHTUNG ************************************** # Die nun zu implementierenden Funktionen spielen eine zentrale Rolle im weiteren # Verlauf des Fachprojekts. Achten Sie auf eine effiziente und 'saubere' Umsetzung. # Verwenden Sie geeignete Datenstrukturen und passende Python Funktionen. # Wenn Ihnen Ihr Ansatz sehr aufwaendig vorkommt, haben Sie vermutlich nicht die # passenden Datenstrukturen / Algorithmen / (highlevel) Python / NumPy Funktionen # verwendet. Fragen Sie in diesem Fall! # # Schauen Sie sich jetzt schon gruendlich die Klassen und deren Interfaces in den # mitgelieferten Modulen an. Wenn Sie Ihre Datenstrukturen von Anfang an dazu # passend waehlen, erleichtert dies deren spaetere Benutzung. Zusaetzlich bieten # diese Klassen bereits etwas Inspiration fuer Python-typisches Design, wie zum # Beispiel Duck-Typing. # # Zu einigen der vorgebenen Intefaces finden Sie Unit Tests in dem Paket 'test'. # Diese sind sehr hilfreich um zu ueberpruefen, ob ihre Implementierung zusammen # mit anderen mitgelieferten Implementierungen / Interfaces funktionieren wird. # Stellen Sie immer sicher, dass die Unit tests fuer die von Ihnen verwendeten # Funktionen erfolgreich sind. # Hinweis: Im Verlauf des Fachprojekts werden die Unit Tests nach und nach erfolg- # reich sein. Falls es sie zu Beginn stoert, wenn einzelne Unit Tests fehlschlagen # koennen Sie diese durch einen 'decorator' vor der Methodendefinition voruebergehend # abschalten: @unittest.skip('') # https://docs.python.org/2/library/unittest.html#skipping-tests-and-expected-failures # Denken Sie aber daran sie spaeter wieder zu aktivieren. # # Wenn etwas unklar ist, fragen Sie! # ********************************************************************************* # # Klassifikation von Dokumenten # # Nachdem Sie sich nun mit der Struktur und den Eigenschaften des Brown # Corpus vertraut gemacht haben, soll er die Datengrundlage fuer die # Evaluierung von Algorithmen zur automatischen Klassifikation von # Dokumenten bilden. # In der Regel bestehen diese Algorithmen aus drei Schritten: # - Vorverarbeitung # - Merkmalsberechnung # - Klassifikation # # Bei der Anwendung auf Dokumente (Texte) werden diese Schritte wie folgt # umgesetzt: # - Vorverarbeitung: Filterung von stopwords und Abbildung von Woertern auf # Wortstaemme. # - Merkmalsberechnung: Jedes Dokument wird numerisch durch einen Vektor # repraesentiert (--> NumPy), der moeglichst die # bzgl. der Klassifikation bedeutungsunterscheidenden # Informationen enthaehlt. # - Klassifikation: Jedem Merkmalsvektor (Dokument) wird ein Klassenindex # (Kategorie) zugeordnet. # # Details finden Sie zum Beispiel in: # http://www5.informatik.uni-erlangen.de/fileadmin/Persons/NiemannHeinrich/klassifikation-von-mustern/m00-www.pdf (section 1.3) # # Eine sehr verbreitete Merkmalsrepraesentation fuer (textuelle) Dokumente sind # sogenannte Bag-of-Words. # Dabei wird jedes Dokument durch ein Histogram (Verteilung) ueber Wortfrequenzen # repraesentiert. Man betrachtet dazu das Vorkommen von 'typischen' Woertern, die # durch ein Vokabular gegeben sind. # # Bestimmen Sie ein Vokabular, also die typischen Woerter, fuer den Brown Corpus. # Berechnen Sie dazu die 500 haeufigsten Woerter (nach stemming und Filterung von # stopwords und Satzzeichen) normalizer = WordListNormalizer() normalized_words = normalizer.normalize_words(brown.words()) vocabulary = BagOfWords.most_freq_words(normalized_words[1], 500) print(vocabulary) print('finished vocab') # Berechnen Sie Bag-of-Words Repraesentationen fuer jedes Dokument des Brown Corpus. # Verwenden Sie absolute Frequenzen. # Speichern Sie die Bag-of-Word Repraesentationen fuer jede Kategorie in einem # 2-D NumPy Array. Speichern Sie den Bag-of-Words Vektor fuer jedes Dokument in # einer Zeile, so dass das Array (ndarray) folgende Dimension hat: # |Dokument_kat| X |Vokabular| # # |Dokument_kat| entspricht der Anzahl Dokumente einer Kategorie. # |Vokabular| entspricht der Anzahl Woerter im Vokabular (hier 500). # # Eine einfache Zuordnung von Kategorie und Bag-of-Words Matrix ist durch ein # Dictionary moeglich. # # Implementieren Sie die Funktion BagOfWords.category_bow_dict im Modul features. bow = BagOfWords(vocabulary) cat_word_dict = { cat: [brown.words(doc) for doc in brown.fileids(categories=cat)] for cat in brown_categories } print('calculating cat_to_bow') cat_to_bow = bow.category_bow_dict(cat_word_dict) print(cat_to_bow) # Um einen Klassifikator statistisch zu evaluieren, benoetigt man eine Trainingsstichprobe # und eine Teststichprobe der Daten die klassifiziert werden sollen. # Die Trainingsstichprobe benoetigt man zum Erstellen oder Trainieren des Klassifikators. # Dabei werden in der Regel die Modellparameter des Klassifikators statistisch aus den # Daten der Traingingsstichprobe geschaetzt. Die Klassenzugehoerigkeiten sind fuer die # Beispiele aus der Trainingsstichprobe durch so genannte Klassenlabels gegeben. # # Nachdem man den Klassifikator trainiert hat, interessiert man sich normalerweise dafuer # wie gut er sich unter realen Bedingung verhaelt. Das heisst, dass der Klassifikator bei # der Klassifikation zuvor unbekannter Daten moeglichst wenige Fehler machen soll. # Dies simuliert man mit der Teststichprobe. Da auch fuer jedes Beispiel aus der Teststichprobe # die Klassenzugehoerigkeit bekannt ist, kann man am Ende die Klassifikationsergebnisse mit # den wahren Klassenlabels (aus der Teststichprobe) vergleichen und eine Fehlerrate angeben. # In dem gegebenen Brown Corpus ist keine Aufteilung in Trainings und Testdaten vorgegeben. # # Waehlen Sie daher die ersten 80% der Dokumente UEBER ALLE KATEGORIEN als Trainingstichprobe # und die letzten 20% der Dokumente UEBER ALLE KATEGORIEN als Teststichprobe. # # Erklaeren Sie, warum Sie die Stichproben ueber alle Kategorien zusammenstellen MUESSEN. # # Bitte beachten Sie, dass wir im Rahmen des Fachprojekts keinen Test auf unbekannten Testdaten # simulieren. Wir haben ja bereits fuer die Erstellung der Vokabulars (haeufigste Woerter, # siehe oben) den kompletten Datensatz verwendet. # Stattdessen betrachten wir hier ein so genanntes Validierungsszenario, in dem wir die # Klassifikationsleistung auf dem Brown Corpus optimieren. Die Ergebnisse lassen sich somit # nur sehr bedingt auf unbekannte Daten uebertragen. # # Erstellen Sie nun die NumPy Arrays train_samples, train_labels, test_samples und test_labels, # so dass diese mit den estimate und classify Methoden der Klassen im classificaton Modul # verwendet werden koennen. Teilen Sie die Daten wie oben angegeben zu 80% in # Trainingsdaten und 20% in Testdaten auf. # # Hinweis: Vollziehen Sie nach, wie die Klasse CrossValidation im evaluation Modul # funktioniert. Wenn Sie moechten, koennen die Klasse zur Aufteilung der Daten # verwenden. cross_validator = CrossValidation(cat_to_bow, 5) train_samples, train_labels, test_samples, test_labels = cross_validator.corpus_fold( 0) print('finished cross validation') # Klassifizieren Sie nun alle Dokumente der Teststichprobe nach dem Prinzip des k-naechste- # Nachbarn Klassifikators. Dabei wird die Distanz zwischen dem Merkmalsvektors eines # Testbeispiels und allen Merkmalsvektoren aus der Trainingstichprobe berechnet. Das # Klassenlabel des Testbeispiels wird dann ueber einen Mehrheitsentscheid der Klassenlabels # der k aehnlichsten Merkmalsvektoren aus der Trainingsstichprobe bestimmt. # http://www5.informatik.uni-erlangen.de/fileadmin/Persons/NiemannHeinrich/klassifikation-von-mustern/m00-www.pdf (Abschnitt 4.2.7) # # Bestimmen Sie die Distanzen von Testdaten zu Trainingsdaten mit cdist: # http://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html # Bestimmen Sie die k-naechsten Nachbarn auf Grundlage der zuvor berechneten # Distanzen mit argsort: # http://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html # Ueberlegen Sie, welche zuvor von Ihnen implementierte Funktion Sie wiederverwenden # koennen, um den Mehrheitsentscheid umzusetzen. # # Implementieren Sie die Funktionen estimate und classify in der Klasse KNNClassifier # im Modul classification. # # Verwenden Sie die Euklidische Distanz und betrachten Sie zunaechst nur # den naechsten Nachbarn (k=1). # # HINWEIS: Hier ist zunaechst nur die Implementierung eines naechster Nachbar # Klassifikators erforderlich. Diese soll aber in der naechsten Aufgabe zu einer # Implementierung eines k-naechste Nachbarn Klassifikators erweitert werden. # Beruechsichtigen Sie das in ihrer Implementierung. Um die beiden Varianten # zu testen, finden Sie zwei Unit-Test Methoden test_nn und test_knn in dem Modul # test.classification_test # knn_1 = KNNClassifier(1, 'euclidean') knn_1.estimate(train_samples, train_labels) nearest_1 = knn_1.classify(test_samples) print(nearest_1) print('finished classification') # Nachdem Sie mit dem KNNClassifier fuer jedes Testbeispiel ein Klassenlabel geschaetzt haben, # koennen Sie dieses mit dem tatsaechlichen Klassenlabel vergleichen. Dieses koennen Sie wie # bei den Traingingsdaten dem Corpus entnehmen. # # Ermitteln Sie eine Gesamtfehlerrate und je eine Fehlerrate pro Kategorie. # Implementieren Sie dazu die Klasse ClassificationEvaluator im evaluation Modul. # # Warum ist diese Aufteilung der Daten in Training und Test problematisch? Was sagen die Ergebnisse aus? evaluator = ClassificationEvaluator(nearest_1, test_labels) cat_err_rates = evaluator.category_error_rates() print(evaluator.error_rate(None)) print(cat_err_rates) print('done')
def aufgabe4(): # # Mit dem Naechster Nachbar Klassifikator wurde ein Dokumente zu einer Klassen zugeordnet, # indem zunaechst aehnliche Dokumente aus einer Trainingsdatenbank ermittelt wurden. # Ueber die Klassenzugehoerigkeit dieser aehnlichen Dokumente aus dem Training # wurde dann das unbekannte Dokument einer Klasse zugeordnet. # Dabei wurden aber noch keine Zusammenhaenge zwischen einzelnen Woertern analysiert # und beruecksichtigt. Daher geht es nun um Topic Modelle. Topic Modelle beschreiben # diese Zusammenhaenge durch einen mathematischen Unterraum. Die Vektoren, die # diesen Unterraum aufspannen, sind die Topics, die jeweils fuer typische Wort- # konfigurationen stehen. Dokumente werden nun nicht mehr durch Frequenzen von # Woertern repraesentiert, sondern als Linearkombination von Topics im Topic # Vektorraum. Es ist zu beachten, dass fuer die Topic-Modellierung keine Informationen # ueber die Dokumentenkategorien benoetigt wird. # # Um ein besseres Verstaendnis fuer diese mathematischen Unterraeume zu entwickeln, # schauen wir uns zunaechst die Hauptkomponentenanalyse an. # # Ein 3D Beispieldatensatz wird aus einer Normalverteilung generiert. # Diese ist durch einen Mittelwert und eine Kovarianzmatrix definiert mean = np.array([10, 10, 10]) cov = np.array([[3, .2, .9], [.2, 5, .4], [.9, .4, 9]]) n_samples = 1000 limits_samples = ((0, 20), (0, 20), (0, 20)) samples = np.random.multivariate_normal(mean, cov, n_samples) # Plotten der Beispieldaten fig = plt.figure() ax = fig.add_subplot(111, projection='3d') PCAExample.plot_sample_data(samples, ax=ax) PCAExample.set_axis_limits(ax, limits=limits_samples) # In der Klasse PCAExample wird ein Unterraum mittels Hauptkomponentenanalyse # statistisch geschaetzt. Der Vektorraum wird beispielhaft visualisiert. pca_example = PCAExample(samples, target_dim=3) pca_example.plot_subspace(limits=limits_samples, color='r', linewidth=0.05, alpha=0.3) #plt.show() # Nun wird die Dimension des Unterraums reduziert. # Implementieren Sie die Reduktion im Konstruktor von PCAExample. Der neue # Vektorraum wird wieder visualisiert. pca_example_2d = PCAExample(samples, target_dim=2) pca_example_2d.plot_subspace(limits=limits_samples, color='b', linewidth=0.01, alpha=0.3) # Transformieren Sie nun die 3D Beispieldaten in den 2D Unterraum. # Implementieren Sie dazu die Methode transform_samples. Die Daten werden # dann in einem 2D Plot dargestellt. # # Optional: Verwenden Sie Unterraeume mit Dimensionen 3, 2 und 1. Transformieren # und plotten Sie die Daten. #pca_example_1d = PCAExample(samples, target_dim=1) #pca_example_1d.plot_subspace(limits=limits_samples, color='g', linewidth=0.01, alpha=0.3, ellipsoid=False) #samples_1d = pca_example_1d.transform_samples(samples) #fig = plt.figure() #ax = fig.add_subplot(111) #PCAExample.plot_sample_data(samples_1d, ax=ax) #PCAExample.set_axis_limits(ax, limits=((-10, 10), (-10, 10))) # Optional: Generieren und transformieren Sie weitere 3D Beispieldaten. Benutzen Sie # dabei auch andere Parameter fuer die Normalverteilung. # # Optional: Visualisieren Sie die transformierten 2D Daten auch in dem vorherigen # 3D Plot. samples_2d = pca_example_2d.transform_samples(samples) fig = plt.figure() ax = fig.add_subplot(111) PCAExample.plot_sample_data(samples_2d, ax=ax) PCAExample.set_axis_limits(ax, limits=((-10, 10), (-10, 10))) #plt.show() # Berechnen Sie nun die Kovarianzmatrix der transformierten Daten. # Welche Eigenschaften hat diese Matrix? (Dimension, etc.) # In welcher Groessenordnung liegen die einzelnen Eintraege? Erklaeren Sie das # anhand des vorherigen 2D Plots. # Vergleichen Sie das Ergebnis mit der Kovarianzmatrix, die oben zur Generierung # der Daten verwendet wurde. # Was erwarten Sie fuer den Mittelwert der transformierten Daten (noetig fuer # die Berechnung der Kovarianzmatrix) ? # # Verwenden Sie bei der Berechnung nicht die eingebaute numpy.cov Funktion # (hoechstens zur Kontrolle, achten Sie dabei auf den "bias" Parameter) # Verwenden Sie bei der Berechnung keine Schleifen, sondern nur Matrixoperationen. # Erklaeren Sie die Vorgehensweise. samples_mean = np.sum(samples_2d, axis=0) / n_samples X = samples_2d - samples_mean samples_2d_cov = np.dot(X.T, X) / n_samples print(samples_2d_cov) # # Latent Semantic Indexing # # Im folgenden soll ein Topic-Raum mittels Latent Semantic Indexing verwendet # werden. Das Prinzip geht unmittelbar auf die Hauptkomponentenanalyse zurueck. # Siehe: http://lsa.colorado.edu/papers/JASIS.lsi.90.pdf (Seite 12) # Grundsaetzlicher Unterschied ist, dass der Unterraum nicht durch eine Eigenewert- # analyse der Kovarianzmatrix bestimmt wird. Stattdessen ergibt sich der Unterraum # aus einer Zerlegung der Term-Dokument (!) Matrix mit einer Singulaerwertzerlegung. # Man kann zeigen, dass diese Singulaerwertzerlegung implizit einer Eigenwert- # analyse einer Termkorrelationsmatrix entspricht. Deren Berechnung unterscheidet # sich von der Berechnung der Kovarianzmatrix insbesondere darin, dass die Daten # nicht vom Mittelwert befreit werden. # Sei t die Anzahl der Terms (Groesse des Vokabulars), d die Anzahl der Dokumente, # m der Rang von X (Maximale Anzahl von Topics, die sich aus X bestimmen lassen). # D' ist die Transponierte von D. # # X = T * S * D' # t x d t x m m x m m x d # # In Analogie zur Hauptkomponentenanalyse findet man nun die Vektoren, die # den Unterraum aufspannen, in den Spalten von T. Die Matrix S hat nur Eintraege # auf der Diagonalen und enthaelt die Singulaerwerte zu den Spaltenvektoren in # T. (T und D enthalten die linken respektive rechten Singulaervektoren.) # Die Singulaerwerte entsprechen den Eigenwerten in der Hauptkomponentenanalyse. # Sie sind ein Mass fuer die Variabilitaet in den einzelnen Topics. Bei D handelt # es sich um die Koeffizienten der d Dokumente im Topic Raum (Ergebnis der # Transformation von den Bag-of-Words Repraesentationen aus X in den Topic Raum.) # # # Aus der Singulaerwertzerlegung (Formel oben) ergibt sich, wie man einen Topic- # Raum statistisch aus Beispieldaten schaetzt. Um den Topic-Raum aber mit unbekannten Daten # zu verwenden, muessen diese in den Topic-Raum transformiert werden. # Stellen Sie dazu die obige Formel nach D um. # # D = X' * T * S^-1 # d x m d x t t x m m x m # # Die zu transformierenden Bag-of-Words # Repaesentationen koennen dann fuer X eingesetzt werden. Dabei ist wichtig zu # beachten: # Die Spaltenvektoren in T sind orthonormal (zueinander) T' * T = I # Die Spaltenvektoren in D sind orthonormal (zueinander) D' * D = I # Dabei ist I die Einheitsmatrix, T' und D' sind die Transponierten in T und D. # Fuer Matrizen A und B gilt: (A * B)' = B' * A' # # Ueberlegen Sie wie die Transponierte einer Matrix gebildet wird und was das # fuer eine Matrix bedeutet, deren Eintraege nur auf der Hauptdiagonalen von # # Antwort: Die Matrix wird an der Hauptdiagonalen gespiegelt, bzw. die Zeilen und Spalten werden # vertauscht. Das bedeutet für die Hauptdiagonale, dass sie bei jeder Transponierung gleich bleibt # # Erlaeutern Sie die Funktion der einzelnen Matrizen in der sich ergebenden # Transformationsvorschrift. # # Das Schaetzen eines Topic-Raums soll an folgendem einfachen Beispiel veranschaulicht # werden. Sei dazu bow_train eine Dokument-Term Matrix mit 9 Dokumenten und 3 Terms. # Welcher Zusammenhang zwischen den Terms faellt Ihnen auf? # # Antwort: Der zweite Term scheint nicht besonders topic bezogen und kommt in jedem Dokument mind. 1 mal vor # die anderen beiden Terms sind dagegen eher topic bezogen, vor allem das dritte bow_train = np.array([[2, 5, 0], [4, 1, 0], [3, 3, 1], [9, 8, 2], [1, 5, 3], [0, 7, 9], [2, 9, 6], [0, 2, 3], [5, 3, 3]]) # Zerlegung der Dokument-Term Matrix mit der Singulaerwertzerlegung T, S_arr, D_ = np.linalg.svd(bow_train.T, full_matrices=False) S = np.diag(S_arr) print('Matrix T, Spaltenvektoren definieren Topic Raum') print(T) print('Matrix S, Singulaerwerte zu den Vektoren des Topic Raums') print(S) print('Matrix D, Koeffizienten der Termvektoren in bof Topic Raum') print(D_.T) # Transformieren Sie nun die folgenden Termvektoren in den Topic Raum # Was erwarten Sie fuer die Topic Zugehoerigkeiten? bow_test = np.array([[5, 0, 0], [0, 5, 0], [0, 0, 5], [5, 5, 0], [0, 5, 5]]) coefficients = np.dot(np.dot(bow_test, T), np.linalg.inv(S)) print(coefficients) # # Warum lassen sich die Koeffizienten der Termvektoren so schwer interpretieren? # Antwort: extrem kleine Werte -> besser: visualisieren # # Um eine bessere Vorstellung von der Bedeutung der einzelnen Topics zu bekommen, # plotten Sie die Bag-of-Words Repraesentationen sowie die Topic-Koeffizienten der # Trainingsdaten (bow_train) und der Testdaten (bow_test) in verschiedenen Farben. # Erstellen Sie dazu jeweils einen Plot fuer Bag-of-Words Repraesentationen und einen # Plot fuer Topic-Koeffizienten. Achten Sie auf eine geeignete Skalierung der Axen. # Um die Datenpunkte in den beiden Plots besser einander zuordnen zu koennen, plotten # Sie zusaetzlich die Termfrequenzen neben jeden Datenpunkt (als Annotation). # Mehrere Daten (Trainings-, Testdaten, Annotationen) lassen sich in einem gemeinsamen # Plot darzustellen indem sie nacheinander zu dem gleichen Axis Objekt hinzugefuegt # werden. Zum Erstellen der Plots orientieren Sie sich an den entsprechenden # Funktionen aus dem Beispiel zur Hauptkomponentenanalyse (oben). Schauen Sie sich # auch deren weitere Parameter (und zusaetzlich vorhandene Hilfsfunktionen) an. fig = plt.figure() ax = fig.add_subplot(111, projection='3d') annotations_D_test = PCAExample.samples_coordinate_annotations(bow_test) annotations_D_train = PCAExample.samples_coordinate_annotations(bow_train) PCAExample.plot_sample_data(D_.T, ax=ax, annotations=annotations_D_train, color='r') PCAExample.plot_sample_data(coefficients, ax=ax, annotations=annotations_D_test, color='b') PCAExample.set_axis_limits(ax, limits=((-1, 1), (-1, 1), (-1, 1))) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') PCAExample.plot_sample_data(bow_train, ax=ax, color='b', annotations=annotations_D_train) PCAExample.plot_sample_data(bow_test, ax=ax, color='r', annotations=annotations_D_test) PCAExample.set_axis_limits(ax, limits=((0, 10), (0, 10), (0, 10))) # # Fuehren Sie nun eine Dimensionsreduktion der Trainings und Testdaten auf zwei # Dimensionen durch und plotten Sie die Topic-Koeffizienten (inkl. Bag-of-Words # Annotationen). Vergleichen Sie alle drei Plots miteinander. Welchen Effekt hat # die Topic Modellierung im Bezug auf typische Termkonfigurationen? # # Optional: Transformieren Sie die Daten in einen Topic-Raum mit Dimension Eins # und plotten Sie die Koeffizienten inkl. deren Bag-of-Words Annotationen. # T_2d = T[:, :2] S_2d = S[:2, :2] D_2d_test = np.dot(np.dot(bow_test, T_2d), np.linalg.inv(S_2d)) D_2d_train = np.dot(np.dot(bow_train, T_2d), np.linalg.inv(S_2d)) ax = fig.add_subplot(111) annotations_D_test = PCAExample.samples_coordinate_annotations(bow_test) annotations_D_train = PCAExample.samples_coordinate_annotations(bow_train) PCAExample.plot_sample_data(D_2d_train, ax=ax, annotations=annotations_D_train, color='r') PCAExample.plot_sample_data(D_2d_test, ax=ax, annotations=annotations_D_test, color='b') PCAExample.set_axis_limits(ax, limits=((-0.75, 0.75), (-0.75, 0.75))) plt.show() # # Integrieren Sie nun die Topic-Raum Modellierung mittels Singulaerwertzerlegung # in die Kreuzvalidierung auf dem Brown Corpus. Berechnen Sie dabei fuer # jede Aufteilung von Training und Test einen neuen Topic-Raum. Transformieren # Sie die Bag-of-Words Repraesentationen und fuehren Sie die Klassifikation # wie zuvor mit dem Naechster-Nachbar-Klassifikator durch. Verwenden Sie dabei # verschiedene Distanzmasse und evaluieren Sie die Klassifikationsfehlerrate # fuer verschiedene Dimensionalitaeten des Topic-Raums. Die anderen Parameter # waehlen Sie gemaess der besten bisherigen Ergebnisse. # # Implementieren Sie die Klasse TopicFeatureTransform im features Modul # und verwenden Sie sie mit der CrossValidation Klasse (evaluation Modul). # # Optional: Fuehren Sie eine automatische Gridsuche ueber den kompletten Paramterraum # durch. Legen Sie sinnvolle Wertebereiche und Schrittweiten fuer die einzelnen # Parameter fest. Wie lassen sich diese bestimmen? # # Optional: Passen Sie das Suchgrid dynamisch gemaess der Ergebnisse in den einzelnen # Wertebereichen an. CorpusLoader.load() brown = CorpusLoader.brown_corpus() brown_categories = brown.categories() brown_words = brown.words() words_normalizer = WordListNormalizer() filtered_list, stemmed_list = words_normalizer.normalize_words(brown_words) vocabulary = BagOfWords.most_freq_words(stemmed_list, 500) cat_word_dict = {} for category in brown_categories: words_of_all_documents = [] for document in brown.fileids(category): filtered_list, stemmed_list = words_normalizer.normalize_words( brown.words(fileids=document)) words_of_all_documents.append(stemmed_list) cat_word_dict[category] = words_of_all_documents bag_of_words = BagOfWords(vocabulary) category_bow_dict = bag_of_words.category_bow_dict(cat_word_dict) cross_validation = CrossValidation(category_bow_dict, 5) knn_classifier = KNNClassifier(k_neighbors=4, metric='cosine') topic_feature_transform = TopicFeatureTransform(topic_dim=25) overall_result, class_result = cross_validation.validate( knn_classifier, feature_transform=topic_feature_transform) print(overall_result) print(class_result)
def detect(self, img, detected_faces=None): filename = utils.getFilename(img) config.maps_folder = config.temp_folder config.faces_folder = config.temp_folder config.descriptors_folder = config.temp_folder print('Processing ' + filename) image = cv2.imread(img) if image is None: print('ERROR processing ' + filename + ': image not found') return -1 #Check if image is colored try: _, _, channels = image.shape if channels < 3: raise Exception() except Exception as e: print( 'ERROR: image is grayscale. Illuminant maps analysis cannot be performed.' ) return -1 #Loads classifier # Extracting image features # Extract the faces in the image faces, _ = self.extractFaces(img, detected_faces) #Prediction map predictions = {} counters = {} for i in range(len(faces)): predictions[i], counters[i] = 0, 0 #Image is precessable if there are more than one image if len(faces) > 1: # If there are two or more faces, process the image # Extract maps self.extractIlluminationMaps(img) # Extract image descriptors and features for illum in config.illuminantTypes: for desc in self.descriptors: clfPath = config.classification_folder + 'model_' + illum + '_' + desc.lower( ) + '.pkl' if os.path.isfile(clfPath): clf = KNNClassifier.load(clfPath) features = self.extractFeatures(img, label=detected_faces, faces=faces, illum=illum, descriptor=desc, output=True) #Predict over sample for sample in features: prediction = clf.predict( np.array(sample.feature.split(), dtype=float).reshape((1, -1)), True)[0][1] predictions[sample.first] += prediction predictions[sample.second] += prediction counters[sample.first] += 1 counters[sample.second] += 1 #Majority voting threshold = config.majorityVotingThreshold score = 0 detected = False fakeFaces = [] for i in predictions: if score < predictions[i] / counters[i]: score = predictions[i] / counters[i] if predictions[i] / counters[i] > threshold: fakeFaces.append(i) print('\tFace ' + str(i + 1) + ' is FAKE. Score ' + str(score)) if not detected: detected = not detected else: print('\tFace ' + str(i + 1) + ' is NORMAL. Score ' + str(predictions[i] / counters[i])) if detected: print('Image is FAKE') else: print('Image is ORIGINAL') orig = cv2.imread(img, cv2.COLOR_BGR2GRAY) #Display spliced faces rows, cols, _ = orig.shape outputMask = np.zeros((rows, cols)) faceScores = orig.copy() idx = 0 font = cv2.FONT_HERSHEY_SIMPLEX for (x, y, w, h) in faces: face_score = predictions[idx] / counters[i] if idx not in fakeFaces: cv2.rectangle(faceScores, (x, y), (x + w, y + h), (0, 255, 0), 8) cv2.putText(faceScores, str("{:.3f}".format(face_score)), (x, y + h + 80), font, 1.8, (0, 255, 0), 3) else: cv2.rectangle(faceScores, (x, y), (x + w, y + h), (0, 0, 255), 8) cv2.putText(faceScores, str("{:.3f}".format(face_score)), (x, y + h + 80), font, 1.8, (0, 0, 255), 3) #Set score in detection map outputMask[y:y + h, x:x + w] = face_score idx += 1 faceScores = utils.resizeImage(faceScores, 1000) if self.display_result: cv2.imshow('output', faceScores) cv2.waitKey() regionMask = np.zeros(orig.shape) regionMask[..., 0] = outputMask.copy() regionMask[..., 1] = outputMask.copy() regionMask[..., 2] = outputMask.copy() # Write output mask outputMask *= 255 cv2.imwrite(config.faceOutputDetectionImage, outputMask) return score else: # discard the current image print('Not suitable number of faces found in the image') return -1
def train(self, images, labels): # Extract image features from each images in training set if self.extract_features or self.extract_maps: for i in range(len(images)): #Extract the faces in the image faces, _ = self.extractFaces(images[i], labels[i]) if len(faces) > 1: #If there are two or more faces, process the image filename = utils.getFilename(images[i]) print('Processing ' + filename) #Extract maps if self.extract_maps: self.extractIlluminationMaps(images[i]) #Extract face paired features if self.extract_features: # Extract image descriptors and features for illum in config.illuminantTypes: for desc in self.descriptors: self.extractFeatures(images[i], labels[i], faces=faces, illum=illum, descriptor=desc) else: #else discard the current image print('Not suitable number of faces found in the image') # Sample training if not self.cross_validation: # Train one model for each descriptor for illum in config.illuminantTypes: for desc in self.descriptors: trainingData, trainingLabels, _ = self.getTrainingData( images, desc, illum=illum) if len(trainingData) > 0: # Creates an instance of Neighbours Classifier and fit the data. clf = KNNClassifier(config.KNeighbours, 'uniform') clf.train(trainingData, trainingLabels) clf.store(config.classification_folder + 'model_' + illum + '_' + desc.lower() + '.pkl') print(illum + "/" + desc.upper() + ' classification model created correctly') else: #Crossvalidate dataset witk K-fold crossvalidation print('Evaluate dataset with crossvalidation') trainingDesc = {} for illum in config.illuminantTypes: for desc in self.descriptors: key = illum + "_" + desc trainingDesc[key] = self.getTrainingData(images, desc, illum=illum) #Counting misclassified samples for accuracy score misclassified = 0 refKey = config.illuminantTypes[0] + "_" + self.descriptors[0] #Splits dataset in train and test for crossvalidation splits = splitDataset(trainingDesc[refKey][0], config.folds) outputs_labels = trainingDesc[refKey][1] outputs_scores = np.zeros(len(trainingDesc[refKey][0])) for (trainIndex, testIndex) in splits: classifiers = {} for illum in config.illuminantTypes: for desc in self.descriptors: key = illum + "_" + desc trainingData, trainingLabels, _ = trainingDesc[key] if len(trainingData) > 0 and len(trainingLabels) > 0: trainingData = trainingData[trainIndex] trainingLabels = trainingLabels[trainIndex] #Training model for illum type and descriptor clf = KNNClassifier(config.KNeighbours, 'uniform') clf.train(trainingData, trainingLabels) classifiers[key] = clf outputs = [] outputs_probs = [] for illum in config.illuminantTypes: for desc in self.descriptors: key = illum + "_" + desc testData, _, _ = trainingDesc[key] if len(testData) > 0: testData = testData[testIndex] prediction = classifiers[key].predict( testData) * config.descriptors_weights[desc] outputs.append(prediction) prediction = classifiers[key].predict( testData, True) * config.descriptors_weights[desc] outputs_probs.append(prediction) output = np.zeros(len(testIndex)) output_prob = np.zeros(len(testIndex)) for i in range(len(outputs)): predictions = outputs[i] output += predictions predictions_prob = outputs_probs[i] for j in range(len(predictions)): output_prob[j] += predictions_prob[j][1] #If voting is majority, classify as fake outputs_scores[testIndex] = output_prob counter = 0 _, trainingLabels, _ = trainingDesc[refKey] testLabels = trainingLabels[testIndex] totalModels = len(classifiers) for val in np.nditer(output): if val > totalModels / 2: if testLabels[counter] != 1: misclassified += 1 else: if testLabels[counter] != 0: misclassified += 1 counter += 1 scipy.io.savemat( 'classification_output.mat', dict(labels=outputs_labels, scores=outputs_scores)) print('Number of classifiers: ' + str(totalModels)) totalSamples = len(trainingDesc[refKey][0]) print('Misclassified: ' + str(misclassified) + '/' + str(totalSamples)) accuracy = (totalSamples - misclassified) / totalSamples print('Accuracy: ' + str(accuracy))
def aufgabe3(): # ********************************** ACHTUNG ************************************** # Die nun zu implementierenden Funktionen spielen eine zentrale Rolle im weiteren # Verlauf des Fachprojekts. Achten Sie auf eine effiziente und 'saubere' Umsetzung. # Verwenden Sie geeignete Datenstrukturen und passende Python Funktionen. # Wenn Ihnen Ihr Ansatz sehr aufwaendig vorkommt, haben Sie vermutlich nicht die # passenden Datenstrukturen / Algorithmen / (highlevel) Python / NumPy Funktionen # verwendet. Fragen Sie in diesem Fall! # # Schauen Sie sich jetzt schon gruendlich die Klassen und deren Interfaces in den # mitgelieferten Modulen an. Wenn Sie Ihre Datenstrukturen von Anfang an dazu # passend waehlen, erleichtert dies deren spaetere Benutzung. Zusaetzlich bieten # diese Klassen bereits etwas Inspiration fuer Python-typisches Design, wie zum # Beispiel Duck-Typing. # # Zu einigen der vorgebenen Intefaces finden Sie Unit Tests in dem Paket 'test'. # Diese sind sehr hilfreich um zu ueberpruefen, ob ihre Implementierung zusammen # mit anderen mitgelieferten Implementierungen / Interfaces funktionieren wird. # Stellen Sie immer sicher, dass die Unit tests fuer die von Ihnen verwendeten # Funktionen erfolgreich sind. # Hinweis: Im Verlauf des Fachprojekts werden die Unit Tests nach und nach erfolg- # reich sein. Falls es sie zu Beginn stoert, wenn einzelne Unit Tests fehlschlagen # koennen Sie diese durch einen 'decorator' vor der Methodendefinition voruebergehend # abschalten: @unittest.skip('') # https://docs.python.org/2/library/unittest.html#skipping-tests-and-expected-failures # Denken Sie aber daran sie spaeter wieder zu aktivieren. # # Wenn etwas unklar ist, fragen Sie! # ********************************************************************************* print('loading brown') CorpusLoader.load() brown = CorpusLoader.brown_corpus() # Um eine willkuerliche Aufteilung der Daten in Training und Test zu vermeiden, # (machen Sie sich bewusst warum das problematisch ist) # verwendet man zur Evaluierung von Klassifikatoren eine Kreuzvalidierung. # Dabei wird der gesamte Datensatz in k disjunkte Ausschnitte (Folds) aufgeteilt. # Jeder dieser Ausschnitte wird einmal als Test Datensatz verwendet, waehrend alle # anderen k-1 Ausschnitte als Trainings Datensatz verwendet werden. Man erhaehlt also # k Gesamtfehlerraten und k klassenspezifische Fehlerraten ide man jeweils zu einer # gemeinsamen Fehlerrate fuer die gesamte Kreuzvalidierung mittelt. Beachten Sie, # dass dabei ein gewichtetes Mittel gebildet werden muss, da die einzelnen Test Folds # nicht unbedingt gleich gross sein muessen. # Fuehren Sie aufbauend auf den Ergebnissen aus aufgabe2 eine 5-Fold Kreuzvalidierung # fuer den k-Naechste-Nachbarn Klassifikator auf dem Brown Corpus durch. Dazu koennen # Sie die Klasse CrossValidation im evaluation Modul verwenden. # # Vollziehen Sie dazu nach wie die Klasse die Daten in Trainging und Test Folds aufteilt. # Fertigen Sie zu dem Schema eine Skizze an. Diskutieren Sie Vorteile und Nachteile. # Schauen Sie sich an, wie die eigentliche Kreuzvalidierung funktioniert. Erklaeren Sie # wie das Prinzip des Duck-Typing hier angewendet wird. # # Hinweise: # # Die Klasse CrossValidator verwendet die Klasse ClassificationEvaluator, die Sie schon # fuer aufgabe2 implementieren sollten. Kontrollieren Sie Ihre Umsetzung im Sinne der # Verwendung im CrossValidator. # # Fuer das Verstaendnis der Implementierung der Klasse CrossValidator ist der Eclipse- # Debugger sehr hilfreich. brown_categories = brown.categories() n_neighbours = 1 metric = 'euclidean' classifier = KNNClassifier(n_neighbours, metric) normalizer = WordListNormalizer() normalized_words = normalizer.normalize_words(brown.words()) vocabulary = BagOfWords.most_freq_words(normalized_words[1], 500) bow = BagOfWords(vocabulary) cat_word_dict = { cat: [brown.words(doc) for doc in brown.fileids(categories=cat)] for cat in brown_categories } n_folds = 5 category_bow_dict = bow.category_bow_dict(cat_word_dict) cross_validator = CrossValidation(category_bow_dict=category_bow_dict, n_folds=n_folds) crossval_overall_result, crossval_class_results = cross_validator.validate( classifier) print("ran cross validation for {}-nearest neighbour".format(n_neighbours)) print(crossval_overall_result) print(crossval_class_results) # Bag-of-Words Weighting # # Bisher enthalten die Bag-of-Words Histogramme absolute Frequenzen. # Dadurch sind die Repraesentationen abhaengig von der absoluten Anzahl # von Woertern in den Dokumenten. # Dies kann vermieden werden, in dem man die Bag-of-Words Histogramme mit # einem Normalisierungsfaktor gewichtet. # # Normalisieren Sie die Bag-of-Words Histogramme so, dass relative Frequenzen # verwendet werden. Implementieren und verwenden Sie die Klasse RelativeTermFrequencies # im features Modul. # # Wie erklaeren Sie das Ergebnis? Schauen Sie sich dazu noch einmal die # mittelere Anzahl von Woertern pro Dokument an (aufgabe2). # # Wie in der Literatur ueblich, verwenden wir den # Begriff des "Term". Ein Term bezeichnet ein Wort aus dem Vokabular ueber # dem die Bag-of-Words Histogramme gebildet werden. Ein Bag-of-Words Histogramm # wird daher auch als Term-Vektor bezeichnet. rel_category_bow_dict = { cat: RelativeTermFrequencies.weighting(category_bow_dict[cat]) for cat in category_bow_dict } cross_validator = CrossValidation(category_bow_dict=rel_category_bow_dict, n_folds=n_folds) crossval_overall_result, crossval_class_results = cross_validator.validate( classifier) print("ran cross validation for {}-nearest neighbour (relative)".format( n_neighbours)) print(crossval_overall_result) print(crossval_class_results) # Zusaetzlich kann man noch die inverse Frequenz von Dokumenten beruecksichtigen # in denen ein bestimmter Term vorkommt. Diese Normalisierung wird als # inverse document frequency bezeichnet. Die Idee dahinter ist Woerter die in # vielen Dokumenten vorkommen weniger stark im Bag-of-Words Histogramm zu gewichten. # Die zugrundeliegende Annahme ist aehnlich wie bei den stopwords (aufgabe1), dass # Woerter, die in vielen Dokumenten vorkommen, weniger Bedeutung fuer die # Unterscheidung von Dokumenten in verschiedene Klassen / Kategorien haben als # Woerter, die nur in wenigen Dokumenten vorkommen. # Diese Gewichtung laesst sich statistisch aus den Beispieldaten ermitteln. # # Zusammen mit der relativen Term Gewichtung ergibt sich die so genannte # "term frequency inverse document frequency" # # Anzahl von term in document Anzahl Dokumente # tfidf( term, document ) = ---------------------------- x log ( ---------------------------------- ) # Anzahl Woerter in document Anzahl Dokumente die term enthalten # # http://www.tfidf.com # # Eklaeren Sie die Formel. Plotten Sie die inverse document frequency fuer jeden # Term ueber dem Brown Corpus. # # Implementieren und verwenden Sie die Klasse RelativeInverseDocumentWordFrequecies # im features Modul, in der Sie ein tfidf Gewichtungsschema umsetzen. # Ermitteln Sie die Gesamt- und klassenspezifischen Fehlerraten mit der Kreuzvalidierung. # Vergleichen Sie das Ergebnis mit der absolten und relativen Gewichtung. # Erklaeren Sie die Unterschiede in den klassenspezifischen Fehlerraten. Schauen Sie # sich dazu die Verteilungen der Anzahl Woerter und Dokumente je Kategorie aus aufgabe1 # an. In wie weit ist eine Interpretation moeglich? tfidf = RelativeInverseDocumentWordFrequecies(vocabulary, cat_word_dict) rel_category_bow_dict = { cat: tfidf.weighting(category_bow_dict[cat]) for cat in category_bow_dict } cross_validator = CrossValidation(category_bow_dict=rel_category_bow_dict, n_folds=n_folds) crossval_overall_result, crossval_class_results = cross_validator.validate( classifier) print("ran cross validation for {}-nearest neighbour (relative-inverse)". format(n_neighbours)) print(crossval_overall_result) print(crossval_class_results) # Evaluieren Sie die beste Klassifikationsleistung # # Ermitteln Sie nun die Parameter fuer die beste Klassifikationsleistung des # k-naechste-Nachbarn Klassifikators auf dem Brown Corpus mit der Kreuzvalidierung. # Dabei wird gleichzeitig immer nur ein Parameter veraendert. Man hat eine lokal # optimale Parameterkonfiguration gefunden, wenn jede Aenderung eines Parameters # zu einer Verschlechterung der Fehlerrate fuehrt. # # Erlaeutern Sie warum eine solche Parameterkonfiguration lokal optimal ist. # # Testen Sie mindestens die angegebenen Werte fuer die folgenden Parameter: # 1. Groesse des Vokabulars typischer Woerter (100, 500, 1000, 2000) # 2. Gewichtung der Bag-of-Words Histogramme (absolute, relative, relative with inverse document frequency) # 3. Distanzfunktion fuer die Bestimmung der naechsten Nachbarn (Cityblock, Euclidean, Cosine) # 4. Anzahl der betrachteten naechsten Nachbarn (1, 2, 3, 4, 5, 6) # # Erklaeren Sie den Effekt aller Parameter. # # Erklaeren Sie den Effekt zwischen Gewichtungsschema und Distanzfunktion. # vocabulary sizes as specified voc_sizes = (100, 500, 1000, 2000) # weightings as specified weightings = ('abs', 'rel', 'tfidf') # metrices as specified dists = ("cityblock", "euclidean", "cosine") # numbers of neighbours as specified neighbours = (1, 2, 3, 4, 5, 6) # indices of best options, to keep track idx_vs = 0 idx_wghts = 0 idx_dsts = 0 idx_nn = 0 normalizer = WordListNormalizer() cat_word_dict = normalizer.category_wordlists_dict(corpus=brown) # Flatten the category word lists for computing overall word frequencies # The * operator expands the list/iterator to function arguments # itertools.chain concatenates all its parameters to a single list print 'Building Bag-of-Words vocabulary...' wordlists = itertools.chain(*(cat_word_dict.itervalues())) normalized_words = itertools.chain(*wordlists) vocabulary = BagOfWords.most_freq_words(normalized_words) # print("normalizing") # # normalizing # normalizer = WordListNormalizer() # # normalized words # normalized_words = normalizer.normalize_words(brown.words())[1] # print("normalized words") # # normalized wordlists # cat_word_dict = normalizer.category_wordlists_dict(brown) # print("normalized wordlists") # # # initializing the vocabulary at maximum size and then taking slices # vocabulary = BagOfWords.most_freq_words(normalized_words, 2000) # print('initializing configuration') # # exp_config = ExpConfigurations(vocabulary ,cat_word_dict, # voc_sizes, weightings, dists, neighbours) # print(exp_config.run()) # for row in exp_config.__log: # print(row) config = Configuration(brown, cat_word_dict, vocabulary, voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx_nn], weightings[idx_wghts]) config.fit() err_overall = config.eval()[0] # list of configuration results config_table = [['voc_sizes', 'metric', 'neighbours', 'weightings', 'err'], [ voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx_nn], weightings[idx_wghts], err_overall ]] print('calculating size') # local optimum for vocabulary size for idx, _ in enumerate(voc_sizes[1:]): tmp_config = Configuration(brown, cat_word_dict, vocabulary, voc_sizes[idx + 1], dists[idx_dsts], neighbours[idx_nn], weightings[idx_wghts]) tmp_config.fit() tmp_err = tmp_config.eval()[0] if err_overall > tmp_err: err_overall = deepcopy(tmp_err) idx_vs = deepcopy(idx + 1) config_table.append([ voc_sizes[idx + 1], dists[idx_dsts], neighbours[idx_nn], weightings[idx_wghts], tmp_err ]) print(voc_sizes[idx_vs]) print('calculating weights') # local optimum for weighting for idx, _ in enumerate(weightings[1:]): tmp_config = Configuration(brown, cat_word_dict, vocabulary, voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx_nn], weightings[idx + 1]) tmp_config.fit() tmp_err = tmp_config.eval()[0] if err_overall > tmp_err: err_overall = deepcopy(tmp_err) idx_wghts = deepcopy(idx + 1) config_table.append([ voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx_nn], weightings[idx + 1], tmp_err ]) print(weightings[idx_wghts]) print('calculating metric') # local optimum for metric for idx, _ in enumerate(dists[1:]): tmp_config = Configuration(brown, cat_word_dict, vocabulary, voc_sizes[idx_vs], dists[idx + 1], neighbours[idx_nn], weightings[idx_wghts]) tmp_config.fit() tmp_err = tmp_config.eval()[0] if err_overall > tmp_err: err_overall = deepcopy(tmp_err) idx_dsts = deepcopy(idx + 1) config_table.append([ voc_sizes[idx_vs], dists[idx + 1], neighbours[idx_nn], weightings[idx_wghts], tmp_err ]) print(dists[idx_dsts]) print('calculating neighbours') # local optimum for neighbours for idx, _ in enumerate(neighbours[1:]): tmp_config = Configuration(brown, cat_word_dict, vocabulary, voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx + 1], weightings[idx_wghts]) tmp_config.fit() tmp_err = tmp_config.eval()[0] if err_overall > tmp_err: err_overall = deepcopy(tmp_err) idx_nn = deepcopy(idx + 1) config_table.append([ voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx + 1], weightings[idx_wghts], tmp_err ]) print(neighbours[idx_nn]) # ideal should be 2000, relative, cityblock, 4 print('local optimum at\nsize: {}\nweight: {}\nmetric: {}\nneighbours: {}'. format(voc_sizes[idx_vs], weightings[idx_wghts], dists[idx_dsts], neighbours[idx_nn])) for row in config_table: print(row)
args = parser.parse_args() verbose = args.verbose terse = args.terse force_train = args.retrain use_tesseract = args.tesseract tesslangpath = args.tesslangpath segmenter = MinContourSegmenter(blur_y=5, blur_x=5, min_width=5, block_size=17, c=6, max_ratio=4.0) extractor = SimpleFeatureExtractor(feature_size=10, stretch=False) classifier = KNNClassifier(k=3) ocr = OCR(segmenter, extractor, classifier) for file_to_train in args.trainfile: training_image = ImageFile(file_to_train) if not training_image.isGrounded() or force_train: #trainingsegmenter = ContourSegmenter(blur_y=1, blur_x=1, min_width=3, min_height=15, max_height=50, min_area=30, block_size=23, c=3) # tweaked for black font trainingsegmenter = ContourSegmenter( blur_y=1, blur_x=1, min_width=3, min_height=15, max_height=50, min_area=30, block_size=3, c=5,