So lösen Sie ein altes Problem mit ML in Python und .Net


Es kommt vor, dass einige Aufgaben Sie viele Jahre lang verfolgen. Für mich wurde das Zusammenkleben von Textsätzen, bei denen der Übergang zu einer neuen Zeile und oft auch der Zeilenumbruch fest verstopft sind, zu einer solchen Aufgabe. In der Praxis ist dies Text, der aus PDF oder OCR extrahiert wurde. Oft findet man solche Texte auf den Websites von Online-Bibliotheken, in Archiven alter Dokumente, die von DOS-Redakteuren bearbeitet wurden. Und eine solche Formatierung stört dann die ordnungsgemäße Aufteilung in Sätze (und mit Silbentrennungen in Token) für die nachfolgende NLP-Verarbeitung. Und es ist banal, ein solches Dokument in den Suchergebnissen anzuzeigen - es wird hässlich.


Ich habe dieses Problem mehrmals gelöst - in Delphi, C #. Dann war es ein harter Algorithmus, bei dem ich mit meinen Händen zum Beispiel schrieb, wie breit der Text sein könnte, so dass dieser Text als "auf die alte Weise" formatiert angesehen wurde. Dies funktionierte nicht immer perfekt, aber im Allgemeinen war es genug.


Im Moment krieche ich in einigen ML-Projekten in Python. An einem Punkt stellte sich heraus, dass das nächste Korpus von Dokumenten aus Texten besteht, die aus PDF-Versionen wissenschaftlicher Artikel extrahiert wurden. Natürlich wurde der Text mit einem harten Zeilenumbruch durch die Zeichen am Ende des Absatzes mit Bindestrichen extrahiert. Das heißt, es war unmöglich, mit solchen Texten normal weiter zu arbeiten. Python ist attraktiv, weil es fast alles hat! Aber ein paar Stunden Suchen haben nichts Vernünftiges gebracht (vielleicht war es natürlich das, wonach ich gesucht habe). Und dann habe ich mich noch einmal entschlossen, einen Postprozessor für solche Dokumente zu schreiben. Sie hatten zwei Möglichkeiten: Portieren Sie Ihren bisherigen Code mit C # oder schreiben Sie etwas, das Sie lernen könnten. Der zweite Ansatz wurde schließlich durch die Tatsache ausgelöst, dass wissenschaftliche Texte teilweise aus zweispaltigen und teilweise aus einspaltigen Texten exportiert wurden. Auch verschiedene Schriftgrößen. Dies führte dazu, dass die alte Version mit fest verdrahteten zulässigen Grenzen oft falsch funktionierte. Wieder manuell sitzen, Optionen auswählen - nun, nein, bald wird die Singularität kommen , ich habe keine Zeit dafür! Es ist also entschieden - wir schreiben eine Bibliothek mit maschinellem Lernen.


Der gesamte Code befindet sich im Repository :



Markup


Was ist die Begeisterung und Komplexität des maschinellen Lernens? Wenn der Algorithmus irgendwo fehlschlägt, müssen Sie das Programm häufig nicht selbst ändern. Es reicht aus, neue Daten zu sammeln (häufig müssen sie gleichzeitig mit Anmerkungen versehen werden) und die Erstellung des Modells neu zu starten. Der Computer erledigt den Rest für Sie. Natürlich besteht die Möglichkeit, dass Sie für neue Daten neue Funktionen entwickeln und die Architektur ändern müssen. In den meisten Fällen müssen Sie jedoch nur überprüfen, ob alles gut funktioniert hat. Dies ist auch eine Schwierigkeit - das Sammeln und Markieren von Daten kann schwierig sein. Oder sehr schwierig. Und auch - furchtbar langweilig :-)


Das Langweiligste ist also das Markup. Der Korpusordner enthält Dokumente, die ich gerade aus dem Krapivin2009-Dokumententext entnommen habe, mit dem ich gerade gearbeitet habe. Es gibt 10 Dokumente, die mir typisch erschienen. Ich habe nur 3 markiert, da bereits zu Beginn des Trainings auf dieser Basis eine ausreichende Qualität des „Klebstoffs“ erzielt wurde. Wenn sich in Zukunft herausstellt, dass nicht alles so einfach ist, werden neue Dokumente mit Markup in diesen Ordner gelegt und der Lernprozess wiederholt.


In diesem Fall schien es mir zweckmäßig, dass die Dateien Text blieben, daher bestand das Markup-Format darin, am Anfang der Zeile ein Zeichen einzufügen, dass diese Zeile an die vorherige geklebt werden sollte (das Zeichen '+') oder nicht (das Zeichen '*'). Hier ist ein Ausschnitt (Datei 1005058.txt ):


*Introduction *Customers on the web are often overwhelmed with options and flooded with promotional messages for +products or services they neither need nor want. When users cannot find what they are searching for, the +e-commerce site struggles to maintain good customer relations. *Employing a recommender system as part of a site's Customer Relationship Management (CRM) activities +can overcome the problems associated with providing users with too little information, or too much of +the wrong information. Recommender systems are able to assist customers during catalog browsing and are +an effective way to cross-sell and improve customer loyalty. *In this paper, we will compare several recommender systems being used as an essential component of +CRM tools under development at Verizon. Our solutions are purposely for the current customers and current +products - recommendations for new customers and new products are out of the scope of this paper. 

Ein paar Stunden langwierige Arbeit und 3 Dateien mit 2300 Beispielen (eine Zeile - ein Beispiel) stehen bereit. Dies reicht in vielen Fällen bereits für einfache Klassifikatoren wie die dann angewandte logistische Regression aus.


Eigenschaften


Klassifikatoren arbeiten nicht direkt mit Textdaten. Einträge werden mit Features bedient - entweder Zahlen oder Boolesche Zeichen (die wiederum in Zahlen 0/1 übersetzt werden), dass ein Feature vorhanden ist oder nicht. Das Erstellen der richtigen Funktionen aus guten Daten ist der Schlüssel zum Erfolg des maschinellen Lernens. Ein Merkmal unseres Falles ist, dass unser Korpus englische Texte sind. Und ich möchte zumindest eine minimale Sprachunabhängigkeit erreichen. Zumindest in europäischen Sprachen. Daher verwenden wir für Textfunktionen einen kleinen Trick.


Das Konvertieren von Text in eine Liste von Features und Beschriftungen, ob mit der vorherigen Zeile geklebt werden soll, wird von der Hilfsfunktion _featurize_text_with_annotation ausgeführt :


 x, y = pdf_lines_gluer._featurize_text_with_annotation(raw_text) 

Hinweis - hier und weiter gehen hauptsächlich Codefragmente in Python, die Sie vollständig in einem Laptop sehen können .


Verwendete Funktionen:


  • 'this_len' - die Länge der aktuellen Zeile in Zeichen.
  • 'mean_len' - die durchschnittliche Zeilenlänge im Bereich -5 ... + 5 Zeilen.
  • 'prev_len' - die Länge der vorherigen Zeile in Zeichen.
  • 'first_chars' - hier ist unsere knifflige Funktion. Die ersten 2 Zeichen der Zeichenfolge werden hier platziert. Gleichzeitig werden alle Kleinbuchstaben (eines beliebigen Alphabets) durch das englische Zeichen 'a' ersetzt, Großbuchstaben durch 'A' und Zahlen durch '0'. Dies reduziert die Anzahl möglicher Zeichen erheblich und fasst sie zusammen. Beispiele für das, was passiert: 'Aa', 'aa', 'AA', '0.', 'a-' ...
  • 'isalpha' - ob der Buchstabe das letzte Zeichen der vorherigen Zeile ist.
  • 'isdigit' - Gibt an, ob die Ziffer das letzte Zeichen der vorherigen Zeile ist.
  • 'islower' - Gibt an, ob der Kleinbuchstabe das letzte Zeichen der vorherigen Zeile ist.
  • 'punct' - ein Interpunktionszeichen, das mit der vorherigen Zeile endet, oder ein Leerzeichen für andere Zeichen.

Ein Beispiel für eine Reihe von Funktionen für eine Zeile:


 {'this_len': 12, 'mean_len': 75.0, 'prev_len': 0, 'first_chars': 'Aa', 'isalpha': False, 'isdigit': False, 'islower': False, 'punct': ' '} 

Damit der Klassifizierer aus dem sklearn-Paket mit ihnen arbeiten kann, verwenden wir die DictVectorizer-Klasse, mit der Zeichenfolgenfunktionen (wir haben 'first_chars') in mehrere Spalten mit dem Titel (Namen können über get_feature_names () abgerufen werden) als 'first_chars = konvertiert werden Aa ',' first_chars = 0. '. Boolesche Merkmale werden zu Nullen und Einsen, während numerische Werte Zahlen bleiben - Feldnamen ändern sich nicht. Äußerlich gibt die Methode numpy.array von ungefähr diesem Typ zurück (es wird nur eine Zeile angezeigt):


 [[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 39.1 30. 0. 1. 36. ]] 

Klassifikator Training


Nachdem wir eine Reihe von Funktionen in Form eines Arrays von Gleitkommazahlen erhalten haben, können wir nun mit dem Lernprozess beginnen. Dazu verwenden wir die logistische Regression als Klassifikator. Klassen sind unausgeglichen, daher setzen wir die Option class_weight = 'ausgeglichen' und überprüfen das Ergebnis im Testteil des Falls:


 from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report clf = LogisticRegression(random_state=1974, solver='liblinear', max_iter=2000, class_weight='balanced') clf.fit(x_train, y_train) y_pred = clf.predict(x_test) print(classification_report(y_true=y_test, y_pred=y_pred)) 

Wir bekommen solche Qualitätsindikatoren:


  precision recall f1-score support False 0.82 0.92 0.86 207 True 0.96 0.91 0.94 483 accuracy 0.91 690 macro avg 0.89 0.91 0.90 690 weighted avg 0.92 0.91 0.91 690 

Wie Sie sehen können, haben wir in etwa 1/10 der Fälle Fehler verschiedener Art. Aber in der Praxis ist nicht alles so beängstigend. Tatsache ist, dass selbst bei Augenmarkierungen nicht immer klar ist, wo sich das Ende des Absatzes befindet und wo nur das Ende des Satzes. Daher kann auch das Markup selbst solche Fehler enthalten. Die kritischsten Fehler sind jedoch nicht dort, wo sie an der Grenze des Vorschlags auftreten, sondern dort, wo der Vorschlag zerrissen bleibt. Und in der Realität gibt es nur sehr wenige solche Fehler.


Text wiederherstellen


Es ist an der Zeit, den durch das Extrahieren aus PDF beschädigten Text wiederherzustellen. Wir können bereits bestimmen, ob die Linie mit der vorherigen geklebt werden soll, aber es gibt noch einen Punkt - die Silbentrennung. Hier ist alles ziemlich einfach, also habe ich diesen Teil hart codiert (ich erlaube mir einen Pseudocode):


      :         :       :      :        \n 

Mit einer solchen Strategie bewaffnet stellen wir den englischen Text wieder her (es gibt Fehler wie "ff" und "fi" im Original - er wurde einfach aus dem Fall Krapivin2009 kopiert):


Englischer Originaltext
 text = """The rapid expansion of wireless services such as cellular voice, PCS (Personal Communications Services), mobile data and wireless LANs in recent years is an indication that signicant value is placed on accessibility and portability as key features of telecommunication (Salkintzis and Mathiopoulos (Guest Ed.), 2000). devices have maximum utility when they can be used any- where at anytime". One of the greatest limitations to that goal, how- ever, is nite power supplies. Since batteries provide limited power, a general constraint of wireless communication is the short continuous operation time of mobile terminals. Therefore, power management is y Corresponding Author: Dr. Krishna Sivalingam. Part of the research was supported by Air Force Oce of Scientic Research grants F-49620-97-1- 0471 and F-49620-99-1-0125; by Telcordia Technologies and by Intel. Part of the work was done while the rst author was at Washington State Univer- sity. The authors' can be reached at cej@bbn.com, krishna@eecs.wsu.edu, pagrawal@research.telcordia.com, jcchen@research.telcordia.com c 2001 Kluwer Academic Publishers. Printed in the Netherlands. Jones, Sivalingam, Agrawal and Chen one of the most challenging problems in wireless communication, and recent research has addressed this topic (Bambos, 1998). Examples include a collection of papers available in (Zorzi (Guest Ed.), 1998) and a recent conference tutorial (Srivastava, 2000), both devoted to energy ecient design of wireless networks. Studies show that the signicant consumers of power in a typical laptop are the microprocessor (CPU), liquid crystal display (LCD), hard disk, system memory (DRAM), keyboard/mouse, CDROM drive, oppy drive, I/O subsystem, and the wireless network interface card (Udani and Smith, 1996, Stemm and Katz, 1997). A typical example from a Toshiba 410 CDT mobile computer demonstrates that nearly 36% of power consumed is by the display, 21% by the CPU/memory, 18% by the wireless interface, and 18% by the hard drive. Consequently, energy conservation has been largely considered in the hardware design of the mobile terminal (Chandrakasan and Brodersen, 1995) and in components such as CPU, disks, displays, etc. Signicant additional power savings may result by incorporating low-power strategies into the design of network protocols used for data communication. This paper addresses the incorporation of energy conservation at all layers of the protocol stack for wireless networks. The remainder of this paper is organized as follows. Section 2 introduces the network architectures and wireless protocol stack considered in this paper. Low-power design within the physical layer is brie y discussed in Section 2.3. Sources of power consumption within mobile terminals and general guidelines for reducing the power consumed are presented in Section 3. Section 4 describes work dealing with energy ecient protocols within the MAC layer of wireless networks, and power conserving protocols within the LLC layer are addressed in Section 5. Section 6 discusses power aware protocols within the network layer. Opportunities for saving battery power within the transport layer are discussed in Section 7. Section 8 presents techniques at the OS/middleware and application layers for energy ecient operation. Finally, Section 9 summarizes and concludes the paper. 2. Background This section describes the wireless network architectures considered in this paper. Also, a discussion of the wireless protocol stack is included along with a brief description of each individual protocol layer. The physical layer is further discussed. """ corrected = pdf_lines_gluer._preprocess_pdf(text, clf, v) print(corrected) 

Nach der Genesung erhalten wir:


Wiederhergestellter englischer Text

Die rasche Ausweitung von drahtlosen Diensten wie Mobilfunk, PCS (Personal Communications Services), mobilen Daten und drahtlosen LANs in den letzten Jahren ist ein Hinweis darauf, dass Zugänglichkeit und Portabilität als Schlüsselmerkmale der Telekommunikation einen hohen Stellenwert haben (Salkintzis und Mathiopoulos (Guest Ed .), 2000). Geräte haben maximalen Nutzen, wenn sie jederzeit und überall verwendet werden können. "Eine der größten Einschränkungen für dieses Ziel sind jedoch Endstromversorgungen. Da Batterien nur eine begrenzte Leistung liefern, ist die kurze Dauerbetriebszeit des Mobiltelefons eine allgemeine Einschränkung der drahtlosen Kommunikation Daher ist Power Management ein korrespondierender Autor: Dr. Krishna Sivalingam. Ein Teil der Forschung wurde von Air Force Oce of Scientic Research mit den Zuschüssen F-49620-97-10471 und F-49620-99-1-0125 von Telcordia unterstützt Technologien und von Intel. Ein Teil der Arbeit wurde durchgeführt, als der erste Autor an der Washington State University war. Die Autoren können unter cej@bbn.com, krishna@eecs.wsu.edu, pagrawal@research.telcordia.com, erreicht werden. jcchen@research.telcordia.com c
2001 Kluwer Academic Publishers. Gedruckt in den Niederlanden.
Jones, Sivalingam, Agrawal und Chen sind eines der schwierigsten Probleme in der drahtlosen Kommunikation, und neuere Forschungen haben sich mit diesem Thema befasst (Bambos, 1998). Beispiele hierfür sind eine Sammlung von Artikeln, die in (Zorzi (Guest Ed.), 1998) verfügbar sind, und ein kürzlich veröffentlichtes Konferenz-Tutorial (Srivastava, 2000), die sich beide mit dem energieeffizienten Design drahtloser Netzwerke befassen.
Studien zeigen, dass die wichtigsten Stromverbraucher in einem typischen Laptop der Mikroprozessor (CPU), das Flüssigkristalldisplay (LCD), die Festplatte, der Systemspeicher (DRAM), die Tastatur / Maus, das CD-ROM-Laufwerk, das Gegenlaufwerk, das E / A-Subsystem, sind. und die drahtlose Netzwerkschnittstellenkarte (Udani und Smith, 1996, Stemm und Katz, 1997). Ein typisches Beispiel eines mobilen Toshiba 410 CDT-Computers zeigt, dass fast 36% des Stromverbrauchs vom Display, 21% von der CPU / dem Speicher stammen.
18% über die drahtlose Schnittstelle und 18% über die Festplatte. Infolgedessen wurde die Energieeinsparung beim Hardware-Design des mobilen Endgeräts (Chandrakasan und Brodersen, 1995) sowie bei Komponenten wie CPU, Festplatten, Displays usw. weitgehend berücksichtigt. Durch die Einbeziehung von Strategien mit geringem Stromverbrauch in den Entwurf von Netzwerkprotokollen, die für die Datenkommunikation verwendet werden, können erhebliche zusätzliche Energieeinsparungen erzielt werden. Dieses Dokument befasst sich mit der Einbeziehung der Energieeinsparung auf allen Ebenen des Protokollstapels für drahtlose Netzwerke.
Der Rest dieses Papiers ist wie folgt organisiert. In Abschnitt 2 werden die in diesem Dokument berücksichtigten Netzwerkarchitekturen und der drahtlose Protokollstapel vorgestellt. Low-Power-Design innerhalb der physischen Schicht ist kurz
diskutiert in Abschnitt 2.3. Die Quellen des Stromverbrauchs in mobilen Endgeräten und allgemeine Richtlinien zur Reduzierung des Stromverbrauchs sind in Abschnitt 3 aufgeführt. Abschnitt 4 beschreibt die Arbeit mit energieeffizienten Protokollen innerhalb der MAC-Schicht von drahtlosen Netzwerken, und Energieeinsparungsprotokolle innerhalb der LLC-Schicht werden in Abschnitt 3 behandelt
5. In Abschnitt 6 werden leistungsbewusste Protokolle innerhalb der Netzwerkschicht erläutert. Möglichkeiten zum Einsparen von Batteriestrom innerhalb der Transportschicht werden in Abschnitt 7 erörtert. In Abschnitt 8 werden Techniken auf der OS / Middleware- und Anwendungsschicht für einen energieeffizienten Betrieb vorgestellt.
Schließlich fasst Abschnitt 9 das Papier zusammen und schließt es ab.
2. Hintergrund
In diesem Abschnitt werden die in diesem Dokument berücksichtigten drahtlosen Netzwerkarchitekturen beschrieben. Außerdem ist eine Diskussion des drahtlosen Protokollstapels zusammen mit einer kurzen Beschreibung jeder einzelnen Protokollschicht enthalten. Die physikalische Schicht wird weiter diskutiert.


Es gibt einen kontroversen Ort, aber im Allgemeinen wurden Sätze wiederhergestellt und dieser Text kann bereits als ganze Sätze verarbeitet werden.


Wir planten jedoch eine sprachunabhängige Option. Und genau darauf zielen unsere Funktionen ab. Lassen Sie uns russischen Text einchecken (auch ein Textfragment aus PDF):


Russischer Originaltext
 ru_text = """       -       (. 1.10),    ,   - .       ,      , -   .       ,       .          : 1.        ,       -  (   ,   . 1.10,    ). 2.    ( )           ,     .      ,     .""" corrected = pdf_lines_gluer._preprocess_pdf(ru_text, clf, v) print(corrected) 

Erhalten:


Restaurierter russischer Text

Die Support-Vektor-Methode wurde entwickelt, um Klassifizierungsprobleme zu lösen, indem nach guten Entscheidungsgrenzen gesucht wird (Abb. 1.10), die zwei Punktmengen trennen, die zu verschiedenen Kategorien gehören. Die entscheidende Grenze kann eine Linie oder Fläche sein, die eine Stichprobe von Trainingsdaten in Räume unterteilt, die zu zwei Kategorien gehören. Um neue Punkte zu klassifizieren, reicht es aus, nur zu überprüfen, auf welcher Seite des Randes sie sich befinden.
Die Suchvektormethode sucht in zwei Schritten nach solchen Grenzen:
1. Daten werden in einen neuen Raum höherer Dimension abgebildet, in dem die Grenze als Hyperebene dargestellt werden kann (wenn die Daten zweidimensional wären, wie in Abb. 1.10 dargestellt, degeneriert die Hyperebene zu einer Linie).
2. Eine gute Entscheidungsgrenze (Teilen der Hyperebene) wird berechnet, indem der Abstand von der Hyperebene zu den nächsten Punkten jeder Klasse maximiert wird. Dieser Schritt wird als Maximieren der Lücke bezeichnet. Dies ermöglicht es uns, die Klassifizierung neuer Stichproben, die nicht zum Trainingsdatensatz gehören, zu verallgemeinern.


Hier ist alles perfekt.


Verwendung (Codegenerierung)


Zuerst hatte ich vor, ein Paket zu erstellen, das mit PIP geliefert werden kann, aber dann habe ich mir (für mich) einen einfacheren Weg ausgedacht. Die Funktionen erwiesen sich als nicht sehr umfangreich, die logistische Regression selbst und DictVectorizer haben eine einfache Struktur:


  • Für DictVectorizer reicht es aus, die Feature- Namen und Vokabelfelder zu speichern
  • LogisticRegression hat coef , classes , intercept_

Daher wurde eine andere Option mit der Codegenerierung geboren (im Laptop steht sie im Abschnitt "Als Code serialisieren"):


  1. Wir lesen die Datei pdf_lines_gluer.py , die Hilfscode zum Vektorisieren und Wiederherstellen von Text mit einem trainierten Klassifikator enthält.
  2. An der Stelle, die in der Quelle als "# Code hier einfügen #" angegeben ist, fügen wir den Code ein, der den DictVectorizer und LogisticRegression in dem Zustand initialisiert, den wir nach dem Training in unserem Laptop erhalten haben. Wir fügen hier auch die einzige öffentliche (so weit wie möglich für Python) preprocess_pdf-Funktion ein:
     def preprocess_pdf(text: str) -> str: return _preprocess_pdf(text, _clf, _v) 
  3. Der resultierende Code wird in die Datei pdf_preprocessor.py geschrieben

Diese generierte Datei pdf_preprocessor.py enthält alles, was wir brauchen. Um es zu verwenden, nehmen Sie einfach diese eine Datei und legen Sie sie in Ihrem Projekt ab. Verwendung:


 from pdf_preprocessor import preprocess_pdf ... print(preprocess_pdf(text)) 

Wenn Sie Probleme mit einigen Texten haben, müssen Sie Folgendes tun:


  1. Legen Sie Ihre Texte in den Korpusordner und kommentieren Sie sie.
  2. Starten Sie Ihren Laptop https://github.com/serge-sotnyk/pdf-lines-gluer/blob/master/pdf_gluer.ipynb - bei aktuellen Texten dauert es weniger als 5 Sekunden.
  3. Nehmen Sie die neue Version der Datei pdf_preprocessor.py und testen Sie sie

Vielleicht geht etwas schief und die Qualität wird Sie nicht befriedigen. Dann wird es etwas komplizierter - Sie müssen neue Funktionen hinzufügen, bis Sie die richtige Kombination gefunden haben.


C # und ML.NET


In unserem Unternehmen basiert der größte Teil des Backend-Codes auf .Net. Die Interaktion mit Python ist hier natürlich unangenehm. Und ich hätte gerne eine ähnliche Lösung in C #. Ich habe die Entwicklung des ML.NET- Frameworks lange verfolgt . Ich habe letztes Jahr kleine Versuche unternommen, etwas zu tun, aber sie waren enttäuschend mit der unzureichenden Abdeckung verschiedener Fälle, einer geringen Menge an Dokumentation und der Instabilität der API. Seit dem Frühjahr dieses Jahres ist das Framework in einen Release-Zustand übergegangen und ich habe beschlossen, es erneut zu versuchen. Darüber hinaus wurde bereits die mühsamste Arbeit mit dem Layout des Körpers geleistet.


Auf den ersten Blick fügte das Framework Komfort hinzu. Häufiger fing ich an, die notwendigen Unterlagen zu finden (obwohl sie in sklearn noch weit von Qualität und Quantität entfernt sind). Vor allem aber - vor einem Jahr kannte ich sklearn noch nicht. Und jetzt begann ich zu sehen, dass viele Dinge in ML.NET versuchten, das Bild und die Ähnlichkeit zu verbessern (soweit möglich, angesichts der unterschiedlichen Plattformen). Diese Analogien haben es einfacher gemacht, die Prinzipien von ML.NET in der Praxis zu lernen.


Ein Arbeitsprojekt auf dieser Plattform kann unter https://github.com/serge-sotnyk/pdf-postprocess.cs eingesehen werden


Die allgemeinen Prinzipien blieben gleich - im Korpusordner befinden sich anotisierte (und nicht so) Dokumente. Nach dem Start des ModelCreator-Projekts wird neben dem Korpusordner der Modellordner angezeigt, in dem das Archiv mit dem trainierten Modell abgelegt wird. Dies ist immer noch dieselbe logistische Regression mit denselben Funktionen.


Aber hier habe ich mich nicht mehr mit der Codegenerierung beschäftigt. Um das trainierte Modell zu verwenden, verwenden Sie das PdfPostprocessor-Projekt (das intern das PdfPostprocessModel.zip-Modell als Ressource kompiliert hat). Danach kann das Modell verwendet werden, wie im minimalen Beispiel gezeigt - https://github.com/serge-sotnyk/pdf-postprocess.cs/blob/master/MinimalUsageExample/Program.cs :


 using PdfPostprocessor; ... static void Main(string[] args) { var postprocessor = new Postprocessor(); Console.WriteLine(); Console.WriteLine("Restored paragraphs in the English text:"); Console.WriteLine(postprocessor.RestoreText(EnText)); Console.WriteLine(); Console.WriteLine("Restored paragraphs in the Russian text:"); Console.WriteLine(postprocessor.RestoreText(RuText)); } 

Während das Kopieren des Modells aus dem Modellordner in das PdfPostprocessor-Projekt manuell ausgeführt wird, war es für mich bequemer, besser zu steuern, welches Modell in das endgültige Projekt aufgenommen wird.


Es gibt ein Nuget-Paket - PdfPostprocessor. Verwenden Sie den überladenen Postprozessor-Konstruktor, um das von Ihnen trainierte Paket und Modell zu verwenden.


Vergleichen von Optionen in Python und C #


Obwohl die Entwicklungserfahrung auf zwei Plattformen noch nicht abgeschlossen ist, kann es sinnvoll sein, sie kurz nacherzählen. Ich war lange Zeit kein militanter Unterstützer einer bestimmten Plattform und habe Verständnis für die Gefühle von Gläubigen verschiedener Glaubensrichtungen. Sie müssen auch verstehen, dass ich den größten Teil meines Lebens immer noch mit Sprachen mit statischer Typisierung arbeite, sodass sie mir nur ein wenig näher sind.


Was mir beim Wechsel zu C # nicht gefallen hat


  • Ausführlichkeit. Der Python-Code ist jedoch kompakter. Dies ist das Fehlen von Operator-Klammern und Klammern nach if, z. Der Mangel an endlosen neuen. Aktive Nutzung von Feldern, da diese bei Bedarf leicht in Eigenschaften umgewandelt werden können. Selbst an die Tatsache, dass der Datenschutz in Python, der einfach durch einen Unterstrich am Anfang des Bezeichners angezeigt wird, daran gewöhnt ist und sich in der Praxis als sehr praktisch und bequemer herausstellte als eine Reihe von Datenschutzmodifikatoren in anderen Sprachen. Die Kürze der Konstruktionen beschleunigt die Entwicklung und erleichtert das Lesen des Codes.
  • In den meisten Fällen sieht der Python-Code sauberer und eleganter aus (dies ist nur subjektiv). Dies erleichtert das Lesen und Verwalten.
  • Für Python gibt es für fast alles eine Art Funktion oder Dekorator in einer Art Paket, aber in C # muss viel hinzugefügt werden. Dadurch wird der Code mit verschiedenen Hilfsfunktionen und Klassen weiter aufgeblasen. Und es dauert noch länger.
  • Der Dokumentationsgrad von C # und seinen Frameworks ist erheblich geringer als im Python-Ökosystem.
  • Die strengere Typisierung von ML.NET im Vergleich zum alles fressenden sklearn zwang uns auch dazu, einige Zeit damit zu verbringen, nach den richtigen Transformationen zu suchen, und der vorherige Absatz trug nicht zur Lösung dieses Problems bei.

Was hat Ihnen beim Wechsel zu C # gefallen?


  • Ein Gefühl der Zuverlässigkeit. Bereits nicht sehr oft, aber ziemlich regelmäßig, führt mich der alles fressende Python zu schwer fassbaren Problemen. Und jetzt, als der Code nach C # portiert wurde, gab es einen Fehler, der einige Funktionen unbrauchbar machte. Nach der Korrektur stieg die Genauigkeit um einige Prozent.
  • Geschwindigkeit. Im Python-Code musste ich auf die Funktionen verzichten, mit denen in früheren Angeboten eine Klebeentscheidung getroffen wurde. Wenn Sie dem Klassifizierer nacheinander Vorschläge unterbreiten, ist die Gesamtgeschwindigkeit niedriger als die des Baseboards. Damit die Datenverarbeitung in Python schnell ist, muss sie so weit wie möglich vektorisiert werden. Manchmal lehnen wir potenziell nützliche Optionen ab, oder es ist sehr schwierig, sie zu erstellen.
  • Linq. Sie sind viel praktischer als das List Comprehension (LC) in Python. Sogar ein LC mit einem für zwingt mich, zuerst was nach in zu schreiben, dann zum Anfang zurückzukehren und anzuhängen und erst dann einen Ausdruck am Anfang von LC zu schreiben. Es ist nur so, dass ich denke, in dieser Reihenfolge - die Quelle von Datensätzen, Elementen, in die konvertiert werden soll. LINQ ( "" ) . LC ( for) . , , .
  • Lambda. , . , C# .

— . , .Net , . - — REST C#.


C# . — , - . Microsoft Kotlin — .Net , . Python- — , Julia . .


Fazit


:


  • , — , , - . , , - .
  • . , ML.NET - . .
  • , Python- .Net. , .

Source: https://habr.com/ru/post/de457072/


All Articles