Loslegen
Anweisungen
In dieser nicht bewerteten Aufgabe solltest du deine Python-Kenntnisse auffrischen und sicherstellen, dass deine Umgebung eingerichtet ist und Notebooks ausführen kann.
Folge diesem Python-Lernpfad und richte anschließend dein System ein, indem du dir diese Einführungsvideos ansiehst:
https://www.youtube.com/playlist?list=PLlrxD0HtieHhS8VzuMCfQD4uJ9yne1mE6
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in maschinelles Lernen
Pre-Vorlesungsquiz
> 🎥 Klicke auf das Bild oben für ein kurzes Video, das diese Lektion durchgeht.
Willkommen zu diesem Kurs über klassisches maschinelles Lernen für Anfänger! Egal, ob du völlig neu auf diesem Gebiet bist oder ein erfahrener ML-Praktiker, der sein Wissen in einem Bereich auffrischen möchte – wir freuen uns, dass du dabei bist! Wir möchten einen freundlichen Ausgangspunkt für dein ML-Studium schaffen und sind gerne bereit, dein Feedback zu bewerten, zu beantworten und einzubeziehen.
> 🎥 Klicke auf das Bild oben für ein Video: John Guttag vom MIT stellt maschinelles Lernen vor
Einstieg in maschinelles Lernen
Bevor du mit diesem Lehrplan beginnst, musst du deinen Computer einrichten und bereit machen, um Notebooks lokal auszuführen.
- Konfiguriere deine Maschine mit diesen Videos. Nutze die folgenden Links, um zu lernen, wie man Python installiert und einen Texteditor einrichtet für die Entwicklung.
- Lerne Python. Es wird außerdem empfohlen, grundlegende Kenntnisse in Python zu haben, einer Programmiersprache, die für Datenwissenschaftler nützlich ist und die wir in diesem Kurs verwenden.
- Lerne Node.js und JavaScript. Wir verwenden JavaScript auch einige Male in diesem Kurs beim Erstellen von Web-Apps, daher benötigst du node und npm installiert sowie Visual Studio Code für die Python- und JavaScript-Entwicklung.
- Erstelle ein GitHub-Konto. Da du uns hier auf GitHub gefunden hast, hast du vielleicht schon eins, aber falls nicht, erstelle eins und forke diesen Lehrplan, um ihn selbst zu verwenden. (Gib uns gerne auch einen Stern 😊)
- Erkunde Scikit-learn. Mache dich mit Scikit-learn vertraut, einem Satz von ML-Bibliotheken, die wir in diesen Lektionen referenzieren.
Was ist maschinelles Lernen?
Der Begriff „maschinelles Lernen“ ist einer der populärsten und am häufigsten verwendeten Begriffe heute. Es ist sehr wahrscheinlich, dass du diesen Begriff zumindest einmal gehört hast, wenn du irgendeine Vertrautheit mit Technologie hast, unabhängig davon, in welchem Bereich du arbeitest. Die Mechanik des maschinellen Lernens ist jedoch für die meisten Menschen ein Rätsel. Für einen ML-Anfänger kann das Thema manchmal überwältigend wirken. Daher ist es wichtig, zu verstehen, was maschinelles Lernen tatsächlich ist, und es Schritt für Schritt durch praktische Beispiele kennenzulernen.
Die Hype-Kurve

> Google Trends zeigt die aktuelle „Hype-Kurve“ des Begriffs „machine learning“
Ein geheimnisvolles Universum
Wir leben in einem Universum voller faszinierender Geheimnisse. Große Wissenschaftler wie Stephen Hawking, Albert Einstein und viele weitere haben ihr Leben der Suche nach bedeutungsvollen Informationen gewidmet, die die Geheimnisse der Welt um uns herum enthüllen. Das ist der menschliche Zustand des Lernens: Ein Kind lernt Jahr für Jahr neue Dinge und entdeckt die Struktur seiner Welt, während es zum Erwachsenen heranwächst.
Das Gehirn des Kindes
Das Gehirn und die Sinne eines Kindes nehmen die Fakten seiner Umgebung wahr und lernen allmählich die verborgenen Muster des Lebens, die dem Kind helfen, logische Regeln zu erstellen, um gelernte Muster zu erkennen. Der Lernprozess des menschlichen Gehirns macht den Menschen zum anspruchsvollsten Lebewesen auf dieser Welt. Indem wir kontinuierlich lernen, versteckte Muster entdecken und diese dann innovativ weiterentwickeln, können wir uns im Laufe unseres Lebens immer weiter verbessern. Diese Lernfähigkeit und sich entwickelnde Kapazität steht im Zusammenhang mit einem Konzept namens Gehirnplastizität. Oberflächlich betrachtet kann man einige motivierende Ähnlichkeiten zwischen dem Lernprozess des menschlichen Gehirns und den Konzepten des maschinellen Lernens ziehen.
Das menschliche Gehirn
Das menschliche Gehirn nimmt Dinge aus der realen Welt wahr, verarbeitet die wahrgenommenen Informationen, trifft rationale Entscheidungen und führt je nach Situation bestimmte Handlungen aus. Dies nennen wir intelligentes Verhalten. Wenn wir einen Nachbau dieses intelligenten Verhaltensprozesses in eine Maschine programmieren, nennt man das künstliche Intelligenz (KI).
Einige Begriffserklärungen
Obwohl die Begriffe verwechselt werden können, ist maschinelles Lernen (ML) ein wichtiger Teilbereich der künstlichen Intelligenz. ML beschäftigt sich damit, spezialisierte Algorithmen zu verwenden, um bedeutungsvolle Informationen zu entdecken und verborgene Muster aus wahrgenommenen Daten zu finden, um den rationalen Entscheidungsprozess zu unterstützen.
KI, ML, Deep Learning

> Ein Diagramm, das die Beziehungen zwischen KI, ML, Deep Learning und Data Science zeigt. Infografik von Jen Looper inspiriert von dieser Grafik
Zu behandelnde Konzepte
In diesem Lehrplan behandeln wir nur die Kernkonzepte des maschinellen Lernens, die ein Anfänger kennen muss. Wir decken das an, was wir als „klassisches maschinelles Lernen“ bezeichnen, hauptsächlich mit Scikit-learn, einer ausgezeichneten Bibliothek, die viele Studenten verwenden, um die Grundlagen zu lernen. Um breitere Konzepte der künstlichen Intelligenz oder des Deep Learnings zu verstehen, ist ein starkes Grundwissen im maschinellen Lernen unverzichtbar, und daher möchten wir es hier anbieten.
In diesem Kurs lernst du:
- Kernkonzepte des maschinellen Lernens
- Die Geschichte des ML
- ML und Fairness
- Regressions-ML-Techniken
- Klassifikations-ML-Techniken
- Clustering-ML-Techniken
- Natürliche Sprachverarbeitung-ML-Techniken
- Zeitreihen-Prognose-ML-Techniken
- Verstärkendes Lernen
- Anwendungen von ML in der Praxis
Was wir nicht behandeln
- Deep Learning
- Neuronale Netzwerke
- KI
Um ein besseres Lernerlebnis zu ermöglichen, vermeiden wir die Komplexität von neuronalen Netzwerken, „Deep Learning“ – vielschichtige Modellbildung mittels neuronalen Netzwerken – und KI, die wir in einem anderen Lehrplan besprechen werden. Wir werden außerdem einen zukünftigen Lehrplan zu Data Science anbieten, der sich auf diesen Aspekt dieses größeren Fachgebiets konzentriert.
Warum maschinelles Lernen studieren?
Maschinelles Lernen wird aus Systemsicht als die Erstellung automatisierter Systeme definiert, die verborgene Muster aus Daten lernen können, um intelligente Entscheidungen zu unterstützen.
Diese Motivation ist lose inspiriert davon, wie das menschliche Gehirn bestimmte Dinge basierend auf Daten lernt, die es aus der Außenwelt wahrnimmt.
✅ Überlege einen Moment, warum ein Unternehmen versuchen würde, maschinelle Lernstrategien zu verwenden, anstatt eine regelbasierte Hard-Coded-Engine zu erstellen.
Warum Datenqualität wichtig ist
Hochwertige Daten verbessern die Modellleistung. Schlechte oder verrauschte Daten können zu ungenauen Vorhersagen führen, selbst bei der Verwendung fortschrittlicher maschineller Lernalgorithmen.
Anwendungen des maschinellen Lernens
Anwendungen des maschinellen Lernens sind inzwischen fast überall zu finden und ebenso allgegenwärtig wie die Daten, die unsere Gesellschaften durchströmen, erzeugt von unseren Smartphones, vernetzten Geräten und anderen Systemen. Angesichts des enormen Potenzials moderner maschineller Lernalgorithmen erforschen Forscher deren Fähigkeit, multidimensionale und multidisziplinäre reale Probleme mit großartigen positiven Ergebnissen zu lösen.
Beispiele angewandten ML
Maschinelles Lernen kann auf viele Arten genutzt werden:
- Um die Wahrscheinlichkeit einer Krankheit aus der medizinischen Vorgeschichte oder Berichten eines Patienten vorherzusagen.
- Um Wetterdaten zu nutzen, um Wetterereignisse vorherzusagen.
- Um die Stimmung eines Texts zu verstehen.
- Um Fake-News zu erkennen, um die Verbreitung von Propaganda zu stoppen.
Finanzen, Wirtschaft, Geowissenschaften, Raumfahrt, Biomedizintechnik, Kognitionswissenschaft und sogar Fachgebiete der Geisteswissenschaften haben maschinelles Lernen adaptiert, um die schwierigen, datenverarbeitungsintensiven Probleme ihres Bereichs zu lösen.
Fazit
Maschinelles Lernen automatisiert den Prozess der Mustererkennung, indem es bedeutungsvolle Erkenntnisse aus realen oder generierten Daten findet. Es hat sich im Geschäfts-, Gesundheits- und Finanzwesen als äußerst wertvoll erwiesen, unter anderem.
In naher Zukunft wird das Verstehen der Grundlagen des maschinellen Lernens für Menschen aus allen Bereichen ein Muss sein, wegen seiner weit verbreiteten Anwendung.
🚀 Herausforderung
Skizziere auf Papier oder mit einer Online-App wie Excalidraw dein Verständnis der Unterschiede zwischen KI, ML, Deep Learning und Data Science. Füge einige Ideen über Probleme hinzu, die jede dieser Techniken gut lösen kann.
Post-Vorlesungsquiz
Rückblick & Selbststudium
Um mehr darüber zu lernen, wie du mit ML-Algorithmen in der Cloud arbeiten kannst, folge diesem Learning Path.
Mache einen Learning Path zu den Grundlagen des ML.
Aufgabe
<!-- CO-OP TRANSLATOR DISCLAIMER START --> Haftungsausschluss: Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache gilt als maßgebliche Quelle. Bei kritischen Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Verwendung dieser Übersetzung entstehen. <!-- CO-OP TRANSLATOR DISCLAIMER END -->
Erstelle eine Zeitleiste
Anweisungen
Verwende dieses Repository, um eine Zeitleiste zu einem Aspekt der Geschichte von Algorithmen, Mathematik, Statistik, KI oder ML oder einer Kombination dieser Themen zu erstellen. Du kannst dich auf eine Person, eine Idee oder einen langen Zeitraum des Denkens konzentrieren. Stelle sicher, dass du multimediale Elemente hinzufügst.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Eine veröffentlichte Zeitleiste wird als GitHub-Seite präsentiert | Der Code ist unvollständig und nicht veröffentlicht | Die Zeitleiste ist unvollständig, schlecht recherchiert und nicht veröffentlicht |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Geschichte des maschinellen Lernens
> Sketchnote von Tomomi Imura
Quiz vor der Vorlesung
> 🎥 Klicken Sie auf das Bild oben, um ein kurzes Video zu dieser Lektion anzusehen.
In dieser Lektion gehen wir die wichtigsten Meilensteine in der Geschichte des maschinellen Lernens und der künstlichen Intelligenz durch.
Die Geschichte der künstlichen Intelligenz (KI) als Forschungsfeld ist eng mit der Geschichte des maschinellen Lernens verbunden, da die Algorithmen und rechnerischen Fortschritte, die ML zugrunde liegen, zur Entwicklung der KI beigetragen haben. Es ist hilfreich, sich daran zu erinnern, dass, obwohl sich diese Bereiche als eigenständige Forschungsgebiete in den 1950er Jahren herauskristallisierten, wichtige algorithmische, statistische, mathematische, rechnerische und technische Entdeckungen diese Ära vorwegnahmen und überlappten. Tatsächlich beschäftigen sich Menschen schon seit Hunderten von Jahren mit diesen Fragen: Dieser Artikel beleuchtet die historischen intellektuellen Grundlagen der Idee einer „denkenden Maschine“.
Bedeutende Entdeckungen
- 1763, 1812 Bayes-Theorem und seine Vorläufer. Dieses Theorem und seine Anwendungen bilden die Grundlage für Inferenz, indem sie die Wahrscheinlichkeit eines Ereignisses basierend auf Vorwissen beschreiben.
- 1805 Methode der kleinsten Quadrate des französischen Mathematikers Adrien-Marie Legendre. Diese Theorie, die Sie in unserer Regressionseinheit kennenlernen werden, hilft bei der Datenanpassung.
- 1913 Markow-Ketten, benannt nach dem russischen Mathematiker Andrey Markov, beschreiben eine Abfolge möglicher Ereignisse basierend auf einem vorherigen Zustand.
- 1957 Perzeptron, ein von dem amerikanischen Psychologen Frank Rosenblatt erfundener linearer Klassifikator, der die Grundlage für Fortschritte im Deep Learning bildet.
- 1967 Nächster-Nachbar-Algorithmus, ursprünglich entwickelt, um Routen zu kartieren. Im ML-Kontext wird er zur Mustererkennung verwendet.
- 1970 Backpropagation wird verwendet, um Feedforward-Neuronale Netze zu trainieren.
- 1982 Rekurrente Neuronale Netze sind künstliche neuronale Netze, die aus Feedforward-Netzen abgeleitet sind und zeitliche Graphen erstellen.
✅ Recherchieren Sie ein wenig. Welche anderen Daten sind Ihrer Meinung nach entscheidend in der Geschichte des maschinellen Lernens und der KI?
1950: Maschinen, die denken
Alan Turing, eine wahrhaft bemerkenswerte Persönlichkeit, die 2019 von der Öffentlichkeit zum größten Wissenschaftler des 20. Jahrhunderts gewählt wurde, wird zugeschrieben, das Fundament für das Konzept einer „denkenden Maschine“ gelegt zu haben. Er setzte sich mit Skeptikern auseinander und suchte nach empirischen Beweisen für dieses Konzept, unter anderem durch die Entwicklung des Turing-Tests, den Sie in unseren NLP-Lektionen näher kennenlernen werden.
1956: Dartmouth Summer Research Project
„Das Dartmouth Summer Research Project zur künstlichen Intelligenz war ein wegweisendes Ereignis für das Feld der künstlichen Intelligenz“, und hier wurde der Begriff „künstliche Intelligenz“ geprägt (Quelle).
> Jeder Aspekt des Lernens oder eines anderen Merkmals von Intelligenz kann im Prinzip so präzise beschrieben werden, dass eine Maschine es simulieren kann.
Der leitende Forscher, Mathematikprofessor John McCarthy, hoffte, „auf der Grundlage der Vermutung vorzugehen, dass jeder Aspekt des Lernens oder eines anderen Merkmals von Intelligenz im Prinzip so präzise beschrieben werden kann, dass eine Maschine es simulieren kann.“ Zu den Teilnehmern gehörte auch eine weitere Koryphäe des Feldes, Marvin Minsky.
Der Workshop wird dafür verantwortlich gemacht, mehrere Diskussionen angestoßen und gefördert zu haben, darunter „den Aufstieg symbolischer Methoden, Systeme, die sich auf begrenzte Domänen konzentrieren (frühe Expertensysteme), und deduktive Systeme versus induktive Systeme.“ (Quelle).
1956 - 1974: „Die goldenen Jahre“
Von den 1950er Jahren bis Mitte der 1970er Jahre herrschte großer Optimismus, dass KI viele Probleme lösen könnte. 1967 erklärte Marvin Minsky zuversichtlich: „Innerhalb einer Generation ... wird das Problem, ‚künstliche Intelligenz‘ zu schaffen, im Wesentlichen gelöst sein.“ (Minsky, Marvin (1967), Computation: Finite and Infinite Machines, Englewood Cliffs, N.J.: Prentice-Hall)
Die Forschung zur Verarbeitung natürlicher Sprache blühte auf, Suchalgorithmen wurden verfeinert und leistungsfähiger, und das Konzept der „Mikrowelten“ wurde entwickelt, in denen einfache Aufgaben mit einfachen Sprachbefehlen ausgeführt werden konnten.
Die Forschung wurde gut von Regierungsbehörden finanziert, Fortschritte in der Rechenleistung und bei Algorithmen wurden erzielt, und Prototypen intelligenter Maschinen wurden gebaut. Einige dieser Maschinen umfassen:
-
Shakey der Roboter, der sich bewegen und „intelligent“ entscheiden konnte, wie Aufgaben ausgeführt werden sollten.
> Shakey im Jahr 1972
-
Eliza, ein früher „Chatterbot“, konnte mit Menschen kommunizieren und als primitiver „Therapeut“ fungieren. Sie werden mehr über Eliza in den NLP-Lektionen erfahren.
> Eine Version von Eliza, einem Chatbot
-
„Blocks World“ war ein Beispiel für eine Mikrowelt, in der Blöcke gestapelt und sortiert werden konnten, und Experimente zur Entscheidungsfindung von Maschinen durchgeführt wurden. Fortschritte mit Bibliotheken wie SHRDLU trieben die Sprachverarbeitung voran.
> 🎥 Klicken Sie auf das Bild oben für ein Video: Blocks World mit SHRDLU
1974 - 1980: „KI-Winter“
Mitte der 1970er Jahre wurde klar, dass die Komplexität der Entwicklung „intelligenter Maschinen“ unterschätzt und ihr Potenzial angesichts der verfügbaren Rechenleistung überschätzt worden war. Die Finanzierung versiegte, und das Vertrauen in das Feld nahm ab. Einige Probleme, die das Vertrauen beeinträchtigten, waren:
- Einschränkungen. Die Rechenleistung war zu begrenzt.
- Kombinatorische Explosion. Die Anzahl der zu trainierenden Parameter wuchs exponentiell, je mehr von Computern verlangt wurde, ohne dass die Rechenleistung und -fähigkeit parallel dazu wuchsen.
- Mangel an Daten. Es gab einen Mangel an Daten, der den Prozess des Testens, Entwickelns und Verfeinerns von Algorithmen behinderte.
- Stellen wir die richtigen Fragen?. Die gestellten Fragen selbst wurden infrage gestellt. Forscher sahen sich Kritik an ihren Ansätzen ausgesetzt:
- Turing-Tests wurden unter anderem durch die „Chinese Room“-Theorie infrage gestellt, die besagt, dass „das Programmieren eines digitalen Computers zwar den Anschein erwecken kann, Sprache zu verstehen, aber kein echtes Verständnis erzeugen kann.“ (Quelle)
- Die Ethik der Einführung künstlicher Intelligenzen wie des „Therapeuten“ ELIZA in die Gesellschaft wurde hinterfragt.
Gleichzeitig begannen sich verschiedene Schulen der KI-Forschung zu bilden. Es entstand eine Dichotomie zwischen "Scruffy" vs. "Neat AI"-Praktiken. Scruffy-Labore optimierten Programme stundenlang, bis sie die gewünschten Ergebnisse erzielten. Neat-Labore „konzentrierten sich auf Logik und formale Problemlösung“. ELIZA und SHRDLU waren bekannte Scruffy-Systeme. In den 1980er Jahren, als die Nachfrage nach reproduzierbaren ML-Systemen wuchs, setzte sich der Neat-Ansatz allmählich durch, da seine Ergebnisse besser erklärbar sind.
1980er Jahre: Expertensysteme
Mit dem Wachstum des Feldes wurde sein Nutzen für Unternehmen deutlicher, und in den 1980er Jahren verbreiteten sich „Expertensysteme“. „Expertensysteme waren eine der ersten wirklich erfolgreichen Formen von KI-Software.“ (Quelle)
Dieser Systemtyp ist tatsächlich hybrid und besteht teilweise aus einer Regel-Engine, die Geschäftsanforderungen definiert, und einer Inferenz-Engine, die das Regelwerk nutzt, um neue Fakten abzuleiten.
In dieser Ära wurde auch den neuronalen Netzen zunehmend Aufmerksamkeit geschenkt.
1987 - 1993: „KI-Abkühlung“
Die Verbreitung spezialisierter Hardware für Expertensysteme hatte den unglücklichen Effekt, zu spezialisiert zu werden. Der Aufstieg von Personal Computern konkurrierte mit diesen großen, spezialisierten, zentralisierten Systemen. Die Demokratisierung des Rechnens hatte begonnen und ebnete schließlich den Weg für die moderne Explosion von Big Data.
1993 - 2011
Diese Epoche markierte eine neue Ära für ML und KI, um einige der Probleme zu lösen, die zuvor durch den Mangel an Daten und Rechenleistung verursacht worden waren. Die Menge an Daten begann rapide zu wachsen und wurde zunehmend verfügbar, sowohl zum Guten als auch zum Schlechten, insbesondere mit dem Aufkommen des Smartphones um 2007. Die Rechenleistung wuchs exponentiell, und Algorithmen entwickelten sich parallel dazu weiter. Das Feld begann, sich zu einer echten Disziplin zu entwickeln, während die unstrukturierten Ansätze der Vergangenheit allmählich einer gereiften Struktur wichen.
Heute
Heute berühren maschinelles Lernen und KI fast jeden Bereich unseres Lebens. Diese Ära erfordert ein sorgfältiges Verständnis der Risiken und potenziellen Auswirkungen dieser Algorithmen auf das menschliche Leben. Wie Brad Smith von Microsoft erklärt hat: „Informationstechnologie wirft Fragen auf, die das Herzstück grundlegender Menschenrechtsfragen wie Datenschutz und Meinungsfreiheit betreffen. Diese Fragen erhöhen die Verantwortung von Technologieunternehmen, die diese Produkte entwickeln. Unserer Ansicht nach erfordern sie auch eine durchdachte staatliche Regulierung und die Entwicklung von Normen für akzeptable Nutzungen.“ (Quelle)
Es bleibt abzuwarten, was die Zukunft bringt, aber es ist wichtig, diese Computersysteme sowie die Software und Algorithmen, die sie ausführen, zu verstehen. Wir hoffen, dass dieses Curriculum Ihnen hilft, ein besseres Verständnis zu erlangen, damit Sie selbst entscheiden können.
> 🎥 Klicken Sie auf das Bild oben für ein Video: Yann LeCun spricht in diesem Vortrag über die Geschichte des Deep Learning
🚀 Herausforderung
Tauchen Sie in einen dieser historischen Momente ein und erfahren Sie mehr über die Menschen dahinter. Es gibt faszinierende Persönlichkeiten, und keine wissenschaftliche Entdeckung wurde jemals in einem kulturellen Vakuum gemacht. Was entdecken Sie?
Quiz nach der Vorlesung
Rückblick & Selbststudium
Hier sind einige Inhalte zum Anschauen und Anhören:
Dieser Podcast, in dem Amy Boyd über die Entwicklung der KI spricht
Aufgabe
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erkunden Sie die Responsible AI Toolbox
Anweisungen
In dieser Lektion haben Sie die Responsible AI Toolbox kennengelernt, ein „Open-Source-, gemeinschaftlich vorangetriebenes Projekt, das Data Scientists dabei unterstützt, KI-Systeme zu analysieren und zu verbessern.“ Für diese Aufgabe erkunden Sie eines der RAI Toolbox Notebooks und berichten Ihre Erkenntnisse in einem Bericht oder einer Präsentation.
Bewertungsraster
| Kriterien | Vorbildlich | Ausreichend | Verbesserungsbedürftig |
|---|---|---|---|
| Ein Bericht oder eine Powerpoint-Präsentation wird präsentiert, die Fairlearns Systeme, das ausgeführte Notebook und die aus dessen Ausführung gezogenen Schlussfolgerungen behandelt | Ein Bericht wird präsentiert, jedoch ohne Schlussfolgerungen | Es wird kein Bericht präsentiert |
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatische Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das ursprüngliche Dokument in seiner Originalsprache gilt als maßgebliche Quelle. Für wichtige Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Aufbau von Machine-Learning-Lösungen mit verantwortungsbewusster KI
> Sketchnote von Tomomi Imura
Quiz vor der Vorlesung
Einführung
In diesem Lehrplan werden Sie entdecken, wie Machine Learning unser tägliches Leben beeinflusst. Schon jetzt sind Systeme und Modelle in alltägliche Entscheidungsprozesse eingebunden, wie z. B. bei medizinischen Diagnosen, Kreditgenehmigungen oder der Betrugserkennung. Daher ist es wichtig, dass diese Modelle zuverlässig arbeiten und vertrauenswürdige Ergebnisse liefern. Genau wie jede andere Softwareanwendung können KI-Systeme Erwartungen nicht erfüllen oder unerwünschte Ergebnisse liefern. Deshalb ist es entscheidend, das Verhalten eines KI-Modells zu verstehen und erklären zu können.
Stellen Sie sich vor, was passieren kann, wenn die Daten, die Sie zur Erstellung dieser Modelle verwenden, bestimmte demografische Gruppen wie Ethnie, Geschlecht, politische Ansichten oder Religion nicht berücksichtigen oder unverhältnismäßig repräsentieren. Was passiert, wenn die Ergebnisse des Modells so interpretiert werden, dass sie eine bestimmte demografische Gruppe bevorzugen? Welche Konsequenzen hat das für die Anwendung? Und was passiert, wenn das Modell ein schädliches Ergebnis liefert? Wer ist für das Verhalten des KI-Systems verantwortlich? Diese Fragen werden wir in diesem Lehrplan untersuchen.
In dieser Lektion werden Sie:
- Ein Bewusstsein für die Bedeutung von Fairness im Machine Learning und fairnessbezogene Schäden entwickeln.
- Die Praxis des Erkundens von Ausreißern und ungewöhnlichen Szenarien kennenlernen, um Zuverlässigkeit und Sicherheit zu gewährleisten.
- Verstehen, warum es wichtig ist, inklusive Systeme zu entwerfen, die alle Menschen einbeziehen.
- Erforschen, wie entscheidend es ist, die Privatsphäre und Sicherheit von Daten und Menschen zu schützen.
- Die Bedeutung eines transparenten Ansatzes erkennen, um das Verhalten von KI-Modellen zu erklären.
- Verstehen, warum Verantwortlichkeit essenziell ist, um Vertrauen in KI-Systeme aufzubauen.
Voraussetzungen
Als Voraussetzung sollten Sie den "Responsible AI Principles"-Lernpfad absolvieren und das folgende Video zum Thema ansehen:
Erfahren Sie mehr über verantwortungsbewusste KI, indem Sie diesem Lernpfad folgen.
> 🎥 Klicken Sie auf das Bild oben für ein Video: Microsofts Ansatz für verantwortungsbewusste KI
Fairness
KI-Systeme sollten alle Menschen fair behandeln und vermeiden, ähnliche Gruppen unterschiedlich zu beeinflussen. Beispielsweise sollten KI-Systeme bei medizinischen Behandlungen, Kreditanträgen oder Beschäftigungsentscheidungen dieselben Empfehlungen für Menschen mit ähnlichen Symptomen, finanziellen Verhältnissen oder beruflichen Qualifikationen geben. Jeder von uns trägt unbewusste Vorurteile mit sich, die unsere Entscheidungen und Handlungen beeinflussen. Diese Vorurteile können sich in den Daten widerspiegeln, die wir zur Schulung von KI-Systemen verwenden. Solche Verzerrungen können manchmal unbeabsichtigt auftreten. Es ist oft schwierig, bewusst zu erkennen, wann man Vorurteile in Daten einführt.
„Unfairness“ umfasst negative Auswirkungen oder „Schäden“ für eine Gruppe von Menschen, z. B. definiert durch Ethnie, Geschlecht, Alter oder Behinderungsstatus. Die Hauptarten von fairnessbezogenen Schäden lassen sich wie folgt klassifizieren:
- Zuweisung: Wenn z. B. ein Geschlecht oder eine Ethnie gegenüber einer anderen bevorzugt wird.
- Qualität des Dienstes: Wenn die Daten für ein spezifisches Szenario trainiert wurden, die Realität jedoch viel komplexer ist, führt dies zu einer schlechten Leistung des Dienstes. Ein Beispiel ist ein Seifenspender, der Menschen mit dunkler Hautfarbe nicht erkennen konnte. Referenz
- Herabwürdigung: Unfaire Kritik oder Etikettierung von etwas oder jemandem. Ein Beispiel ist eine Bildkennzeichnungstechnologie, die dunkelhäutige Menschen fälschlicherweise als Gorillas bezeichnete.
- Über- oder Unterrepräsentation: Die Idee, dass eine bestimmte Gruppe in einem bestimmten Beruf nicht sichtbar ist, und jede Funktion, die dies weiter fördert, trägt zu Schaden bei.
- Stereotypisierung: Die Zuordnung vorgefertigter Eigenschaften zu einer bestimmten Gruppe. Ein Beispiel ist ein Sprachübersetzungssystem zwischen Englisch und Türkisch, das aufgrund von stereotypischen Geschlechterassoziationen Ungenauigkeiten aufweist.
> Übersetzung ins Türkische
> Übersetzung zurück ins Englische
Beim Entwerfen und Testen von KI-Systemen müssen wir sicherstellen, dass KI fair ist und nicht so programmiert wird, dass sie voreingenommene oder diskriminierende Entscheidungen trifft, die auch Menschen nicht treffen dürfen. Fairness in KI und Machine Learning zu gewährleisten, bleibt eine komplexe soziotechnische Herausforderung.
Zuverlässigkeit und Sicherheit
Um Vertrauen aufzubauen, müssen KI-Systeme zuverlässig, sicher und konsistent unter normalen und unerwarteten Bedingungen sein. Es ist wichtig zu wissen, wie sich KI-Systeme in verschiedenen Situationen verhalten, insbesondere bei Ausreißern. Beim Aufbau von KI-Lösungen sollte ein erheblicher Fokus darauf gelegt werden, wie eine Vielzahl von Umständen gehandhabt werden kann, denen die KI-Lösungen begegnen könnten. Zum Beispiel muss ein selbstfahrendes Auto die Sicherheit der Menschen als oberste Priorität betrachten. Daher muss die KI, die das Auto antreibt, alle möglichen Szenarien berücksichtigen, denen das Auto begegnen könnte, wie z. B. Nacht, Gewitter, Schneestürme, Kinder, die über die Straße rennen, Haustiere, Straßenbauarbeiten usw. Wie gut ein KI-System eine Vielzahl von Bedingungen zuverlässig und sicher bewältigen kann, spiegelt das Maß an Voraussicht wider, das der Datenwissenschaftler oder KI-Entwickler während des Designs oder Tests des Systems berücksichtigt hat.
> 🎥 Klicken Sie hier für ein Video:
Inklusivität
KI-Systeme sollten so gestaltet sein, dass sie alle Menschen einbeziehen und befähigen. Beim Entwerfen und Implementieren von KI-Systemen identifizieren und adressieren Datenwissenschaftler und KI-Entwickler potenzielle Barrieren im System, die Menschen unbeabsichtigt ausschließen könnten. Zum Beispiel gibt es weltweit 1 Milliarde Menschen mit Behinderungen. Mit den Fortschritten in der KI können sie leichter auf eine Vielzahl von Informationen und Möglichkeiten in ihrem täglichen Leben zugreifen. Durch die Beseitigung von Barrieren entstehen Chancen, KI-Produkte mit besseren Erfahrungen zu entwickeln, die allen zugutekommen.
> 🎥 Klicken Sie hier für ein Video: Inklusivität in der KI
Sicherheit und Datenschutz
KI-Systeme sollten sicher sein und die Privatsphäre der Menschen respektieren. Menschen vertrauen Systemen weniger, die ihre Privatsphäre, Informationen oder ihr Leben gefährden. Beim Training von Machine-Learning-Modellen verlassen wir uns auf Daten, um die besten Ergebnisse zu erzielen. Dabei muss die Herkunft und Integrität der Daten berücksichtigt werden. Zum Beispiel: Wurden die Daten von Nutzern bereitgestellt oder waren sie öffentlich zugänglich? Während der Arbeit mit den Daten ist es entscheidend, KI-Systeme zu entwickeln, die vertrauliche Informationen schützen und Angriffen widerstehen können. Da KI immer weiter verbreitet wird, wird der Schutz der Privatsphäre und die Sicherung wichtiger persönlicher und geschäftlicher Informationen immer kritischer und komplexer. Datenschutz- und Datensicherheitsfragen erfordern besondere Aufmerksamkeit, da der Zugang zu Daten für KI-Systeme essenziell ist, um genaue und fundierte Vorhersagen und Entscheidungen über Menschen zu treffen.
> 🎥 Klicken Sie hier für ein Video: Sicherheit in der KI
- Als Branche haben wir bedeutende Fortschritte im Bereich Datenschutz und Sicherheit gemacht, die maßgeblich durch Vorschriften wie die DSGVO (Datenschutz-Grundverordnung) vorangetrieben wurden.
- Dennoch müssen wir bei KI-Systemen die Spannung zwischen dem Bedarf an mehr persönlichen Daten, um Systeme persönlicher und effektiver zu machen, und dem Datenschutz anerkennen.
- Genau wie bei der Einführung vernetzter Computer mit dem Internet sehen wir auch einen starken Anstieg der Sicherheitsprobleme im Zusammenhang mit KI.
- Gleichzeitig wird KI genutzt, um die Sicherheit zu verbessern. Zum Beispiel werden die meisten modernen Antiviren-Scanner heute von KI-Heuristiken angetrieben.
- Wir müssen sicherstellen, dass unsere Datenwissenschaftsprozesse harmonisch mit den neuesten Datenschutz- und Sicherheitspraktiken zusammenarbeiten.
Transparenz
KI-Systeme sollten verständlich sein. Ein wesentlicher Bestandteil der Transparenz ist die Erklärung des Verhaltens von KI-Systemen und ihrer Komponenten. Die Verbesserung des Verständnisses von KI-Systemen erfordert, dass Interessengruppen verstehen, wie und warum sie funktionieren, damit sie potenzielle Leistungsprobleme, Sicherheits- und Datenschutzbedenken, Vorurteile, ausschließende Praktiken oder unbeabsichtigte Ergebnisse identifizieren können. Wir glauben auch, dass diejenigen, die KI-Systeme nutzen, ehrlich und offen darüber sein sollten, wann, warum und wie sie diese einsetzen. Ebenso über die Grenzen der Systeme, die sie verwenden. Zum Beispiel: Wenn eine Bank ein KI-System zur Unterstützung ihrer Kreditentscheidungen einsetzt, ist es wichtig, die Ergebnisse zu überprüfen und zu verstehen, welche Daten die Empfehlungen des Systems beeinflussen. Regierungen beginnen, KI branchenübergreifend zu regulieren, daher müssen Datenwissenschaftler und Organisationen erklären, ob ein KI-System die regulatorischen Anforderungen erfüllt, insbesondere wenn es zu einem unerwünschten Ergebnis kommt.
> 🎥 Klicken Sie hier für ein Video: Transparenz in der KI
- Da KI-Systeme so komplex sind, ist es schwierig zu verstehen, wie sie funktionieren und ihre Ergebnisse zu interpretieren.
- Dieses mangelnde Verständnis beeinflusst, wie diese Systeme verwaltet, operationalisiert und dokumentiert werden.
- Noch wichtiger ist, dass dieses mangelnde Verständnis die Entscheidungen beeinflusst, die auf Basis der Ergebnisse dieser Systeme getroffen werden.
Verantwortlichkeit
Die Menschen, die KI-Systeme entwerfen und einsetzen, müssen für deren Betrieb verantwortlich sein. Die Notwendigkeit der Verantwortlichkeit ist besonders wichtig bei sensiblen Technologien wie Gesichtserkennung. In letzter Zeit gibt es eine wachsende Nachfrage nach Gesichtserkennungstechnologie, insbesondere von Strafverfolgungsbehörden, die das Potenzial der Technologie beispielsweise bei der Suche nach vermissten Kindern sehen. Diese Technologien könnten jedoch von einer Regierung genutzt werden, um die Grundfreiheiten ihrer Bürger zu gefährden, indem sie beispielsweise eine kontinuierliche Überwachung bestimmter Personen ermöglichen. Daher müssen Datenwissenschaftler und Organisationen verantwortlich dafür sein, wie ihr KI-System Einzelpersonen oder die Gesellschaft beeinflusst.
> 🎥 Klicken Sie auf das Bild oben für ein Video: Warnungen vor Massenüberwachung durch Gesichtserkennung
Letztendlich ist eine der größten Fragen für unsere Generation, als die erste Generation, die KI in die Gesellschaft bringt, wie wir sicherstellen können, dass Computer den Menschen gegenüber rechenschaftspflichtig bleiben und dass die Menschen, die Computer entwerfen, allen anderen gegenüber rechenschaftspflichtig bleiben.
Auswirkungen bewerten
Bevor ein Machine-Learning-Modell trainiert wird, ist es wichtig, eine Auswirkungsbewertung durchzuführen, um den Zweck des KI-Systems zu verstehen: Was ist der beabsichtigte Nutzen? Wo wird es eingesetzt? Und wer wird mit dem System interagieren? Diese Bewertungen helfen Prüfern oder Testern, die das System bewerten, zu wissen, welche Faktoren bei der Identifizierung potenzieller Risiken und erwarteter Konsequenzen zu berücksichtigen sind.
Die folgenden Bereiche stehen bei einer Auswirkungsbewertung im Fokus:
- Negative Auswirkungen auf Einzelpersonen: Es ist wichtig, sich über Einschränkungen, Anforderungen, nicht unterstützte Verwendungen oder bekannte Begrenzungen bewusst zu sein, die die Leistung des Systems beeinträchtigen könnten, um sicherzustellen, dass das System nicht auf eine Weise verwendet wird, die Einzelpersonen schaden könnte.
- Datenanforderungen: Ein Verständnis dafür zu gewinnen, wie und wo das System Daten verwendet, ermöglicht es Prüfern, Datenanforderungen zu identifizieren, die berücksichtigt werden müssen (z. B. DSGVO- oder HIPAA-Datenvorschriften). Außerdem sollte geprüft werden, ob die Quelle oder Menge der Daten für das Training ausreicht.
- Zusammenfassung der Auswirkungen: Eine Liste potenzieller Schäden erstellen, die durch die Nutzung des Systems entstehen könnten. Während des gesamten ML-Lebenszyklus überprüfen, ob die identifizierten Probleme behoben oder adressiert wurden.
- Ziele für die sechs Kernprinzipien: Bewerten, ob die Ziele jedes Prinzips erreicht wurden und ob es Lücken gibt.
Debugging mit verantwortungsbewusster KI
Ähnlich wie beim Debugging einer Softwareanwendung ist das Debugging eines KI-Systems ein notwendiger Prozess, um Probleme im System zu identifizieren und zu lösen. Es gibt viele Faktoren, die dazu führen können, dass ein Modell nicht wie erwartet oder verantwortungsvoll funktioniert. Die meisten traditionellen Leistungsmetriken für Modelle sind quantitative Zusammenfassungen der Modellleistung, die nicht ausreichen, um zu analysieren, wie ein Modell gegen die Prinzipien der verantwortungsbewussten KI verstößt. Darüber hinaus ist ein Machine-Learning-Modell eine Blackbox, die es schwierig macht, die Gründe für seine Ergebnisse zu verstehen oder Erklärungen zu liefern, wenn es Fehler macht. Später in diesem Kurs lernen wir, wie man das Responsible AI Dashboard verwendet, um KI-Systeme zu debuggen. Das Dashboard bietet ein umfassendes Werkzeug für Datenwissenschaftler und KI-Entwickler, um:
- Fehleranalyse: Die Fehlerverteilung des Modells zu identifizieren, die die Fairness oder Zuverlässigkeit des Systems beeinträchtigen könnte.
- Modellübersicht: Zu entdecken, wo es Leistungsunterschiede des Modells über verschiedene Datenkohorten hinweg gibt.
- Datenanalyse: Die Datenverteilung zu verstehen und potenzielle Verzerrungen in den Daten zu identifizieren, die zu Fairness-, Inklusivitäts- und Zuverlässigkeitsproblemen führen könnten.
- Modellinterpretierbarkeit: Zu verstehen, was die Vorhersagen des Modells beeinflusst. Dies hilft, das Verhalten des Modells zu erklären, was für Transparenz und Verantwortlichkeit wichtig ist.
🚀 Herausforderung
Um Schäden von vornherein zu vermeiden, sollten wir:
- eine Vielfalt an Hintergründen und Perspektiven unter den Menschen haben, die an den Systemen arbeiten
- in Datensätze investieren, die die Vielfalt unserer Gesellschaft widerspiegeln
- bessere Methoden im gesamten Machine-Learning-Lebenszyklus entwickeln, um verantwortungsbewusste KI zu erkennen und zu korrigieren, wenn sie auftritt
Denken Sie an reale Szenarien, in denen die Unzuverlässigkeit eines Modells beim Erstellen und Verwenden offensichtlich wird. Was sollten wir noch berücksichtigen?
Quiz nach der Vorlesung
Rückblick & Selbststudium
In dieser Lektion haben Sie einige Grundlagen zu den Konzepten von Fairness und Unfairness im Machine Learning gelernt. Schauen Sie sich diesen Workshop an, um tiefer in die Themen einzutauchen:
- Auf der Suche nach verantwortungsvoller KI: Prinzipien in die Praxis umsetzen von Besmira Nushi, Mehrnoosh Sameki und Amit Sharma
> 🎥 Klicken Sie auf das Bild oben für ein Video: RAI Toolbox: Ein Open-Source-Framework für den Aufbau verantwortungsvoller KI von Besmira Nushi, Mehrnoosh Sameki und Amit Sharma
Lesen Sie außerdem:
-
Microsofts RAI-Ressourcenzentrum: Responsible AI Resources – Microsoft AI
-
Microsofts FATE-Forschungsgruppe: FATE: Fairness, Accountability, Transparency, and Ethics in AI - Microsoft Research
RAI Toolbox:
Lesen Sie über die Tools von Azure Machine Learning, um Fairness sicherzustellen:
Aufgabe
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Interviewe einen Data Scientist
Anweisungen
Sprich in deinem Unternehmen, einer Benutzergruppe oder unter deinen Freunden oder Kommilitonen mit jemandem, der beruflich als Data Scientist arbeitet. Schreibe eine kurze Arbeit (500 Wörter) über ihre täglichen Aufgaben. Sind sie Spezialisten oder arbeiten sie „Full Stack“?
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Aufsatz in der richtigen Länge, mit angegebenen Quellen, wird als .doc-Datei präsentiert | Der Aufsatz ist schlecht attribuiert oder kürzer als die geforderte Länge | Kein Aufsatz wird präsentiert |
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Techniken des maschinellen Lernens
Der Prozess des Erstellens, Verwendens und Wartens von Modellen des maschinellen Lernens und deren genutzten Daten ist ein ganz anderer Prozess als viele andere Entwicklungsworkflows. In dieser Lektion werden wir den Prozess entmystifizieren und die wichtigsten Techniken skizzieren, die Sie kennen müssen. Sie werden:
- Die Prozesse, die dem maschinellen Lernen zugrunde liegen, auf hohem Niveau verstehen.
- Grundkonzepte wie „Modelle“, „Vorhersagen“ und „Trainingsdaten“ erkunden.
Vorlesungsquiz
> 🎥 Klicken Sie auf das Bild oben für ein kurzes Video, das durch diese Lektion führt.
Einführung
Auf hohem Niveau besteht das Handwerk der Erstellung von Prozessen des maschinellen Lernens (ML) aus mehreren Schritten:
- Die Frage festlegen. Die meisten ML-Prozesse beginnen mit einer Frage, die nicht durch ein einfaches bedingtes Programm oder regelbasiertes System beantwortet werden kann. Diese Fragen drehen sich oft um Vorhersagen basierend auf einer Datensammlung.
- Daten sammeln und vorbereiten. Um Ihre Frage beantworten zu können, benötigen Sie Daten. Die Qualität und manchmal auch die Menge Ihrer Daten bestimmt, wie gut Sie Ihre ursprüngliche Frage beantworten können. Die Visualisierung der Daten ist ein wichtiger Aspekt dieser Phase. Diese Phase umfasst auch die Aufteilung der Daten in Trainings- und Testgruppen zum Aufbau eines Modells.
- Eine Trainingsmethode wählen. Abhängig von Ihrer Frage und der Natur Ihrer Daten müssen Sie entscheiden, wie Sie ein Modell trainieren möchten, um Ihre Daten am besten widerzuspiegeln und genaue Vorhersagen zu treffen. Dies ist der Teil Ihres ML-Prozesses, der spezifische Expertise und oft eine beträchtliche Menge an Experimenten erfordert.
- Das Modell trainieren. Mithilfe Ihrer Trainingsdaten verwenden Sie verschiedene Algorithmen, um ein Modell zu trainieren, das Muster in den Daten erkennt. Das Modell kann interne Gewichte verwenden, die angepasst werden können, um bestimmten Teilen der Daten Vorrang zu geben und so ein besseres Modell zu erstellen.
- Das Modell bewerten. Sie verwenden zuvor nie gesehene Daten (Ihre Testdaten) aus Ihrem gesammelten Datensatz, um die Leistung des Modells zu überprüfen.
- Parameteranpassung. Basierend auf der Leistung Ihres Modells können Sie den Prozess wiederholen und verschiedene Parameter oder Variablen verwenden, die das Verhalten der zum Training verwendeten Algorithmen steuern.
- Vorhersagen treffen. Verwenden Sie neue Eingaben, um die Genauigkeit Ihres Modells zu testen.
Welche Frage sollte man stellen
Computer sind besonders gut darin, verborgene Muster in Daten zu entdecken. Diese Nützlichkeit ist sehr hilfreich für Forscher, die Fragen zu einem bestimmten Gebiet haben, die nicht leicht durch ein regelbasiertes System beantwortet werden können. Bei einer versicherungsmathematischen Aufgabe könnte ein Datenwissenschaftler zum Beispiel handgefertigte Regeln zur Mortalität von Rauchern versus Nichtrauchern erstellen.
Wenn jedoch viele andere Variablen mit einbezogen werden, könnte sich ein ML-Modell als effizienter erweisen, um zukünftige Sterblichkeitsraten basierend auf der bisherigen Gesundheitsgeschichte vorherzusagen. Ein fröhlicheres Beispiel könnte das Erstellen von Wettervorhersagen für den Monat April an einem bestimmten Ort sein, basierend auf Daten, die Breite, Länge, Klimawandel, Nähe zum Ozean, Muster des Jetstreams und mehr enthalten.
✅ Diese Präsentation über Wettermodelle bietet eine historische Perspektive zur Verwendung von ML in der Wetteranalyse.
Aufgaben vor dem Aufbau
Bevor Sie mit dem Aufbau Ihres Modells beginnen, müssen Sie mehrere Aufgaben erledigen. Um Ihre Frage zu testen und eine Hypothese auf Basis der Vorhersagen eines Modells zu bilden, müssen Sie mehrere Elemente identifizieren und konfigurieren.
Daten
Um Ihre Frage mit einer gewissen Sicherheit beantworten zu können, benötigen Sie eine gute Menge an Daten vom richtigen Typ. An diesem Punkt müssen Sie zwei Dinge tun:
- Daten sammeln. Unter Berücksichtigung der vorherigen Lektion zur Fairness in der Datenanalyse sammeln Sie Ihre Daten sorgfältig. Seien Sie sich der Herkunft dieser Daten bewusst, etwaiger inhärenter Verzerrungen und dokumentieren Sie deren Ursprung.
- Daten vorbereiten. Im Datenvorbereitungsprozess sind mehrere Schritte erforderlich. Möglicherweise müssen Sie Daten aus verschiedenen Quellen sammeln und normalisieren. Sie können die Qualität und Menge der Daten durch verschiedene Methoden verbessern, z. B. durch Umwandlung von Zeichenketten in Zahlen (wie wir es in Clustering tun). Sie können auch neue Daten basierend auf den Originaldaten erzeugen (wie wir es in Classification tun). Sie können die Daten säubern und bearbeiten (wie wir es vor der Web-App Lektion tun). Schließlich müssen Sie sie je nach Trainingsmethode möglicherweise auch zufällig mischen und durchmischen.
✅ Nachdem Sie Ihre Daten gesammelt und verarbeitet haben, nehmen Sie sich einen Moment Zeit, um zu sehen, ob deren Form es Ihnen erlaubt, Ihre beabsichtigte Frage zu bearbeiten. Es kann sein, dass die Daten für Ihre Aufgabe nicht gut geeignet sind, wie wir in unseren Clustering Lektionen entdecken!
Merkmale und Ziel
Ein Merkmal ist eine messbare Eigenschaft Ihrer Daten. In vielen Datensätzen wird es als Spaltenüberschrift wie „Datum“, „Größe“ oder „Farbe“ dargestellt. Ihre Merkmalsvariable, meist als X im Code dargestellt, repräsentiert die Eingangsvariable, die zum Trainieren eines Modells verwendet wird.
Ein Ziel ist das, was Sie vorhersagen möchten. Das Ziel, meist als y im Code dargestellt, repräsentiert die Antwort auf die Frage, die Sie Ihren Daten stellen möchten: Im Dezember, welche Farbe werden Kürbisse am günstigsten haben? In San Francisco, welche Viertel werden den besten Immobilien-Preis haben? Manchmal wird das Ziel auch als Label-Attribut bezeichnet.
Auswahl Ihrer Merkmalsvariablen
🎓 Merkmalsauswahl und Merkmalsextraktion Wie wissen Sie, welche Variable Sie beim Aufbau eines Modells wählen sollen? Wahrscheinlich durchlaufen Sie einen Prozess der Merkmalsauswahl oder Merkmalsextraktion, um die richtigen Variablen für das leistungsfähigste Modell auszuwählen. Sie sind jedoch nicht dasselbe: „Merkmalsextraktion erstellt neue Merkmale aus Funktionen der ursprünglichen Merkmale, während Merkmalsauswahl eine Teilmenge der Merkmale zurückgibt.“ (Quelle)
Visualisieren Sie Ihre Daten
Ein wichtiger Bestandteil des Werkzeugsatzes eines Datenwissenschaftlers ist die Fähigkeit, Daten mit mehreren exzellenten Bibliotheken wie Seaborn oder MatPlotLib zu visualisieren. Die visuelle Darstellung Ihrer Daten kann Ihnen helfen, verborgene Korrelationen zu entdecken, die Sie nutzen können. Ihre Visualisierungen können Ihnen auch helfen, Verzerrungen oder unausgewogene Daten zu erkennen (wie wir in Classification entdecken).
Teilen Sie Ihren Datensatz auf
Vor dem Training müssen Sie Ihren Datensatz in zwei oder mehr unterschiedlich große Teile aufteilen, die dennoch die Daten gut repräsentieren.
- Training. Dieser Teil des Datensatzes wird verwendet, um Ihr Modell zu trainieren. Dieser Satz macht den Großteil des ursprünglichen Datensatzes aus.
- Testen. Ein Testdatensatz ist eine unabhängige Datenmenge, oft aus den Originaldaten gewonnen, die Sie verwenden, um die Leistung des gebauten Modells zu bestätigen.
- Validierung. Ein Validierungssatz ist eine kleinere unabhängige Gruppe von Beispielen, die Sie zur Feinabstimmung der Hyperparameter oder Architektur des Modells nutzen, um das Modell zu verbessern. Je nach Größe Ihrer Daten und der gestellten Frage benötigen Sie diesen dritten Satz möglicherweise nicht (wie wir in Time Series Forecasting anmerken).
Aufbau eines Modells
Mit Ihren Trainingsdaten ist es Ihr Ziel, ein Modell oder eine statistische Darstellung Ihrer Daten durch verschiedene Algorithmen zu trainieren. Das Trainieren eines Modells setzt es den Daten aus und ermöglicht ihm, Annahmen über wahrgenommene Muster zu treffen, diese zu validieren und anzunehmen oder abzulehnen.
Wählen Sie eine Trainingsmethode
Je nach Ihrer Frage und der Natur Ihrer Daten wählen Sie eine Methode, um das Modell zu trainieren. Wenn Sie durch die Dokumentation von Scikit-learn - die wir in diesem Kurs verwenden - gehen, finden Sie viele Möglichkeiten, ein Modell zu trainieren. Je nach Ihrer Erfahrung müssen Sie möglicherweise mehrere verschiedene Methoden ausprobieren, um das beste Modell zu erstellen. Häufig durchlaufen Datenwissenschaftler einen Prozess, bei dem sie die Leistung eines Modells durch die Überprüfung von zuvor unbekannten Daten, die auf Genauigkeit, Verzerrung und andere Qualitätsprobleme geprüft werden, evaluieren und die passendste Trainingsmethode für die jeweilige Aufgabe auswählen.
Trainieren Sie ein Modell
Mit Ihren Trainingsdaten sind Sie bereit, es zu „fitten“, um ein Modell zu erstellen. Sie werden feststellen, dass Sie in vielen ML-Bibliotheken den Code model.fit sehen – zu diesem Zeitpunkt übergeben Sie Ihre Merkmalsvariable als Array von Werten (normalerweise 'X') und eine Zielvariable (normalerweise 'y').
Bewerten Sie das Modell
Sobald der Trainingsprozess abgeschlossen ist (es können viele Iterationen oder „Epochen“ nötig sein, um ein großes Modell zu trainieren), können Sie die Qualität des Modells anhand von Testdaten einschätzen. Diese Daten sind ein Teil des ursprünglichen Datensatzes, den das Modell noch nicht analysiert hat. Sie können eine Tabelle mit Metriken zur Qualität Ihres Modells ausgeben.
🎓 Modellanpassung
Im Kontext des maschinellen Lernens bezieht sich Modellanpassung auf die Genauigkeit der zugrundeliegenden Funktion des Modells, während es versucht, Daten zu analysieren, mit denen es nicht vertraut ist.
🎓 Underfitting und Overfitting sind häufige Probleme, die die Qualität des Modells beeinträchtigen, wenn das Modell entweder nicht gut genug oder zu gut anpasst. Dies führt dazu, dass das Modell entweder zu genau oder zu lose mit seinen Trainingsdaten übereinstimmt. Ein überangepasstes Modell sagt die Trainingsdaten zu gut vorher, da es die Details und das Rauschen der Daten zu genau gelernt hat. Ein unterangepasstes Modell ist ungenau, da es weder seine Trainingsdaten noch neue Daten, die es noch nicht „gesehen“ hat, genau analysieren kann.
> Infografik von Jen Looper
Parameteranpassung
Sobald Ihr erstes Training abgeschlossen ist, beobachten Sie die Qualität des Modells und überlegen, es zu verbessern, indem Sie dessen „Hyperparameter“ anpassen. Lesen Sie mehr über den Prozess in der Dokumentation.
Vorhersage
Dies ist der Moment, in dem Sie völlig neue Daten verwenden können, um die Genauigkeit Ihres Modells zu testen. In einem „angewandten“ ML-Setting, bei dem Sie Web-Anwendungen erstellen, um das Modell in der Produktion zu nutzen, könnte dieser Prozess die Erfassung von Benutzereingaben (beispielsweise ein Button-Klick) umfassen, um eine Variable zu setzen und an das Modell zur Inferenz oder Bewertung zu senden.
In diesen Lektionen entdecken Sie, wie Sie diese Schritte nutzen, um Daten vorzubereiten, Modelle zu erstellen, zu testen, zu bewerten und Vorhersagen zu treffen – all die Gesten eines Datenwissenschaftlers und mehr, während Sie auf dem Weg sind, ein „Full Stack“ ML Engineer zu werden.
🚀Herausforderung
Zeichnen Sie ein Flussdiagramm, das die Schritte eines ML-Praktikers widerspiegelt. Wo sehen Sie sich gerade im Prozess? Wo prognostizieren Sie Schwierigkeiten? Was erscheint Ihnen leicht?
Nachvorlesungs-Quiz
Rückblick & Selbststudium
Suchen Sie online nach Interviews mit Datenwissenschaftlern, die ihren Arbeitsalltag beschreiben. Hier ist eines.
Aufgabe
Interviewen Sie einen Datenwissenschaftler
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir auf Genauigkeit achten, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache gilt als maßgebliche Quelle. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Verwendung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Einführung in das maschinelle Lernen
In diesem Abschnitt des Lehrplans werden Sie in die grundlegenden Konzepte des maschinellen Lernens eingeführt, einschließlich dessen, was es ist, seiner Geschichte und der Techniken, die Forscher einsetzen, um es in realen Szenarien anzuwenden. Lassen Sie uns gemeinsam diese spannende Welt des ML erkunden!
> Foto von <a href="https://unsplash.com/@bill_oxford?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Bill Oxford</a> auf <a href="https://unsplash.com/s/photos/globe?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
Lektionen
- Einführung in das maschinelle Lernen
- Die Geschichte des maschinellen Lernens und der KI
- Fairness und maschinelles Lernen
- Techniken des maschinellen Lernens
Urheberrechte
"Einführung in das maschinelle Lernen" wurde mit ♥️ von einem Team geschrieben, darunter Muhammad Sakib Khan Inan, Ornella Altunyan und Jen Looper
"Die Geschichte des maschinellen Lernens" wurde mit ♥️ von Jen Looper und Amy Boyd geschrieben
"Fairness und maschinelles Lernen" wurde mit ♥️ von Tomomi Imura geschrieben
"Techniken des maschinellen Lernens" wurde mit ♥️ von Jen Looper und Chris Noring geschrieben
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir auf Genauigkeit achten, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache ist als maßgebliche Quelle zu betrachten. Für wichtige Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Verwendung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Regression mit Scikit-learn
Anweisungen
Schauen Sie sich das Linnerud-Dataset in Scikit-learn an. Dieses Dataset hat mehrere Zielvariablen: 'Es besteht aus drei Übungsvariablen (Daten) und drei physiologischen Variablen (Zielvariablen), die von zwanzig Männern mittleren Alters in einem Fitnessclub gesammelt wurden.'
Beschreiben Sie in Ihren eigenen Worten, wie man ein Regressionsmodell erstellt, das die Beziehung zwischen dem Taillenumfang und der Anzahl der durchgeführten Sit-ups darstellt. Machen Sie dasselbe für die anderen Datenpunkte in diesem Dataset.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein beschreibender Absatz wird eingereicht | Ein gut geschriebener Absatz wird eingereicht | Einige Sätze werden eingereicht | Keine Beschreibung wird geliefert |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einstieg in Python und Scikit-learn für Regressionsmodelle

> Sketchnote von Tomomi Imura
Quiz vor der Lektion
> ### Diese Lektion ist auch in R verfügbar!
Einführung
In diesen vier Lektionen lernen Sie, wie man Regressionsmodelle erstellt. Wir werden gleich besprechen, wofür diese verwendet werden. Aber bevor Sie loslegen, stellen Sie sicher, dass Sie die richtigen Werkzeuge eingerichtet haben, um den Prozess zu starten!
In dieser Lektion lernen Sie:
- Wie Sie Ihren Computer für lokale Machine-Learning-Aufgaben konfigurieren.
- Wie Sie mit Jupyter-Notebooks arbeiten.
- Wie Sie Scikit-learn verwenden, einschließlich der Installation.
- Wie Sie lineare Regression durch eine praktische Übung erkunden.
Installationen und Konfigurationen
> 🎥 Klicken Sie auf das Bild oben, um ein kurzes Video zur Konfiguration Ihres Computers für ML anzusehen.
- Installieren Sie Python. Stellen Sie sicher, dass Python auf Ihrem Computer installiert ist. Sie werden Python für viele Aufgaben in den Bereichen Datenwissenschaft und maschinelles Lernen verwenden. Die meisten Computersysteme haben Python bereits vorinstalliert. Es gibt auch nützliche Python Coding Packs, die die Einrichtung für einige Benutzer erleichtern.
Einige Anwendungen von Python erfordern jedoch eine bestimmte Version der Software, während andere eine andere Version benötigen. Aus diesem Grund ist es sinnvoll, in einer virtuellen Umgebung zu arbeiten.
- Installieren Sie Visual Studio Code. Stellen Sie sicher, dass Visual Studio Code auf Ihrem Computer installiert ist. Folgen Sie diesen Anweisungen, um Visual Studio Code zu installieren. In diesem Kurs werden Sie Python in Visual Studio Code verwenden, daher sollten Sie sich mit der Konfiguration von Visual Studio Code für die Python-Entwicklung vertraut machen.
> Machen Sie sich mit Python vertraut, indem Sie diese Sammlung von Lernmodulen durcharbeiten.
>
>
>
> 🎥 Klicken Sie auf das Bild oben, um ein Video über die Verwendung von Python in VS Code anzusehen.
-
Installieren Sie Scikit-learn, indem Sie diesen Anweisungen folgen. Da Sie sicherstellen müssen, dass Sie Python 3 verwenden, wird empfohlen, eine virtuelle Umgebung zu nutzen. Beachten Sie, dass es spezielle Anweisungen gibt, wenn Sie diese Bibliothek auf einem M1 Mac installieren.
-
Installieren Sie Jupyter Notebook. Sie müssen das Jupyter-Paket installieren.
Ihre ML-Entwicklungsumgebung
Sie werden Notebooks verwenden, um Ihren Python-Code zu entwickeln und Machine-Learning-Modelle zu erstellen. Diese Art von Datei ist ein gängiges Werkzeug für Datenwissenschaftler und kann an ihrer Endung .ipynb erkannt werden.
Notebooks sind eine interaktive Umgebung, die es Entwicklern ermöglicht, sowohl Code zu schreiben als auch Notizen und Dokumentationen rund um den Code hinzuzufügen. Dies ist besonders hilfreich für experimentelle oder forschungsorientierte Projekte.
> 🎥 Klicken Sie auf das Bild oben, um ein kurzes Video zu dieser Übung anzusehen.
Übung - Arbeiten mit einem Notebook
In diesem Ordner finden Sie die Datei notebook.ipynb.
- Öffnen Sie notebook.ipynb in Visual Studio Code.
Ein Jupyter-Server wird mit Python 3+ gestartet. Sie finden Bereiche im Notebook, die ausgeführt werden können, also Codeabschnitte. Sie können einen Codeblock ausführen, indem Sie das Symbol auswählen, das wie eine Wiedergabetaste aussieht.
- Wählen Sie das
md-Symbol und fügen Sie etwas Markdown sowie den folgenden Text hinzu: # Willkommen in Ihrem Notebook.
Fügen Sie anschließend etwas Python-Code hinzu.
- Geben Sie print('hello notebook') in den Codeblock ein.
- Wählen Sie den Pfeil, um den Code auszuführen.
Sie sollten die folgende Ausgabe sehen:
```output
hello notebook
```

Sie können Ihren Code mit Kommentaren versehen, um das Notebook selbst zu dokumentieren.
✅ Denken Sie einen Moment darüber nach, wie unterschiedlich die Arbeitsumgebung eines Webentwicklers im Vergleich zu der eines Datenwissenschaftlers ist.
Einführung in Scikit-learn
Jetzt, da Python in Ihrer lokalen Umgebung eingerichtet ist und Sie sich mit Jupyter-Notebooks vertraut gemacht haben, machen wir uns ebenso mit Scikit-learn vertraut (ausgesprochen sci wie in science). Scikit-learn bietet eine umfangreiche API, die Ihnen bei der Durchführung von ML-Aufgaben hilft.
Laut ihrer Website ist "Scikit-learn eine Open-Source-Bibliothek für maschinelles Lernen, die sowohl überwachtes als auch unüberwachtes Lernen unterstützt. Sie bietet auch verschiedene Werkzeuge für Modellanpassung, Datenvorverarbeitung, Modellauswahl und -bewertung sowie viele andere Hilfsmittel."
In diesem Kurs werden Sie Scikit-learn und andere Werkzeuge verwenden, um Machine-Learning-Modelle für sogenannte "traditionelle Machine-Learning"-Aufgaben zu erstellen. Wir haben bewusst auf neuronale Netze und Deep Learning verzichtet, da diese besser in unserem kommenden Lehrplan "KI für Anfänger" behandelt werden.
Scikit-learn macht es einfach, Modelle zu erstellen und zu bewerten. Es konzentriert sich hauptsächlich auf die Verwendung numerischer Daten und enthält mehrere vorgefertigte Datensätze, die als Lernwerkzeuge dienen. Es bietet auch vorgefertigte Modelle, die Schüler ausprobieren können. Lassen Sie uns den Prozess des Ladens vorgefertigter Daten und der Verwendung eines eingebauten Schätzers für ein erstes ML-Modell mit Scikit-learn erkunden.
Übung - Ihr erstes Scikit-learn-Notebook
> Dieses Tutorial wurde vom Beispiel zur linearen Regression auf der Scikit-learn-Website inspiriert.
> 🎥 Klicken Sie auf das Bild oben, um ein kurzes Video zu dieser Übung anzusehen.
In der Datei notebook.ipynb, die mit dieser Lektion verbunden ist, löschen Sie alle Zellen, indem Sie auf das Symbol "Papierkorb" klicken.
In diesem Abschnitt arbeiten Sie mit einem kleinen Datensatz über Diabetes, der in Scikit-learn integriert ist und zu Lernzwecken dient. Stellen Sie sich vor, Sie möchten eine Behandlung für Diabetespatienten testen. Machine-Learning-Modelle könnten Ihnen helfen, herauszufinden, welche Patienten basierend auf Kombinationen von Variablen besser auf die Behandlung ansprechen würden. Selbst ein sehr einfaches Regressionsmodell könnte, wenn es visualisiert wird, Informationen über Variablen liefern, die Ihnen helfen könnten, Ihre theoretischen klinischen Studien zu organisieren.
✅ Es gibt viele Arten von Regressionsmethoden, und welche Sie wählen, hängt von der Frage ab, die Sie beantworten möchten. Wenn Sie beispielsweise die wahrscheinliche Größe einer Person in einem bestimmten Alter vorhersagen möchten, würden Sie lineare Regression verwenden, da Sie einen numerischen Wert suchen. Wenn Sie hingegen herausfinden möchten, ob eine bestimmte Küche als vegan betrachtet werden sollte oder nicht, suchen Sie nach einer Kategorisierung und würden logistische Regression verwenden. Sie werden später mehr über logistische Regression lernen. Überlegen Sie sich einige Fragen, die Sie an Daten stellen könnten, und welche dieser Methoden dafür besser geeignet wäre.
Lassen Sie uns mit dieser Aufgabe beginnen.
Bibliotheken importieren
Für diese Aufgabe importieren wir einige Bibliotheken:
- matplotlib. Ein nützliches Grafikwerkzeug, das wir verwenden, um ein Liniendiagramm zu erstellen.
- numpy. numpy ist eine nützliche Bibliothek für den Umgang mit numerischen Daten in Python.
- sklearn. Dies ist die Scikit-learn-Bibliothek.
Importieren Sie einige Bibliotheken, um Ihre Aufgaben zu unterstützen.
- Fügen Sie die Importe hinzu, indem Sie den folgenden Code eingeben:
python
import matplotlib.pyplot as plt
import numpy as np
from sklearn import datasets, linear_model, model_selection
Oben importieren Sie matplotlib, numpy und datasets, linear_model sowie model_selection aus sklearn. model_selection wird verwendet, um Daten in Trainings- und Testsets aufzuteilen.
Der Diabetes-Datensatz
Der integrierte Diabetes-Datensatz enthält 442 Datenproben zu Diabetes mit 10 Merkmalvariablen, darunter:
- age: Alter in Jahren
- bmi: Body-Mass-Index
- bp: Durchschnittlicher Blutdruck
- s1 tc: T-Zellen (eine Art von weißen Blutkörperchen)
✅ Dieser Datensatz enthält das Konzept von "Geschlecht" als Merkmalvariable, das für die Forschung zu Diabetes wichtig ist. Viele medizinische Datensätze enthalten diese Art von binärer Klassifikation. Überlegen Sie, wie solche Kategorisierungen bestimmte Teile der Bevölkerung von Behandlungen ausschließen könnten.
Laden Sie nun die X- und y-Daten.
> 🎓 Denken Sie daran, dass dies überwachtes Lernen ist und wir ein benanntes 'y'-Ziel benötigen.
In einer neuen Codezelle laden Sie den Diabetes-Datensatz, indem Sie load_diabetes() aufrufen. Der Eingabeparameter return_X_y=True signalisiert, dass X eine Datenmatrix und y das Regressionsziel sein wird.
-
Fügen Sie einige Print-Befehle hinzu, um die Form der Datenmatrix und ihr erstes Element anzuzeigen:
python X, y = datasets.load_diabetes(return_X_y=True) print(X.shape) print(X[0])Was Sie als Antwort erhalten, ist ein Tupel. Sie weisen die beiden ersten Werte des Tupels
Xundyzu. Erfahren Sie mehr über Tupel.Sie können sehen, dass diese Daten 442 Elemente in Arrays mit 10 Elementen enthalten:
text (442, 10) [ 0.03807591 0.05068012 0.06169621 0.02187235 -0.0442235 -0.03482076 -0.04340085 -0.00259226 0.01990842 -0.01764613]✅ Denken Sie über die Beziehung zwischen den Daten und dem Regressionsziel nach. Lineare Regression sagt Beziehungen zwischen Merkmal X und Zielvariable y voraus. Können Sie das Ziel für den Diabetes-Datensatz in der Dokumentation finden? Was zeigt dieser Datensatz, wenn man das Ziel betrachtet?
-
Wählen Sie als Nächstes einen Teil dieses Datensatzes aus, um ihn zu plotten, indem Sie die dritte Spalte des Datensatzes auswählen. Sie können dies tun, indem Sie den
:-Operator verwenden, um alle Zeilen auszuwählen, und dann die dritte Spalte mit dem Index (2) auswählen. Sie können die Daten auch in ein 2D-Array umformen, wie es für das Plotten erforderlich ist, indem Siereshape(n_rows, n_columns)verwenden. Wenn einer der Parameter -1 ist, wird die entsprechende Dimension automatisch berechnet.
python
X = X[:, 2]
X = X.reshape((-1,1))
✅ Drucken Sie die Daten jederzeit aus, um ihre Form zu überprüfen.
- Jetzt, da Sie die Daten zum Plotten bereit haben, können Sie sehen, ob eine Maschine helfen kann, eine logische Trennung zwischen den Zahlen in diesem Datensatz zu bestimmen. Dazu müssen Sie sowohl die Daten (X) als auch das Ziel (y) in Test- und Trainingssets aufteilen. Scikit-learn bietet eine einfache Möglichkeit, dies zu tun; Sie können Ihre Testdaten an einem bestimmten Punkt aufteilen.
python
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.33)
-
Jetzt sind Sie bereit, Ihr Modell zu trainieren! Laden Sie das lineare Regressionsmodell und trainieren Sie es mit Ihren X- und y-Trainingssets, indem Sie
model.fit()verwenden:python model = linear_model.LinearRegression() model.fit(X_train, y_train)✅
model.fit()ist eine Funktion, die Sie in vielen ML-Bibliotheken wie TensorFlow sehen werden. -
Erstellen Sie dann eine Vorhersage mit Testdaten, indem Sie die Funktion
predict()verwenden. Diese wird verwendet, um die Linie zwischen den Datengruppen zu zeichnen.python y_pred = model.predict(X_test) -
Jetzt ist es an der Zeit, die Daten in einem Diagramm darzustellen. Matplotlib ist ein sehr nützliches Werkzeug für diese Aufgabe. Erstellen Sie ein Streudiagramm aller X- und y-Testdaten und verwenden Sie die Vorhersage, um eine Linie an der passendsten Stelle zwischen den Datengruppierungen des Modells zu zeichnen.
python plt.scatter(X_test, y_test, color='black') plt.plot(X_test, y_pred, color='blue', linewidth=3) plt.xlabel('Scaled BMIs') plt.ylabel('Disease Progression') plt.title('A Graph Plot Showing Diabetes Progression Against BMI') plt.show()
✅ Überlege ein wenig, was hier passiert. Eine gerade Linie verläuft durch viele kleine Datenpunkte, aber was genau macht sie? Kannst du erkennen, wie du diese Linie nutzen könntest, um vorherzusagen, wo ein neuer, unbekannter Datenpunkt in Bezug auf die y-Achse des Plots liegen sollte? Versuche, den praktischen Nutzen dieses Modells in Worte zu fassen.
Herzlichen Glückwunsch, du hast dein erstes lineares Regressionsmodell erstellt, eine Vorhersage damit gemacht und es in einem Plot dargestellt!
🚀Herausforderung
Plotte eine andere Variable aus diesem Datensatz. Hinweis: Bearbeite diese Zeile: X = X[:,2]. Angesichts des Ziels dieses Datensatzes, was kannst du über den Verlauf von Diabetes als Krankheit herausfinden?
Quiz nach der Vorlesung
Rückblick & Selbststudium
In diesem Tutorial hast du mit einfacher linearer Regression gearbeitet, anstatt mit univariater oder multipler linearer Regression. Lies ein wenig über die Unterschiede zwischen diesen Methoden oder sieh dir dieses Video an.
Lies mehr über das Konzept der Regression und denke darüber nach, welche Arten von Fragen mit dieser Technik beantwortet werden können. Nimm an diesem Tutorial teil, um dein Verständnis zu vertiefen.
Aufgabe
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Lineare Regression für Diabetes-Datensatz - Lektion 1
Benötigte Bibliotheken importieren
import matplotlib.pyplot as plt
import numpy as np
from sklearn import datasets, linear_model, model_selection
Laden Sie den Diabetes-Datensatz, aufgeteilt in X-Daten und y-Merkmale
X, y = datasets.load_diabetes(return_X_y=True)
print(X.shape)
print(X[0])
Wählen Sie nur ein Merkmal aus, auf das Sie sich bei dieser Übung konzentrieren möchten
# Selecting the 3rd feature
X = X[:, 2]
print(X.shape)
#Reshaping to get a 2D array
X = X.reshape(-1, 1)
print(X.shape)
print(X)
Teilen Sie die Trainings- und Testdaten sowohl für X als auch für y auf
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.33)
Wählen Sie das Modell aus und passen Sie es an die Trainingsdaten an
model = linear_model.LinearRegression()
model.fit(X_train, y_train)
Verwenden Sie Testdaten, um eine Linie vorherzusagen
y_pred = model.predict(X_test)
Zeigen Sie die Ergebnisse in einem Diagramm
plt.scatter(X_test, y_test, color='black')
plt.plot(X_test, y_pred, color='blue', linewidth=3)
plt.show()
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in die Regression - Lektion 1
Einordnung in den Kontext
✅ Es gibt viele Arten von Regressionsmethoden, und welche du wählst, hängt von der Frage ab, die du beantworten möchtest. Möchtest du beispielsweise die wahrscheinliche Körpergröße einer Person in einem bestimmten Alter vorhersagen, würdest du lineare Regression verwenden, da du nach einem numerischen Wert suchst. Wenn du hingegen herausfinden möchtest, ob eine bestimmte Küche als vegan betrachtet werden sollte oder nicht, suchst du nach einer Kategorisierung, und dafür würdest du logistische Regression verwenden. Mehr über logistische Regression wirst du später lernen. Überlege dir ein paar Fragen, die du an Daten stellen könntest, und welche dieser Methoden dafür am besten geeignet wäre.
In diesem Abschnitt wirst du mit einem kleinen Datensatz über Diabetes arbeiten. Stell dir vor, du möchtest eine Behandlung für Diabetespatienten testen. Machine-Learning-Modelle könnten dir dabei helfen, herauszufinden, welche Patienten besser auf die Behandlung ansprechen würden, basierend auf Kombinationen von Variablen. Selbst ein sehr einfaches Regressionsmodell könnte, wenn es visualisiert wird, Informationen über Variablen liefern, die dir bei der Organisation deiner theoretischen klinischen Studien helfen könnten.
Also, lass uns mit dieser Aufgabe beginnen!
<p > <img src="../../images/encouRage.jpg" width="630"/> <figcaption>Kunstwerk von @allison_horst</figcaption>
<!--
<br>Kunstwerk von @allison_horst-->
1. Laden unseres Werkzeugkastens
Für diese Aufgabe benötigen wir die folgenden Pakete:
-
tidyverse: Das tidyverse ist eine Sammlung von R-Paketen, die darauf ausgelegt ist, Datenwissenschaft schneller, einfacher und unterhaltsamer zu machen! -
tidymodels: Das tidymodels Framework ist eine Sammlung von Paketen für Modellierung und maschinelles Lernen.
Sie können sie wie folgt installieren:
install.packages(c("tidyverse", "tidymodels"))
Das untenstehende Skript überprüft, ob Sie die für dieses Modul benötigten Pakete installiert haben, und installiert sie für Sie, falls einige fehlen.
suppressWarnings(if(!require("pacman")) install.packages("pacman"))
pacman::p_load(tidyverse, tidymodels)
Lassen Sie uns nun diese großartigen Pakete laden und in unserer aktuellen R-Sitzung verfügbar machen. (Dies dient nur zur Veranschaulichung, pacman::p_load() hat das bereits für Sie erledigt.)
# load the core Tidyverse packages
library(tidyverse)
# load the core Tidymodels packages
library(tidymodels)
2. Der Diabetes-Datensatz
In dieser Übung werden wir unsere Regressionsfähigkeiten unter Beweis stellen, indem wir Vorhersagen auf einem Diabetes-Datensatz treffen. Der Diabetes-Datensatz umfasst 442 Stichproben mit Daten zu Diabetes, darunter 10 Prädiktorvariablen: Alter, Geschlecht, Body-Mass-Index, durchschnittlicher Blutdruck und sechs Messungen des Blutserums sowie eine Zielvariable y: ein quantitativer Messwert für den Krankheitsverlauf ein Jahr nach der Ausgangsmessung.
| Anzahl der Beobachtungen | 442 |
|---|---|
| Anzahl der Prädiktoren | Die ersten 10 Spalten sind numerische Prädiktoren |
| Zielvariable | Spalte 11 ist ein quantitativer Messwert für den Krankheitsverlauf ein Jahr nach der Ausgangsmessung |
| Informationen zu den Prädiktoren | - Alter in Jahren |
| - Geschlecht | |
| - bmi Body-Mass-Index | |
| - bp durchschnittlicher Blutdruck | |
| - s1 tc, Gesamtserumcholesterin | |
| - s2 ldl, Low-Density-Lipoproteine | |
| - s3 hdl, High-Density-Lipoproteine | |
| - s4 tch, Gesamtcholesterin / HDL | |
| - s5 ltg, möglicherweise Logarithmus des Serumtriglyceridspiegels | |
| - s6 glu, Blutzuckerspiegel |
> 🎓 Denke daran, dies ist überwachtes Lernen, und wir benötigen eine benannte Zielvariable 'y'.
Bevor du Daten mit R bearbeiten kannst, musst du die Daten in den Speicher von R importieren oder eine Verbindung zu den Daten herstellen, die R für den Fernzugriff auf die Daten verwenden kann.
> Das readr-Paket, das Teil des Tidyverse ist, bietet eine schnelle und benutzerfreundliche Möglichkeit, rechteckige Daten in R einzulesen.
Lass uns nun den Diabetes-Datensatz von der folgenden URL laden: <https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html>
Außerdem werden wir eine Plausibilitätsprüfung unserer Daten mit glimpse() durchführen und die ersten 5 Zeilen mit slice() anzeigen.
Bevor wir weitermachen, möchten wir noch etwas vorstellen, das du oft in R-Code sehen wirst 🥁🥁: den Pipe-Operator %>%
Der Pipe-Operator (%>%) führt Operationen in logischer Reihenfolge aus, indem er ein Objekt an eine Funktion oder einen Ausdruck weiterleitet. Du kannst dir den Pipe-Operator so vorstellen, als würdest du in deinem Code "und dann" sagen.
# Import the data set
diabetes <- read_table2(file = "https://www4.stat.ncsu.edu/~boos/var.select/diabetes.rwrite1.txt")
# Get a glimpse and dimensions of the data
glimpse(diabetes)
# Select the first 5 rows of the data
diabetes %>%
slice(1:5)
glimpse() zeigt uns, dass diese Daten 442 Zeilen und 11 Spalten enthalten, wobei alle Spalten den Datentyp double haben.
<br>
> glimpse() und slice() sind Funktionen aus dplyr. Dplyr, ein Teil des Tidyverse, ist eine Grammatik für Datenmanipulation, die eine konsistente Reihe von Verben bereitstellt, um die häufigsten Herausforderungen bei der Datenmanipulation zu lösen.
<br>
Da wir nun die Daten haben, konzentrieren wir uns auf ein Merkmal (bmi), das wir für diese Übung verwenden möchten. Dafür müssen wir die gewünschten Spalten auswählen. Wie machen wir das?
dplyr::select() ermöglicht es uns, Spalten in einem Dataframe auszuwählen (und optional umzubenennen).
# Select predictor feature `bmi` and outcome `y`
diabetes_select <- diabetes %>%
select(c(bmi, y))
# Print the first 5 rows
diabetes_select %>%
slice(1:10)
3. Trainings- und Testdaten
Es ist gängige Praxis im überwachten Lernen, die Daten in zwei Teilmengen aufzuteilen: einen (in der Regel größeren) Satz, mit dem das Modell trainiert wird, und einen kleineren "Rückhalte"-Satz, mit dem überprüft wird, wie gut das Modell funktioniert hat.
Da wir nun die Daten vorbereitet haben, können wir prüfen, ob eine Maschine helfen kann, eine logische Aufteilung zwischen den Zahlen in diesem Datensatz zu bestimmen. Wir können das rsample-Paket verwenden, das Teil des Tidymodels-Frameworks ist, um ein Objekt zu erstellen, das die Informationen darüber enthält, wie die Daten aufgeteilt werden sollen. Anschließend können zwei weitere rsample-Funktionen verwendet werden, um die erstellten Trainings- und Testdatensätze zu extrahieren:
set.seed(2056)
# Split 67% of the data for training and the rest for tesing
diabetes_split <- diabetes_select %>%
initial_split(prop = 0.67)
# Extract the resulting train and test sets
diabetes_train <- training(diabetes_split)
diabetes_test <- testing(diabetes_split)
# Print the first 3 rows of the training set
diabetes_train %>%
slice(1:10)
4. Trainieren eines linearen Regressionsmodells mit Tidymodels
Jetzt sind wir bereit, unser Modell zu trainieren!
In Tidymodels spezifizieren Sie Modelle mit parsnip(), indem Sie drei Konzepte angeben:
-
Der Modelltyp unterscheidet Modelle wie lineare Regression, logistische Regression, Entscheidungsbaum-Modelle und so weiter.
-
Der Modus des Modells umfasst gängige Optionen wie Regression und Klassifikation; einige Modelltypen unterstützen beide, während andere nur einen Modus haben.
-
Die Engine des Modells ist das rechnerische Werkzeug, das verwendet wird, um das Modell anzupassen. Oft sind dies R-Pakete, wie
"lm"oder"ranger".
Diese Modellinformationen werden in einer Modellspezifikation erfasst, also erstellen wir eine!
# Build a linear model specification
lm_spec <-
# Type
linear_reg() %>%
# Engine
set_engine("lm") %>%
# Mode
set_mode("regression")
# Print the model specification
lm_spec
Nachdem ein Modell spezifiziert wurde, kann das Modell mit der fit()-Funktion geschätzt oder trainiert werden, typischerweise unter Verwendung einer Formel und einiger Daten.
y ~ . bedeutet, dass wir y als die vorhergesagte Größe/Zielvariable anpassen, erklärt durch alle Prädiktoren/Merkmale, also . (in diesem Fall haben wir nur einen Prädiktor: bmi).
# Build a linear model specification
lm_spec <- linear_reg() %>%
set_engine("lm") %>%
set_mode("regression")
# Train a linear regression model
lm_mod <- lm_spec %>%
fit(y ~ ., data = diabetes_train)
# Print the model
lm_mod
Aus den Modell-Ausgaben können wir die während des Trainings gelernten Koeffizienten erkennen. Sie repräsentieren die Koeffizienten der Ausgleichsgeraden, die den geringsten Gesamtfehler zwischen der tatsächlichen und der vorhergesagten Variablen liefert. <br>
5. Vorhersagen für den Testdatensatz treffen
Nachdem wir nun ein Modell trainiert haben, können wir es verwenden, um die Krankheitsprogression y für den Testdatensatz mithilfe von parsnip::predict() vorherzusagen. Dies wird genutzt, um die Linie zwischen den Datenclustern zu ziehen.
# Make predictions for the test set
predictions <- lm_mod %>%
predict(new_data = diabetes_test)
# Print out some of the predictions
predictions %>%
slice(1:5)
Woohoo! 💃🕺 Wir haben gerade ein Modell trainiert und es verwendet, um Vorhersagen zu treffen!
Beim Erstellen von Vorhersagen ist es in der tidymodels-Konvention üblich, immer ein Tibble/Data-Frame mit standardisierten Spaltennamen zu erzeugen. Dies erleichtert es, die Originaldaten und die Vorhersagen in einem nutzbaren Format zu kombinieren, um sie für nachfolgende Operationen wie das Plotten zu verwenden.
dplyr::bind_cols() verbindet effizient mehrere Data-Frames spaltenweise.
# Combine the predictions and the original test set
results <- diabetes_test %>%
bind_cols(predictions)
results %>%
slice(1:5)
6. Modellierungsergebnisse visualisieren
Jetzt ist es an der Zeit, dies visuell darzustellen 📈. Wir erstellen ein Streudiagramm aller y- und bmi-Werte des Testdatensatzes und verwenden dann die Vorhersagen, um eine Linie an der passendsten Stelle zwischen den Datenclustern des Modells zu zeichnen.
R bietet mehrere Systeme zur Erstellung von Grafiken, aber ggplot2 ist eines der elegantesten und vielseitigsten. Es ermöglicht dir, Grafiken durch Kombination unabhängiger Komponenten zu erstellen.
# Set a theme for the plot
theme_set(theme_light())
# Create a scatter plot
results %>%
ggplot(aes(x = bmi)) +
# Add a scatter plot
geom_point(aes(y = y), size = 1.6) +
# Add a line plot
geom_line(aes(y = .pred), color = "blue", size = 1.5)
✅ Denk mal darüber nach, was hier genau passiert. Eine gerade Linie verläuft durch viele kleine Datenpunkte, aber was macht sie eigentlich genau? Kannst du erkennen, wie du diese Linie nutzen könntest, um vorherzusagen, wo ein neuer, noch nicht gesehener Datenpunkt in Bezug auf die y-Achse des Plots liegen sollte? Versuche, den praktischen Nutzen dieses Modells in Worte zu fassen.
Herzlichen Glückwunsch, du hast dein erstes lineares Regressionsmodell erstellt, eine Vorhersage damit gemacht und es in einem Plot dargestellt!
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erkundung von Visualisierungen
Es gibt mehrere verschiedene Bibliotheken, die für die Datenvisualisierung verfügbar sind. Erstelle einige Visualisierungen mit den Kürbisdaten aus dieser Lektion mithilfe von matplotlib und seaborn in einem Beispiel-Notebook. Welche Bibliotheken sind einfacher zu verwenden?
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Notebook wird mit zwei Erkundungen/Visualisierungen eingereicht | Ein Notebook wird mit einer Erkundung/Visualisierung eingereicht | Ein Notebook wird nicht eingereicht |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erstellen eines Regressionsmodells mit Scikit-learn: Daten vorbereiten und visualisieren

Infografik von Dasani Madipalli
Quiz vor der Lektion
> ### Diese Lektion ist auch in R verfügbar!
Einführung
Nachdem Sie nun die notwendigen Werkzeuge eingerichtet haben, um mit dem Aufbau von Machine-Learning-Modellen in Scikit-learn zu beginnen, können Sie anfangen, Fragen an Ihre Daten zu stellen. Wenn Sie mit Daten arbeiten und ML-Lösungen anwenden, ist es entscheidend, die richtigen Fragen zu stellen, um das volle Potenzial Ihres Datensatzes auszuschöpfen.
In dieser Lektion lernen Sie:
- Wie Sie Ihre Daten für den Modellaufbau vorbereiten.
- Wie Sie Matplotlib für die Datenvisualisierung nutzen.
Die richtigen Fragen an Ihre Daten stellen
Die Frage, die Sie beantwortet haben möchten, bestimmt, welche Art von ML-Algorithmen Sie verwenden. Und die Qualität der Antwort hängt stark von der Beschaffenheit Ihrer Daten ab.
Werfen Sie einen Blick auf die Daten, die für diese Lektion bereitgestellt wurden. Sie können diese .csv-Datei in VS Code öffnen. Ein kurzer Blick zeigt sofort, dass es Lücken gibt und eine Mischung aus Zeichenketten und numerischen Daten vorliegt. Es gibt auch eine seltsame Spalte namens 'Package', in der die Daten eine Mischung aus 'sacks', 'bins' und anderen Werten sind. Die Daten sind tatsächlich ein bisschen chaotisch.
> 🎥 Klicken Sie auf das Bild oben, um ein kurzes Video zur Vorbereitung der Daten für diese Lektion anzusehen.
Es ist tatsächlich nicht sehr häufig, dass man einen Datensatz erhält, der vollständig bereit ist, um direkt ein ML-Modell zu erstellen. In dieser Lektion lernen Sie, wie Sie einen Rohdatensatz mit Standard-Python-Bibliotheken vorbereiten. Außerdem lernen Sie verschiedene Techniken zur Visualisierung der Daten kennen.
Fallstudie: 'Der Kürbismarkt'
In diesem Ordner finden Sie eine .csv-Datei im Stammverzeichnis des data-Ordners namens US-pumpkins.csv, die 1757 Zeilen mit Daten über den Kürbismarkt enthält, sortiert nach Städten. Dies sind Rohdaten, die aus den Specialty Crops Terminal Markets Standard Reports des US-Landwirtschaftsministeriums extrahiert wurden.
Daten vorbereiten
Diese Daten sind gemeinfrei. Sie können in vielen separaten Dateien, nach Städten sortiert, von der USDA-Website heruntergeladen werden. Um zu vermeiden, dass zu viele separate Dateien vorliegen, haben wir alle Städtedaten in eine Tabelle zusammengeführt, sodass die Daten bereits etwas vorbereitet wurden. Schauen wir uns die Daten nun genauer an.
Die Kürbis-Daten - erste Eindrücke
Was fällt Ihnen an diesen Daten auf? Sie haben bereits gesehen, dass es eine Mischung aus Zeichenketten, Zahlen, Lücken und seltsamen Werten gibt, die Sie interpretieren müssen.
Welche Frage könnten Sie mit diesen Daten unter Verwendung einer Regressionsmethode stellen? Wie wäre es mit: "Den Preis eines Kürbisses für einen bestimmten Monat vorhersagen". Wenn Sie die Daten erneut betrachten, gibt es einige Änderungen, die Sie vornehmen müssen, um die für diese Aufgabe erforderliche Datenstruktur zu erstellen.
Übung - Analysieren der Kürbis-Daten
Verwenden wir Pandas, ein sehr nützliches Tool zur Datenanalyse, um diese Kürbis-Daten zu analysieren und vorzubereiten.
Zuerst fehlende Daten überprüfen
Zunächst müssen Sie Schritte unternehmen, um fehlende Daten zu überprüfen:
- Konvertieren Sie die Daten in ein Monatsformat (es handelt sich um US-Daten, daher ist das Format
MM/DD/YYYY). - Extrahieren Sie den Monat in eine neue Spalte.
Öffnen Sie die Datei notebook.ipynb in Visual Studio Code und importieren Sie die Tabelle in ein neues Pandas-Dataframe.
-
Verwenden Sie die Funktion
head(), um die ersten fünf Zeilen anzuzeigen.python import pandas as pd pumpkins = pd.read_csv('../data/US-pumpkins.csv') pumpkins.head()✅ Welche Funktion würden Sie verwenden, um die letzten fünf Zeilen anzuzeigen?
-
Überprüfen Sie, ob im aktuellen Dataframe fehlende Daten vorhanden sind:
python pumpkins.isnull().sum()Es gibt fehlende Daten, aber möglicherweise sind diese für die aktuelle Aufgabe nicht relevant.
-
Um Ihr Dataframe einfacher zu gestalten, wählen Sie nur die benötigten Spalten aus, indem Sie die Funktion
locverwenden, die aus dem ursprünglichen Dataframe eine Gruppe von Zeilen (als erster Parameter übergeben) und Spalten (als zweiter Parameter übergeben) extrahiert. Der Ausdruck:im folgenden Fall bedeutet "alle Zeilen".python columns_to_select = ['Package', 'Low Price', 'High Price', 'Date'] pumpkins = pumpkins.loc[:, columns_to_select]
Zweitens, den Durchschnittspreis eines Kürbisses bestimmen
Überlegen Sie, wie Sie den Durchschnittspreis eines Kürbisses in einem bestimmten Monat bestimmen können. Welche Spalten würden Sie für diese Aufgabe auswählen? Hinweis: Sie benötigen 3 Spalten.
Lösung: Nehmen Sie den Durchschnitt der Spalten Low Price und High Price, um die neue Spalte Price zu füllen, und konvertieren Sie die Spalte Date, sodass nur der Monat angezeigt wird. Glücklicherweise gibt es laut der oben durchgeführten Überprüfung keine fehlenden Daten für Daten oder Preise.
-
Um den Durchschnitt zu berechnen, fügen Sie den folgenden Code hinzu:
```python price = (pumpkins['Low Price'] + pumpkins['High Price']) / 2
month = pd.DatetimeIndex(pumpkins['Date']).month
```
✅ Sie können beliebige Daten mit print(month) überprüfen.
-
Kopieren Sie nun Ihre konvertierten Daten in ein neues Pandas-Dataframe:
python new_pumpkins = pd.DataFrame({'Month': month, 'Package': pumpkins['Package'], 'Low Price': pumpkins['Low Price'],'High Price': pumpkins['High Price'], 'Price': price})Wenn Sie Ihr Dataframe ausgeben, sehen Sie einen sauberen, aufgeräumten Datensatz, auf dessen Grundlage Sie Ihr neues Regressionsmodell erstellen können.
Aber Moment! Etwas ist hier seltsam
Wenn Sie sich die Spalte Package ansehen, werden Kürbisse in vielen verschiedenen Konfigurationen verkauft. Einige werden in '1 1/9 bushel'-Maßen verkauft, andere in '1/2 bushel'-Maßen, einige pro Kürbis, einige pro Pfund und einige in großen Kisten mit unterschiedlichen Breiten.
> Kürbisse scheinen schwer konsistent zu wiegen
Wenn man sich die Originaldaten ansieht, ist es interessant, dass alles mit Unit of Sale gleich 'EACH' oder 'PER BIN' auch den Package-Typ pro Zoll, pro Kiste oder 'each' hat. Kürbisse scheinen schwer konsistent zu wiegen, daher filtern wir sie, indem wir nur Kürbisse mit dem String 'bushel' in ihrer Package-Spalte auswählen.
-
Fügen Sie einen Filter am Anfang der Datei unter dem ersten .csv-Import hinzu:
python pumpkins = pumpkins[pumpkins['Package'].str.contains('bushel', case=True, regex=True)]Wenn Sie die Daten jetzt ausgeben, sehen Sie, dass Sie nur die etwa 415 Zeilen mit Daten erhalten, die Kürbisse nach dem Bushel enthalten.
Aber Moment! Es gibt noch etwas zu tun
Haben Sie bemerkt, dass die Bushel-Menge pro Zeile variiert? Sie müssen die Preise normalisieren, sodass Sie die Preise pro Bushel anzeigen. Führen Sie also einige Berechnungen durch, um dies zu standardisieren.
-
Fügen Sie diese Zeilen nach dem Block hinzu, der das
new_pumpkins-Dataframe erstellt:```python new_pumpkins.loc[new_pumpkins['Package'].str.contains('1 1/9'), 'Price'] = price/(1 + 1/9)
new_pumpkins.loc[new_pumpkins['Package'].str.contains('1/2'), 'Price'] = price/(1/2) ```
✅ Laut The Spruce Eats hängt das Gewicht eines Bushels von der Art des Produkts ab, da es sich um eine Volumenmessung handelt. "Ein Bushel Tomaten wiegt beispielsweise 56 Pfund... Blätter und Grünzeug nehmen mehr Platz mit weniger Gewicht ein, daher wiegt ein Bushel Spinat nur 20 Pfund." Das ist alles ziemlich kompliziert! Lassen Sie uns die Umrechnung von Bushel zu Pfund ignorieren und stattdessen den Preis pro Bushel berechnen. All diese Studien zu Bushels von Kürbissen zeigen jedoch, wie wichtig es ist, die Natur Ihrer Daten zu verstehen!
Nun können Sie die Preise pro Einheit basierend auf ihrer Bushel-Messung analysieren. Wenn Sie die Daten noch einmal ausgeben, sehen Sie, wie sie standardisiert wurden.
✅ Haben Sie bemerkt, dass Kürbisse, die nach dem halben Bushel verkauft werden, sehr teuer sind? Können Sie herausfinden, warum? Hinweis: Kleine Kürbisse sind viel teurer als große, wahrscheinlich weil es viel mehr davon pro Bushel gibt, da ein großer hohler Kürbis viel Platz einnimmt.
Visualisierungsstrategien
Ein Teil der Aufgabe eines Datenwissenschaftlers besteht darin, die Qualität und Beschaffenheit der Daten, mit denen er arbeitet, zu demonstrieren. Dazu erstellen sie oft interessante Visualisierungen, wie Diagramme, Grafiken und Charts, die verschiedene Aspekte der Daten zeigen. Auf diese Weise können sie Beziehungen und Lücken visuell darstellen, die sonst schwer zu erkennen wären.
> 🎥 Klicken Sie auf das Bild oben, um ein kurzes Video zur Visualisierung der Daten für diese Lektion anzusehen.
Visualisierungen können auch dabei helfen, die am besten geeignete Machine-Learning-Technik für die Daten zu bestimmen. Ein Streudiagramm, das einer Linie zu folgen scheint, deutet beispielsweise darauf hin, dass die Daten gut für eine lineare Regression geeignet sind.
Eine Datenvisualisierungsbibliothek, die gut in Jupyter-Notebooks funktioniert, ist Matplotlib (die Sie auch in der vorherigen Lektion gesehen haben).
> Erhalten Sie mehr Erfahrung mit der Datenvisualisierung in diesen Tutorials.
Übung - Experimentieren mit Matplotlib
Versuchen Sie, einige grundlegende Diagramme zu erstellen, um das neue Dataframe anzuzeigen, das Sie gerade erstellt haben. Was würde ein einfaches Liniendiagramm zeigen?
-
Importieren Sie Matplotlib am Anfang der Datei, unter dem Pandas-Import:
python import matplotlib.pyplot as plt -
Führen Sie das gesamte Notebook erneut aus, um es zu aktualisieren.
-
Fügen Sie am Ende des Notebooks eine Zelle hinzu, um die Daten als Box-Diagramm darzustellen:
python price = new_pumpkins.Price month = new_pumpkins.Month plt.scatter(price, month) plt.show()
Ist dies ein nützliches Diagramm? Überrascht Sie etwas daran?
Es ist nicht besonders nützlich, da es nur die Verteilung Ihrer Daten in einem bestimmten Monat anzeigt.
Machen Sie es nützlich
Um Diagramme nützlich zu machen, müssen Sie die Daten in der Regel irgendwie gruppieren. Versuchen wir, ein Diagramm zu erstellen, bei dem die y-Achse die Monate zeigt und die Daten die Verteilung darstellen.
-
Fügen Sie eine Zelle hinzu, um ein gruppiertes Balkendiagramm zu erstellen:
python new_pumpkins.groupby(['Month'])['Price'].mean().plot(kind='bar') plt.ylabel("Pumpkin Price")
Dies ist eine nützlichere Datenvisualisierung! Es scheint darauf hinzudeuten, dass die höchsten Preise für Kürbisse im September und Oktober auftreten. Entspricht das Ihrer Erwartung? Warum oder warum nicht?
🚀 Herausforderung
Erforschen Sie die verschiedenen Arten von Visualisierungen, die Matplotlib bietet. Welche Arten sind am besten für Regressionsprobleme geeignet?
Quiz nach der Lektion
Rückblick & Selbststudium
Schauen Sie sich die vielen Möglichkeiten zur Datenvisualisierung an. Erstellen Sie eine Liste der verschiedenen verfügbaren Bibliotheken und notieren Sie, welche für bestimmte Aufgaben am besten geeignet sind, z. B. 2D-Visualisierungen vs. 3D-Visualisierungen. Was entdecken Sie?
Aufgabe
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
import pandas as pd
import matplotlib.pyplot as plt
pumpkins = pd.read_csv('../../data/US-pumpkins.csv')
pumpkins = pumpkins[pumpkins['Package'].str.contains('bushel', case=True, regex=True)]
pumpkins.head()
pumpkins.isnull().sum()
# A set of new columns for a new dataframe. Filter out nonmatching columns
columns_to_select = ['Package', 'Low Price', 'High Price', 'Date']
pumpkins = pumpkins.loc[:, columns_to_select]
# Get an average between low and high price for the base pumpkin price
price = (pumpkins['Low Price'] + pumpkins['High Price']) / 2
# Convert the date to its month only
month = pd.DatetimeIndex(pumpkins['Date']).month
# Create a new dataframe with this basic data
new_pumpkins = pd.DataFrame({'Month': month, 'Package': pumpkins['Package'], 'Low Price': pumpkins['Low Price'],'High Price': pumpkins['High Price'], 'Price': price})
# Convert the price if the Package contains fractional bushel values
new_pumpkins.loc[new_pumpkins['Package'].str.contains('1 1/9'), 'Price'] = price/(1 + 1/9)
new_pumpkins.loc[new_pumpkins['Package'].str.contains('1/2'), 'Price'] = price/(1/2)
print(new_pumpkins)
price = new_pumpkins.Price
month = new_pumpkins.Month
plt.scatter(price, month)
plt.show()
new_pumpkins.groupby(['Month'])['Price'].mean().plot(kind='bar')
plt.ylabel("Pumpkin Price")
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erstellen eines Regressionsmodells: Daten vorbereiten und visualisieren
Lineare Regression für Kürbisse - Lektion 2
Einführung
Jetzt, da Sie mit den Werkzeugen ausgestattet sind, die Sie für den Einstieg in den Aufbau von Machine-Learning-Modellen mit Tidymodels und dem Tidyverse benötigen, können Sie beginnen, Fragen an Ihre Daten zu stellen. Wenn Sie mit Daten arbeiten und ML-Lösungen anwenden, ist es äußerst wichtig, zu verstehen, wie man die richtigen Fragen stellt, um das Potenzial Ihres Datensatzes vollständig auszuschöpfen.
In dieser Lektion lernen Sie:
-
Wie Sie Ihre Daten für den Modellaufbau vorbereiten.
-
Wie Sie
ggplot2für die Datenvisualisierung nutzen.
Die Frage, die Sie beantwortet haben möchten, bestimmt, welche Art von ML-Algorithmen Sie verwenden werden. Und die Qualität der Antwort, die Sie erhalten, hängt stark von der Beschaffenheit Ihrer Daten ab.
Lassen Sie uns dies anhand einer praktischen Übung genauer betrachten.
<p > <img src="../../images/unruly_data.jpg" width="700"/> <figcaption>Kunstwerk von @allison_horst</figcaption>
<!--
<br>Kunstwerk von \@allison_horst-->
1. Importieren von Kürbisdaten und Aufrufen des Tidyverse
Wir benötigen die folgenden Pakete, um diese Lektion zu bearbeiten:
tidyverse: Das tidyverse ist eine Sammlung von R-Paketen, die darauf ausgelegt ist, Datenwissenschaft schneller, einfacher und unterhaltsamer zu machen!
Sie können sie wie folgt installieren:
install.packages(c("tidyverse"))
Das untenstehende Skript überprüft, ob Sie die für dieses Modul benötigten Pakete haben, und installiert sie für Sie, falls einige fehlen.
suppressWarnings(if(!require("pacman")) install.packages("pacman"))
pacman::p_load(tidyverse)
Lassen Sie uns nun einige Pakete starten und die Daten laden, die für diese Lektion bereitgestellt wurden!
# Load the core Tidyverse packages
library(tidyverse)
# Import the pumpkins data
pumpkins <- read_csv(file = "https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv")
# Get a glimpse and dimensions of the data
glimpse(pumpkins)
# Print the first 50 rows of the data set
pumpkins %>%
slice_head(n =50)
Ein schneller glimpse() zeigt sofort, dass es Lücken gibt und eine Mischung aus Zeichenketten (chr) und numerischen Daten (dbl). Das Date-Feld ist vom Typ Zeichenkette, und es gibt auch eine seltsame Spalte namens Package, in der die Daten eine Mischung aus sacks, bins und anderen Werten sind. Die Daten sind, ehrlich gesagt, ein bisschen chaotisch 😤.
Tatsächlich ist es nicht sehr häufig, ein Datenset zu erhalten, das vollständig einsatzbereit ist, um direkt ein ML-Modell daraus zu erstellen. Aber keine Sorge, in dieser Lektion wirst du lernen, wie man ein rohes Datenset mit Standardbibliotheken in R vorbereitet 🧑🔧. Außerdem wirst du verschiedene Techniken zur Visualisierung der Daten kennenlernen. 📈📊 <br>
> Eine Auffrischung: Der Pipe-Operator (%>%) führt Operationen in logischer Reihenfolge aus, indem er ein Objekt an eine Funktion oder einen Ausdruck weiterleitet. Du kannst den Pipe-Operator so verstehen, als würdest du in deinem Code "und dann" sagen.
2. Überprüfung auf fehlende Daten
Eines der häufigsten Probleme, mit denen Datenwissenschaftler umgehen müssen, sind unvollständige oder fehlende Daten. R stellt fehlende oder unbekannte Werte mit einem speziellen Platzhalter dar: NA (Not Available).
Wie können wir also feststellen, ob der Data Frame fehlende Werte enthält?
<br>
- Eine einfache Möglichkeit wäre die Verwendung der Basis-R-Funktion anyNA, die die logischen Werte TRUE oder FALSE zurückgibt.
pumpkins %>%
anyNA()
Super, es scheint, als ob einige Daten fehlen! Das ist ein guter Ausgangspunkt.
- Eine andere Möglichkeit wäre, die Funktion
is.na()zu verwenden, die anzeigt, welche einzelnen Spaltenelemente mit einem logischenTRUEfehlen.
pumpkins %>%
is.na() %>%
head(n = 7)
Okay, erledigt, aber bei einem so großen Dataframe wie diesem wäre es ineffizient und praktisch unmöglich, alle Zeilen und Spalten einzeln zu überprüfen😴.
- Eine intuitivere Methode wäre, die Summe der fehlenden Werte für jede Spalte zu berechnen:
pumpkins %>%
is.na() %>%
colSums()
Viel besser! Es fehlen einige Daten, aber vielleicht spielt das für die Aufgabe keine Rolle. Mal sehen, welche weiteren Analysen Ergebnisse bringen.
> Neben den großartigen Paketen und Funktionen verfügt R über eine sehr gute Dokumentation. Zum Beispiel können Sie help(colSums) oder ?colSums verwenden, um mehr über die Funktion zu erfahren.
3. Dplyr: Eine Grammatik für Datenmanipulation
<p> <img src="../../images/dplyr_wrangling.png" width="569"/> <figcaption>Illustration von @allison_horst</figcaption>
<!--
<br/>Illustration von \@allison_horst-->
dplyr, ein Paket im Tidyverse, ist eine Grammatik für Datenmanipulation, die eine einheitliche Sammlung von Verben bereitstellt, um die häufigsten Herausforderungen bei der Datenmanipulation zu lösen. In diesem Abschnitt werden wir einige der Verben von dplyr erkunden!
<br>
dplyr::select()
select() ist eine Funktion aus dem Paket dplyr, mit der du Spalten auswählen kannst, die du behalten oder ausschließen möchtest.
Um deinen Data Frame übersichtlicher zu gestalten, kannst du mit select() mehrere Spalten entfernen und nur die behalten, die du benötigst.
Zum Beispiel werden wir in dieser Übung die Spalten Package, Low Price, High Price und Date für unsere Analyse verwenden. Lass uns diese Spalten auswählen.
# Select desired columns
pumpkins <- pumpkins %>%
select(Package, `Low Price`, `High Price`, Date)
# Print data set
pumpkins %>%
slice_head(n = 5)
dplyr::mutate()
mutate() ist eine Funktion im Paket dplyr, mit der Sie Spalten erstellen oder ändern können, während die bestehenden Spalten erhalten bleiben.
Die allgemeine Struktur von mutate lautet:
data %>% mutate(new_column_name = what_it_contains)
Lassen Sie uns mutate ausprobieren, indem wir die Spalte Date verwenden und die folgenden Operationen durchführen:
-
Konvertieren Sie die Daten (derzeit vom Typ Zeichenkette) in ein Monatsformat (es handelt sich um US-Daten, das Format ist also
MM/DD/YYYY). -
Extrahieren Sie den Monat aus den Daten in eine neue Spalte.
Im R-Paket lubridate wird die Arbeit mit Datums- und Zeitdaten erleichtert. Also verwenden wir dplyr::mutate(), lubridate::mdy(), lubridate::month() und schauen, wie wir die oben genannten Ziele erreichen können. Wir können die Spalte Date entfernen, da wir sie in den nachfolgenden Operationen nicht mehr benötigen.
# Load lubridate
library(lubridate)
pumpkins <- pumpkins %>%
# Convert the Date column to a date object
mutate(Date = mdy(Date)) %>%
# Extract month from Date
mutate(Month = month(Date)) %>%
# Drop Date column
select(-Date)
# View the first few rows
pumpkins %>%
slice_head(n = 7)
Woohoo! 🤩
Als Nächstes erstellen wir eine neue Spalte Price, die den Durchschnittspreis eines Kürbisses darstellt. Jetzt berechnen wir den Durchschnitt der Spalten Low Price und High Price, um die neue Spalte Price zu füllen.
<br>
# Create a new column Price
pumpkins <- pumpkins %>%
mutate(Price = (`Low Price` + `High Price`)/2)
# View the first few rows of the data
pumpkins %>%
slice_head(n = 5)
Yeees!💪
„Aber Moment mal!“, wirst du sagen, nachdem du das gesamte Datenset mit View(pumpkins) durchgesehen hast, „Hier stimmt doch etwas nicht!“🤔
Wenn du dir die Spalte Package ansiehst, werden Kürbisse in vielen verschiedenen Konfigurationen verkauft. Einige werden in 1 1/9 bushel-Maßen verkauft, andere in 1/2 bushel-Maßen, einige pro Kürbis, einige pro Pfund und einige in großen Kisten mit unterschiedlichen Breiten.
Lass uns das überprüfen:
# Verify the distinct observations in Package column
pumpkins %>%
distinct(Package)
Erstaunlich!👏
Kürbisse scheinen sehr schwer konsistent zu wiegen zu sein, daher filtern wir sie, indem wir nur Kürbisse mit dem String bushel in der Spalte Package auswählen und diese in einen neuen Dataframe new_pumpkins speichern.
<br>
dplyr::filter() und stringr::str_detect()
dplyr::filter(): erstellt eine Teilmenge der Daten, die nur Zeilen enthält, die Ihre Bedingungen erfüllen, in diesem Fall Kürbisse mit dem String bushel in der Spalte Package.
stringr::str_detect(): erkennt das Vorhandensein oder Fehlen eines Musters in einem String.
Das stringr-Paket bietet einfache Funktionen für gängige String-Operationen.
# Retain only pumpkins with "bushel"
new_pumpkins <- pumpkins %>%
filter(str_detect(Package, "bushel"))
# Get the dimensions of the new data
dim(new_pumpkins)
# View a few rows of the new data
new_pumpkins %>%
slice_head(n = 5)
Du kannst sehen, dass wir uns auf etwa 415 Zeilen Daten beschränkt haben, die Kürbisse in großen Mengen enthalten. 🤩 <br>
dplyr::case_when()
Aber Moment! Es gibt noch etwas zu tun
Hast du bemerkt, dass die Menge pro Scheffel je nach Zeile variiert? Du musst die Preise normalisieren, sodass sie pro Scheffel angezeigt werden und nicht pro 1 1/9 oder 1/2 Scheffel. Zeit für etwas Mathematik, um das zu standardisieren.
Wir verwenden die Funktion case_when(), um die Spalte "Price" je nach bestimmten Bedingungen zu mutieren. case_when ermöglicht es, mehrere if_else()-Anweisungen zu vektorisieren.
# Convert the price if the Package contains fractional bushel values
new_pumpkins <- new_pumpkins %>%
mutate(Price = case_when(
str_detect(Package, "1 1/9") ~ Price/(1 + 1/9),
str_detect(Package, "1/2") ~ Price/(1/2),
TRUE ~ Price))
# View the first few rows of the data
new_pumpkins %>%
slice_head(n = 30)
Jetzt können wir die Preise pro Einheit basierend auf ihrer Buschel-Messung analysieren. All diese Untersuchung der Kürbis-Buschel zeigt jedoch, wie wichtig es ist, die Natur Ihrer Daten zu verstehen!
> ✅ Laut The Spruce Eats hängt das Gewicht eines Buschels von der Art des Produkts ab, da es sich um eine Volumenmessung handelt. "Ein Buschel Tomaten soll beispielsweise 56 Pfund wiegen... Blätter und Grünzeug nehmen mehr Platz mit weniger Gewicht ein, sodass ein Buschel Spinat nur 20 Pfund wiegt." Das ist alles ziemlich kompliziert! Lassen wir die Umrechnung von Buschel zu Pfund beiseite und setzen stattdessen den Preis pro Buschel an. All diese Untersuchung der Kürbis-Buschel zeigt jedoch, wie wichtig es ist, die Natur Ihrer Daten zu verstehen! > > ✅ Ist Ihnen aufgefallen, dass Kürbisse, die pro halbem Buschel verkauft werden, sehr teuer sind? Können Sie herausfinden, warum? Hinweis: Kleine Kürbisse sind viel teurer als große, wahrscheinlich weil es viel mehr von ihnen pro Buschel gibt, da der ungenutzte Raum von einem großen hohlen Kuchen-Kürbis eingenommen wird.
Nun, zum Schluss, einfach aus Abenteuerlust 💁♀️, verschieben wir die Spalte "Month" an die erste Position, also vor die Spalte "Package".
dplyr::relocate() wird verwendet, um die Position von Spalten zu ändern.
# Create a new data frame new_pumpkins
new_pumpkins <- new_pumpkins %>%
relocate(Month, .before = Package)
new_pumpkins %>%
slice_head(n = 7)
Gute Arbeit! 👌 Du hast jetzt einen sauberen, aufgeräumten Datensatz, mit dem du dein neues Regressionsmodell erstellen kannst!
<br>
4. Datenvisualisierung mit ggplot2
<p > <img src="../../images/data-visualization.png" width="600"/> <figcaption>Infografik von Dasani Madipalli</figcaption>
<!--
{width="600"}-->
Es gibt ein weises Sprichwort, das so lautet:
> "Das einfache Diagramm hat dem Datenanalysten mehr Informationen geliefert als jedes andere Hilfsmittel." --- John Tukey
Ein Teil der Aufgabe eines Data Scientists besteht darin, die Qualität und die Eigenschaften der Daten, mit denen er arbeitet, zu demonstrieren. Dazu erstellen sie oft interessante Visualisierungen, wie Diagramme, Grafiken und Charts, die verschiedene Aspekte der Daten zeigen. Auf diese Weise können sie Beziehungen und Lücken visuell darstellen, die sonst schwer zu erkennen wären.
Visualisierungen können auch dabei helfen, die am besten geeignete Machine-Learning-Technik für die Daten zu bestimmen. Ein Streudiagramm, das einer Linie zu folgen scheint, deutet beispielsweise darauf hin, dass die Daten gut für eine lineare Regression geeignet sind.
R bietet mehrere Systeme zur Erstellung von Grafiken, aber ggplot2 ist eines der elegantesten und vielseitigsten. Mit ggplot2 können Sie Grafiken erstellen, indem Sie unabhängige Komponenten kombinieren.
Beginnen wir mit einem einfachen Streudiagramm für die Spalten Price und Month.
In diesem Fall starten wir mit ggplot(), geben einen Datensatz und eine ästhetische Zuordnung (mit aes()) an und fügen dann Schichten hinzu (wie geom_point()) für Streudiagramme.
# Set a theme for the plots
theme_set(theme_light())
# Create a scatter plot
p <- ggplot(data = new_pumpkins, aes(x = Price, y = Month))
p + geom_point()
Ist das ein nützlicher Plot 🤷? Überrascht dich irgendetwas daran?
Er ist nicht besonders nützlich, da er lediglich deine Daten als eine Ansammlung von Punkten in einem bestimmten Monat darstellt. <br>
Wie machen wir es nützlich?
Um Diagramme mit nützlichen Daten anzuzeigen, müssen die Daten normalerweise irgendwie gruppiert werden. In unserem Fall würde beispielsweise das Ermitteln des Durchschnittspreises von Kürbissen für jeden Monat mehr Einblicke in die zugrunde liegenden Muster unserer Daten liefern. Das führt uns zu einem weiteren dplyr-Überblick:
dplyr::group_by() %>% summarize()
Gruppierte Aggregationen in R können einfach berechnet werden mit
dplyr::group_by() %>% summarize()
-
dplyr::group_by()ändert die Analyseebene von dem gesamten Datensatz zu einzelnen Gruppen, wie beispielsweise pro Monat. -
dplyr::summarize()erstellt einen neuen Dataframe mit einer Spalte für jede Gruppierungsvariable und einer Spalte für jede der angegebenen Zusammenfassungsstatistiken.
Zum Beispiel können wir dplyr::group_by() %>% summarize() verwenden, um die Kürbisse basierend auf der Monat-Spalte zu gruppieren und dann den Durchschnittspreis für jeden Monat zu berechnen.
# Find the average price of pumpkins per month
new_pumpkins %>%
group_by(Month) %>%
summarise(mean_price = mean(Price))
Knapp und bündig!✨
Kategorische Merkmale wie Monate werden besser mit einem Balkendiagramm 📊 dargestellt. Die Ebenen, die für Balkendiagramme zuständig sind, sind geom_bar() und geom_col(). Sieh dir ?geom_bar an, um mehr zu erfahren.
Lass uns eins erstellen!
# Find the average price of pumpkins per month then plot a bar chart
new_pumpkins %>%
group_by(Month) %>%
summarise(mean_price = mean(Price)) %>%
ggplot(aes(x = Month, y = mean_price)) +
geom_col(fill = "midnightblue", alpha = 0.7) +
ylab("Pumpkin Price")
🤩🤩 Dies ist eine nützlichere Datenvisualisierung! Sie scheint darauf hinzudeuten, dass die höchsten Preise für Kürbisse im September und Oktober auftreten. Entspricht das deinen Erwartungen? Warum oder warum nicht?
Herzlichen Glückwunsch zum Abschluss der zweiten Lektion 👏! Du hast deine Daten für den Modellaufbau vorbereitet und anschließend weitere Erkenntnisse mithilfe von Visualisierungen gewonnen!
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erstellen eines Regressionsmodells
Anweisungen
In dieser Lektion wurde gezeigt, wie man ein Modell mit sowohl linearer als auch polynomialer Regression erstellt. Nutzen Sie dieses Wissen, um einen Datensatz zu finden oder einen der integrierten Datensätze von Scikit-learn zu verwenden, um ein neues Modell zu erstellen. Erklären Sie in Ihrem Notebook, warum Sie die gewählte Technik verwendet haben, und demonstrieren Sie die Genauigkeit Ihres Modells. Falls es nicht genau ist, erklären Sie, warum.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| präsentiert ein vollständiges Notebook mit einer gut dokumentierten Lösung | die Lösung ist unvollständig | die Lösung ist fehlerhaft oder fehleranfällig |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Kürbispreise
Lade die benötigten Bibliotheken und den Datensatz. Konvertiere die Daten in ein DataFrame, das einen Teil der Daten enthält:
- Nur Kürbisse auswählen, die pro Scheffel bepreist sind
- Das Datum in einen Monat umwandeln
- Den Preis als Durchschnitt aus Höchst- und Tiefstpreisen berechnen
- Den Preis so umrechnen, dass er die Bepreisung pro Scheffelmenge widerspiegelt
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
pumpkins = pd.read_csv('../data/US-pumpkins.csv')
pumpkins.head()
pumpkins = pumpkins[pumpkins['Package'].str.contains('bushel', case=True, regex=True)]
columns_to_select = ['Package', 'Variety', 'City Name', 'Low Price', 'High Price', 'Date']
pumpkins = pumpkins.loc[:, columns_to_select]
price = (pumpkins['Low Price'] + pumpkins['High Price']) / 2
month = pd.DatetimeIndex(pumpkins['Date']).month
day_of_year = pd.to_datetime(pumpkins['Date']).apply(lambda dt: (dt-datetime(dt.year,1,1)).days)
new_pumpkins = pd.DataFrame(
{'Month': month,
'DayOfYear' : day_of_year,
'Variety': pumpkins['Variety'],
'City': pumpkins['City Name'],
'Package': pumpkins['Package'],
'Low Price': pumpkins['Low Price'],
'High Price': pumpkins['High Price'],
'Price': price})
new_pumpkins.loc[new_pumpkins['Package'].str.contains('1 1/9'), 'Price'] = price/1.1
new_pumpkins.loc[new_pumpkins['Package'].str.contains('1/2'), 'Price'] = price*2
new_pumpkins.head()
Ein einfaches Streudiagramm erinnert uns daran, dass wir nur Monatsdaten von August bis Dezember haben. Wir benötigen wahrscheinlich mehr Daten, um Schlussfolgerungen auf lineare Weise ziehen zu können.
import matplotlib.pyplot as plt
plt.scatter('Month','Price',data=new_pumpkins)
plt.scatter('DayOfYear','Price',data=new_pumpkins)
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erstelle ein Regressionsmodell mit Scikit-learn: Regression auf vier Arten
Anmerkung für Anfänger
Lineare Regression wird verwendet, wenn wir einen numerischen Wert vorhersagen möchten (zum Beispiel Hauspreis, Temperatur oder Umsatz). Sie funktioniert, indem sie eine Gerade findet, die die Beziehung zwischen Eingabemerkmalen und Ausgabe bestmöglich darstellt.
In dieser Lektion konzentrieren wir uns darauf, das Konzept zu verstehen, bevor wir fortgeschrittenere Regressionstechniken erkunden.
> Infografik von Dasani Madipalli
Vorlesungsquiz
> ### Diese Lektion ist auch in R verfügbar!
Einführung
Bis jetzt hast du erkundet, was Regression ist, anhand von Beispieldaten aus dem Kürbis-Preis-Datensatz, den wir in dieser Lektion verwenden werden. Du hast ihn auch mit Matplotlib visualisiert.
Jetzt bist du bereit, tiefer in Regression für ML einzutauchen. Während die Visualisierung dabei hilft, die Daten zu verstehen, liegt die wahre Stärke von Machine Learning im Trainieren von Modellen. Modelle werden auf historischen Daten trainiert, um Datenabhängigkeiten automatisch zu erfassen, und ermöglichen es, Vorhersagen für neue Daten zu machen, die das Modell vorher nicht gesehen hat.
In dieser Lektion lernst du mehr über zwei Arten der Regression: einfache lineare Regression und polynomiale Regression sowie einige der Mathematik, die diesen Techniken zugrunde liegt. Diese Modelle werden uns erlauben, Kürbisse je nach unterschiedlichen Eingabedaten vorherzusagen.
> 🎥 Klicke auf das Bild oben für eine kurze Videoübersicht zur linearen Regression.
> Im gesamten Lehrplan gehen wir von minimalen mathematischen Vorkenntnissen aus und möchten es für Studierende aus anderen Fachrichtungen zugänglich machen. Achte also auf Anmerkungen, 🧮 Hervorhebungen, Diagramme und andere Lernhilfen zur Unterstützung des Verständnisses.
Voraussetzungen
Du solltest jetzt mit der Struktur der Kürbisdaten vertraut sein, die wir untersuchen. Du findest sie vorab geladen und bereinigt in der Datei notebook.ipynb dieser Lektion. Dort wird der Kürbisp steht pro Bushel in einem neuen DataFrame angezeigt. Stelle sicher, dass du diese Notebooks in Visual Studio Code in passenden Umgebungen ausführen kannst.
Vorbereitung
Zur Erinnerung: Du lädst diese Daten, um Fragen an sie stellen zu können.
- Wann ist die beste Zeit, Kürbisse zu kaufen?
- Welchen Preis kann ich für eine Kiste mit Mini-Kürbissen erwarten?
- Sollte ich sie in halben Bushel-Körben oder im 1 1/9 Bushel-Karton kaufen? Lass uns weiter in diese Daten eintauchen.
In der vorherigen Lektion hast du ein Pandas DataFrame erstellt und mit einem Teil des ursprünglichen Datensatzes gefüllt, wobei die Preise pro Bushel standardisiert wurden. Dadurch konntest du jedoch nur etwa 400 Datenpunkte und nur für die Herbstmonate erfassen.
Betrachte die Daten, die wir in dem Notebook dieser Lektion vorab geladen haben. Die Daten sind vorab geladen und ein erster Streudiagramm wird gezeichnet, um Monatsdaten zu zeigen. Vielleicht können wir mehr Details über die Natur der Daten erhalten, wenn wir sie weiter bereinigen.
Eine Linie der linearen Regression
Wie du in Lektion 1 gelernt hast, ist das Ziel einer linearen Regression, eine Linie zu zeichnen, um:
- Variablenbeziehungen zu zeigen. Die Beziehung zwischen Variablen darstellen
- Vorhersagen zu machen. Genau vorhersagen, wo ein neuer Datenpunkt in Bezug auf diese Linie liegen würde.
Typisch für die Methode der kleinsten Quadrate ist es, diese Art von Linie zu zeichnen. Der Begriff "Methode der kleinsten Quadrate" bezieht sich auf den Prozess, den Gesamtfehler in unserem Modell zu minimieren. Für jeden Datenpunkt messen wir den vertikalen Abstand (genannt Residuum) zwischen dem tatsächlichen Punkt und unserer Regressionslinie.
Wir quadrieren diese Abstände aus zwei Hauptgründen:
-
Betrag statt Richtung: Wir möchten einen Fehler von -5 genauso behandeln wie einen Fehler von +5. Das Quadrieren macht alle Werte positiv.
-
Bestrafung von Ausreißern: Das Quadrieren gibt größeren Fehlern mehr Gewicht, wodurch die Linie gezwungen wird, näher an weit entfernten Punkten zu bleiben.
Dann addieren wir alle quadrierten Werte zusammen. Unser Ziel ist es, genau die Linie zu finden, bei der diese Summe am geringsten ist – daher der Name "Methode der kleinsten Quadrate".
> 🧮 Zeig mir die Mathematik
>
> Diese Linie, genannt Line of Best Fit, kann durch eine Gleichung ausgedrückt werden:
>
> > Y = a + bX
>
>
> X ist die „erklärende Variable“. Y ist die „abhängige Variable“. Die Steigung der Linie ist b und a ist der y-Achsenabschnitt, also der Wert von Y, wenn X = 0 ist.
>
>
>
> Zuerst berechne die Steigung b. Infografik von Jen Looper
>
> Anders ausgedrückt, und bezogen auf die ursprüngliche Frage unserer Kürbisdaten: "Vorhersage des Preises eines Kürbisses pro Bushel nach Monat", würde X den Preis darstellen und Y den Verkaufsmonat.
>
>
>
> Berechne den Wert von Y. Wenn du etwa $4 zahlst, muss es April sein! Infografik von Jen Looper
>
> Die Rechnung, die die Linie berechnet, muss die Steigung der Linie zeigen, die auch vom Achsenabschnitt abhängt, also von dem Punkt, an dem Y liegt, wenn X = 0 ist.
>
> Du kannst die Berechnungsmethode für diese Werte auf der Website Math is Fun nachlesen. Besuche auch diesen Least-Squares-Rechner, um zu sehen, wie die Werte die Linie beeinflussen.
Korrelation
Ein weiterer Begriff, den du verstehen solltest, ist der Korrelationskoeffizient zwischen bestimmten X- und Y-Variablen. Mit einem Streudiagramm kannst du diesen Koeffizienten schnell visualisieren. Ein Diagramm mit Datenpunkten, die sich in einer geordneten Linie anordnen, hat eine hohe Korrelation, während ein Diagramm mit verstreuten Punkten zwischen X und Y eine niedrige Korrelation aufweist.
Ein gutes lineares Regressionsmodell hat einen hohen (näher bei 1 als bei 0) Korrelationskoeffizienten, wenn die Methode der kleinsten Quadrate mit einer Regressionslinie verwendet wird.
✅ Führe das zu dieser Lektion gehörende Notebook aus und sieh dir das Streudiagramm Monat zu Preis an. Hat die Datenzuordnung von Monat zu Preis für Kürbisverkäufe deiner visuellen Interpretation nach eine hohe oder niedrige Korrelation? Ändert sich das, wenn du statt Monat eine feinere Maßeinheit wie Tag des Jahres (z.B. Anzahl der Tage seit Jahresbeginn) verwendest?
Im folgenden Code gehen wir davon aus, dass wir die Daten bereinigt und einen DataFrame mit dem Namen new_pumpkins erhalten haben, ähnlich dem Folgenden:
| ID | Monat | TagDesJahres | Sorte | Stadt | Verpackung | Niedriger Preis | Hoher Preis | Preis |
|---|---|---|---|---|---|---|---|---|
| 70 | 9 | 267 | PIE TYPE | BALTIMORE | 1 1/9 Bushel Kartons | 15.0 | 15.0 | 13.636364 |
| 71 | 9 | 267 | PIE TYPE | BALTIMORE | 1 1/9 Bushel Kartons | 18.0 | 18.0 | 16.363636 |
| 72 | 10 | 274 | PIE TYPE | BALTIMORE | 1 1/9 Bushel Kartons | 18.0 | 18.0 | 16.363636 |
| 73 | 10 | 274 | PIE TYPE | BALTIMORE | 1 1/9 Bushel Kartons | 17.0 | 17.0 | 15.454545 |
| 74 | 10 | 281 | PIE TYPE | BALTIMORE | 1 1/9 Bushel Kartons | 15.0 | 15.0 | 13.636364 |
> Der Code zum Bereinigen der Daten ist in notebook.ipynb verfügbar. Wir haben die gleichen Bereinigungsschritte wie in der vorherigen Lektion durchgeführt und die Spalte DayOfYear mit folgendem Ausdruck berechnet:
day_of_year = pd.to_datetime(pumpkins['Date']).apply(lambda dt: (dt-datetime(dt.year,1,1)).days)
Nachdem du die Mathematik hinter der linearen Regression verstanden hast, erstellen wir nun ein Regressionsmodell, um zu sehen, ob wir vorhersagen können, welches Kürbis-Paket die besten Preise hat. Jemand, der Kürbisse für einen Feiertag-Kürbisgarten kauft, möchte diese Information möglicherweise nutzen, um seine Kürbiskäufe zu optimieren.
Suche nach Korrelation
> 🎥 Klicke auf das Bild oben für eine kurze Videoübersicht über Korrelation.
Aus der vorherigen Lektion hast du wahrscheinlich gesehen, dass der Durchschnittspreis für verschiedene Monate so aussieht:
<img alt="Average price by month" src="../../../../translated_images/de/barchart.a833ea9194346d76.webp" width="50%"/>
Das deutet darauf hin, dass es eine Korrelation geben sollte, und wir können versuchen, ein lineares Regressionsmodell zu trainieren, um die Beziehung zwischen Monat und Preis oder zwischen DayOfYear und Preis vorherzusagen. Hier ist das Streudiagramm, das die letztere Beziehung zeigt:
<img alt="Scatter plot of Price vs. Day of Year" src="../../../../translated_images/de/scatter-dayofyear.bc171c189c9fd553.webp" width="50%" />
Sehen wir uns die Korrelation mit der corr Funktion an:
print(new_pumpkins['Month'].corr(new_pumpkins['Price']))
print(new_pumpkins['DayOfYear'].corr(new_pumpkins['Price']))
Es scheint, dass die Korrelation ziemlich gering ist, -0,15 bei Monat und -0,17 bei DayOfYear, aber es könnte eine andere wichtige Beziehung geben. Es sieht so aus, als gäbe es verschiedene Preiscluster, die unterschiedlichen Kürbissorten entsprechen. Um diese Hypothese zu bestätigen, zeichnen wir jede Kürbiskategorie mit einer anderen Farbe. Indem wir der scatter Funktion einen ax Parameter übergeben, können wir alle Punkte im gleichen Diagramm darstellen:
ax=None
colors = ['red','blue','green','yellow']
for i,var in enumerate(new_pumpkins['Variety'].unique()):
df = new_pumpkins[new_pumpkins['Variety']==var]
ax = df.plot.scatter('DayOfYear','Price',ax=ax,c=colors[i],label=var)
<img alt="Scatter plot of Price vs. Day of Year" src="../../../../translated_images/de/scatter-dayofyear-color.65790faefbb9d54f.webp" width="50%" />
Unsere Untersuchung legt nahe, dass die Sorte mehr Einfluss auf den Gesamtpreis hat als das tatsächliche Verkaufsdatum. Das können wir mit einem Balkendiagramm sehen:
new_pumpkins.groupby('Variety')['Price'].mean().plot(kind='bar')
<img alt="Bar graph of price vs variety" src="../../../../translated_images/de/price-by-variety.744a2f9925d9bcb4.webp" width="50%" />
Konzentrieren wir uns nun nur auf eine Kürbissorte, den 'Pie Type', und sehen uns den Einfluss des Datums auf den Preis an:
pie_pumpkins = new_pumpkins[new_pumpkins['Variety']=='PIE TYPE']
pie_pumpkins.plot.scatter('DayOfYear','Price')
<img alt="Scatter plot of Price vs. Day of Year" src="../../../../translated_images/de/pie-pumpkins-scatter.d14f9804a53f927e.webp" width="50%" />
Wenn wir jetzt die Korrelation zwischen Preis und DayOfYear mit der corr Funktion berechnen, erhalten wir ungefähr -0,27 – was bedeutet, dass es sinnvoll ist, ein Vorhersagemodell zu trainieren.
> Bevor du ein lineares Regressionsmodell trainierst, ist es wichtig sicherzustellen, dass unsere Daten sauber sind. Lineare Regression funktioniert schlecht mit fehlenden Werten, daher ist es sinnvoll, leere Zellen zu entfernen:
pie_pumpkins.dropna(inplace=True)
pie_pumpkins.info()
Eine andere Möglichkeit wäre, diese leeren Werte mit Mittelwerten der jeweiligen Spalte zu füllen.
Einfache lineare Regression
> 🎥 Klicke auf das Bild oben für eine kurze Videoübersicht zu linearer und polynomialer Regression.
Um unser Modell der linearen Regression zu trainieren, verwenden wir die Scikit-learn-Bibliothek.
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
Wir beginnen, indem wir Eingabewerte (Features) und die erwartete Ausgabe (Label) in getrennte Numpy-Arrays aufteilen:
X = pie_pumpkins['DayOfYear'].to_numpy().reshape(-1,1)
y = pie_pumpkins['Price']
> Beachte, dass wir die Eingabedaten mittels reshape umformen mussten, damit das Linear Regression-Paket sie korrekt versteht. Lineare Regression erwartet ein 2D-Array als Eingabe, wobei jede Zeile des Arrays einem Vektor von Eingabewerten entspricht. In unserem Fall, da wir nur ein Eingabewert haben, brauchen wir ein Array mit der Form N×1, wobei N die Größe des Datensatzes ist.
Dann müssen wir die Daten in Trainings- und Testdatensätze aufteilen, damit wir unser Modell nach dem Training validieren können:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
Schließlich dauert das eigentliche Training des linearen Regressionsmodells nur zwei Codezeilen. Wir definieren das LinearRegression-Objekt und passen es mit der fit-Methode an unsere Daten an:
lin_reg = LinearRegression()
lin_reg.fit(X_train,y_train)
Das LinearRegression-Objekt enthält nach dem fit-ten alle Koeffizienten der Regression, auf die über die Eigenschaft .coef_ zugegriffen werden kann. In unserem Fall gibt es nur einen Koeffizienten, der ungefähr -0,017 betragen sollte. Das bedeutet, dass die Preise mit der Zeit etwas zu sinken scheinen, aber nicht zu stark, ungefähr 2 Cent pro Tag. Wir können auch den Schnittpunkt der Regression mit der Y-Achse mithilfe von lin_reg.intercept_ abrufen – dieser wird in unserem Fall etwa 21 betragen und zeigt den Preis am Anfang des Jahres an.
Um zu sehen, wie genau unser Modell ist, können wir Preise in einem Testdatensatz vorhersagen und dann messen, wie nah unsere Vorhersagen an den erwarteten Werten sind. Dies kann mittels Root Mean Square Error (RMSE) geschehen, das die Wurzel aus dem Mittelwert aller quadrierten Differenzen zwischen erwartetem und vorhergesagtem Wert ist.
pred = lin_reg.predict(X_test)
rmse = np.sqrt(mean_squared_error(y_test,pred))
print(f'RMSE: {rmse:3.3} ({rmse/np.mean(pred)*100:3.3}%)')
Unser Fehler scheint bei etwa 2 Punkten zu liegen, was ca. 17 % entspricht. Nicht allzu gut. Ein weiterer Indikator für die Modellqualität ist der Bestimmtheitsmaß, der folgendermaßen ermittelt werden kann:
score = lin_reg.score(X_train,y_train)
print('Model determination: ', score)
Wenn der Wert 0 ist, bedeutet dies, dass das Modell die Eingabedaten nicht berücksichtigt und als schlechtester linearer Prädiktor fungiert, was einfach dem Mittelwert des Ergebnisses entspricht. Ein Wert von 1 bedeutet, dass wir alle erwarteten Ausgaben perfekt vorhersagen können. In unserem Fall liegt der Koeffizient bei etwa 0,06, was recht niedrig ist.
Wir können auch die Testdaten zusammen mit der Regressionslinie plotten, um besser zu sehen, wie die Regression in unserem Fall funktioniert:
plt.scatter(X_test,y_test)
plt.plot(X_test,pred)
<img alt="Linear regression" src="../../../../translated_images/de/linear-results.f7c3552c85b0ed1c.webp" width="50%" />
Polynomiale Regression
Eine andere Art der linearen Regression ist die Polynomiale Regression. Während es manchmal eine lineare Beziehung zwischen Variablen gibt – je größer der Kürbis im Volumen, desto höher der Preis – können diese Beziehungen manchmal nicht als Ebene oder Gerade dargestellt werden.
✅ Hier sind weitere Beispiele für Daten, die eine polynomiale Regression benötigen könnten.
Schauen Sie sich die Beziehung zwischen Datum und Preis noch einmal an. Sollte dieses Streudiagramm zwangsläufig durch eine Gerade analysiert werden? Können die Preise nicht schwanken? In solchen Fällen kann man polynomiale Regression versuchen.
✅ Polynome sind mathematische Ausdrücke, die aus einer oder mehreren Variablen und Koeffizienten bestehen können.
Die polynomiale Regression erstellt eine gekrümmte Linie, um besser zu nichtlinearen Daten zu passen. In unserem Fall sollten wir durch Einbeziehung einer quadrierten DayOfYear-Variable in die Eingabedaten in der Lage sein, unsere Daten mit einer parabolischen Kurve anzupassen, die an einem bestimmten Punkt innerhalb des Jahres ein Minimum hat.
Scikit-learn bietet eine hilfreiche Pipeline-API, um verschiedene Verarbeitungsschritte zusammenzuführen. Eine Pipeline ist eine Kette von Estimatoren. In unserem Fall erstellen wir eine Pipeline, die zuerst polynomiale Merkmale zum Modell hinzufügt und dann die Regression trainiert:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
pipeline.fit(X_train,y_train)
Die Verwendung von PolynomialFeatures(2) bedeutet, dass wir alle Polynome zweiten Grades aus den Eingabedaten einschließen. In unserem Fall bedeutet das nur DayOfYear<sup>2</sup>, aber bei zwei Eingabevariablen X und Y werden zusätzlich X<sup>2</sup>, XY und Y<sup>2</sup> hinzugefügt. Wir können auch Polynome höheren Grades verwenden, wenn wir möchten.
Pipelines können auf die gleiche Weise wie das ursprüngliche LinearRegression-Objekt verwendet werden, d.h. wir können die Pipeline fit-ten und dann predict aufrufen, um Vorhersagen zu erhalten:
pred = pipeline.predict(X_test)
rmse = np.sqrt(mean_squared_error(y_test,pred))
print(f'RMSE: {rmse:3.3} ({rmse/np.mean(pred)*100:3.3}%)')
score = pipeline.score(X_train,y_train)
print('Model determination: ', score)
Um die glatte Annäherungskurve zu zeichnen, verwenden wir np.linspace, um einen gleichmäßigen Bereich von Eingabewerten zu erzeugen, anstatt direkt die ungeordneten Testdaten zu verwenden (was eine Zickzacklinie ergeben würde):
X_range = np.linspace(X_test.min(), X_test.max(), 100).reshape(-1,1)
y_range = pipeline.predict(X_range)
plt.scatter(X_test, y_test)
plt.plot(X_range, y_range)
Hier ist der Graph, der Testdaten und die Annäherungskurve zeigt:
<img alt="Polynomial regression" src="../../../../translated_images/de/poly-results.ee587348f0f1f60b.webp" width="50%" />
Mit polynomieller Regression können wir etwas geringeren RMSE und höhere Bestimmtheitsmaße erzielen, aber nicht signifikant. Wir müssen weitere Merkmale berücksichtigen!
> Sie können sehen, dass die minimalen Kürbiskurse irgendwo um Halloween beobachtet werden. Wie können Sie das erklären?
🎃 Herzlichen Glückwunsch, Sie haben gerade ein Modell erstellt, das dabei helfen kann, den Preis von Backkürbissen vorherzusagen. Wahrscheinlich können Sie dasselbe Verfahren für alle Kürbissorten wiederholen, aber das wäre mühsam. Lernen wir nun, wie wir die Kürbissorte in unser Modell einbeziehen!
Kategorische Merkmale
In der idealen Welt wollen wir Preise für verschiedene Kürbissorten mit demselben Modell vorhersagen können. Die Spalte Variety unterscheidet sich jedoch etwas von Spalten wie Month, da sie nicht-numerische Werte enthält. Solche Spalten nennt man kategorisch.
> 🎥 Klicken Sie auf das Bild oben für eine kurze Videoübersicht zum Umgang mit kategorialen Merkmalen.
Hier sehen Sie, wie der Durchschnittspreis von der Sorte abhängt:
<img alt="Durchschnittspreis nach Sorte" src="../../../../translated_images/de/price-by-variety.744a2f9925d9bcb4.webp" width="50%" />
Um die Sorte zu berücksichtigen, müssen wir sie zunächst in numerische Form umwandeln oder kodieren. Es gibt verschiedene Vorgehensweisen:
- Eine einfache numerische Kodierung erstellt eine Tabelle der verschiedenen Sorten und ersetzt dann den Sortennamen durch einen Index in dieser Tabelle. Das ist keine gute Idee für lineare Regression, weil das Modell den tatsächlichen numerischen Wert des Index nimmt und mit einem Koeffizienten multipliziert zum Ergebnis hinzufügt. In unserem Fall ist die Beziehung zwischen dem Index und dem Preis eindeutig nicht-linear, selbst wenn wir sicherstellen, dass die Indizes in einer bestimmten Reihenfolge angeordnet sind.
- One-Hot-Kodierung ersetzt die Spalte
Varietydurch 4 verschiedene Spalten, je eine für jede Sorte. Jede Spalte enthält1, wenn die entsprechende Zeile diese Sorte hat, und0sonst. Das bedeutet, dass es vier Koeffizienten in der linearen Regression gibt, einen für jede Kürbissorte, der für den „Startpreis“ (bzw. „zusätzlichen Preis“) für diese Sorte verantwortlich ist.
Der folgende Code zeigt, wie wir eine Sorte als One-Hot kodieren können:
pd.get_dummies(new_pumpkins['Variety'])
| ID | FAIRYTALE | MINIATURE | MIXED HEIRLOOM VARIETIES | PIE TYPE |
|---|---|---|---|---|
| 70 | 0 | 0 | 0 | 1 |
| 71 | 0 | 0 | 0 | 1 |
| ... | ... | ... | ... | ... |
| 1738 | 0 | 1 | 0 | 0 |
| 1739 | 0 | 1 | 0 | 0 |
| 1740 | 0 | 1 | 0 | 0 |
| 1741 | 0 | 1 | 0 | 0 |
| 1742 | 0 | 1 | 0 | 0 |
Um lineare Regression mit der One-Hot-kodierten Sorte als Eingabe zu trainieren, müssen wir nur die Daten in X und y richtig initialisieren:
X = pd.get_dummies(new_pumpkins['Variety'])
y = new_pumpkins['Price']
Der Rest des Codes ist derselbe wie oben für das Training der linearen Regression. Wenn Sie es ausprobieren, werden Sie sehen, dass der mittlere quadratische Fehler ungefähr gleich bleibt, wir aber eine deutlich höhere Bestimmtheitsmaßzahl (~77 %) erhalten. Für noch genauere Vorhersagen können wir weitere kategoriale Merkmale sowie numerische Merkmale wie Month oder DayOfYear einbeziehen. Um ein großes Merkmal-Array zu erhalten, können wir join verwenden:
X = pd.get_dummies(new_pumpkins['Variety']) \
.join(new_pumpkins['Month']) \
.join(pd.get_dummies(new_pumpkins['City'])) \
.join(pd.get_dummies(new_pumpkins['Package']))
y = new_pumpkins['Price']
Hier berücksichtigen wir auch City und Package-Typ, was uns einen RMSE von 2,84 (10,5 %) und eine Bestimmtheitsmaßzahl von 0,94 gibt!
Alles zusammenführen
Um das beste Modell zu erstellen, können wir kombinierte (one-hot-kodierte kategoriale + numerische) Daten aus dem obigen Beispiel zusammen mit Polynomialer Regression verwenden. Hier ist der vollständige Code zu Ihrer Bequemlichkeit:
# Trainingsdaten einrichten
X = pd.get_dummies(new_pumpkins['Variety']) \
.join(new_pumpkins['Month']) \
.join(pd.get_dummies(new_pumpkins['City'])) \
.join(pd.get_dummies(new_pumpkins['Package']))
y = new_pumpkins['Price']
# Trainings- und Testdaten aufteilen
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
# Pipeline einrichten und trainieren
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
pipeline.fit(X_train,y_train)
# Ergebnisse für Testdaten vorhersagen
pred = pipeline.predict(X_test)
# RMSE und Bestimmtheitsmaß berechnen
rmse = mean_squared_error(y_test, pred, squared=False)
print(f'RMSE: {rmse:3.3} ({rmse/pred.mean()*100:3.3}%)')
score = pipeline.score(X_train,y_train)
print('Model determination: ', score)
Damit sollten wir den besten Bestimmtheitsmaß von fast 97 % und RMSE = 2,23 (~8 % Vorhersagefehler) erhalten.
| Modell | RMSE | Bestimmtheitsmaß |
|---|---|---|
DayOfYear Linear |
2,77 (17,2 %) | 0,07 |
DayOfYear Polynomial |
2,73 (17,0 %) | 0,08 |
Variety Linear |
5,24 (19,7 %) | 0,77 |
| Alle Merkmale Linear | 2,84 (10,5 %) | 0,94 |
| Alle Merkmale Polynomial | 2,23 (8,25 %) | 0,97 |
🏆 Gut gemacht! Sie haben in einer Lektion vier Regressionsmodelle erstellt und die Modellqualität auf 97 % verbessert. Im abschließenden Abschnitt über Regression lernen Sie logistische Regression kennen, um Kategorien zu bestimmen.
🚀Herausforderung
Testen Sie in diesem Notebook verschiedene Variablen, um zu sehen, wie Korrelation mit der Modellgenauigkeit zusammenhängt.
Quiz nach der Vorlesung
Wiederholung & Selbststudium
In dieser Lektion haben wir über Lineare Regression gelernt. Es gibt noch andere wichtige Regressionstypen. Lesen Sie über Stepwise-, Ridge-, Lasso- und Elasticnet-Techniken. Ein guter Kurs zum Weiterlernen ist der Stanford Statistical Learning Course
Aufgabe
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache ist als maßgebliche Quelle anzusehen. Für wichtige Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die durch die Nutzung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Lineare und Polynomiale Regression für Kürbissepreise - Lektion 3
Laden Sie die erforderlichen Bibliotheken und den Datensatz. Konvertieren Sie die Daten in ein DataFrame, das eine Teilmenge der Daten enthält:
- Nur Kürbisse, die pro Scheffel bepreist sind
- Konvertieren Sie das Datum in einen Monat
- Berechnen Sie den Preis als Durchschnitt aus Höchst- und Tiefstpreis
- Passen Sie den Preis an die Preisgestaltung pro Scheffelmenge an
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
pumpkins = pd.read_csv('../../data/US-pumpkins.csv')
pumpkins.head()
pumpkins = pumpkins[pumpkins['Package'].str.contains('bushel', case=True, regex=True)]
new_columns = ['Package', 'Variety', 'City Name', 'Month', 'Low Price', 'High Price', 'Date']
pumpkins = pumpkins.drop([c for c in pumpkins.columns if c not in new_columns], axis=1)
price = (pumpkins['Low Price'] + pumpkins['High Price']) / 2
month = pd.DatetimeIndex(pumpkins['Date']).month
day_of_year = pd.to_datetime(pumpkins['Date']).apply(lambda dt: (dt-datetime(dt.year,1,1)).days)
new_pumpkins = pd.DataFrame(
{'Month': month,
'DayOfYear' : day_of_year,
'Variety': pumpkins['Variety'],
'City': pumpkins['City Name'],
'Package': pumpkins['Package'],
'Low Price': pumpkins['Low Price'],
'High Price': pumpkins['High Price'],
'Price': price})
new_pumpkins.loc[new_pumpkins['Package'].str.contains('1 1/9'), 'Price'] = price/1.1
new_pumpkins.loc[new_pumpkins['Package'].str.contains('1/2'), 'Price'] = price*2
new_pumpkins.head()
Ein Streudiagramm erinnert uns daran, dass wir nur Monatsdaten von August bis Dezember haben. Wahrscheinlich benötigen wir mehr Daten, um in der Lage zu sein, linear gültige Schlussfolgerungen zu ziehen.
new_pumpkins.plot.scatter('Month','Price')
new_pumpkins.plot.scatter('DayOfYear','Price')
Schauen wir, ob eine Korrelation besteht:
print(new_pumpkins['Month'].corr(new_pumpkins['Price']))
print(new_pumpkins['DayOfYear'].corr(new_pumpkins['Price']))
Es sieht so aus, als sei die Korrelation ziemlich gering, aber es gibt eine andere wichtigere Beziehung – denn die Preiswerte im obigen Diagramm scheinen mehrere unterschiedliche Cluster zu bilden. Lassen Sie uns ein Diagramm erstellen, das verschiedene Kürbissorten zeigt:
ax=None
colors = ['red','blue','green','yellow']
for i,var in enumerate(new_pumpkins['Variety'].unique()):
ax = new_pumpkins[new_pumpkins['Variety']==var].plot.scatter('DayOfYear','Price',ax=ax,c=colors[i],label=var)
new_pumpkins.groupby('Variety')['Price'].mean().plot(kind='bar')
Vorerst konzentrieren wir uns nur auf eine Sorte - Kuchentyp.
pie_pumpkins = new_pumpkins[new_pumpkins['Variety']=='PIE TYPE']
print(pie_pumpkins['DayOfYear'].corr(pie_pumpkins['Price']))
pie_pumpkins.plot.scatter('DayOfYear','Price')
Lineare Regression
Wir werden Scikit Learn verwenden, um ein lineares Regressionsmodell zu trainieren:
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error
from sklearn.model_selection import train_test_split
X = pie_pumpkins['DayOfYear'].to_numpy().reshape(-1,1)
y = pie_pumpkins['Price']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
lin_reg = LinearRegression()
lin_reg.fit(X_train,y_train)
pred = lin_reg.predict(X_test)
mse = np.sqrt(mean_squared_error(y_test,pred))
print(f'Mean error: {mse:3.3} ({mse/np.mean(pred)*100:3.3}%)')
plt.scatter(X_test,y_test)
plt.plot(X_test,pred)
Die Steigung der Geraden kann aus den Koeffizienten der linearen Regression bestimmt werden:
lin_reg.coef_, lin_reg.intercept_
Wir können das trainierte Modell verwenden, um den Preis vorherzusagen:
# Pumpkin price on programmer's day
lin_reg.predict([[256]])
Polynomiale Regression
Manchmal ist die Beziehung zwischen den Merkmalen und den Ergebnissen von Natur aus nicht-linear. Zum Beispiel könnten Kürbispreise im Winter (Monate=1,2) hoch sein, dann im Sommer (Monate=5-7) fallen und anschließend wieder steigen. Die lineare Regression kann diese Beziehung nicht genau erfassen.
In diesem Fall können wir in Betracht ziehen, zusätzliche Merkmale hinzuzufügen. Ein einfacher Weg ist die Verwendung von Polynomen aus Eingabemerkmalen, was zu einer polynomialen Regression führen würde. In Scikit Learn können wir polynomiale Merkmale automatisch mit Pipelines vorab berechnen:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
pipeline.fit(X_train,y_train)
pred = pipeline.predict(X_test)
mse = np.sqrt(mean_squared_error(y_test,pred))
print(f'Mean error: {mse:3.3} ({mse/np.mean(pred)*100:3.3}%)')
score = pipeline.score(X_train,y_train)
print('Model determination: ', score)
X_range = np.linspace(X_test.min(), X_test.max(), 100).reshape(-1,1)
y_range = pipeline.predict(X_range)
plt.scatter(X_test, y_test)
plt.plot(X_range, y_range)
Sortenvarianten der Kodierung
In einer idealen Welt möchten wir mit demselben Modell die Preise für verschiedene Kürbissorten vorhersagen können. Um die Sorte zu berücksichtigen, müssen wir sie zunächst in eine numerische Form umwandeln oder kodieren. Es gibt mehrere Möglichkeiten, dies zu tun:
- Einfache numerische Kodierung, die eine Tabelle verschiedener Sorten erstellt und dann den Sortennamen durch einen Index in dieser Tabelle ersetzt. Dies ist keine gute Idee für die lineare Regression, da die lineare Regression den numerischen Wert des Index berücksichtigt und der numerische Wert wahrscheinlich nicht numerisch mit dem Preis korreliert.
- One-Hot-Kodierung, bei der die
Variety-Spalte durch 4 verschiedene Spalten ersetzt wird, eine für jede Sorte, die 1 enthält, wenn die entsprechende Zeile zur gegebenen Sorte gehört, und sonst 0.
Der folgende Code zeigt, wie man eine Sorte one-hot kodieren kann:
pd.get_dummies(new_pumpkins['Variety'])
Lineare Regression auf Sorte
Wir werden nun den gleichen Code wie oben verwenden, aber anstelle von DayOfYear verwenden wir unsere One-Hot-codierte Sorte als Eingabe:
X = pd.get_dummies(new_pumpkins['Variety'])
y = new_pumpkins['Price']
def run_linear_regression(X,y):
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
lin_reg = LinearRegression()
lin_reg.fit(X_train,y_train)
pred = lin_reg.predict(X_test)
mse = np.sqrt(mean_squared_error(y_test,pred))
print(f'Mean error: {mse:3.3} ({mse/np.mean(pred)*100:3.3}%)')
score = lin_reg.score(X_train,y_train)
print('Model determination: ', score)
run_linear_regression(X,y)
Wir können auch versuchen, andere Merkmale auf dieselbe Weise zu verwenden und sie mit numerischen Merkmalen wie Month oder DayOfYear zu kombinieren:
X = pd.get_dummies(new_pumpkins['Variety']) \
.join(new_pumpkins['Month']) \
.join(pd.get_dummies(new_pumpkins['City'])) \
.join(pd.get_dummies(new_pumpkins['Package']))
y = new_pumpkins['Price']
run_linear_regression(X,y)
Polynomiale Regression
Polynomiale Regression kann auch mit kategorialen Merkmalen verwendet werden, die im One-Hot-Encoding vorliegen. Der Code zum Trainieren der polynomialen Regression wäre im Wesentlichen derselbe wie oben gesehen.
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
pipeline.fit(X_train,y_train)
pred = pipeline.predict(X_test)
mse = np.sqrt(mean_squared_error(y_test,pred))
print(f'Mean error: {mse:3.3} ({mse/np.mean(pred)*100:3.3}%)')
score = pipeline.score(X_train,y_train)
print('Model determination: ', score)
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, können automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten. Das Originaldokument in seiner Ursprungssprache gilt als maßgebliche Quelle. Für wichtige Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Verwendung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Lineare und polynomiale Regression für Kürbispreise - Lektion 3
<p > <img src="../../images/linear-polynomial.png" width="800"/> <figcaption>Infografik von Dasani Madipalli</figcaption>
Einführung
Bisher hast du untersucht, was Regression ist, anhand von Beispieldaten aus dem Kürbispreis-Datensatz, den wir in dieser Lektion verwenden werden. Du hast sie auch mit ggplot2 visualisiert. 💪
Jetzt bist du bereit, tiefer in die Regression für maschinelles Lernen einzutauchen. In dieser Lektion wirst du mehr über zwei Arten der Regression lernen: einfache lineare Regression und polynomiale Regression, zusammen mit einigen mathematischen Grundlagen dieser Techniken.
> Im gesamten Lehrplan gehen wir von minimalen mathematischen Kenntnissen aus und versuchen, das Thema für Studierende aus anderen Bereichen zugänglich zu machen. Achte daher auf Hinweise, 🧮 Erläuterungen, Diagramme und andere Lernhilfen, die das Verständnis erleichtern.
Vorbereitung
Zur Erinnerung: Du lädst diese Daten, um Fragen dazu zu stellen.
-
Wann ist der beste Zeitpunkt, Kürbisse zu kaufen?
-
Welchen Preis kann ich für eine Kiste mit Miniaturkürbissen erwarten?
-
Sollte ich sie in halben Scheffelkörben oder in einer 1 1/9 Scheffelbox kaufen? Lass uns weiter in diese Daten eintauchen.
In der vorherigen Lektion hast du ein tibble (eine moderne Neuinterpretation des Dataframes) erstellt und es mit einem Teil des ursprünglichen Datensatzes gefüllt, wobei du die Preise standardisiert nach Scheffel angegeben hast. Dadurch konntest du jedoch nur etwa 400 Datenpunkte sammeln, und das nur für die Herbstmonate. Vielleicht können wir durch eine gründlichere Bereinigung der Daten mehr Details über die Natur der Daten erhalten? Mal sehen... 🕵️♀️
Für diese Aufgabe benötigen wir die folgenden Pakete:
-
tidyverse: Das tidyverse ist eine Sammlung von R-Paketen, die Datenwissenschaft schneller, einfacher und unterhaltsamer macht! -
tidymodels: Das tidymodels Framework ist eine Sammlung von Paketen für Modellierung und maschinelles Lernen. -
janitor: Das janitor-Paket bietet einfache kleine Werkzeuge zur Untersuchung und Bereinigung von unordentlichen Daten. -
corrplot: Das corrplot-Paket bietet ein visuelles Explorationswerkzeug für Korrelationsmatrizen, das die automatische Neuordnung von Variablen unterstützt, um versteckte Muster zwischen Variablen zu erkennen.
Du kannst sie wie folgt installieren:
install.packages(c("tidyverse", "tidymodels", "janitor", "corrplot"))
Das untenstehende Skript überprüft, ob du die für dieses Modul benötigten Pakete hast, und installiert sie für dich, falls sie fehlen.
suppressWarnings(if (!require("pacman")) install.packages("pacman"))
pacman::p_load(tidyverse, tidymodels, janitor, corrplot)
Wir werden später diese großartigen Pakete laden und sie in unserer aktuellen R-Sitzung verfügbar machen. (Das dient nur zur Veranschaulichung, pacman::p_load() hat das bereits für Sie erledigt.)
1. Eine lineare Regressionslinie
Wie Sie in Lektion 1 gelernt haben, besteht das Ziel einer linearen Regression darin, eine Linie der besten Anpassung zu zeichnen, um:
-
Variable Beziehungen zu zeigen. Die Beziehung zwischen Variablen darzustellen.
-
Vorhersagen zu treffen. Präzise Vorhersagen darüber zu machen, wo ein neuer Datenpunkt im Verhältnis zu dieser Linie liegen würde.
Um diese Art von Linie zu zeichnen, verwenden wir eine statistische Technik namens Least-Squares Regression. Der Begriff least-squares bedeutet, dass alle Datenpunkte um die Regressionslinie herum quadriert und dann addiert werden. Idealerweise ist diese endgültige Summe so klein wie möglich, da wir eine geringe Anzahl von Fehlern oder least-squares anstreben. Die Linie der besten Anpassung ist daher die Linie, die uns den niedrigsten Wert für die Summe der quadrierten Fehler liefert – daher der Name Least-Squares Regression.
Wir tun dies, weil wir eine Linie modellieren möchten, die die geringste kumulative Entfernung von all unseren Datenpunkten hat. Wir quadrieren die Terme vor dem Addieren, da uns die Größe und nicht die Richtung interessiert.
> 🧮 Zeig mir die Mathematik
>
> Diese Linie, genannt Linie der besten Anpassung, kann durch eine Gleichung ausgedrückt werden:
>
> Y = a + bX
>
> X ist die 'erklärende Variable oder Prädiktor'. Y ist die 'abhängige Variable oder Ergebnis'. Die Steigung der Linie ist b und a ist der y-Achsenabschnitt, der den Wert von Y angibt, wenn X = 0.
>
>
Infografik von Jen Looper
>
> Zuerst berechnen wir die Steigung b.
>
> Anders ausgedrückt, und bezogen auf die ursprüngliche Frage zu unseren Kürbisdaten: "den Preis eines Kürbisses pro Scheffel nach Monat vorhersagen", würde X den Preis und Y den Verkaufsmonat darstellen.
>
>
Infografik von Jen Looper
>
> Berechnen Sie den Wert von Y. Wenn Sie etwa 4 \$ zahlen, muss es April sein!
>
> Die Mathematik, die die Linie berechnet, muss die Steigung der Linie demonstrieren, die auch vom Achsenabschnitt abhängt, oder wo Y liegt, wenn X = 0.
>
> Sie können die Methode zur Berechnung dieser Werte auf der Website Math is Fun beobachten. Besuchen Sie auch diesen Least-Squares-Rechner, um zu sehen, wie die Werte der Zahlen die Linie beeinflussen.
Gar nicht so beängstigend, oder? 🤓
Korrelation
Ein weiterer Begriff, den Sie verstehen sollten, ist der Korrelationskoeffizient zwischen den gegebenen X- und Y-Variablen. Mithilfe eines Streudiagramms können Sie diesen Koeffizienten schnell visualisieren. Ein Diagramm mit Datenpunkten, die in einer ordentlichen Linie angeordnet sind, hat eine hohe Korrelation, während ein Diagramm mit Datenpunkten, die überall zwischen X und Y verstreut sind, eine niedrige Korrelation aufweist.
Ein gutes lineares Regressionsmodell ist eines, das einen hohen (näher an 1 als an 0) Korrelationskoeffizienten mit der Least-Squares Regression-Methode und einer Regressionslinie aufweist.
2. Ein Tanz mit Daten: Erstellen eines Dataframes für das Modellieren
<p > <img src="../../images/janitor.jpg" width="700"/> <figcaption>Kunstwerk von @allison_horst</figcaption>
<!--
{width="700"}-->
Lade die benötigten Bibliotheken und den Datensatz. Konvertiere die Daten in einen Dataframe, der einen Teil der Daten enthält:
-
Nur Kürbisse auswählen, die nach Scheffelpreis bewertet sind
-
Das Datum in einen Monat umwandeln
-
Den Preis als Durchschnitt aus hohen und niedrigen Preisen berechnen
-
Den Preis so umrechnen, dass er die Bewertung nach Scheffelmenge widerspiegelt
> Diese Schritte haben wir in der vorherigen Lektion behandelt.
# Load the core Tidyverse packages
library(tidyverse)
library(lubridate)
# Import the pumpkins data
pumpkins <- read_csv(file = "https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv")
# Get a glimpse and dimensions of the data
glimpse(pumpkins)
# Print the first 50 rows of the data set
pumpkins %>%
slice_head(n = 5)
Im Geiste des reinen Abenteuers lassen Sie uns das janitor package erkunden, das einfache Funktionen zum Untersuchen und Bereinigen von unordentlichen Daten bietet. Zum Beispiel werfen wir einen Blick auf die Spaltennamen unserer Daten:
# Return column names
pumpkins %>%
names()
🤔 Wir können es besser machen. Lassen Sie uns diese Spaltennamen friendR machen, indem wir sie mit der snake_case-Konvention mit janitor::clean_names umwandeln. Um mehr über diese Funktion zu erfahren: ?clean_names
# Clean names to the snake_case convention
pumpkins <- pumpkins %>%
clean_names(case = "snake")
# Return column names
pumpkins %>%
names()
Viel tidyR 🧹! Jetzt ein Tanz mit den Daten, wie in der vorherigen Lektion, mit dplyr! 💃
# Select desired columns
pumpkins <- pumpkins %>%
select(variety, city_name, package, low_price, high_price, date)
# Extract the month from the dates to a new column
pumpkins <- pumpkins %>%
mutate(date = mdy(date),
month = month(date)) %>%
select(-date)
# Create a new column for average Price
pumpkins <- pumpkins %>%
mutate(price = (low_price + high_price)/2)
# Retain only pumpkins with the string "bushel"
new_pumpkins <- pumpkins %>%
filter(str_detect(string = package, pattern = "bushel"))
# Normalize the pricing so that you show the pricing per bushel, not per 1 1/9 or 1/2 bushel
new_pumpkins <- new_pumpkins %>%
mutate(price = case_when(
str_detect(package, "1 1/9") ~ price/(1.1),
str_detect(package, "1/2") ~ price*2,
TRUE ~ price))
# Relocate column positions
new_pumpkins <- new_pumpkins %>%
relocate(month, .before = variety)
# Display the first 5 rows
new_pumpkins %>%
slice_head(n = 5)
Gute Arbeit! 👌 Du hast jetzt einen sauberen, aufgeräumten Datensatz, mit dem du dein neues Regressionsmodell erstellen kannst!
Wie wäre es mit einem Streudiagramm?
# Set theme
theme_set(theme_light())
# Make a scatter plot of month and price
new_pumpkins %>%
ggplot(mapping = aes(x = month, y = price)) +
geom_point(size = 1.6)
Ein Streudiagramm erinnert uns daran, dass wir nur Monatsdaten von August bis Dezember haben. Wir benötigen wahrscheinlich mehr Daten, um Schlussfolgerungen auf eine lineare Weise ziehen zu können.
Werfen wir erneut einen Blick auf unsere Modellierungsdaten:
# Display first 5 rows
new_pumpkins %>%
slice_head(n = 5)
Was wäre, wenn wir den Preis eines Kürbisses basierend auf den Spalten Stadt oder Paket, die vom Typ Zeichenkette sind, vorhersagen wollten? Oder noch einfacher, wie könnten wir die Korrelation (die erfordert, dass beide Eingaben numerisch sind) zwischen beispielsweise Paket und Preis finden? 🤷🤷
Maschinelle Lernmodelle funktionieren am besten mit numerischen Merkmalen anstelle von Textwerten, daher müssen kategorische Merkmale in der Regel in numerische Darstellungen umgewandelt werden.
Das bedeutet, dass wir einen Weg finden müssen, unsere Prädiktoren so umzuformatieren, dass sie für ein Modell effektiver nutzbar sind – ein Prozess, der als Feature Engineering bekannt ist.
3. Vorverarbeitung von Daten für die Modellierung mit Recipes 👩🍳👨🍳
Aktivitäten, die Prädiktorwerte umformatieren, um sie für ein Modell effektiver nutzbar zu machen, werden als Feature Engineering bezeichnet.
Verschiedene Modelle haben unterschiedliche Anforderungen an die Vorverarbeitung. Zum Beispiel erfordert die Methode der kleinsten Quadrate die Kodierung kategorischer Variablen wie Monat, Sorte und Stadtname. Dies bedeutet einfach, dass eine Spalte mit kategorischen Werten in eine oder mehrere numerische Spalten übersetzt wird, die die ursprüngliche Spalte ersetzen.
Angenommen, Ihre Daten enthalten die folgende kategorische Variable:
| Stadt |
|---|
| Denver |
| Nairobi |
| Tokio |
Sie können ordinale Kodierung anwenden, um jeder Kategorie einen eindeutigen Ganzzahlwert zuzuweisen, wie folgt:
| Stadt |
|---|
| 0 |
| 1 |
| 2 |
Und genau das werden wir mit unseren Daten machen!
In diesem Abschnitt werden wir ein weiteres großartiges Tidymodels-Paket erkunden: recipes - das entwickelt wurde, um Ihnen bei der Vorverarbeitung Ihrer Daten vor dem Training Ihres Modells zu helfen. Im Kern ist ein Recipe ein Objekt, das definiert, welche Schritte auf einen Datensatz angewendet werden sollen, um ihn für die Modellierung vorzubereiten.
Nun erstellen wir ein Recipe, das unsere Daten für die Modellierung vorbereitet, indem es für alle Beobachtungen in den Prädiktorspalten einen eindeutigen Ganzzahlwert ersetzt:
# Specify a recipe
pumpkins_recipe <- recipe(price ~ ., data = new_pumpkins) %>%
step_integer(all_predictors(), zero_based = TRUE)
# Print out the recipe
pumpkins_recipe
Super! 👏 Wir haben gerade unser erstes Rezept erstellt, das ein Ergebnis (Preis) und die dazugehörigen Prädiktoren spezifiziert und alle Prädiktorspalten in eine Menge von Ganzzahlen kodiert 🙌! Lass uns das schnell aufschlüsseln:
-
Der Aufruf von
recipe()mit einer Formel teilt dem Rezept die Rollen der Variablen mit, wobei die Daten ausnew_pumpkinsals Referenz verwendet werden. Zum Beispiel wurde derprice-Spalte die Rolleoutcomezugewiesen, während die restlichen Spalten die Rollepredictorerhalten haben. -
step_integer(all_predictors(), zero_based = TRUE)gibt an, dass alle Prädiktoren in eine Menge von Ganzzahlen umgewandelt werden sollen, wobei die Nummerierung bei 0 beginnt.
Wir sind sicher, dass du dir gerade Gedanken machst wie: "Das ist so cool!! Aber was, wenn ich überprüfen möchte, ob die Rezepte genau das tun, was ich von ihnen erwarte? 🤔"
Das ist ein großartiger Gedanke! Siehst du, sobald dein Rezept definiert ist, kannst du die Parameter schätzen, die erforderlich sind, um die Daten tatsächlich vorzubereiten, und dann die verarbeiteten Daten extrahieren. Normalerweise musst du das nicht tun, wenn du Tidymodels verwendest (wir werden gleich die übliche Vorgehensweise sehen -> workflows), aber es kann nützlich sein, wenn du eine Art Plausibilitätsprüfung durchführen möchtest, um sicherzustellen, dass die Rezepte das tun, was du erwartest.
Dafür brauchst du zwei weitere Verben: prep() und bake(). Und wie immer helfen dir unsere kleinen R-Freunde von Allison Horst dabei, das besser zu verstehen!
<p > <img src="../../images/recipes.png" width="550"/> <figcaption>Kunstwerk von @allison_horst</figcaption>
prep(): schätzt die erforderlichen Parameter aus einem Trainingssatz, die später auf andere Datensätze angewendet werden können. Zum Beispiel, für eine gegebene Prädiktorspalte, welche Beobachtung wird der Ganzzahl 0, 1, 2 usw. zugewiesen.
bake(): nimmt ein vorbereitetes Rezept und wendet die Operationen auf jeden beliebigen Datensatz an.
Das gesagt, lassen Sie uns unsere Rezepte vorbereiten und anwenden, um wirklich zu bestätigen, dass die Prädiktorspalten im Hintergrund zuerst kodiert werden, bevor ein Modell angepasst wird.
# Prep the recipe
pumpkins_prep <- prep(pumpkins_recipe)
# Bake the recipe to extract a preprocessed new_pumpkins data
baked_pumpkins <- bake(pumpkins_prep, new_data = NULL)
# Print out the baked data set
baked_pumpkins %>%
slice_head(n = 10)
Woo-hoo!🥳 Die verarbeiteten Daten baked_pumpkins haben alle ihre Prädiktoren kodiert, was bestätigt, dass die im Rezept definierten Vorverarbeitungsschritte wie erwartet funktionieren. Das macht es zwar schwieriger für dich zu lesen, aber viel verständlicher für Tidymodels! Nimm dir etwas Zeit, um herauszufinden, welche Beobachtung einer entsprechenden Ganzzahl zugeordnet wurde.
Es ist auch erwähnenswert, dass baked_pumpkins ein Dataframe ist, auf dem wir Berechnungen durchführen können.
Zum Beispiel können wir versuchen, eine gute Korrelation zwischen zwei Punkten deiner Daten zu finden, um möglicherweise ein gutes Vorhersagemodell zu erstellen. Dafür verwenden wir die Funktion cor(). Gib ?cor() ein, um mehr über die Funktion zu erfahren.
# Find the correlation between the city_name and the price
cor(baked_pumpkins$city_name, baked_pumpkins$price)
# Find the correlation between the package and the price
cor(baked_pumpkins$package, baked_pumpkins$price)
Wie sich herausstellt, gibt es nur eine schwache Korrelation zwischen der Stadt und dem Preis. Allerdings gibt es eine etwas stärkere Korrelation zwischen dem Paket und seinem Preis. Das ergibt Sinn, oder? Normalerweise gilt: Je größer die Obst- oder Gemüsekiste, desto höher der Preis.
Während wir schon dabei sind, können wir auch versuchen, eine Korrelationsmatrix aller Spalten mit dem corrplot-Paket zu visualisieren.
# Load the corrplot package
library(corrplot)
# Obtain correlation matrix
corr_mat <- cor(baked_pumpkins %>%
# Drop columns that are not really informative
select(-c(low_price, high_price)))
# Make a correlation plot between the variables
corrplot(corr_mat, method = "shade", shade.col = NA, tl.col = "black", tl.srt = 45, addCoef.col = "black", cl.pos = "n", order = "original")
🤩🤩 Viel besser.
Eine gute Frage, die man jetzt zu diesen Daten stellen könnte, wäre: 'Welchen Preis kann ich für ein bestimmtes Kürbispaket erwarten?' Lassen Sie uns direkt loslegen!
> Hinweis: Wenn Sie das vorbereitete Rezept pumpkins_prep mit new_data = NULL bake(), extrahieren Sie die verarbeiteten (d.h. kodierten) Trainingsdaten. Wenn Sie ein anderes Datenset hätten, beispielsweise ein Testset, und sehen möchten, wie ein Rezept es vorverarbeiten würde, könnten Sie einfach pumpkins_prep mit new_data = test_set backen.
4. Erstellen Sie ein lineares Regressionsmodell
<p > <img src="../../images/linear-polynomial.png" width="800"/> <figcaption>Infografik von Dasani Madipalli</figcaption>
<!--
{width="800"}-->
Jetzt, da wir ein Rezept erstellt und tatsächlich bestätigt haben, dass die Daten angemessen vorverarbeitet werden, bauen wir nun ein Regressionsmodell, um die folgende Frage zu beantworten: Welchen Preis kann ich für ein bestimmtes Kürbispaket erwarten?
Trainiere ein lineares Regressionsmodell mit dem Trainingsdatensatz
Wie Sie wahrscheinlich schon herausgefunden haben, ist die Spalte price die Zielvariable, während die Spalte package die Prädiktorvariable ist.
Um dies zu tun, werden wir die Daten zunächst so aufteilen, dass 80 % in den Trainings- und 20 % in den Testdatensatz gehen. Anschließend definieren wir ein Rezept, das die Prädiktorspalte in eine Reihe von Ganzzahlen kodiert, und erstellen eine Modellspezifikation. Wir werden unser Rezept nicht vorbereiten und backen, da wir bereits wissen, dass es die Daten wie erwartet vorverarbeitet.
set.seed(2056)
# Split the data into training and test sets
pumpkins_split <- new_pumpkins %>%
initial_split(prop = 0.8)
# Extract training and test data
pumpkins_train <- training(pumpkins_split)
pumpkins_test <- testing(pumpkins_split)
# Create a recipe for preprocessing the data
lm_pumpkins_recipe <- recipe(price ~ package, data = pumpkins_train) %>%
step_integer(all_predictors(), zero_based = TRUE)
# Create a linear model specification
lm_spec <- linear_reg() %>%
set_engine("lm") %>%
set_mode("regression")
Gut gemacht! Jetzt, da wir ein Rezept und eine Modellspezifikation haben, müssen wir eine Möglichkeit finden, diese zusammen in einem Objekt zu bündeln, das zunächst die Daten vorverarbeitet (prep+bake im Hintergrund), das Modell auf den vorverarbeiteten Daten anpasst und auch potenzielle Nachbearbeitungsaktivitäten ermöglicht. Klingt das nicht beruhigend?🤩
In Tidymodels wird dieses praktische Objekt workflow genannt und enthält bequem alle Modellierungskomponenten! Das ist das, was wir in Python als Pipelines bezeichnen würden.
Also, lass uns alles in einem Workflow bündeln!📦
# Hold modelling components in a workflow
lm_wf <- workflow() %>%
add_recipe(lm_pumpkins_recipe) %>%
add_model(lm_spec)
# Print out the workflow
lm_wf
Obendrein kann ein Workflow auf ähnliche Weise angepasst/trainiert werden wie ein Modell.
# Train the model
lm_wf_fit <- lm_wf %>%
fit(data = pumpkins_train)
# Print the model coefficients learned
lm_wf_fit
Aus den Modellergebnissen können wir die während des Trainings gelernten Koeffizienten sehen. Sie repräsentieren die Koeffizienten der Linie der besten Anpassung, die uns den geringsten Gesamtfehler zwischen der tatsächlichen und der vorhergesagten Variablen liefert.
Modellleistung mit dem Testdatensatz bewerten
Es ist Zeit herauszufinden, wie das Modell abgeschnitten hat 📏! Wie machen wir das?
Nachdem wir das Modell trainiert haben, können wir es verwenden, um Vorhersagen für den test_set mit parsnip::predict() zu treffen. Anschließend können wir diese Vorhersagen mit den tatsächlichen Label-Werten vergleichen, um zu bewerten, wie gut (oder nicht!) das Modell funktioniert.
Beginnen wir damit, Vorhersagen für den Testdatensatz zu machen und die Spalten an den Testdatensatz anzufügen.
# Make predictions for the test set
predictions <- lm_wf_fit %>%
predict(new_data = pumpkins_test)
# Bind predictions to the test set
lm_results <- pumpkins_test %>%
select(c(package, price)) %>%
bind_cols(predictions)
# Print the first ten rows of the tibble
lm_results %>%
slice_head(n = 10)
Ja, Sie haben gerade ein Modell trainiert und verwendet, um Vorhersagen zu treffen! 🔮 Ist es gut? Lassen Sie uns die Leistung des Modells bewerten!
In Tidymodels machen wir das mit yardstick::metrics()! Für die lineare Regression konzentrieren wir uns auf die folgenden Metriken:
-
Root Mean Square Error (RMSE): Die Quadratwurzel des MSE. Dies ergibt eine absolute Metrik in derselben Einheit wie das Label (in diesem Fall der Preis eines Kürbisses). Je kleiner der Wert, desto besser das Modell (vereinfacht gesagt repräsentiert es den durchschnittlichen Betrag, um den die Vorhersagen falsch sind!). -
Coefficient of Determination (üblicherweise bekannt als R-squared oder R2): Eine relative Metrik, bei der ein höherer Wert eine bessere Anpassung des Modells bedeutet. Im Wesentlichen repräsentiert diese Metrik, wie viel der Varianz zwischen vorhergesagten und tatsächlichen Label-Werten das Modell erklären kann.
# Evaluate performance of linear regression
metrics(data = lm_results,
truth = price,
estimate = .pred)
Da geht die Modellleistung. Mal sehen, ob wir eine bessere Einschätzung bekommen, indem wir ein Streudiagramm der Pakete und Preise visualisieren und dann die Vorhersagen verwenden, um eine Linie der besten Anpassung darüber zu legen.
Das bedeutet, dass wir den Testdatensatz vorbereiten und verarbeiten müssen, um die Paketspalte zu kodieren und diese dann mit den Vorhersagen unseres Modells zu verbinden.
# Encode package column
package_encode <- lm_pumpkins_recipe %>%
prep() %>%
bake(new_data = pumpkins_test) %>%
select(package)
# Bind encoded package column to the results
lm_results <- lm_results %>%
bind_cols(package_encode %>%
rename(package_integer = package)) %>%
relocate(package_integer, .after = package)
# Print new results data frame
lm_results %>%
slice_head(n = 5)
# Make a scatter plot
lm_results %>%
ggplot(mapping = aes(x = package_integer, y = price)) +
geom_point(size = 1.6) +
# Overlay a line of best fit
geom_line(aes(y = .pred), color = "orange", size = 1.2) +
xlab("package")
Wie Sie sehen können, generalisiert das lineare Regressionsmodell die Beziehung zwischen einem Paket und seinem entsprechenden Preis nicht besonders gut.
🎃 Herzlichen Glückwunsch, Sie haben gerade ein Modell erstellt, das helfen kann, den Preis einiger Kürbissorten vorherzusagen. Ihr Kürbisfeld für die Feiertage wird wunderschön sein. Aber Sie können wahrscheinlich ein besseres Modell erstellen!
5. Erstellen Sie ein polynomiales Regressionsmodell
<p > <img src="../../images/linear-polynomial.png" width="800"/> <figcaption>Infografik von Dasani Madipalli</figcaption>
<!--
{width="800"}-->
Manchmal haben unsere Daten keine lineare Beziehung, aber wir möchten trotzdem ein Ergebnis vorhersagen. Die polynomiale Regression kann uns helfen, Vorhersagen für komplexere nicht-lineare Beziehungen zu treffen.
Nehmen wir zum Beispiel die Beziehung zwischen Verpackung und Preis in unserem Kürbis-Datensatz. Während es manchmal eine lineare Beziehung zwischen Variablen gibt – je größer der Kürbis im Volumen, desto höher der Preis – können diese Beziehungen manchmal nicht als Ebene oder gerade Linie dargestellt werden.
> ✅ Hier sind einige weitere Beispiele für Daten, die polynomiale Regression verwenden könnten. > > Werfen Sie einen weiteren Blick auf die Beziehung zwischen Sorte und Preis im vorherigen Diagramm. Sieht dieser Streudiagramm so aus, als sollte er unbedingt mit einer geraden Linie analysiert werden? Vielleicht nicht. In diesem Fall können Sie polynomiale Regression ausprobieren. > > ✅ Polynome sind mathematische Ausdrücke, die aus einer oder mehreren Variablen und Koeffizienten bestehen können.
Trainieren eines polynomialen Regressionsmodells mit dem Trainingssatz
Die polynomiale Regression erstellt eine gekrümmte Linie, um nichtlineare Daten besser anzupassen.
Schauen wir, ob ein polynomiales Modell besser darin ist, Vorhersagen zu treffen. Wir folgen einem ähnlichen Verfahren wie zuvor:
-
Erstellen Sie ein Rezept, das die Vorverarbeitungsschritte angibt, die an unseren Daten durchgeführt werden müssen, um sie für die Modellierung vorzubereiten, z. B.: Kodierung von Prädiktoren und Berechnung von Polynomen eines Grades n.
-
Erstellen Sie eine Modellspezifikation.
-
Bündeln Sie das Rezept und die Modellspezifikation in einen Workflow.
-
Erstellen Sie ein Modell, indem Sie den Workflow anpassen.
-
Bewerten Sie, wie gut das Modell auf den Testdaten abschneidet.
Legen wir los!
# Specify a recipe
poly_pumpkins_recipe <-
recipe(price ~ package, data = pumpkins_train) %>%
step_integer(all_predictors(), zero_based = TRUE) %>%
step_poly(all_predictors(), degree = 4)
# Create a model specification
poly_spec <- linear_reg() %>%
set_engine("lm") %>%
set_mode("regression")
# Bundle recipe and model spec into a workflow
poly_wf <- workflow() %>%
add_recipe(poly_pumpkins_recipe) %>%
add_model(poly_spec)
# Create a model
poly_wf_fit <- poly_wf %>%
fit(data = pumpkins_train)
# Print learned model coefficients
poly_wf_fit
Modellleistung bewerten
👏👏Du hast ein Polynommodell erstellt – lass uns Vorhersagen für den Testdatensatz machen!
# Make price predictions on test data
poly_results <- poly_wf_fit %>% predict(new_data = pumpkins_test) %>%
bind_cols(pumpkins_test %>% select(c(package, price))) %>%
relocate(.pred, .after = last_col())
# Print the results
poly_results %>%
slice_head(n = 10)
Woo-hoo, lass uns bewerten, wie das Modell auf dem test_set mit yardstick::metrics() abgeschnitten hat.
metrics(data = poly_results, truth = price, estimate = .pred)
🤩🤩 Viel bessere Leistung.
Das rmse sank von etwa 7 auf etwa 3, was darauf hinweist, dass der Fehler zwischen dem tatsächlichen Preis und dem vorhergesagten Preis reduziert wurde. Man kann dies grob so interpretieren, dass falsche Vorhersagen im Durchschnitt um etwa 3 \$ danebenliegen. Das rsq stieg von etwa 0,4 auf 0,8.
Alle diese Metriken zeigen, dass das polynomiale Modell deutlich besser abschneidet als das lineare Modell. Gute Arbeit!
Lass uns sehen, ob wir das visualisieren können!
# Bind encoded package column to the results
poly_results <- poly_results %>%
bind_cols(package_encode %>%
rename(package_integer = package)) %>%
relocate(package_integer, .after = package)
# Print new results data frame
poly_results %>%
slice_head(n = 5)
# Make a scatter plot
poly_results %>%
ggplot(mapping = aes(x = package_integer, y = price)) +
geom_point(size = 1.6) +
# Overlay a line of best fit
geom_line(aes(y = .pred), color = "midnightblue", size = 1.2) +
xlab("package")
Du kannst eine geschwungene Linie sehen, die besser zu deinen Daten passt! 🤩
Du kannst dies noch glatter machen, indem du eine polynomiale Formel an geom_smooth übergibst, wie hier:
# Make a scatter plot
poly_results %>%
ggplot(mapping = aes(x = package_integer, y = price)) +
geom_point(size = 1.6) +
# Overlay a line of best fit
geom_smooth(method = lm, formula = y ~ poly(x, degree = 4), color = "midnightblue", size = 1.2, se = FALSE) +
xlab("package")
Ganz wie eine geschmeidige Kurve!🤩
So erstellen Sie eine neue Vorhersage:
# Make a hypothetical data frame
hypo_tibble <- tibble(package = "bushel baskets")
# Make predictions using linear model
lm_pred <- lm_wf_fit %>% predict(new_data = hypo_tibble)
# Make predictions using polynomial model
poly_pred <- poly_wf_fit %>% predict(new_data = hypo_tibble)
# Return predictions in a list
list("linear model prediction" = lm_pred,
"polynomial model prediction" = poly_pred)
Die Vorhersage des polynomial model ergibt Sinn, wenn man die Streudiagramme von price und package betrachtet! Und falls dies ein besseres Modell als das vorherige ist, basierend auf denselben Daten, solltest du für diese teureren Kürbisse ein höheres Budget einplanen!
🏆 Gut gemacht! Du hast in einer Lektion zwei Regressionsmodelle erstellt. Im letzten Abschnitt über Regression wirst du etwas über logistische Regression lernen, um Kategorien zu bestimmen.
🚀Challenge
Teste mehrere verschiedene Variablen in diesem Notebook, um zu sehen, wie die Korrelation mit der Modellgenauigkeit zusammenhängt.
Post-lecture quiz
Review & Selbststudium
In dieser Lektion haben wir über Lineare Regression gelernt. Es gibt andere wichtige Arten der Regression. Lies über Stepwise-, Ridge-, Lasso- und Elasticnet-Techniken. Ein guter Kurs, um mehr darüber zu lernen, ist der Stanford Statistical Learning course.
Wenn du mehr darüber erfahren möchtest, wie du das großartige Tidymodels-Framework nutzen kannst, sieh dir bitte die folgenden Ressourcen an:
-
Tidymodels-Website: Get started with Tidymodels
-
Max Kuhn und Julia Silge, Tidy Modeling with R.
DANK AN:
Allison Horst für die Erstellung der großartigen Illustrationen, die R einladender und ansprechender machen. Weitere Illustrationen findest du in ihrer Galerie.
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Wiederholung einiger Regressionen
Anweisungen
In der Lektion hast du einen Teil der Kürbisdaten verwendet. Gehe nun zurück zu den ursprünglichen Daten und versuche, alle Daten, bereinigt und standardisiert, zu verwenden, um ein Logistisches Regressionsmodell zu erstellen.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Notebook wird präsentiert mit einem gut erklärten und gut funktionierenden Modell | Ein Notebook wird präsentiert mit einem Modell, das minimal funktioniert | Ein Notebook wird präsentiert mit einem schlecht funktionierenden Modell oder gar keinem |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Kürbissorten und Farbe
Lade die benötigten Bibliotheken und den Datensatz. Konvertiere die Daten in ein DataFrame, das einen Teil der Daten enthält:
Schauen wir uns die Beziehung zwischen Farbe und Sorte an.
import pandas as pd
import numpy as np
full_pumpkins = pd.read_csv('../data/US-pumpkins.csv')
full_pumpkins.head()
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Logistische Regression zur Vorhersage von Kategorien

Quiz vor der Lektion
> ### Diese Lektion ist auch in R verfügbar!
Einführung
In dieser letzten Lektion zur Regression, einer der grundlegenden klassischen ML-Techniken, werfen wir einen Blick auf die logistische Regression. Diese Technik wird verwendet, um Muster zu erkennen und binäre Kategorien vorherzusagen. Ist diese Süßigkeit Schokolade oder nicht? Ist diese Krankheit ansteckend oder nicht? Wird dieser Kunde dieses Produkt wählen oder nicht?
In dieser Lektion lernen Sie:
- Eine neue Bibliothek für Datenvisualisierung
- Techniken für die logistische Regression
✅ Vertiefen Sie Ihr Verständnis für diese Art der Regression in diesem Learn-Modul
Voraussetzungen
Nachdem wir mit den Kürbisdaten gearbeitet haben, sind wir nun vertraut genug, um zu erkennen, dass es eine binäre Kategorie gibt, mit der wir arbeiten können: Color.
Lassen Sie uns ein Modell der logistischen Regression erstellen, um vorherzusagen, welche Farbe ein gegebener Kürbis wahrscheinlich hat (orange 🎃 oder weiß 👻), basierend auf einigen Variablen.
> Warum sprechen wir in einer Lektion über Regression über binäre Klassifikation? Nur aus sprachlicher Bequemlichkeit, da die logistische Regression eigentlich eine Klassifikationsmethode ist, wenn auch eine lineare. Lernen Sie in der nächsten Lektion weitere Methoden zur Klassifikation von Daten kennen.
Die Frage definieren
Für unsere Zwecke formulieren wir dies als Binärfrage: 'Weiß' oder 'Nicht Weiß'. Es gibt auch eine 'gestreifte' Kategorie in unserem Datensatz, aber es gibt nur wenige Instanzen davon, sodass wir sie nicht verwenden. Sie verschwindet ohnehin, sobald wir Nullwerte aus dem Datensatz entfernen.
> 🎃 Fun Fact: Weiße Kürbisse werden manchmal als 'Geisterkürbisse' bezeichnet. Sie sind nicht sehr leicht zu schnitzen, daher sind sie nicht so beliebt wie die orangefarbenen, aber sie sehen cool aus! Wir könnten unsere Frage also auch so formulieren: 'Geist' oder 'Nicht Geist'. 👻
Über logistische Regression
Die logistische Regression unterscheidet sich in einigen wichtigen Punkten von der linearen Regression, die Sie zuvor kennengelernt haben.
> 🎥 Klicken Sie auf das Bild oben für eine kurze Videoübersicht zur logistischen Regression.
Binäre Klassifikation
Die logistische Regression bietet nicht dieselben Funktionen wie die lineare Regression. Erstere liefert eine Vorhersage über eine binäre Kategorie ("weiß oder nicht weiß"), während letztere kontinuierliche Werte vorhersagen kann, z. B. wie stark der Preis eines Kürbisses basierend auf seinem Ursprung und der Erntezeit steigen wird.
> Infografik von Dasani Madipalli
Andere Klassifikationen
Es gibt andere Arten der logistischen Regression, darunter multinomial und ordinal:
- Multinomial, bei der es mehr als eine Kategorie gibt - "Orange, Weiß und Gestreift".
- Ordinal, bei der es geordnete Kategorien gibt, nützlich, wenn wir unsere Ergebnisse logisch ordnen möchten, wie z. B. unsere Kürbisse, die nach einer endlichen Anzahl von Größen (mini, sm, med, lg, xl, xxl) geordnet sind.

Variablen MÜSSEN NICHT korrelieren
Erinnern Sie sich, wie die lineare Regression mit stärker korrelierten Variablen besser funktionierte? Bei der logistischen Regression ist das Gegenteil der Fall – die Variablen müssen nicht übereinstimmen. Das funktioniert gut für diese Daten, die nur schwache Korrelationen aufweisen.
Sie benötigen viele saubere Daten
Die logistische Regression liefert genauere Ergebnisse, wenn Sie mehr Daten verwenden; unser kleiner Datensatz ist für diese Aufgabe nicht optimal, also behalten Sie das im Hinterkopf.
> 🎥 Klicken Sie auf das Bild oben für eine kurze Videoübersicht zur Datenvorbereitung für die lineare Regression.
✅ Überlegen Sie, welche Arten von Daten sich gut für die logistische Regression eignen würden.
Übung - Daten bereinigen
Bereinigen Sie zunächst die Daten ein wenig, indem Sie Nullwerte entfernen und nur einige der Spalten auswählen:
-
Fügen Sie den folgenden Code hinzu:
```python
columns_to_select = ['City Name','Package','Variety', 'Origin','Item Size', 'Color'] pumpkins = full_pumpkins.loc[:, columns_to_select]
pumpkins.dropna(inplace=True) ```
Sie können sich jederzeit Ihren neuen DataFrame ansehen:
python pumpkins.info
Visualisierung - Kategorisches Diagramm
Bis jetzt haben Sie das Starter-Notebook mit Kürbisdaten geladen und bereinigt, sodass ein Datensatz mit einigen Variablen, einschließlich Color, erhalten bleibt. Lassen Sie uns den DataFrame im Notebook mit einer anderen Bibliothek visualisieren: Seaborn, das auf Matplotlib basiert, das wir zuvor verwendet haben.
Seaborn bietet einige interessante Möglichkeiten, Ihre Daten zu visualisieren. Zum Beispiel können Sie die Verteilungen der Daten für jede Variety und Color in einem kategorischen Diagramm vergleichen.
-
Erstellen Sie ein solches Diagramm mit der Funktion
catplot, indem Sie unsere Kürbisdatenpumpkinsverwenden und eine Farbzuordnung für jede Kürbiskategorie (orange oder weiß) angeben:```python import seaborn as sns
palette = { 'ORANGE': 'orange', 'WHITE': 'wheat', }
sns.catplot( data=pumpkins, y="Variety", hue="Color", kind="count", palette=palette, ) ```

Durch die Beobachtung der Daten können Sie sehen, wie die Farbdaten mit der Sorte zusammenhängen.
✅ Welche interessanten Untersuchungen können Sie sich anhand dieses kategorischen Diagramms vorstellen?
Datenvorverarbeitung: Feature- und Label-Encoding
Unser Kürbisdatensatz enthält Zeichenkettenwerte für alle Spalten. Mit kategorialen Daten zu arbeiten, ist für Menschen intuitiv, aber nicht für Maschinen. Maschinelle Lernalgorithmen arbeiten gut mit Zahlen. Deshalb ist Encoding ein sehr wichtiger Schritt in der Datenvorverarbeitungsphase, da es uns ermöglicht, kategoriale Daten in numerische Daten umzuwandeln, ohne Informationen zu verlieren. Gutes Encoding führt zu einem guten Modell.
Für das Feature-Encoding gibt es zwei Haupttypen von Encodern:
-
Ordinal-Encoder: Er eignet sich gut für ordinale Variablen, also kategoriale Variablen, deren Daten einer logischen Reihenfolge folgen, wie die Spalte
Item Sizein unserem Datensatz. Er erstellt eine Zuordnung, sodass jede Kategorie durch eine Zahl dargestellt wird, die der Reihenfolge der Kategorie in der Spalte entspricht.```python from sklearn.preprocessing import OrdinalEncoder
item_size_categories = [['sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo']] ordinal_features = ['Item Size'] ordinal_encoder = OrdinalEncoder(categories=item_size_categories) ```
-
Kategorischer Encoder: Er eignet sich gut für nominale Variablen, also kategoriale Variablen, deren Daten keiner logischen Reihenfolge folgen, wie alle Merkmale außer
Item Sizein unserem Datensatz. Es handelt sich um ein One-Hot-Encoding, was bedeutet, dass jede Kategorie durch eine binäre Spalte dargestellt wird: Die codierte Variable ist gleich 1, wenn der Kürbis zu dieser Sorte gehört, und 0, andernfalls.```python from sklearn.preprocessing import OneHotEncoder
categorical_features = ['City Name', 'Package', 'Variety', 'Origin'] categorical_encoder = OneHotEncoder(sparse_output=False) ```
Dann wird ColumnTransformer verwendet, um mehrere Encoder in einem einzigen Schritt zu kombinieren und auf die entsprechenden Spalten anzuwenden.
from sklearn.compose import ColumnTransformer
ct = ColumnTransformer(transformers=[
('ord', ordinal_encoder, ordinal_features),
('cat', categorical_encoder, categorical_features)
])
ct.set_output(transform='pandas')
encoded_features = ct.fit_transform(pumpkins)
Zum Codieren des Labels verwenden wir die LabelEncoder-Klasse von Scikit-learn, eine Dienstprogrammsklasse, die dabei hilft, Labels zu normalisieren, sodass sie nur Werte zwischen 0 und n_classes-1 (hier 0 und 1) enthalten.
from sklearn.preprocessing import LabelEncoder
label_encoder = LabelEncoder()
encoded_label = label_encoder.fit_transform(pumpkins['Color'])
Sobald wir die Merkmale und das Label codiert haben, können wir sie in einem neuen DataFrame encoded_pumpkins zusammenführen.
encoded_pumpkins = encoded_features.assign(Color=encoded_label)
✅ Welche Vorteile hat die Verwendung eines Ordinal-Encoders für die Spalte Item Size?
Beziehungen zwischen Variablen analysieren
Nachdem wir unsere Daten vorverarbeitet haben, können wir die Beziehungen zwischen den Merkmalen und dem Label analysieren, um eine Vorstellung davon zu bekommen, wie gut das Modell das Label anhand der Merkmale vorhersagen kann. Die beste Möglichkeit, diese Art von Analyse durchzuführen, ist das Plotten der Daten. Wir verwenden erneut die Seaborn-Funktion catplot, um die Beziehungen zwischen Item Size, Variety und Color in einem kategorischen Diagramm zu visualisieren. Um die Daten besser darzustellen, verwenden wir die codierte Spalte Item Size und die nicht codierte Spalte Variety.
palette = {
'ORANGE': 'orange',
'WHITE': 'wheat',
}
pumpkins['Item Size'] = encoded_pumpkins['ord__Item Size']
g = sns.catplot(
data=pumpkins,
x="Item Size", y="Color", row='Variety',
kind="box", orient="h",
sharex=False, margin_titles=True,
height=1.8, aspect=4, palette=palette,
)
g.set(xlabel="Item Size", ylabel="").set(xlim=(0,6))
g.set_titles(row_template="{row_name}")

Verwenden Sie einen Swarm-Plot
Da Color eine binäre Kategorie (Weiß oder Nicht Weiß) ist, benötigt sie 'einen spezialisierten Ansatz zur Visualisierung'. Es gibt andere Möglichkeiten, die Beziehung dieser Kategorie zu anderen Variablen zu visualisieren.
Sie können Variablen nebeneinander mit Seaborn-Diagrammen visualisieren.
-
Probieren Sie einen 'Swarm'-Plot aus, um die Verteilung der Werte darzustellen:
python palette = { 0: 'orange', 1: 'wheat' } sns.swarmplot(x="Color", y="ord__Item Size", data=encoded_pumpkins, palette=palette)
Achtung: Der obige Code könnte eine Warnung generieren, da Seaborn Schwierigkeiten hat, eine solche Menge an Datenpunkten in einem Swarm-Plot darzustellen. Eine mögliche Lösung ist, die Größe der Marker mit dem Parameter 'size' zu verringern. Beachten Sie jedoch, dass dies die Lesbarkeit des Diagramms beeinträchtigen kann.
> 🧮 Zeigen Sie mir die Mathematik
>
> Die logistische Regression basiert auf dem Konzept der 'Maximum-Likelihood' unter Verwendung von Sigmoid-Funktionen. Eine 'Sigmoid-Funktion' sieht auf einem Diagramm wie eine 'S'-Form aus. Sie nimmt einen Wert und ordnet ihn einem Bereich zwischen 0 und 1 zu. Ihre Kurve wird auch als 'logistische Kurve' bezeichnet. Ihre Formel sieht so aus:
>
>
>
> Dabei liegt der Mittelpunkt der Sigmoid-Funktion bei x = 0, L ist der maximale Wert der Kurve, und k ist die Steilheit der Kurve. Wenn das Ergebnis der Funktion größer als 0,5 ist, wird das Label der Klasse '1' der binären Wahl zugeordnet. Andernfalls wird es als '0' klassifiziert.
Erstellen Sie Ihr Modell
Ein Modell zu erstellen, um diese binäre Klassifikation zu finden, ist in Scikit-learn überraschend einfach.
> 🎥 Klicken Sie auf das Bild oben für eine kurze Videoübersicht zum Erstellen eines linearen Regressionsmodells.
-
Wählen Sie die Variablen aus, die Sie in Ihrem Klassifikationsmodell verwenden möchten, und teilen Sie die Trainings- und Testdatensätze mit
train_test_split()auf:```python from sklearn.model_selection import train_test_split
X = encoded_pumpkins[encoded_pumpkins.columns.difference(['Color'])] y = encoded_pumpkins['Color']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
```
-
Jetzt können Sie Ihr Modell trainieren, indem Sie
fit()mit Ihren Trainingsdaten aufrufen, und das Ergebnis ausgeben:```python from sklearn.metrics import f1_score, classification_report from sklearn.linear_model import LogisticRegression
model = LogisticRegression() model.fit(X_train, y_train) predictions = model.predict(X_test)
print(classification_report(y_test, predictions)) print('Predicted labels: ', predictions) print('F1-score: ', f1_score(y_test, predictions)) ```
Werfen Sie einen Blick auf die Bewertung Ihres Modells. Es ist nicht schlecht, wenn man bedenkt, dass Sie nur etwa 1000 Datenzeilen haben:
```output precision recall f1-score support
0 0.94 0.98 0.96 166 1 0.85 0.67 0.75 33 accuracy 0.92 199 macro avg 0.89 0.82 0.85 199 weighted avg 0.92 0.92 0.92 199 Predicted labels: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 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 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 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 1 0 0 0 0 0 0 0 0 1 1] F1-score: 0.7457627118644068```
Bessere Verständlichkeit durch eine Konfusionsmatrix
Während Sie einen Bewertungsbericht Begriffe durch die oben genannten Elemente ausgeben können, könnten Sie Ihr Modell leichter verstehen, indem Sie eine Konfusionsmatrix verwenden, um zu analysieren, wie das Modell abschneidet.
> 🎓 Eine 'Konfusionsmatrix' (oder 'Fehlermatrix') ist eine Tabelle, die die tatsächlichen vs. vorhergesagten positiven und negativen Werte Ihres Modells darstellt und so die Genauigkeit der Vorhersagen misst.
-
Um eine Konfusionsmatrix zu verwenden, rufen Sie
confusion_matrix()auf:python from sklearn.metrics import confusion_matrix confusion_matrix(y_test, predictions)Werfen Sie einen Blick auf die Konfusionsmatrix Ihres Modells:
output array([[162, 4], [ 11, 22]])
In Scikit-learn sind die Zeilen (Achse 0) die tatsächlichen Labels und die Spalten (Achse 1) die vorhergesagten Labels.
| 0 | 1 | |
|---|---|---|
| 0 | TN | FP |
| 1 | FN | TP |
Was passiert hier? Angenommen, unser Modell soll Kürbisse zwischen zwei binären Kategorien klassifizieren: Kategorie 'weiß' und Kategorie 'nicht-weiß'.
- Wenn Ihr Modell einen Kürbis als nicht weiß vorhersagt und er tatsächlich zur Kategorie 'nicht-weiß' gehört, nennen wir das ein True Negative (TN), dargestellt durch die Zahl oben links.
- Wenn Ihr Modell einen Kürbis als weiß vorhersagt und er tatsächlich zur Kategorie 'nicht-weiß' gehört, nennen wir das ein False Negative (FN), dargestellt durch die Zahl unten links.
- Wenn Ihr Modell einen Kürbis als nicht weiß vorhersagt und er tatsächlich zur Kategorie 'weiß' gehört, nennen wir das ein False Positive (FP), dargestellt durch die Zahl oben rechts.
- Wenn Ihr Modell einen Kürbis als weiß vorhersagt und er tatsächlich zur Kategorie 'weiß' gehört, nennen wir das ein True Positive (TP), dargestellt durch die Zahl unten rechts.
Wie Sie sich denken können, ist es wünschenswert, eine größere Anzahl von True Positives und True Negatives sowie eine geringere Anzahl von False Positives und False Negatives zu haben, was darauf hinweist, dass das Modell besser abschneidet. Wie hängt die Konfusionsmatrix mit Präzision und Recall zusammen? Denken Sie daran, dass der oben gedruckte Klassifikationsbericht eine Präzision von 0,85 und einen Recall von 0,67 zeigte.
Präzision = tp / (tp + fp) = 22 / (22 + 4) = 0,8461538461538461
Recall = tp / (tp + fn) = 22 / (22 + 11) = 0,6666666666666666
✅ F: Wie hat das Modell laut der Konfusionsmatrix abgeschnitten? A: Gar nicht schlecht; es gibt eine gute Anzahl an True Negatives, aber auch ein paar False Negatives.
Lassen Sie uns die Begriffe, die wir zuvor gesehen haben, mit Hilfe der Zuordnung von TP/TN und FP/FN in der Konfusionsmatrix noch einmal betrachten:
🎓 Präzision: TP/(TP + FP) Der Anteil relevanter Instanzen unter den abgerufenen Instanzen (z. B. welche Labels korrekt zugeordnet wurden)
🎓 Recall: TP/(TP + FN) Der Anteil relevanter Instanzen, die abgerufen wurden, unabhängig davon, ob sie korrekt zugeordnet wurden oder nicht
🎓 f1-Score: (2 * Präzision * Recall)/(Präzision + Recall) Ein gewichteter Durchschnitt von Präzision und Recall, wobei 1 das Beste und 0 das Schlechteste ist
🎓 Support: Die Anzahl der Vorkommen jedes abgerufenen Labels
🎓 Genauigkeit: (TP + TN)/(TP + TN + FP + FN) Der Prozentsatz der Labels, die für eine Stichprobe korrekt vorhergesagt wurden.
🎓 Makro-Durchschnitt: Die Berechnung des ungewichteten Durchschnitts der Metriken für jedes Label, ohne das Ungleichgewicht der Labels zu berücksichtigen.
🎓 Gewichteter Durchschnitt: Die Berechnung des Durchschnitts der Metriken für jedes Label, wobei das Ungleichgewicht der Labels durch Gewichtung nach ihrem Support (der Anzahl der tatsächlichen Instanzen für jedes Label) berücksichtigt wird.
✅ Können Sie sich vorstellen, welche Metrik Sie beobachten sollten, wenn Sie die Anzahl der False Negatives reduzieren möchten?
Visualisierung der ROC-Kurve dieses Modells
> 🎥 Klicken Sie auf das obige Bild für eine kurze Videoübersicht zu ROC-Kurven
Lassen Sie uns eine weitere Visualisierung durchführen, um die sogenannte 'ROC'-Kurve zu sehen:
from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
y_scores = model.predict_proba(X_test)
fpr, tpr, thresholds = roc_curve(y_test, y_scores[:,1])
fig = plt.figure(figsize=(6, 6))
plt.plot([0, 1], [0, 1], 'k--')
plt.plot(fpr, tpr)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.show()
Verwenden Sie Matplotlib, um die Receiver Operating Characteristic oder ROC des Modells zu zeichnen. ROC-Kurven werden oft verwendet, um die Ausgabe eines Klassifikators in Bezug auf seine True Positives und False Positives zu betrachten. "ROC-Kurven zeigen typischerweise die True Positive Rate auf der Y-Achse und die False Positive Rate auf der X-Achse." Daher sind die Steilheit der Kurve und der Abstand zwischen der Mittellinie und der Kurve wichtig: Sie möchten eine Kurve, die schnell nach oben und über die Linie verläuft. In unserem Fall gibt es zunächst False Positives, und dann verläuft die Linie korrekt nach oben und darüber:

Verwenden Sie abschließend die roc_auc_score API von Scikit-learn, um die tatsächliche 'Fläche unter der Kurve' (AUC) zu berechnen:
auc = roc_auc_score(y_test,y_scores[:,1])
print(auc)
Das Ergebnis ist 0.9749908725812341. Da die AUC von 0 bis 1 reicht, möchten Sie einen hohen Wert erzielen, da ein Modell, das zu 100 % korrekte Vorhersagen trifft, eine AUC von 1 hat; in diesem Fall ist das Modell ziemlich gut.
In zukünftigen Lektionen zu Klassifikationen werden Sie lernen, wie Sie iterativ die Werte Ihres Modells verbessern können. Aber für den Moment: Herzlichen Glückwunsch! Sie haben diese Lektionen zur Regression abgeschlossen!
🚀Herausforderung
Es gibt noch viel mehr über logistische Regression zu entdecken! Aber der beste Weg zu lernen ist, zu experimentieren. Finden Sie einen Datensatz, der sich für diese Art der Analyse eignet, und erstellen Sie ein Modell damit. Was lernen Sie dabei? Tipp: Probieren Sie Kaggle für interessante Datensätze aus.
Quiz nach der Vorlesung
Rückblick & Selbststudium
Lesen Sie die ersten Seiten dieses Papiers von Stanford über einige praktische Anwendungen der logistischen Regression. Denken Sie über Aufgaben nach, die besser für die eine oder andere Art von Regression geeignet sind, die wir bisher studiert haben. Was würde am besten funktionieren?
Aufgabe
Wiederholen Sie diese Regression
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die durch die Nutzung dieser Übersetzung entstehen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Logistische Regression - Lektion 4
Laden Sie die benötigten Bibliotheken und den Datensatz. Konvertieren Sie die Daten in ein DataFrame, das einen Teil der Daten enthält:
import pandas as pd
import numpy as np
full_pumpkins = pd.read_csv('../../data/US-pumpkins.csv')
full_pumpkins.head()
# Select the columns we want to use
columns_to_select = ['City Name','Package','Variety', 'Origin','Item Size', 'Color']
pumpkins = full_pumpkins.loc[:, columns_to_select]
# Drop rows with missing values
pumpkins.dropna(inplace=True)
pumpkins.head()
Werfen wir einen Blick auf unsere Daten!
Indem wir sie mit Seaborn visualisieren
import seaborn as sns
# Specify colors for each values of the hue variable
palette = {
'ORANGE': 'orange',
'WHITE': 'wheat',
}
# Plot a bar plot to visualize how many pumpkins of each variety are orange or white
sns.catplot(
data=pumpkins, y="Variety", hue="Color", kind="count",
palette=palette,
)
Datenvorverarbeitung
Lassen Sie uns Merkmale und Labels codieren, um die Daten besser darzustellen und das Modell zu trainieren.
# Let's look at the different values of the 'Item Size' column
pumpkins['Item Size'].unique()
from sklearn.preprocessing import OrdinalEncoder
# Encode the 'Item Size' column using ordinal encoding
item_size_categories = [['sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo']]
ordinal_features = ['Item Size']
ordinal_encoder = OrdinalEncoder(categories=item_size_categories)
from sklearn.preprocessing import OneHotEncoder
# Encode all the other features using one-hot encoding
categorical_features = ['City Name', 'Package', 'Variety', 'Origin']
categorical_encoder = OneHotEncoder(sparse_output=False)
from sklearn.compose import ColumnTransformer
ct = ColumnTransformer(transformers=[
('ord', ordinal_encoder, ordinal_features),
('cat', categorical_encoder, categorical_features)
])
# Get the encoded features as a pandas DataFrame
ct.set_output(transform='pandas')
encoded_features = ct.fit_transform(pumpkins)
encoded_features.head()
from sklearn.preprocessing import LabelEncoder
# Encode the 'Color' column using label encoding
label_encoder = LabelEncoder()
encoded_label = label_encoder.fit_transform(pumpkins['Color'])
encoded_pumpkins = encoded_features.assign(Color=encoded_label)
encoded_pumpkins.head()
# Let's look at the mapping between the encoded values and the original values
list(label_encoder.inverse_transform([0, 1]))
palette = {
'ORANGE': 'orange',
'WHITE': 'wheat',
}
# We need the encoded Item Size column to use it as the x-axis values in the plot
pumpkins['Item Size'] = encoded_pumpkins['ord__Item Size']
g = sns.catplot(
data=pumpkins,
x="Item Size", y="Color", row='Variety',
kind="box", orient="h",
sharex=False, margin_titles=True,
height=1.8, aspect=4, palette=palette,
)
# Defining axis labels
g.set(xlabel="Item Size", ylabel="").set(xlim=(0,6))
g.set_titles(row_template="{row_name}")
import warnings
warnings.filterwarnings(action='ignore', category=UserWarning, module='seaborn')
# Suppressing warning message claiming that a portion of points cannot be placed into the plot due to the high number of data points
import warnings
warnings.filterwarnings(action='ignore', category=UserWarning, module='seaborn')
palette = {
0: 'orange',
1: 'wheat'
}
sns.swarmplot(x="Color", y="ord__Item Size", hue="Color", data=encoded_pumpkins, palette=palette)
Achtung: Warnungen zu ignorieren ist KEINE gute Praxis und sollte, wenn möglich, vermieden werden. Warnungen enthalten oft nützliche Hinweise, die uns helfen, unseren Code zu verbessern und ein Problem zu lösen.
Der Grund, warum wir diese spezielle Warnung ignorieren, ist, die Lesbarkeit des Plots zu gewährleisten. Das Plotten aller Datenpunkte mit einer reduzierten Markierungsgröße, während die Konsistenz der Farbpalette beibehalten wird, führt zu einer unklaren Visualisierung.
Erstellen Sie Ihr Modell
from sklearn.model_selection import train_test_split
# X is the encoded features
X = encoded_pumpkins[encoded_pumpkins.columns.difference(['Color'])]
# y is the encoded label
y = encoded_pumpkins['Color']
# Split the data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
from sklearn.metrics import f1_score, classification_report
from sklearn.linear_model import LogisticRegression
# Train a logistic regression model on the pumpkin dataset
model = LogisticRegression()
model.fit(X_train, y_train)
predictions = model.predict(X_test)
# Evaluate the model and print the results
print(classification_report(y_test, predictions))
print('Predicted labels: ', predictions)
print('F1-score: ', f1_score(y_test, predictions))
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test, predictions)
from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
y_scores = model.predict_proba(X_test)
# calculate ROC curve
fpr, tpr, thresholds = roc_curve(y_test, y_scores[:,1])
# plot ROC curve
fig = plt.figure(figsize=(6, 6))
# Plot the diagonal 50% line
plt.plot([0, 1], [0, 1], 'k--')
# Plot the FPR and TPR achieved by our model
plt.plot(fpr, tpr)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.show()
# Calculate AUC score
auc = roc_auc_score(y_test,y_scores[:,1])
print(auc)
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erstellen Sie ein logistisches Regressionsmodell - Lektion 4

Quiz vor der Vorlesung
Einführung
In dieser letzten Lektion zur Regression, einer der grundlegenden klassischen ML-Techniken, werfen wir einen Blick auf die logistische Regression. Diese Technik wird verwendet, um Muster zu erkennen und binäre Kategorien vorherzusagen. Ist diese Süßigkeit Schokolade oder nicht? Ist diese Krankheit ansteckend oder nicht? Wird dieser Kunde dieses Produkt wählen oder nicht?
In dieser Lektion lernen Sie:
- Techniken der logistischen Regression
✅ Vertiefen Sie Ihr Verständnis für die Arbeit mit dieser Art von Regression in diesem Learn-Modul
Voraussetzung
Nachdem wir mit den Kürbisdaten gearbeitet haben, sind wir nun vertraut genug, um zu erkennen, dass es eine binäre Kategorie gibt, mit der wir arbeiten können: Color.
Lassen Sie uns ein logistisches Regressionsmodell erstellen, um vorherzusagen, welche Farbe ein gegebener Kürbis wahrscheinlich hat (orange 🎃 oder weiß 👻), basierend auf einigen Variablen.
> Warum sprechen wir über binäre Klassifikation in einer Lektion über Regression? Nur aus sprachlicher Bequemlichkeit, da die logistische Regression eigentlich eine Klassifikationsmethode ist, wenn auch eine lineare. Lernen Sie in der nächsten Lektion weitere Methoden zur Klassifikation von Daten kennen.
Für diese Lektion benötigen wir die folgenden Pakete:
-
tidyverse: Das tidyverse ist eine Sammlung von R-Paketen, die Datenwissenschaft schneller, einfacher und unterhaltsamer macht! -
tidymodels: Das tidymodels Framework ist eine Sammlung von Paketen für Modellierung und maschinelles Lernen. -
janitor: Das janitor-Paket bietet einfache Werkzeuge zur Untersuchung und Bereinigung von unordentlichen Daten. -
ggbeeswarm: Das ggbeeswarm-Paket bietet Methoden zur Erstellung von Beeswarm-Diagrammen mit ggplot2.
Sie können diese Pakete wie folgt installieren:
install.packages(c("tidyverse", "tidymodels", "janitor", "ggbeeswarm"))
Alternativ überprüft das untenstehende Skript, ob Sie die für dieses Modul erforderlichen Pakete installiert haben, und installiert sie bei Bedarf.
suppressWarnings(if (!require("pacman"))install.packages("pacman"))
pacman::p_load(tidyverse, tidymodels, janitor, ggbeeswarm)
Definiere die Frage
Für unsere Zwecke werden wir dies als binär ausdrücken: 'Weiß' oder 'Nicht Weiß'. Es gibt auch eine Kategorie 'gestreift' in unserem Datensatz, aber es gibt nur wenige Instanzen davon, daher werden wir sie nicht verwenden. Sie verschwindet ohnehin, sobald wir Nullwerte aus dem Datensatz entfernen.
> 🎃 Fun Fact: Wir nennen weiße Kürbisse manchmal 'Geister'-Kürbisse. Sie sind nicht sehr leicht zu schnitzen, daher sind sie nicht so beliebt wie die orangenen, aber sie sehen cool aus! Wir könnten unsere Frage also auch so formulieren: 'Geist' oder 'Nicht Geist'. 👻
Über logistische Regression
Die logistische Regression unterscheidet sich in einigen wichtigen Punkten von der linearen Regression, die du zuvor gelernt hast.
Binäre Klassifikation
Die logistische Regression bietet nicht die gleichen Funktionen wie die lineare Regression. Erstere liefert eine Vorhersage über eine binäre Kategorie ("orange oder nicht orange"), während letztere in der Lage ist, kontinuierliche Werte vorherzusagen, zum Beispiel basierend auf der Herkunft eines Kürbisses und der Erntezeit, wie stark sein Preis steigen wird.

Andere Klassifikationen
Es gibt andere Arten der logistischen Regression, einschließlich multinomialer und ordinaler:
-
Multinomial, bei der es mehr als eine Kategorie gibt - "Orange, Weiß und Gestreift".
-
Ordinal, bei der geordnete Kategorien verwendet werden, nützlich, wenn wir unsere Ergebnisse logisch ordnen möchten, wie unsere Kürbisse, die nach einer begrenzten Anzahl von Größen geordnet sind (mini, sm, med, lg, xl, xxl).

Variablen MÜSSEN NICHT korrelieren
Erinnerst du dich, wie die lineare Regression besser mit stärker korrelierten Variablen funktionierte? Die logistische Regression ist das Gegenteil - die Variablen müssen nicht übereinstimmen. Das funktioniert für diese Daten, die nur schwache Korrelationen aufweisen.
Du brauchst viele saubere Daten
Die logistische Regression liefert genauere Ergebnisse, wenn du mehr Daten verwendest; unser kleiner Datensatz ist für diese Aufgabe nicht optimal, also behalte das im Hinterkopf.
✅ Überlege, welche Arten von Daten sich gut für die logistische Regression eignen würden.
Übung - Daten bereinigen
Bereinige zunächst die Daten ein wenig, indem du Nullwerte entfernst und nur einige der Spalten auswählst:
- Füge den folgenden Code hinzu:
# Load the core tidyverse packages
library(tidyverse)
# Import the data and clean column names
pumpkins <- read_csv(file = "https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv") %>%
clean_names()
# Select desired columns
pumpkins_select <- pumpkins %>%
select(c(city_name, package, variety, origin, item_size, color))
# Drop rows containing missing values and encode color as factor (category)
pumpkins_select <- pumpkins_select %>%
drop_na() %>%
mutate(color = factor(color))
# View the first few rows
pumpkins_select %>%
slice_head(n = 5)
Sie können jederzeit einen Blick auf Ihren neuen Dataframe werfen, indem Sie die Funktion glimpse() wie unten gezeigt verwenden:
pumpkins_select %>%
glimpse()
Lassen Sie uns bestätigen, dass wir tatsächlich ein binäres Klassifikationsproblem bearbeiten:
# Subset distinct observations in outcome column
pumpkins_select %>%
distinct(color)
Visualisierung - kategorisches Diagramm
Bis jetzt haben Sie die Kürbisdaten erneut geladen und bereinigt, sodass ein Datensatz mit einigen Variablen, einschließlich Farbe, erhalten bleibt. Lassen Sie uns das Dataframe im Notebook mithilfe der ggplot-Bibliothek visualisieren.
Die ggplot-Bibliothek bietet einige praktische Möglichkeiten, Ihre Daten zu visualisieren. Zum Beispiel können Sie die Verteilungen der Daten für jede Sorte und Farbe in einem kategorischen Diagramm vergleichen.
- Erstellen Sie ein solches Diagramm, indem Sie die Funktion geombar verwenden, unsere Kürbisdaten nutzen und eine Farbzuordnung für jede Kürbiskategorie (orange oder weiß) festlegen:
# Specify colors for each value of the hue variable
palette <- c(ORANGE = "orange", WHITE = "wheat")
# Create the bar plot
ggplot(pumpkins_select, aes(y = variety, fill = color)) +
geom_bar(position = "dodge") +
scale_fill_manual(values = palette) +
labs(y = "Variety", fill = "Color") +
theme_minimal()
Durch die Beobachtung der Daten können Sie erkennen, wie die Farbdaten mit der Sorte zusammenhängen.
✅ Angesichts dieses kategorialen Diagramms, welche interessanten Untersuchungen können Sie sich vorstellen?
Datenvorverarbeitung: Feature-Encoding
Unser Kürbis-Datensatz enthält Zeichenkettenwerte in allen seinen Spalten. Mit kategorischen Daten zu arbeiten ist für Menschen intuitiv, aber nicht für Maschinen. Maschinelle Lernalgorithmen funktionieren besser mit Zahlen. Deshalb ist Encoding ein sehr wichtiger Schritt in der Datenvorverarbeitungsphase, da es uns ermöglicht, kategorische Daten in numerische Daten umzuwandeln, ohne Informationen zu verlieren. Ein gutes Encoding führt zu einem guten Modell.
Für das Feature-Encoding gibt es zwei Haupttypen von Encodern:
-
Ordinaler Encoder: Er eignet sich gut für ordinale Variablen, das sind kategorische Variablen, bei denen die Daten einer logischen Reihenfolge folgen, wie die Spalte
item_sizein unserem Datensatz. Er erstellt eine Zuordnung, bei der jede Kategorie durch eine Zahl repräsentiert wird, die der Reihenfolge der Kategorie in der Spalte entspricht. -
Kategorischer Encoder: Er eignet sich gut für nominale Variablen, das sind kategorische Variablen, bei denen die Daten keiner logischen Reihenfolge folgen, wie alle Merkmale außer
item_sizein unserem Datensatz. Es handelt sich um ein One-Hot-Encoding, was bedeutet, dass jede Kategorie durch eine binäre Spalte repräsentiert wird: Die kodierte Variable ist gleich 1, wenn der Kürbis zu dieser Sorte gehört, und 0, wenn nicht.
Tidymodels bietet ein weiteres praktisches Paket: recipes – ein Paket zur Datenvorverarbeitung. Wir definieren ein recipe, das angibt, dass alle Prädiktorspalten in eine Menge von Ganzzahlen kodiert werden sollen, prep es, um die erforderlichen Mengen und Statistiken für die Operationen zu schätzen, und schließlich bake, um die Berechnungen auf neue Daten anzuwenden.
> Normalerweise wird recipes üblicherweise als Vorverarbeitungswerkzeug für die Modellierung verwendet, wobei es definiert, welche Schritte auf einen Datensatz angewendet werden müssen, um ihn für die Modellierung vorzubereiten. In diesem Fall wird dringend empfohlen, ein workflow() zu verwenden, anstatt ein Rezept manuell mit prep und bake zu schätzen. Das werden wir gleich sehen.
>
> Für den Moment verwenden wir jedoch recipes + prep + bake, um festzulegen, welche Schritte auf einen Datensatz angewendet werden sollen, um ihn für die Datenanalyse vorzubereiten, und anschließend die vorverarbeiteten Daten mit den angewendeten Schritten zu extrahieren.
# Preprocess and extract data to allow some data analysis
baked_pumpkins <- recipe(color ~ ., data = pumpkins_select) %>%
# Define ordering for item_size column
step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%
# Convert factors to numbers using the order defined above (Ordinal encoding)
step_integer(item_size, zero_based = F) %>%
# Encode all other predictors using one hot encoding
step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE) %>%
prep(data = pumpkin_select) %>%
bake(new_data = NULL)
# Display the first few rows of preprocessed data
baked_pumpkins %>%
slice_head(n = 5)
✅ Was sind die Vorteile der Verwendung eines Ordinal Encoders für die Spalte Item Size?
Beziehungen zwischen Variablen analysieren
Nachdem wir unsere Daten vorverarbeitet haben, können wir die Beziehungen zwischen den Merkmalen und dem Label analysieren, um eine Vorstellung davon zu bekommen, wie gut das Modell in der Lage sein wird, das Label anhand der Merkmale vorherzusagen. Der beste Weg, diese Art von Analyse durchzuführen, ist das Plotten der Daten.
Wir werden erneut die ggplot-Funktion geom_boxplot_ verwenden, um die Beziehungen zwischen Item Size, Variety und Color in einem kategorischen Plot zu visualisieren. Um die Daten besser darzustellen, verwenden wir die kodierte Spalte Item Size und die nicht kodierte Spalte Variety.
# Define the color palette
palette <- c(ORANGE = "orange", WHITE = "wheat")
# We need the encoded Item Size column to use it as the x-axis values in the plot
pumpkins_select_plot<-pumpkins_select
pumpkins_select_plot$item_size <- baked_pumpkins$item_size
# Create the grouped box plot
ggplot(pumpkins_select_plot, aes(x = `item_size`, y = color, fill = color)) +
geom_boxplot() +
facet_grid(variety ~ ., scales = "free_x") +
scale_fill_manual(values = palette) +
labs(x = "Item Size", y = "") +
theme_minimal() +
theme(strip.text = element_text(size = 12)) +
theme(axis.text.x = element_text(size = 10)) +
theme(axis.title.x = element_text(size = 12)) +
theme(axis.title.y = element_blank()) +
theme(legend.position = "bottom") +
guides(fill = guide_legend(title = "Color")) +
theme(panel.spacing = unit(0.5, "lines"))+
theme(strip.text.y = element_text(size = 4, hjust = 0))
Verwenden Sie ein Swarm-Plot
Da Farbe eine binäre Kategorie ist (Weiß oder Nicht), benötigt sie 'einen spezialisierten Ansatz für die Visualisierung'.
Versuchen Sie, ein Swarm-Plot zu verwenden, um die Verteilung der Farbe in Bezug auf die item_size darzustellen.
Wir verwenden das ggbeeswarm-Paket, das Methoden bereitstellt, um Bienenstock-ähnliche Plots mit ggplot2 zu erstellen. Bienenstock-Plots sind eine Möglichkeit, Punkte darzustellen, die sich normalerweise überlappen würden, sodass sie stattdessen nebeneinander angeordnet werden.
# Create beeswarm plots of color and item_size
baked_pumpkins %>%
mutate(color = factor(color)) %>%
ggplot(mapping = aes(x = color, y = item_size, color = color)) +
geom_quasirandom() +
scale_color_brewer(palette = "Dark2", direction = -1) +
theme(legend.position = "none")
Jetzt, da wir eine Vorstellung von der Beziehung zwischen den binären Kategorien der Farbe und der größeren Gruppe der Größen haben, wollen wir die logistische Regression untersuchen, um die wahrscheinliche Farbe eines bestimmten Kürbisses zu bestimmen.
Erstellen Sie Ihr Modell
Wählen Sie die Variablen aus, die Sie in Ihrem Klassifikationsmodell verwenden möchten, und teilen Sie die Daten in Trainings- und Testdatensätze auf. rsample, ein Paket in Tidymodels, bietet eine Infrastruktur für effizientes Datensplitting und Resampling:
# Split data into 80% for training and 20% for testing
set.seed(2056)
pumpkins_split <- pumpkins_select %>%
initial_split(prop = 0.8)
# Extract the data in each split
pumpkins_train <- training(pumpkins_split)
pumpkins_test <- testing(pumpkins_split)
# Print out the first 5 rows of the training set
pumpkins_train %>%
slice_head(n = 5)
🙌 Wir sind jetzt bereit, ein Modell zu trainieren, indem wir die Trainingsmerkmale mit dem Trainingslabel (Farbe) verknüpfen.
Wir beginnen damit, ein Rezept zu erstellen, das die Vorverarbeitungsschritte festlegt, die an unseren Daten durchgeführt werden müssen, um sie für die Modellierung vorzubereiten, z. B.: Kategorische Variablen in eine Reihe von Ganzzahlen zu kodieren. Genau wie baked_pumpkins erstellen wir ein pumpkins_recipe, aber wir führen kein prep und bake aus, da dies in einen Workflow eingebunden wird, den Sie in nur wenigen Schritten sehen werden.
Es gibt eine ganze Reihe von Möglichkeiten, ein logistisches Regressionsmodell in Tidymodels zu spezifizieren. Siehe ?logistic_reg(). Für den Moment werden wir ein logistisches Regressionsmodell über die Standard-Engine stats::glm() spezifizieren.
# Create a recipe that specifies preprocessing steps for modelling
pumpkins_recipe <- recipe(color ~ ., data = pumpkins_train) %>%
step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%
step_integer(item_size, zero_based = F) %>%
step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE)
# Create a logistic model specification
log_reg <- logistic_reg() %>%
set_engine("glm") %>%
set_mode("classification")
Jetzt, da wir ein Rezept und eine Modellspezifikation haben, müssen wir eine Möglichkeit finden, diese zusammen in einem Objekt zu bündeln, das zunächst die Daten vorverarbeitet (prep+bake im Hintergrund), das Modell auf den vorverarbeiteten Daten anpasst und auch potenzielle Nachbearbeitungsaktivitäten ermöglicht.
In Tidymodels wird dieses praktische Objekt als workflow bezeichnet und fasst bequem Ihre Modellierungskomponenten zusammen.
# Bundle modelling components in a workflow
log_reg_wf <- workflow() %>%
add_recipe(pumpkins_recipe) %>%
add_model(log_reg)
# Print out the workflow
log_reg_wf
Nachdem ein Workflow festgelegt wurde, kann ein Modell mit der fit()-Funktion trainiert werden. Der Workflow wird ein Rezept schätzen und die Daten vor dem Training vorverarbeiten, sodass wir dies nicht manuell mit prep und bake durchführen müssen.
# Train the model
wf_fit <- log_reg_wf %>%
fit(data = pumpkins_train)
# Print the trained workflow
wf_fit
Das Modell gibt die während des Trainings gelernten Koeffizienten aus.
Nachdem wir das Modell mit den Trainingsdaten trainiert haben, können wir Vorhersagen für die Testdaten mithilfe von parsnip::predict() treffen. Beginnen wir damit, das Modell zu verwenden, um Labels für unseren Testdatensatz sowie die Wahrscheinlichkeiten für jedes Label vorherzusagen. Wenn die Wahrscheinlichkeit größer als 0,5 ist, wird die vorhergesagte Klasse WHITE sein, andernfalls ORANGE.
# Make predictions for color and corresponding probabilities
results <- pumpkins_test %>% select(color) %>%
bind_cols(wf_fit %>%
predict(new_data = pumpkins_test)) %>%
bind_cols(wf_fit %>%
predict(new_data = pumpkins_test, type = "prob"))
# Compare predictions
results %>%
slice_head(n = 10)
Sehr schön! Das bietet einige zusätzliche Einblicke in die Funktionsweise der logistischen Regression.
Bessere Verständlichkeit durch eine Konfusionsmatrix
Jeden einzelnen Vorhersagewert mit seinem entsprechenden "Ground Truth"-Wert zu vergleichen, ist keine besonders effiziente Methode, um zu beurteilen, wie gut das Modell vorhersagt. Glücklicherweise hat Tidymodels noch ein paar weitere Tricks parat: yardstick - ein Paket, das verwendet wird, um die Effektivität von Modellen anhand von Leistungskennzahlen zu messen.
Eine Leistungskennzahl, die mit Klassifikationsproblemen verbunden ist, ist die Konfusionsmatrix. Eine Konfusionsmatrix beschreibt, wie gut ein Klassifikationsmodell funktioniert. Sie zeigt tabellarisch, wie viele Beispiele in jeder Klasse von einem Modell korrekt klassifiziert wurden. In unserem Fall wird sie zeigen, wie viele orangefarbene Kürbisse als orange klassifiziert wurden und wie viele weiße Kürbisse als weiß; die Konfusionsmatrix zeigt auch, wie viele in die falschen Kategorien eingeordnet wurden.
Die Funktion conf_mat() aus yardstick berechnet diese Kreuztabellierung der beobachteten und vorhergesagten Klassen.
# Confusion matrix for prediction results
conf_mat(data = results, truth = color, estimate = .pred_class)
Lassen Sie uns die Verwirrungsmatrix interpretieren. Unser Modell soll Kürbisse zwischen zwei binären Kategorien klassifizieren: Kategorie weiß und Kategorie nicht-weiß.
-
Wenn Ihr Modell einen Kürbis als weiß vorhersagt und er tatsächlich zur Kategorie 'weiß' gehört, nennen wir das ein
true positive, dargestellt durch die Zahl oben links. -
Wenn Ihr Modell einen Kürbis als nicht weiß vorhersagt und er tatsächlich zur Kategorie 'weiß' gehört, nennen wir das ein
false negative, dargestellt durch die Zahl unten links. -
Wenn Ihr Modell einen Kürbis als weiß vorhersagt und er tatsächlich zur Kategorie 'nicht-weiß' gehört, nennen wir das ein
false positive, dargestellt durch die Zahl oben rechts. -
Wenn Ihr Modell einen Kürbis als nicht weiß vorhersagt und er tatsächlich zur Kategorie 'nicht-weiß' gehört, nennen wir das ein
true negative, dargestellt durch die Zahl unten rechts.
| Wahrheit |
|---|
| Vorhersage | WEISS | ORANGE |
| WEISS | TP | FP |
| ORANGE | FN | TN |
Wie Sie sich vielleicht denken können, ist es wünschenswert, eine größere Anzahl von true positives und true negatives sowie eine geringere Anzahl von false positives und false negatives zu haben, da dies darauf hinweist, dass das Modell besser funktioniert.
Die Verwirrungsmatrix ist hilfreich, da sie zu anderen Metriken führt, die uns helfen können, die Leistung eines Klassifikationsmodells besser zu bewerten. Gehen wir einige davon durch:
🎓 Präzision: TP/(TP + FP) definiert als der Anteil der vorhergesagten positiven Ergebnisse, die tatsächlich positiv sind. Auch bekannt als positiver Vorhersagewert.
🎓 Recall: TP/(TP + FN) definiert als der Anteil der positiven Ergebnisse aus der Anzahl der Proben, die tatsächlich positiv waren. Auch bekannt als Sensitivität.
🎓 Spezifität: TN/(TN + FP) definiert als der Anteil der negativen Ergebnisse aus der Anzahl der Proben, die tatsächlich negativ waren.
🎓 Genauigkeit: TP + TN/(TP + TN + FP + FN) Der Prozentsatz der Labels, die für eine Probe korrekt vorhergesagt wurden.
🎓 F-Maß: Ein gewichteter Durchschnitt von Präzision und Recall, wobei der beste Wert 1 und der schlechteste Wert 0 ist.
Lassen Sie uns diese Metriken berechnen!
# Combine metric functions and calculate them all at once
eval_metrics <- metric_set(ppv, recall, spec, f_meas, accuracy)
eval_metrics(data = results, truth = color, estimate = .pred_class)
Visualisiere die ROC-Kurve dieses Modells
Lass uns eine weitere Visualisierung durchführen, um die sogenannte ROC-Kurve anzusehen:
# Make a roc_curve
results %>%
roc_curve(color, .pred_ORANGE) %>%
autoplot()
ROC-Kurven werden häufig verwendet, um die Leistung eines Klassifikators in Bezug auf wahre vs. falsche Positive zu visualisieren. ROC-Kurven zeigen typischerweise die True Positive Rate/Sensitivität auf der Y-Achse und die False Positive Rate/1-Spezifität auf der X-Achse. Daher sind die Steilheit der Kurve und der Abstand zwischen der Mittellinie und der Kurve entscheidend: Man möchte eine Kurve, die schnell nach oben und über die Linie verläuft. In unserem Fall gibt es zunächst falsche Positive, bevor die Linie korrekt nach oben und darüber verläuft.
Abschließend verwenden wir yardstick::roc_auc(), um die tatsächliche Fläche unter der Kurve (Area Under the Curve, AUC) zu berechnen. Eine Möglichkeit, die AUC zu interpretieren, ist die Wahrscheinlichkeit, dass das Modell ein zufällig ausgewähltes positives Beispiel höher einstuft als ein zufällig ausgewähltes negatives Beispiel.
# Calculate area under curve
results %>%
roc_auc(color, .pred_ORANGE)
Das Ergebnis liegt bei etwa 0,975. Da der AUC-Wert zwischen 0 und 1 liegt, strebt man einen hohen Wert an, da ein Modell, das zu 100 % korrekte Vorhersagen trifft, einen AUC-Wert von 1 erreicht. In diesem Fall ist das Modell ziemlich gut.
In zukünftigen Lektionen über Klassifikationen wirst du lernen, wie du die Werte deines Modells verbessern kannst (zum Beispiel, indem du mit unausgeglichenen Daten umgehst, wie in diesem Fall).
🚀Herausforderung
Es gibt noch viel mehr über logistische Regression zu entdecken! Aber der beste Weg, etwas zu lernen, ist, zu experimentieren. Finde einen Datensatz, der sich für diese Art von Analyse eignet, und erstelle ein Modell damit. Was lernst du dabei? Tipp: Schau dir Kaggle für interessante Datensätze an.
Rückblick & Selbststudium
Lies die ersten Seiten von diesem Paper von Stanford, das einige praktische Anwendungen der logistischen Regression beschreibt. Überlege, welche Aufgaben besser für die eine oder andere Art von Regressionsaufgaben geeignet sind, die wir bisher behandelt haben. Was würde am besten funktionieren?
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Regressionsmodelle für maschinelles Lernen
Regionales Thema: Regressionsmodelle für Kürbispreise in Nordamerika 🎃
In Nordamerika werden Kürbisse oft zu Halloween in gruselige Gesichter geschnitzt. Lassen Sie uns mehr über dieses faszinierende Gemüse herausfinden!
> Foto von <a href="https://unsplash.com/@teutschmann?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Beth Teutschmann</a> auf <a href="https://unsplash.com/s/photos/jack-o-lanterns?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
Was Sie lernen werden
> 🎥 Klicken Sie auf das Bild oben für ein kurzes Einführungsvideo zu dieser Lektion
Die Lektionen in diesem Abschnitt behandeln verschiedene Arten von Regression im Kontext des maschinellen Lernens. Regressionsmodelle können helfen, die Beziehung zwischen Variablen zu bestimmen. Dieser Modelltyp kann Werte wie Länge, Temperatur oder Alter vorhersagen und dabei Beziehungen zwischen Variablen aufdecken, während er Datenpunkte analysiert.
In dieser Serie von Lektionen werden Sie die Unterschiede zwischen linearer und logistischer Regression entdecken und erfahren, wann Sie welche bevorzugen sollten.
> 🎥 Klicken Sie auf das Bild oben für ein kurzes Video, das Regressionsmodelle vorstellt.
In dieser Gruppe von Lektionen werden Sie sich darauf vorbereiten, Aufgaben des maschinellen Lernens zu beginnen, einschließlich der Konfiguration von Visual Studio Code zur Verwaltung von Notebooks, der üblichen Umgebung für Datenwissenschaftler. Sie werden Scikit-learn entdecken, eine Bibliothek für maschinelles Lernen, und Ihre ersten Modelle erstellen, wobei der Schwerpunkt in diesem Kapitel auf Regressionsmodellen liegt.
> Es gibt nützliche Low-Code-Tools, die Ihnen helfen können, mehr über die Arbeit mit Regressionsmodellen zu lernen. Probieren Sie Azure ML für diese Aufgabe aus.
Lektionen
Credits
"ML mit Regression" wurde mit ♥️ geschrieben von Jen Looper
♥️ Quiz-Beiträge stammen von: Muhammad Sakib Khan Inan und Ornella Altunyan
Der Kürbis-Datensatz wird von diesem Projekt auf Kaggle vorgeschlagen, und seine Daten stammen aus den Specialty Crops Terminal Markets Standard Reports, die vom Landwirtschaftsministerium der Vereinigten Staaten veröffentlicht werden. Wir haben einige Punkte zur Farbe basierend auf der Sorte hinzugefügt, um die Verteilung zu normalisieren. Diese Daten sind gemeinfrei.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Probieren Sie ein anderes Modell aus
Anweisungen
Nachdem Sie eine Web-App mit einem trainierten Regressionsmodell erstellt haben, verwenden Sie eines der Modelle aus einer früheren Lektion über Regression, um diese Web-App neu zu erstellen. Sie können den Stil beibehalten oder ihn anders gestalten, um die Kürbisdaten widerzuspiegeln. Achten Sie darauf, die Eingaben so zu ändern, dass sie der Trainingsmethode Ihres Modells entsprechen.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Die Web-App funktioniert wie erwartet und ist in der Cloud bereitgestellt | Die Web-App enthält Fehler oder zeigt unerwartete Ergebnisse | Die Web-App funktioniert nicht richtig |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erstellen einer Web-App zur Nutzung eines ML-Modells
In dieser Lektion wirst du ein ML-Modell mit einem außergewöhnlichen Datensatz trainieren: UFO-Sichtungen des letzten Jahrhunderts, basierend auf der Datenbank von NUFORC.
Du wirst lernen:
- Wie man ein trainiertes Modell "pickelt"
- Wie man dieses Modell in einer Flask-App verwendet
Wir werden weiterhin Notebooks verwenden, um Daten zu bereinigen und unser Modell zu trainieren. Du kannst den Prozess jedoch einen Schritt weiterführen, indem du das Modell "in freier Wildbahn" einsetzt, also in einer Web-App.
Dafür musst du eine Web-App mit Flask erstellen.
Quiz vor der Lektion
Eine App erstellen
Es gibt verschiedene Möglichkeiten, Web-Apps zu erstellen, die Machine-Learning-Modelle nutzen. Deine Web-Architektur kann beeinflussen, wie dein Modell trainiert wird. Stell dir vor, du arbeitest in einem Unternehmen, in dem die Data-Science-Abteilung ein Modell trainiert hat, das du in einer App verwenden sollst.
Überlegungen
Es gibt viele Fragen, die du dir stellen musst:
- Ist es eine Web-App oder eine Mobile-App? Wenn du eine Mobile-App erstellst oder das Modell in einem IoT-Kontext verwenden möchtest, könntest du TensorFlow Lite nutzen, um das Modell in einer Android- oder iOS-App einzusetzen.
- Wo wird das Modell gespeichert? In der Cloud oder lokal?
- Offline-Unterstützung. Muss die App offline funktionieren?
- Welche Technologie wurde verwendet, um das Modell zu trainieren? Die gewählte Technologie kann die benötigten Tools beeinflussen.
- Verwendung von TensorFlow. Wenn du ein Modell mit TensorFlow trainierst, bietet dieses Ökosystem die Möglichkeit, ein TensorFlow-Modell für die Verwendung in einer Web-App mit TensorFlow.js zu konvertieren.
- Verwendung von PyTorch. Wenn du ein Modell mit einer Bibliothek wie PyTorch erstellst, kannst du es im ONNX (Open Neural Network Exchange)-Format exportieren, um es in JavaScript-Web-Apps mit Onnx Runtime zu verwenden. Diese Option wird in einer zukünftigen Lektion für ein mit Scikit-learn trainiertes Modell untersucht.
- Verwendung von Lobe.ai oder Azure Custom Vision. Wenn du ein ML-SaaS (Software as a Service)-System wie Lobe.ai oder Azure Custom Vision verwendest, um ein Modell zu trainieren, bietet diese Software Möglichkeiten, das Modell für viele Plattformen zu exportieren, einschließlich der Erstellung einer maßgeschneiderten API, die von deiner Online-Anwendung in der Cloud abgefragt werden kann.
Du hast auch die Möglichkeit, eine komplette Flask-Web-App zu erstellen, die das Modell direkt im Webbrowser trainieren kann. Dies kann auch mit TensorFlow.js in einem JavaScript-Kontext erfolgen.
Für unsere Zwecke, da wir mit Python-basierten Notebooks arbeiten, schauen wir uns die Schritte an, die erforderlich sind, um ein trainiertes Modell aus einem solchen Notebook in ein Format zu exportieren, das von einer Python-basierten Web-App gelesen werden kann.
Werkzeug
Für diese Aufgabe benötigst du zwei Tools: Flask und Pickle, die beide auf Python laufen.
✅ Was ist Flask? Flask wird von seinen Entwicklern als "Micro-Framework" definiert und bietet die grundlegenden Funktionen von Web-Frameworks mit Python sowie eine Template-Engine zur Erstellung von Webseiten. Schau dir dieses Lernmodul an, um das Arbeiten mit Flask zu üben.
✅ Was ist Pickle? Pickle 🥒 ist ein Python-Modul, das die Struktur eines Python-Objekts serialisiert und deserialisiert. Wenn du ein Modell "pickelst", serialisierst oder flachst du dessen Struktur ab, um es im Web zu verwenden. Vorsicht: Pickle ist nicht von Natur aus sicher, also sei vorsichtig, wenn du aufgefordert wirst, eine Datei zu "ent-pickeln". Eine gepickelte Datei hat die Endung .pkl.
Übung - Daten bereinigen
In dieser Lektion wirst du Daten von 80.000 UFO-Sichtungen verwenden, die vom NUFORC (National UFO Reporting Center) gesammelt wurden. Diese Daten enthalten einige interessante Beschreibungen von UFO-Sichtungen, zum Beispiel:
- Lange Beispielbeschreibung. "Ein Mann tritt aus einem Lichtstrahl, der nachts auf ein Grasfeld scheint, und rennt in Richtung des Parkplatzes von Texas Instruments."
- Kurze Beispielbeschreibung. "Die Lichter haben uns verfolgt."
Die Tabelle ufos.csv enthält Spalten über die city, state und country, in denen die Sichtung stattfand, die shape des Objekts sowie dessen latitude und longitude.
Im leeren Notebook, das in dieser Lektion enthalten ist:
-
Importiere
pandas,matplotlibundnumpy, wie du es in den vorherigen Lektionen getan hast, und importiere die UFO-Tabelle. Du kannst dir einen Beispieldatensatz ansehen:```python import pandas as pd import numpy as np
ufos = pd.read_csv('./data/ufos.csv') ufos.head() ```
-
Konvertiere die UFO-Daten in ein kleines DataFrame mit neuen Titeln. Überprüfe die eindeutigen Werte im Feld
Country.```python ufos = pd.DataFrame({'Seconds': ufos['duration (seconds)'], 'Country': ufos['country'],'Latitude': ufos['latitude'],'Longitude': ufos['longitude']})
ufos.Country.unique() ```
-
Reduziere nun die Datenmenge, indem du alle Nullwerte entfernst und nur Sichtungen zwischen 1-60 Sekunden importierst:
```python ufos.dropna(inplace=True)
ufos = ufos[(ufos['Seconds'] >= 1) & (ufos['Seconds'] <= 60)]
ufos.info() ```
-
Importiere die
LabelEncoder-Bibliothek von Scikit-learn, um die Textwerte für Länder in Zahlen umzuwandeln:✅ LabelEncoder kodiert Daten alphabetisch
```python from sklearn.preprocessing import LabelEncoder
ufos['Country'] = LabelEncoder().fit_transform(ufos['Country'])
ufos.head() ```
Deine Daten sollten so aussehen:
output Seconds Country Latitude Longitude 2 20.0 3 53.200000 -2.916667 3 20.0 4 28.978333 -96.645833 14 30.0 4 35.823889 -80.253611 23 60.0 4 45.582778 -122.352222 24 3.0 3 51.783333 -0.783333
Übung - Modell erstellen
Jetzt kannst du dich darauf vorbereiten, ein Modell zu trainieren, indem du die Daten in Trainings- und Testgruppen aufteilst.
-
Wähle die drei Merkmale aus, auf denen du trainieren möchtest, als deinen X-Vektor, und der y-Vektor wird das
Countrysein. Du möchtest in der Lage sein,Seconds,LatitudeundLongitudeeinzugeben und eine Länder-ID zurückzubekommen.```python from sklearn.model_selection import train_test_split
Selected_features = ['Seconds','Latitude','Longitude']
X = ufos[Selected_features] y = ufos['Country']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0) ```
-
Trainiere dein Modell mit logistischer Regression:
```python from sklearn.metrics import accuracy_score, classification_report from sklearn.linear_model import LogisticRegression model = LogisticRegression() model.fit(X_train, y_train) predictions = model.predict(X_test)
print(classification_report(y_test, predictions)) print('Predicted labels: ', predictions) print('Accuracy: ', accuracy_score(y_test, predictions)) ```
Die Genauigkeit ist nicht schlecht (etwa 95%), was nicht überraschend ist, da Country und Latitude/Longitude korrelieren.
Das Modell, das du erstellt hast, ist nicht besonders revolutionär, da du ein Country aus dessen Latitude und Longitude ableiten können solltest. Es ist jedoch eine gute Übung, aus Rohdaten zu trainieren, die du bereinigt, exportiert und dann in einer Web-App verwendet hast.
Übung - Modell "pickeln"
Jetzt ist es an der Zeit, dein Modell zu pickeln! Das kannst du in wenigen Codezeilen tun. Sobald es gepickelt ist, lade dein gepickeltes Modell und teste es mit einem Beispieldatenarray, das Werte für Sekunden, Breitengrad und Längengrad enthält:
import pickle
model_filename = 'ufo-model.pkl'
pickle.dump(model, open(model_filename,'wb'))
model = pickle.load(open('ufo-model.pkl','rb'))
print(model.predict([[50,44,-12]]))
Das Modell gibt '3' zurück, was der Ländercode für das Vereinigte Königreich ist. Verrückt! 👽
Übung - Flask-App erstellen
Jetzt kannst du eine Flask-App erstellen, um dein Modell aufzurufen und ähnliche Ergebnisse auf eine visuell ansprechendere Weise zurückzugeben.
-
Erstelle zunächst einen Ordner namens web-app neben der Datei notebook.ipynb, in der sich auch deine Datei ufo-model.pkl befindet.
-
Erstelle in diesem Ordner drei weitere Ordner: static, mit einem Ordner css darin, und templates. Du solltest nun die folgenden Dateien und Verzeichnisse haben:
output web-app/ static/ css/ templates/ notebook.ipynb ufo-model.pkl✅ Sieh dir den Lösungsordner an, um die fertige App zu sehen
-
Die erste Datei, die du im Ordner web-app erstellst, ist die Datei requirements.txt. Wie package.json in einer JavaScript-App listet diese Datei die Abhängigkeiten auf, die die App benötigt. Füge in requirements.txt die Zeilen hinzu:
text scikit-learn pandas numpy flask -
Führe diese Datei nun aus, indem du zu web-app navigierst:
bash cd web-app -
Gib in deinem Terminal
pip installein, um die in requirements.txt aufgeführten Bibliotheken zu installieren:bash pip install -r requirements.txt -
Jetzt bist du bereit, drei weitere Dateien zu erstellen, um die App fertigzustellen:
- Erstelle app.py im Root-Verzeichnis.
- Erstelle index.html im Verzeichnis templates.
- Erstelle styles.css im Verzeichnis static/css.
-
Baue die Datei styles.css mit ein paar Stilen aus:
```css body { width: 100%; height: 100%; font-family: 'Helvetica'; background: black; color: #fff; text-align: center; letter-spacing: 1.4px; font-size: 30px; }
input { min-width: 150px; }
.grid { width: 300px; border: 1px solid #2d2d2d; display: grid; justify-content: center; margin: 20px auto; }
.box { color: #fff; background: #2d2d2d; padding: 12px; display: inline-block; } ```
-
Baue als Nächstes die Datei index.html aus:
```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>🛸 UFO Appearance Prediction! 👽</title> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}"> </head>
<body> <div class="grid">
<div class="box"> <p>According to the number of seconds, latitude and longitude, which country is likely to have reported seeing a UFO?</p> <form action="{{ url_for('predict')}}" method="post"> <input type="number" name="seconds" placeholder="Seconds" required="required" min="0" max="60" /> <input type="text" name="latitude" placeholder="Latitude" required="required" /> <input type="text" name="longitude" placeholder="Longitude" required="required" /> <button type="submit" class="btn">Predict country where the UFO is seen</button> </form> <p>{{ prediction_text }}</p> </div> </div></body> </html> ```
Schau dir das Templating in dieser Datei an. Beachte die "Mustache"-Syntax um Variablen, die von der App bereitgestellt werden, wie den Vorhersagetext:
{{}}. Es gibt auch ein Formular, das eine Vorhersage an die Route/predictsendet.Schließlich bist du bereit, die Python-Datei zu erstellen, die den Konsum des Modells und die Anzeige der Vorhersagen steuert:
-
Füge in
app.pyFolgendes hinzu:```python import numpy as np from flask import Flask, request, render_template import pickle
app = Flask(name)
model = pickle.load(open("./ufo-model.pkl", "rb"))
@app.route("/") def home(): return render_template("index.html")
@app.route("/predict", methods=["POST"]) def predict():
int_features = [int(x) for x in request.form.values()] final_features = [np.array(int_features)] prediction = model.predict(final_features) output = prediction[0] countries = ["Australia", "Canada", "Germany", "UK", "US"] return render_template( "index.html", prediction_text="Likely country: {}".format(countries[output]) )if name == "main": app.run(debug=True) ```
> 💡 Tipp: Wenn du
debug=Truehinzufügst, während du die Web-App mit Flask ausführst, werden alle Änderungen, die du an deiner Anwendung vornimmst, sofort reflektiert, ohne dass der Server neu gestartet werden muss. Vorsicht! Aktiviere diesen Modus nicht in einer Produktions-App.
Wenn du python app.py oder python3 app.py ausführst, startet dein Webserver lokal, und du kannst ein kurzes Formular ausfüllen, um eine Antwort auf deine brennende Frage zu erhalten, wo UFOs gesichtet wurden!
Bevor du das tust, wirf einen Blick auf die Teile von app.py:
- Zuerst werden Abhängigkeiten geladen und die App gestartet.
- Dann wird das Modell importiert.
- Anschließend wird index.html auf der Home-Route gerendert.
Auf der Route /predict passiert Folgendes, wenn das Formular gesendet wird:
- Die Formularvariablen werden gesammelt und in ein Numpy-Array konvertiert. Sie werden dann an das Modell gesendet, und eine Vorhersage wird zurückgegeben.
- Die Länder, die angezeigt werden sollen, werden aus ihrem vorhergesagten Ländercode in lesbaren Text umgewandelt, und dieser Wert wird zurück an index.html gesendet, um im Template gerendert zu werden.
Ein Modell auf diese Weise mit Flask und einem gepickelten Modell zu verwenden, ist relativ einfach. Das Schwierigste ist, zu verstehen, in welcher Form die Daten an das Modell gesendet werden müssen, um eine Vorhersage zu erhalten. Das hängt davon ab, wie das Modell trainiert wurde. Dieses Modell benötigt drei Datenpunkte, um eine Vorhersage zu treffen.
In einem professionellen Umfeld kannst du sehen, wie wichtig eine gute Kommunikation zwischen den Personen ist, die das Modell trainieren, und denen, die es in einer Web- oder Mobile-App verwenden. In unserem Fall bist du es selbst!
🚀 Herausforderung
Anstatt in einem Notebook zu arbeiten und das Modell in die Flask-App zu importieren, könntest du das Modell direkt in der Flask-App trainieren! Versuche, deinen Python-Code aus dem Notebook zu konvertieren, vielleicht nachdem deine Daten bereinigt wurden, um das Modell innerhalb der App auf einer Route namens train zu trainieren. Was sind die Vor- und Nachteile dieser Methode?
Quiz nach der Lektion
Rückblick & Selbststudium
Es gibt viele Möglichkeiten, eine Web-App zu erstellen, die ML-Modelle nutzt. Erstelle eine Liste der Möglichkeiten, wie du JavaScript oder Python verwenden könntest, um eine Web-App zu erstellen, die Machine Learning nutzt. Überlege dir die Architektur: Sollte das Modell in der App bleiben oder in der Cloud leben? Wenn Letzteres, wie würdest du darauf zugreifen? Zeichne ein Architekturmodell für eine angewandte ML-Weblösung.
Aufgabe
Probiere ein anderes Modell aus
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
import pandas as pd
import numpy as np
ufos = pd.read_csv('../data/ufos.csv')
ufos.head()
ufos = pd.DataFrame({'Seconds': ufos['duration (seconds)'], 'Country': ufos['country'],'Latitude': ufos['latitude'],'Longitude': ufos['longitude']})
ufos.Country.unique()
# 0 au, 1 ca, 2 de, 3 gb, 4 us
ufos.dropna(inplace=True)
ufos = ufos[(ufos['Seconds'] >= 1) & (ufos['Seconds'] <= 60)]
ufos.info()
from sklearn.preprocessing import LabelEncoder
ufos['Country'] = LabelEncoder().fit_transform(ufos['Country'])
ufos.head()
from sklearn.model_selection import train_test_split
Selected_features = ['Seconds','Latitude','Longitude']
X = ufos[Selected_features]
y = ufos['Country']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train, y_train)
predictions = model.predict(X_test)
print(classification_report(y_test, predictions))
print('Predicted labels: ', predictions)
print('Accuracy: ', accuracy_score(y_test, predictions))
import pickle
model_filename = 'ufo-model.pkl'
pickle.dump(model, open(model_filename,'wb'))
model = pickle.load(open('ufo-model.pkl','rb'))
print(model.predict([[50,44,-12]]))
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erstellen Sie eine Web-App zur Nutzung Ihres ML-Modells
In diesem Abschnitt des Lehrplans werden Sie mit einem angewandten ML-Thema vertraut gemacht: wie Sie Ihr Scikit-learn-Modell als Datei speichern können, die innerhalb einer Webanwendung für Vorhersagen verwendet werden kann. Sobald das Modell gespeichert ist, lernen Sie, wie Sie es in einer Web-App verwenden, die mit Flask erstellt wurde. Zunächst erstellen Sie ein Modell mit Daten, die sich mit UFO-Sichtungen befassen! Anschließend entwickeln Sie eine Web-App, die es ermöglicht, eine Anzahl von Sekunden zusammen mit einem Breitengrad- und Längengradwert einzugeben, um vorherzusagen, welches Land eine UFO-Sichtung gemeldet hat.

Foto von <a href="https://unsplash.com/@mdherren?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Michael Herren</a> auf <a href="https://unsplash.com/s/photos/ufo?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
Lektionen
Credits
"Erstellen Sie eine Web-App" wurde mit ♥️ von Jen Looper geschrieben.
♥️ Die Quizfragen wurden von Rohan Raj verfasst.
Der Datensatz stammt von Kaggle.
Die Web-App-Architektur wurde teilweise durch diesen Artikel und dieses Repository von Abhinav Sagar inspiriert.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erkunde Klassifikationsmethoden
Anweisungen
In der Scikit-learn-Dokumentation findest du eine umfangreiche Liste von Möglichkeiten, Daten zu klassifizieren. Mach eine kleine Schnitzeljagd in diesen Dokumenten: Dein Ziel ist es, Klassifikationsmethoden zu finden und sie mit einem Datensatz aus diesem Lehrplan, einer dazu passenden Fragestellung und einer Klassifikationstechnik zu kombinieren. Erstelle eine Tabelle oder ein Dokument in einer .doc-Datei und erkläre, wie der Datensatz mit dem Klassifikationsalgorithmus funktionieren würde.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Dokument wird präsentiert, das einen Überblick über 5 Algorithmen zusammen mit einer Klassifikationstechnik bietet. Der Überblick ist gut erklärt und detailliert. | Ein Dokument wird präsentiert, das einen Überblick über 3 Algorithmen zusammen mit einer Klassifikationstechnik bietet. Der Überblick ist gut erklärt und detailliert. | Ein Dokument wird präsentiert, das einen Überblick über weniger als drei Algorithmen zusammen mit einer Klassifikationstechnik bietet, und der Überblick ist weder gut erklärt noch detailliert. |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in die Klassifikation
In diesen vier Lektionen wirst du einen grundlegenden Schwerpunkt des klassischen maschinellen Lernens erkunden – Klassifikation. Wir werden verschiedene Klassifikationsalgorithmen anhand eines Datensatzes über die großartigen Küchen Asiens und Indiens durchgehen. Hoffentlich hast du Appetit!

> Feiere pan-asiatische Küchen in diesen Lektionen! Bild von Jen Looper
Klassifikation ist eine Form des überwachten Lernens, die viele Gemeinsamkeiten mit Regressionsmethoden hat. Wenn maschinelles Lernen darum geht, Werte oder Namen für Dinge anhand von Datensätzen vorherzusagen, dann fällt die Klassifikation im Allgemeinen in zwei Gruppen: binäre Klassifikation und Mehrklassenklassifikation.
> 🎥 Klicke auf das Bild oben für ein Video: John Guttag vom MIT stellt die Klassifikation vor
Erinnere dich:
- Lineare Regression half dir, Beziehungen zwischen Variablen vorherzusagen und genaue Vorhersagen darüber zu treffen, wo ein neuer Datenpunkt in Bezug auf diese Linie liegen würde. So konntest du beispielsweise vorhersagen, wie viel ein Kürbis im September im Vergleich zu Dezember kosten würde.
- Logistische Regression half dir, "binäre Kategorien" zu entdecken: Bei diesem Preisniveau, ist dieser Kürbis orange oder nicht-orange?
Die Klassifikation verwendet verschiedene Algorithmen, um andere Möglichkeiten zu finden, das Label oder die Klasse eines Datenpunkts zu bestimmen. Lass uns mit diesen Küchendaten arbeiten, um zu sehen, ob wir anhand einer Gruppe von Zutaten die Herkunftsküche bestimmen können.
Quiz vor der Lektion
> ### Diese Lektion ist auch in R verfügbar!
Einführung
Die Klassifikation ist eine der grundlegenden Tätigkeiten von Forschern und Datenwissenschaftlern im Bereich des maschinellen Lernens. Von der einfachen Klassifikation eines binären Wertes ("Ist diese E-Mail Spam oder nicht?") bis hin zur komplexen Bildklassifikation und -segmentierung mithilfe von Computer Vision ist es immer nützlich, Daten in Klassen einzuteilen und Fragen dazu zu stellen.
Wissenschaftlich ausgedrückt erstellt deine Klassifikationsmethode ein prädiktives Modell, das es dir ermöglicht, die Beziehung zwischen Eingabevariablen und Ausgabevariablen abzubilden.

> Binäre vs. Mehrklassenprobleme, die Klassifikationsalgorithmen bewältigen müssen. Infografik von Jen Looper
Bevor wir mit der Bereinigung unserer Daten, ihrer Visualisierung und der Vorbereitung für unsere ML-Aufgaben beginnen, lass uns ein wenig über die verschiedenen Möglichkeiten lernen, wie maschinelles Lernen zur Klassifikation von Daten genutzt werden kann.
Abgeleitet aus der Statistik verwendet die Klassifikation im klassischen maschinellen Lernen Merkmale wie smoker, weight und age, um die Wahrscheinlichkeit der Entwicklung von Krankheit X zu bestimmen. Als eine Technik des überwachten Lernens, ähnlich den Regressionsübungen, die du zuvor durchgeführt hast, sind deine Daten beschriftet, und die ML-Algorithmen verwenden diese Beschriftungen, um Klassen (oder 'Merkmale') eines Datensatzes zu klassifizieren und vorherzusagen und sie einer Gruppe oder einem Ergebnis zuzuordnen.
✅ Nimm dir einen Moment Zeit, um dir einen Datensatz über Küchen vorzustellen. Welche Fragen könnte ein Mehrklassenmodell beantworten? Welche Fragen könnte ein binäres Modell beantworten? Was wäre, wenn du herausfinden möchtest, ob eine bestimmte Küche wahrscheinlich Bockshornklee verwendet? Oder was wäre, wenn du sehen möchtest, ob du mit einer Tüte voller Sternanis, Artischocken, Blumenkohl und Meerrettich ein typisches indisches Gericht zubereiten könntest?
> 🎥 Klicke auf das Bild oben für ein Video. Die ganze Prämisse der Show 'Chopped' ist der 'Mystery-Korb', bei dem Köche aus einer zufälligen Auswahl an Zutaten ein Gericht zaubern müssen. Sicherlich hätte ein ML-Modell geholfen!
Hallo 'Classifier'
Die Frage, die wir an diesen Küchendatensatz stellen möchten, ist tatsächlich eine Mehrklassenfrage, da wir mit mehreren potenziellen Nationalküchen arbeiten. Angesichts einer Reihe von Zutaten, zu welcher dieser vielen Klassen passt die Daten?
Scikit-learn bietet mehrere verschiedene Algorithmen zur Klassifikation von Daten, je nachdem, welche Art von Problem du lösen möchtest. In den nächsten zwei Lektionen wirst du einige dieser Algorithmen kennenlernen.
Übung – Daten bereinigen und ausbalancieren
Die erste Aufgabe, bevor wir mit diesem Projekt beginnen, besteht darin, die Daten zu bereinigen und auszubalancieren, um bessere Ergebnisse zu erzielen. Beginne mit der leeren Datei notebook.ipynb im Stammverzeichnis dieses Ordners.
Das erste, was du installieren musst, ist imblearn. Dies ist ein Scikit-learn-Paket, das dir hilft, die Daten besser auszubalancieren (du wirst gleich mehr über diese Aufgabe erfahren).
-
Um
imblearnzu installieren, führepip installaus, wie folgt:python pip install imblearn -
Importiere die Pakete, die du benötigst, um deine Daten zu importieren und zu visualisieren, und importiere auch
SMOTEausimblearn.python import pandas as pd import matplotlib.pyplot as plt import matplotlib as mpl import numpy as np from imblearn.over_sampling import SMOTEJetzt bist du bereit, die Daten zu importieren.
-
Die nächste Aufgabe besteht darin, die Daten zu importieren:
python df = pd.read_csv('../data/cuisines.csv')
Mit read_csv() liest du den Inhalt der CSV-Datei cusines.csv und speicherst ihn in der Variablen df.
-
Überprüfe die Form der Daten:
python df.head()
Die ersten fünf Zeilen sehen so aus:
```output
| | Unnamed: 0 | cuisine | almond | angelica | anise | anise_seed | apple | apple_brandy | apricot | armagnac | ... | whiskey | white_bread | white_wine | whole_grain_wheat_flour | wine | wood | yam | yeast | yogurt | zucchini |
| --- | ---------- | ------- | ------ | -------- | ----- | ---------- | ----- | ------------ | ------- | -------- | --- | ------- | ----------- | ---------- | ----------------------- | ---- | ---- | --- | ----- | ------ | -------- |
| 0 | 65 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 66 | indian | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 67 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 3 | 68 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4 | 69 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
```
-
Hole dir Informationen über diese Daten, indem du
info()aufrufst:python df.info()Deine Ausgabe sieht so aus:
output <class 'pandas.core.frame.DataFrame'> RangeIndex: 2448 entries, 0 to 2447 Columns: 385 entries, Unnamed: 0 to zucchini dtypes: int64(384), object(1) memory usage: 7.2+ MB
Übung – Küchen entdecken
Jetzt wird die Arbeit interessanter. Lass uns die Verteilung der Daten pro Küche entdecken.
-
Stelle die Daten als Balken dar, indem du
barh()aufrufst:python df.cuisine.value_counts().plot.barh()
Es gibt eine begrenzte Anzahl von Küchen, aber die Verteilung der Daten ist ungleichmäßig. Das kannst du beheben! Bevor du das tust, erkunde noch ein wenig mehr.
-
Finde heraus, wie viele Daten pro Küche verfügbar sind, und gib sie aus:
```python thai_df = df[(df.cuisine == "thai")] japanese_df = df[(df.cuisine == "japanese")] chinese_df = df[(df.cuisine == "chinese")] indian_df = df[(df.cuisine == "indian")] korean_df = df[(df.cuisine == "korean")]
print(f'thai df: {thai_df.shape}') print(f'japanese df: {japanese_df.shape}') print(f'chinese df: {chinese_df.shape}') print(f'indian df: {indian_df.shape}') print(f'korean df: {korean_df.shape}') ```
Die Ausgabe sieht so aus:
output thai df: (289, 385) japanese df: (320, 385) chinese df: (442, 385) indian df: (598, 385) korean df: (799, 385)
Zutaten entdecken
Jetzt kannst du tiefer in die Daten eintauchen und herausfinden, welche typischen Zutaten pro Küche verwendet werden. Du solltest wiederkehrende Daten bereinigen, die Verwirrung zwischen den Küchen stiften. Lass uns mehr über dieses Problem erfahren.
-
Erstelle eine Funktion
create_ingredient()in Python, um ein Zutaten-Datenframe zu erstellen. Diese Funktion beginnt damit, eine nicht hilfreiche Spalte zu entfernen, und sortiert die Zutaten nach ihrer Häufigkeit:python def create_ingredient_df(df): ingredient_df = df.T.drop(['cuisine','Unnamed: 0']).sum(axis=1).to_frame('value') ingredient_df = ingredient_df[(ingredient_df.T != 0).any()] ingredient_df = ingredient_df.sort_values(by='value', ascending=False, inplace=False) return ingredient_df
Jetzt kannst du diese Funktion verwenden, um eine Vorstellung von den zehn beliebtesten Zutaten pro Küche zu bekommen.
-
Rufe
create_ingredient()auf und stelle die Daten mitbarh()dar:python thai_ingredient_df = create_ingredient_df(thai_df) thai_ingredient_df.head(10).plot.barh()
-
Mache dasselbe für die japanischen Daten:
python japanese_ingredient_df = create_ingredient_df(japanese_df) japanese_ingredient_df.head(10).plot.barh()
-
Nun für die chinesischen Zutaten:
python chinese_ingredient_df = create_ingredient_df(chinese_df) chinese_ingredient_df.head(10).plot.barh()
-
Stelle die indischen Zutaten dar:
python indian_ingredient_df = create_ingredient_df(indian_df) indian_ingredient_df.head(10).plot.barh()
-
Schließlich stelle die koreanischen Zutaten dar:
python korean_ingredient_df = create_ingredient_df(korean_df) korean_ingredient_df.head(10).plot.barh()
-
Entferne nun die häufigsten Zutaten, die Verwirrung zwischen verschiedenen Küchen stiften, indem du
drop()aufrufst:
Jeder liebt Reis, Knoblauch und Ingwer!
```python
feature_df= df.drop(['cuisine','Unnamed: 0','rice','garlic','ginger'], axis=1)
labels_df = df.cuisine #.unique()
feature_df.head()
```
Den Datensatz ausbalancieren
Nachdem du die Daten bereinigt hast, verwende SMOTE – "Synthetic Minority Over-sampling Technique" – um sie auszugleichen.
-
Rufe
fit_resample()auf. Diese Strategie generiert neue Stichproben durch Interpolation.python oversample = SMOTE() transformed_feature_df, transformed_label_df = oversample.fit_resample(feature_df, labels_df)Durch das Ausbalancieren deiner Daten erzielst du bessere Ergebnisse bei der Klassifikation. Denke an eine binäre Klassifikation. Wenn die meisten deiner Daten einer Klasse angehören, wird ein ML-Modell diese Klasse häufiger vorhersagen, einfach weil es mehr Daten dafür gibt. Das Ausbalancieren der Daten nimmt verzerrte Daten und hilft, dieses Ungleichgewicht zu beseitigen.
-
Jetzt kannst du die Anzahl der Labels pro Zutat überprüfen:
python print(f'new label count: {transformed_label_df.value_counts()}') print(f'old label count: {df.cuisine.value_counts()}')Deine Ausgabe sieht so aus:
output new label count: korean 799 chinese 799 indian 799 japanese 799 thai 799 Name: cuisine, dtype: int64 old label count: korean 799 indian 598 chinese 442 japanese 320 thai 289 Name: cuisine, dtype: int64Die Daten sind schön sauber, ausgeglichen und sehr lecker!
-
Der letzte Schritt besteht darin, deine ausgeglichenen Daten, einschließlich Labels und Features, in ein neues Datenframe zu speichern, das in eine Datei exportiert werden kann:
python transformed_df = pd.concat([transformed_label_df,transformed_feature_df],axis=1, join='outer') -
Du kannst einen letzten Blick auf die Daten werfen, indem du
transformed_df.head()undtransformed_df.info()aufrufst. Speichere eine Kopie dieser Daten für die Verwendung in zukünftigen Lektionen:python transformed_df.head() transformed_df.info() transformed_df.to_csv("../data/cleaned_cuisines.csv")Diese frische CSV-Datei befindet sich nun im Stamm-Datenordner.
🚀 Herausforderung
Dieses Curriculum enthält mehrere interessante Datensätze. Durchsuche die data-Ordner und sieh nach, ob einer Datensätze enthält, die sich für binäre oder Mehrklassenklassifikation eignen. Welche Fragen würdest du an diesen Datensatz stellen?
Quiz nach der Lektion
Rückblick & Selbststudium
Erkunde die API von SMOTE. Für welche Anwendungsfälle ist sie am besten geeignet? Welche Probleme löst sie?
Aufgabe
Erkunde Klassifikationsmethoden
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Köstliche asiatische und indische Küche
Einführung
Asiatische und indische Gerichte sind bekannt für ihre reichen Aromen, vielfältigen Zutaten und einzigartigen Kochtechniken. In diesem Leitfaden erkunden wir einige der beliebtesten Rezepte und geben Tipps, wie man sie zu Hause zubereiten kann.
Warum asiatische und indische Küche?
Die asiatische und indische Küche bietet eine unglaubliche Vielfalt an Geschmacksrichtungen, die von süß und sauer bis hin zu würzig und herzhaft reichen. Diese Küchen sind nicht nur lecker, sondern auch oft gesund, da sie frische Zutaten und ausgewogene Gewürze verwenden.
Beliebte Gerichte
1. Pad Thai
Pad Thai ist ein klassisches thailändisches Nudelgericht, das oft mit Garnelen, Huhn oder Tofu serviert wird. Es wird mit einer Kombination aus Tamarindensauce, Fischsauce, Zucker und Limettensaft gewürzt.
Zutaten:
- Reisnudeln
- Garnelen, Huhn oder Tofu
- Tamarindensauce
- Fischsauce
- Knoblauch
- Eier
- Frühlingszwiebeln
- Erdnüsse
Zubereitung:
- Reisnudeln nach Packungsanweisung kochen.
- Knoblauch in einer Pfanne anbraten, dann Garnelen, Huhn oder Tofu hinzufügen.
- Eier in die Pfanne geben und verrühren.
- Gekochte Nudeln und die vorbereitete Sauce hinzufügen.
- Mit Frühlingszwiebeln und Erdnüssen garnieren.
2. Butter Chicken
Butter Chicken ist ein cremiges indisches Currygericht, das mit Tomaten, Butter und einer Mischung aus Gewürzen zubereitet wird. Es wird oft mit Naan oder Reis serviert.
Zutaten:
- Hähnchenbrust
- Tomatenpüree
- Sahne
- Butter
- Knoblauch und Ingwer
- Garam Masala
- Kurkuma
- Kreuzkümmel
Zubereitung:
- Hähnchen in einer Marinade aus Joghurt und Gewürzen einlegen.
- Das marinierte Hähnchen anbraten und beiseitestellen.
- Tomatenpüree, Butter und Sahne in einer Pfanne erhitzen.
- Gewürze hinzufügen und das Hähnchen in die Sauce geben.
- Köcheln lassen, bis das Hähnchen zart ist.
Tipps für die Zubereitung
- Frische Zutaten verwenden: Frische Kräuter und Gewürze machen einen großen Unterschied im Geschmack.
- Experimentieren: Scheuen Sie sich nicht, mit verschiedenen Gewürzen und Zutaten zu experimentieren, um Ihren eigenen Stil zu finden.
- Vorbereitung: Bereiten Sie alle Zutaten im Voraus vor, um den Kochprozess zu erleichtern.
Fazit
Die asiatische und indische Küche bietet endlose Möglichkeiten, köstliche und aromatische Gerichte zu kreieren. Mit ein wenig Übung und den richtigen Zutaten können Sie diese Gerichte ganz einfach zu Hause genießen. Probieren Sie es aus und entdecken Sie die Vielfalt dieser wunderbaren Küchen!
Installieren Sie Imblearn, das SMOTE ermöglicht. Dies ist ein Scikit-learn-Paket, das bei der Handhabung unausgeglichener Daten bei der Klassifikation hilft. (https://imbalanced-learn.org/stable/)
pip install imblearn
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
from imblearn.over_sampling import SMOTE
df = pd.read_csv('../../data/cuisines.csv')
Dieses Dataset umfasst 385 Spalten, die alle Arten von Zutaten in verschiedenen Küchen aus einem gegebenen Satz von Küchen anzeigen.
df.head()
df.info()
df.cuisine.value_counts()
Zeigen Sie die Küchen in einem Balkendiagramm
df.cuisine.value_counts().plot.barh()
thai_df = df[(df.cuisine == "thai")]
japanese_df = df[(df.cuisine == "japanese")]
chinese_df = df[(df.cuisine == "chinese")]
indian_df = df[(df.cuisine == "indian")]
korean_df = df[(df.cuisine == "korean")]
print(f'thai df: {thai_df.shape}')
print(f'japanese df: {japanese_df.shape}')
print(f'chinese df: {chinese_df.shape}')
print(f'indian df: {indian_df.shape}')
print(f'korean df: {korean_df.shape}')
def create_ingredient_df(df):
# transpose df, drop cuisine and unnamed rows, sum the row to get total for ingredient and add value header to new df
ingredient_df = df.T.drop(['cuisine','Unnamed: 0']).sum(axis=1).to_frame('value')
# drop ingredients that have a 0 sum
ingredient_df = ingredient_df[(ingredient_df.T != 0).any()]
# sort df
ingredient_df = ingredient_df.sort_values(by='value', ascending=False, inplace=False)
return ingredient_df
thai_ingredient_df = create_ingredient_df(thai_df)
thai_ingredient_df.head(10).plot.barh()
japanese_ingredient_df = create_ingredient_df(japanese_df)
japanese_ingredient_df.head(10).plot.barh()
chinese_ingredient_df = create_ingredient_df(chinese_df)
chinese_ingredient_df.head(10).plot.barh()
indian_ingredient_df = create_ingredient_df(indian_df)
indian_ingredient_df.head(10).plot.barh()
korean_ingredient_df = create_ingredient_df(korean_df)
korean_ingredient_df.head(10).plot.barh()
feature_df= df.drop(['cuisine','Unnamed: 0','rice','garlic','ginger'], axis=1)
labels_df = df.cuisine #.unique()
feature_df.head()
Balancieren Sie Daten mit SMOTE-Oversampling auf die höchste Klasse. Lesen Sie hier mehr: https://imbalanced-learn.org/dev/references/generated/imblearn.over_sampling.SMOTE.html
oversample = SMOTE()
transformed_feature_df, transformed_label_df = oversample.fit_resample(feature_df, labels_df)
print(f'new label count: {transformed_label_df.value_counts()}')
print(f'old label count: {df.cuisine.value_counts()}')
transformed_feature_df.head()
# export transformed data to new df for classification
transformed_df = pd.concat([transformed_label_df,transformed_feature_df],axis=1, join='outer')
transformed_df
transformed_df.info()
Speichern Sie die Datei für die zukünftige Verwendung
transformed_df.to_csv("../../data/cleaned_cuisines.csv")
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Erstellen Sie ein Klassifikationsmodell: Köstliche asiatische und indische Küchen
Einführung in die Klassifikation: Daten bereinigen, vorbereiten und visualisieren
In diesen vier Lektionen wirst du einen grundlegenden Schwerpunkt des klassischen maschinellen Lernens erkunden - Klassifikation. Wir werden verschiedene Klassifikationsalgorithmen mit einem Datensatz über die großartigen Küchen Asiens und Indiens durchgehen. Hoffentlich hast du Appetit!
<p > <img src="../../images/pinch.png" width="600"/> <figcaption>Feiere pan-asiatische Küchen in diesen Lektionen! Bild von Jen Looper</figcaption>
<!--
-->
Klassifikation ist eine Form des überwachten Lernens, die viele Gemeinsamkeiten mit Regressionstechniken hat. Bei der Klassifikation trainierst du ein Modell, um vorherzusagen, zu welcher Kategorie ein Element gehört. Wenn maschinelles Lernen darauf abzielt, Werte oder Namen von Dingen mithilfe von Datensätzen vorherzusagen, fällt die Klassifikation im Allgemeinen in zwei Gruppen: binäre Klassifikation und Mehrklassenklassifikation.
Denke daran:
-
Lineare Regression hat dir geholfen, Beziehungen zwischen Variablen vorherzusagen und genaue Vorhersagen darüber zu treffen, wo ein neuer Datenpunkt in Bezug auf diese Linie liegen würde. So konntest du beispielsweise numerische Werte wie den Preis eines Kürbisses im September vs. Dezember vorhersagen.
-
Logistische Regression hat dir geholfen, "binäre Kategorien" zu entdecken: Bei diesem Preisniveau, ist dieser Kürbis orange oder nicht-orange?
Klassifikation verwendet verschiedene Algorithmen, um andere Möglichkeiten zu finden, das Label oder die Klasse eines Datenpunkts zu bestimmen. Lass uns mit diesen Küchendaten arbeiten, um herauszufinden, ob wir anhand einer Gruppe von Zutaten die Herkunftsküche bestimmen können.
Quiz vor der Lektion
Einführung
Klassifikation ist eine der grundlegenden Tätigkeiten eines Forschers im Bereich maschinelles Lernen und eines Datenwissenschaftlers. Von der einfachen Klassifikation eines binären Wertes ("Ist diese E-Mail Spam oder nicht?") bis hin zur komplexen Bildklassifikation und Segmentierung mithilfe von Computer Vision ist es immer nützlich, Daten in Klassen zu sortieren und Fragen dazu zu stellen.
Um den Prozess wissenschaftlicher auszudrücken: Deine Klassifikationsmethode erstellt ein prädiktives Modell, das es dir ermöglicht, die Beziehung zwischen Eingabevariablen und Ausgabevariablen abzubilden.
<p > <img src="../../images/binary-multiclass.png" width="600"/> <figcaption>Binäre vs. Mehrklassenprobleme, die Klassifikationsalgorithmen bewältigen können. Infografik von Jen Looper</figcaption>
Bevor wir mit dem Bereinigen unserer Daten, ihrer Visualisierung und Vorbereitung für unsere ML-Aufgaben beginnen, lass uns ein wenig über die verschiedenen Möglichkeiten lernen, wie maschinelles Lernen genutzt werden kann, um Daten zu klassifizieren.
Abgeleitet aus der Statistik verwendet die Klassifikation im klassischen maschinellen Lernen Merkmale wie Raucher, Gewicht und Alter, um die Wahrscheinlichkeit der Entwicklung von Krankheit X zu bestimmen. Als eine Technik des überwachten Lernens, ähnlich den Regressionsexperimenten, die du zuvor durchgeführt hast, sind deine Daten beschriftet, und die ML-Algorithmen verwenden diese Beschriftungen, um Klassen (oder 'Merkmale') eines Datensatzes zu klassifizieren und sie einer Gruppe oder einem Ergebnis zuzuordnen.
✅ Nimm dir einen Moment Zeit, um dir einen Datensatz über Küchen vorzustellen. Welche Fragen könnte ein Mehrklassenmodell beantworten? Welche Fragen könnte ein binäres Modell beantworten? Was wäre, wenn du herausfinden möchtest, ob eine bestimmte Küche wahrscheinlich Bockshornklee verwendet? Was wäre, wenn du herausfinden möchtest, ob du mit einer Tüte voller Sternanis, Artischocken, Blumenkohl und Meerrettich ein typisches indisches Gericht zubereiten könntest?
Hallo 'Classifier'
Die Frage, die wir diesem Küchendatensatz stellen möchten, ist tatsächlich eine Mehrklassenfrage, da wir mehrere potenzielle nationale Küchen zur Auswahl haben. Angenommen, wir haben eine Gruppe von Zutaten - zu welcher dieser vielen Klassen passt die Daten?
Tidymodels bietet verschiedene Algorithmen, um Daten zu klassifizieren, je nachdem, welche Art von Problem du lösen möchtest. In den nächsten zwei Lektionen wirst du einige dieser Algorithmen kennenlernen.
Voraussetzung
Für diese Lektion benötigen wir die folgenden Pakete, um unsere Daten zu bereinigen, vorzubereiten und zu visualisieren:
-
tidyverse: Das tidyverse ist eine Sammlung von R-Paketen, die darauf abzielt, Datenwissenschaft schneller, einfacher und unterhaltsamer zu machen! -
tidymodels: Das tidymodels Framework ist eine Sammlung von Paketen für Modellierung und maschinelles Lernen. -
DataExplorer: Das DataExplorer-Paket soll den EDA-Prozess und die Berichterstellung vereinfachen und automatisieren. -
themis: Das themis-Paket bietet zusätzliche Rezeptschritte für den Umgang mit unausgewogenen Daten.
Du kannst sie wie folgt installieren:
install.packages(c("tidyverse", "tidymodels", "DataExplorer", "here"))
Alternativ überprüft das untenstehende Skript, ob du die Pakete hast, die für die Durchführung dieses Moduls erforderlich sind, und installiert sie für dich, falls sie fehlen.
suppressWarnings(if (!require("pacman"))install.packages("pacman"))
pacman::p_load(tidyverse, tidymodels, DataExplorer, themis, here)
Wir werden später diese großartigen Pakete laden und in unserer aktuellen R-Sitzung verfügbar machen. (Dies dient nur zur Veranschaulichung, pacman::p_load() hat das bereits für Sie erledigt)
Übung – Daten bereinigen und ausbalancieren
Die erste Aufgabe, bevor Sie mit diesem Projekt beginnen, besteht darin, Ihre Daten zu bereinigen und auszubalancieren, um bessere Ergebnisse zu erzielen.
Lernen wir die Daten kennen! 🕵️
# Import data
df <- read_csv(file = "https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/4-Classification/data/cuisines.csv")
# View the first 5 rows
df %>%
slice_head(n = 5)
Interessant! Vom Aussehen her ist die erste Spalte eine Art id-Spalte. Lassen Sie uns ein wenig mehr Informationen über die Daten erhalten.
# Basic information about the data
df %>%
introduce()
# Visualize basic information above
df %>%
plot_intro(ggtheme = theme_light())
Aus der Ausgabe können wir sofort erkennen, dass wir 2448 Zeilen und 385 Spalten sowie 0 fehlende Werte haben. Außerdem haben wir eine diskrete Spalte, cuisine.
Übung - mehr über Küchen lernen
Jetzt wird die Arbeit interessanter. Lassen Sie uns die Verteilung der Daten pro Küche entdecken.
# Count observations per cuisine
df %>%
count(cuisine) %>%
arrange(n)
# Plot the distribution
theme_set(theme_light())
df %>%
count(cuisine) %>%
ggplot(mapping = aes(x = n, y = reorder(cuisine, -n))) +
geom_col(fill = "midnightblue", alpha = 0.7) +
ylab("cuisine")
Es gibt eine begrenzte Anzahl von Küchen, aber die Verteilung der Daten ist ungleichmäßig. Du kannst das ändern! Bevor du das tust, erkunde die Daten ein wenig mehr.
Als Nächstes ordnen wir jede Küche in ihre eigene Tibble und finden heraus, wie viele Daten (Zeilen, Spalten) pro Küche verfügbar sind.
> Ein tibble ist ein modernes Daten-Frame.
<p > <img src="../../images/dplyr_filter.jpg" width="600"/> <figcaption>Kunstwerk von @allison_horst</figcaption>
# Create individual tibble for the cuisines
thai_df <- df %>%
filter(cuisine == "thai")
japanese_df <- df %>%
filter(cuisine == "japanese")
chinese_df <- df %>%
filter(cuisine == "chinese")
indian_df <- df %>%
filter(cuisine == "indian")
korean_df <- df %>%
filter(cuisine == "korean")
# Find out how much data is available per cuisine
cat(" thai df:", dim(thai_df), "\n",
"japanese df:", dim(japanese_df), "\n",
"chinese_df:", dim(chinese_df), "\n",
"indian_df:", dim(indian_df), "\n",
"korean_df:", dim(korean_df))
Übung - Entdecken der wichtigsten Zutaten nach Küche mit dplyr
Jetzt kannst du tiefer in die Daten eintauchen und herausfinden, welche typischen Zutaten zu den verschiedenen Küchen gehören. Du solltest wiederkehrende Daten bereinigen, die Verwirrung zwischen den Küchen stiften, also lass uns mehr über dieses Problem lernen.
Erstelle eine Funktion create_ingredient() in R, die ein Zutaten-Datenframe zurückgibt. Diese Funktion beginnt damit, eine wenig hilfreiche Spalte zu entfernen und die Zutaten nach ihrer Häufigkeit zu sortieren.
Die grundlegende Struktur einer Funktion in R ist:
myFunction <- function(arglist){
...
return(value)
}
Eine übersichtliche Einführung in R-Funktionen findest du hier.
Legen wir direkt los! Wir werden dplyr-Verben verwenden, die wir in unseren vorherigen Lektionen gelernt haben. Zur Erinnerung:
-
dplyr::select(): hilft dir, Spalten auszuwählen, die du behalten oder ausschließen möchtest. -
dplyr::pivot_longer(): hilft dir, Daten zu "verlängern", indem die Anzahl der Zeilen erhöht und die Anzahl der Spalten verringert wird. -
dplyr::group_by()unddplyr::summarise(): helfen dir, zusammenfassende Statistiken für verschiedene Gruppen zu finden und sie in einer übersichtlichen Tabelle darzustellen. -
dplyr::filter(): erstellt eine Teilmenge der Daten, die nur Zeilen enthält, die deine Bedingungen erfüllen. -
dplyr::mutate(): hilft dir, Spalten zu erstellen oder zu ändern.
Schau dir dieses kunstvolle Learnr-Tutorial von Allison Horst an, das einige nützliche Datenbearbeitungsfunktionen in dplyr (Teil des Tidyverse) vorstellt.
# Creates a functions that returns the top ingredients by class
create_ingredient <- function(df){
# Drop the id column which is the first colum
ingredient_df = df %>% select(-1) %>%
# Transpose data to a long format
pivot_longer(!cuisine, names_to = "ingredients", values_to = "count") %>%
# Find the top most ingredients for a particular cuisine
group_by(ingredients) %>%
summarise(n_instances = sum(count)) %>%
filter(n_instances != 0) %>%
# Arrange by descending order
arrange(desc(n_instances)) %>%
mutate(ingredients = factor(ingredients) %>% fct_inorder())
return(ingredient_df)
} # End of function
Jetzt können wir die Funktion nutzen, um eine Vorstellung von den zehn beliebtesten Zutaten nach Küche zu bekommen. Probieren wir es mit thai_df aus.
# Call create_ingredient and display popular ingredients
thai_ingredient_df <- create_ingredient(df = thai_df)
thai_ingredient_df %>%
slice_head(n = 10)
Im vorherigen Abschnitt haben wir geom_col() verwendet, lassen Sie uns sehen, wie Sie auch geom_bar verwenden können, um Balkendiagramme zu erstellen. Verwenden Sie ?geom_bar für weitere Informationen.
# Make a bar chart for popular thai cuisines
thai_ingredient_df %>%
slice_head(n = 10) %>%
ggplot(aes(x = n_instances, y = ingredients)) +
geom_bar(stat = "identity", width = 0.5, fill = "steelblue") +
xlab("") + ylab("")
Lass uns dasselbe für die japanischen Daten tun
# Get popular ingredients for Japanese cuisines and make bar chart
create_ingredient(df = japanese_df) %>%
slice_head(n = 10) %>%
ggplot(aes(x = n_instances, y = ingredients)) +
geom_bar(stat = "identity", width = 0.5, fill = "darkorange", alpha = 0.8) +
xlab("") + ylab("")
Was ist mit der chinesischen Küche?
# Get popular ingredients for Chinese cuisines and make bar chart
create_ingredient(df = chinese_df) %>%
slice_head(n = 10) %>%
ggplot(aes(x = n_instances, y = ingredients)) +
geom_bar(stat = "identity", width = 0.5, fill = "cyan4", alpha = 0.8) +
xlab("") + ylab("")
# Get popular ingredients for Indian cuisines and make bar chart
create_ingredient(df = indian_df) %>%
slice_head(n = 10) %>%
ggplot(aes(x = n_instances, y = ingredients)) +
geom_bar(stat = "identity", width = 0.5, fill = "#041E42FF", alpha = 0.8) +
xlab("") + ylab("")
Schließlich die koreanischen Zutaten plotten.
# Get popular ingredients for Korean cuisines and make bar chart
create_ingredient(df = korean_df) %>%
slice_head(n = 10) %>%
ggplot(aes(x = n_instances, y = ingredients)) +
geom_bar(stat = "identity", width = 0.5, fill = "#852419FF", alpha = 0.8) +
xlab("") + ylab("")
Aus den Datenvisualisierungen können wir nun die häufigsten Zutaten entfernen, die Verwirrung zwischen verschiedenen Küchenstilen stiften, indem wir dplyr::select() verwenden.
Jeder liebt Reis, Knoblauch und Ingwer!
# Drop id column, rice, garlic and ginger from our original data set
df_select <- df %>%
select(-c(1, rice, garlic, ginger))
# Display new data set
df_select %>%
slice_head(n = 5)
Datenvorverarbeitung mit Recipes 👩🍳👨🍳 - Umgang mit unausgeglichenen Daten ⚖️
<p > <img src="../../images/recipes.png" width="600"/> <figcaption>Illustration von @allison_horst</figcaption>
Da es in dieser Lektion um Küchen geht, müssen wir recipes in den richtigen Kontext setzen.
Tidymodels bietet ein weiteres praktisches Paket: recipes - ein Paket zur Datenvorverarbeitung.
Werfen wir erneut einen Blick auf die Verteilung unserer Küchen.
# Distribution of cuisines
old_label_count <- df_select %>%
count(cuisine) %>%
arrange(desc(n))
old_label_count
Wie Sie sehen können, gibt es eine ziemlich ungleiche Verteilung in der Anzahl der Küchen. Koreanische Küchen sind fast dreimal so häufig wie thailändische Küchen. Unausgewogene Daten haben oft negative Auswirkungen auf die Modellleistung. Denken Sie an eine binäre Klassifikation. Wenn der Großteil Ihrer Daten zu einer Klasse gehört, wird ein ML-Modell diese Klasse häufiger vorhersagen, einfach weil es dafür mehr Daten gibt. Das Ausbalancieren der Daten gleicht jede Schieflage aus und hilft, dieses Ungleichgewicht zu beseitigen. Viele Modelle erzielen die besten Ergebnisse, wenn die Anzahl der Beobachtungen gleich ist, und haben daher oft Schwierigkeiten mit unausgewogenen Daten.
Es gibt im Wesentlichen zwei Ansätze, um mit unausgewogenen Datensätzen umzugehen:
-
Hinzufügen von Beobachtungen zur Minderheitsklasse:
Over-sampling, z. B. mit einem SMOTE-Algorithmus -
Entfernen von Beobachtungen aus der Mehrheitsklasse:
Under-sampling
Lassen Sie uns nun demonstrieren, wie man mit unausgewogenen Datensätzen mithilfe eines Rezepts umgeht. Ein Rezept kann als eine Art Blaupause betrachtet werden, die beschreibt, welche Schritte auf einen Datensatz angewendet werden sollten, um ihn für die Datenanalyse vorzubereiten.
# Load themis package for dealing with imbalanced data
library(themis)
# Create a recipe for preprocessing data
cuisines_recipe <- recipe(cuisine ~ ., data = df_select) %>%
step_smote(cuisine)
cuisines_recipe
Lassen Sie uns unsere Vorverarbeitungsschritte aufschlüsseln.
-
Der Aufruf von
recipe()mit einer Formel teilt dem Rezept die Rollen der Variablen unter Verwendung derdf_select-Daten als Referenz mit. Zum Beispiel wurde dercuisine-Spalte die Rolleoutcomezugewiesen, während die restlichen Spalten die Rollepredictorerhalten haben. -
step_smote(cuisine)erstellt eine Spezifikation eines Rezeptschritts, der synthetisch neue Beispiele der Minderheitsklasse generiert, indem die nächsten Nachbarn dieser Fälle verwendet werden.
Wenn wir nun die vorverarbeiteten Daten sehen möchten, müssten wir unser Rezept prep() und bake() anwenden.
prep(): schätzt die erforderlichen Parameter aus einem Trainingsdatensatz, die später auf andere Datensätze angewendet werden können.
bake(): nimmt ein vorbereitetes Rezept und wendet die Operationen auf einen beliebigen Datensatz an.
# Prep and bake the recipe
preprocessed_df <- cuisines_recipe %>%
prep() %>%
bake(new_data = NULL) %>%
relocate(cuisine)
# Display data
preprocessed_df %>%
slice_head(n = 5)
# Quick summary stats
preprocessed_df %>%
introduce()
Lassen Sie uns nun die Verteilung unserer Küchen überprüfen und sie mit den unausgewogenen Daten vergleichen.
# Distribution of cuisines
new_label_count <- preprocessed_df %>%
count(cuisine) %>%
arrange(desc(n))
list(new_label_count = new_label_count,
old_label_count = old_label_count)
Yum! Die Daten sind schön sauber, ausgewogen und sehr lecker 😋!
> Normalerweise wird ein Rezept als Vorverarbeitungswerkzeug für das Modellieren verwendet, wobei es definiert, welche Schritte auf einen Datensatz angewendet werden müssen, um ihn für das Modellieren vorzubereiten. In diesem Fall wird typischerweise ein workflow() verwendet (wie wir bereits in unseren vorherigen Lektionen gesehen haben), anstatt ein Rezept manuell zu schätzen.
>
> Daher ist es normalerweise nicht notwendig, prep() und bake() zu verwenden, wenn man mit tidymodels arbeitet. Dennoch sind es hilfreiche Funktionen, die man in seinem Werkzeugkasten haben sollte, um sicherzustellen, dass Rezepte das tun, was man erwartet – so wie in unserem Fall.
>
> Wenn du ein vorbereitetes Rezept mit new_data = NULL bake(), erhältst du die Daten zurück, die du beim Definieren des Rezepts bereitgestellt hast, jedoch mit den angewendeten Vorverarbeitungsschritten.
Speichern wir nun eine Kopie dieser Daten, um sie in zukünftigen Lektionen zu verwenden:
# Save preprocessed data
write_csv(preprocessed_df, "../../../data/cleaned_cuisines_R.csv")
Diese neue CSV-Datei befindet sich jetzt im Hauptdatenordner.
🚀Herausforderung
Dieses Curriculum enthält mehrere interessante Datensätze. Durchsuche die data-Ordner und prüfe, ob sie Datensätze enthalten, die sich für binäre oder Multi-Klassen-Klassifikationen eignen. Welche Fragen würdest du zu diesem Datensatz stellen?
Quiz nach der Vorlesung
Überblick & Selbststudium
-
Schau dir das Paket themis an. Welche anderen Techniken könnten wir verwenden, um mit unausgeglichenen Daten umzugehen?
-
Tidy Models Referenz-Website.
-
H. Wickham und G. Grolemund, R for Data Science: Visualize, Model, Transform, Tidy, and Import Data.
EIN GROSSES DANKESCHÖN AN:
Allison Horst für die Erstellung der großartigen Illustrationen, die R einladender und ansprechender machen. Weitere Illustrationen findest du in ihrer Galerie.
Cassie Breviu und Jen Looper für die Erstellung der ursprünglichen Python-Version dieses Moduls ♥️
<p > <img src="../../images/r_learners_sm.jpeg" width="600"/> <figcaption>Kunstwerk von @allison_horst</figcaption>
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Studieren Sie die Solver
Anweisungen
In dieser Lektion haben Sie die verschiedenen Solver kennengelernt, die Algorithmen mit einem maschinellen Lernprozess kombinieren, um ein genaues Modell zu erstellen. Gehen Sie die im Unterricht aufgeführten Solver durch und wählen Sie zwei aus. Vergleichen und kontrastieren Sie diese beiden Solver in Ihren eigenen Worten. Welche Art von Problem lösen sie? Wie arbeiten sie mit verschiedenen Datenstrukturen? Warum würden Sie einen gegenüber dem anderen bevorzugen?
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Eine .doc-Datei wird mit zwei Absätzen vorgelegt, die jeden Solver durchdacht vergleichen. | Eine .doc-Datei wird mit nur einem Absatz vorgelegt | Die Aufgabe ist unvollständig |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Klassifikationsmodelle erstellen
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Küchenklassifikatoren 1
In dieser Lektion verwenden Sie den Datensatz, den Sie aus der letzten Lektion gespeichert haben, voller ausgewogener, sauberer Daten rund um Küchen.
Sie werden diesen Datensatz mit einer Vielzahl von Klassifikatoren verwenden, um eine bestimmte nationale Küche basierend auf einer Zutatenliste vorherzusagen. Dabei lernen Sie mehr über einige der Möglichkeiten, wie Algorithmen für Klassifizierungsaufgaben genutzt werden können.
Vorlesungsquiz
Vorbereitung
Vorausgesetzt, Sie haben Lektion 1 abgeschlossen, stellen Sie sicher, dass eine Datei cleaned_cuisines.csv im Stammordner /data für diese vier Lektionen existiert.
Übung – eine nationale Küche vorhersagen
-
Arbeiten Sie im Ordner notebook.ipynb dieser Lektion und importieren Sie diese Datei zusammen mit der Pandas-Bibliothek:
python import pandas as pd cuisines_df = pd.read_csv("../data/cleaned_cuisines.csv") cuisines_df.head()Die Daten sehen so aus:
| Unnamed: 0 | cuisine | almond | angelica | anise | anise_seed | apple | apple_brandy | apricot | armagnac | ... | whiskey | white_bread | white_wine | whole_grain_wheat_flour | wine | wood | yam | yeast | yogurt | zucchini | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 1 | indian | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 2 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 3 | 3 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4 | 4 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
-
Importieren Sie nun mehrere weitere Bibliotheken:
python from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split, cross_val_score from sklearn.metrics import accuracy_score,precision_score,confusion_matrix,classification_report, precision_recall_curve from sklearn.svm import SVC import numpy as np -
Teilen Sie die X- und y-Koordinaten in zwei DataFrames für das Training auf.
cuisinekann das Label-DataFrame sein:python cuisines_label_df = cuisines_df['cuisine'] cuisines_label_df.head()Es sieht so aus:
output 0 indian 1 indian 2 indian 3 indian 4 indian Name: cuisine, dtype: object -
Löschen Sie die Spalte
Unnamed: 0und diecuisine-Spalte mittelsdrop(). Speichern Sie den Rest der Daten als trainierbare Merkmale:python cuisines_feature_df = cuisines_df.drop(['Unnamed: 0', 'cuisine'], axis=1) cuisines_feature_df.head()Ihre Merkmale sehen so aus:
| almond | angelica | anise | anise_seed | apple | apple_brandy | apricot | armagnac | artemisia | artichoke | ... | whiskey | white_bread | white_wine | whole_grain_wheat_flour | wine | wood | yam | yeast | yogurt | zucchini | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Jetzt sind Sie bereit, Ihr Modell zu trainieren!
Auswahl des Klassifikators
Da Ihre Daten nun sauber und bereit für das Training sind, müssen Sie entscheiden, welchen Algorithmus Sie für die Aufgabe verwenden möchten.
Scikit-learn gruppiert Klassifikation unter Überwachtem Lernen (Supervised Learning), und in dieser Kategorie finden Sie viele Klassifizierungsmethoden. Die Vielfalt ist auf den ersten Blick ziemlich überwältigend. Die folgenden Methoden beinhalten Klassifikationstechniken:
- Lineare Modelle
- Support Vector Machines
- Stochastischer Gradientenabstieg
- Nächste Nachbarn
- Gaußsche Prozesse
- Entscheidungsbäume
- Ensemble-Methoden (Voting-Klassifikator)
- Multi-Class- und Multioutput-Algorithmen (Multiclass- und Multilabel-Klassifikation, Multiclass-Multioutput-Klassifikation)
> Sie können auch Neuronale Netze zur Klassifikation von Daten einsetzen, aber das liegt außerhalb des Umfangs dieser Lektion.
Welchen Klassifikator wählen?
Welchen Klassifikator sollten Sie wählen? Oft hilft es, mehrere auszuprobieren und nach einem guten Ergebnis zu suchen. Scikit-learn bietet einen direkten Vergleich auf einem erstellten Datensatz, in dem KNeighbors, SVC auf zwei Arten, GaussianProcessClassifier, DecisionTreeClassifier, RandomForestClassifier, MLPClassifier, AdaBoostClassifier, GaussianNB und QuadraticDiscriminantAnalysis verglichen und die Ergebnisse visualisiert werden:

> Plots erstellt aus der Dokumentation von Scikit-learn
> AutoML löst dieses Problem elegant, indem es diese Vergleiche in der Cloud durchführt und Ihnen erlaubt, den besten Algorithmus für Ihre Daten auszuwählen. Probieren Sie es hier
Ein besserer Ansatz
Eine bessere Methode als wildes Raten ist es, den Ideen auf diesem herunterladbaren ML-Spickzettel zu folgen. Hier entdecken wir, dass wir für unser Multiclass-Problem einige Optionen haben:

> Ein Ausschnitt des Algorithmus-Spickzettels von Microsoft, der Multiclass-Klassifikationsmöglichkeiten beschreibt
✅ Laden Sie diesen Spickzettel herunter, drucken Sie ihn aus und hängen Sie ihn an Ihre Wand!
Begründung
Versuchen wir anhand gegebener Einschränkungen die verschiedenen Ansätze zu begründen:
- Neuronale Netze sind zu schwergewichtig. Angesichts unseres sauberen, aber kleinen Datensatzes und der Tatsache, dass wir lokal über Notebooks trainieren, sind neuronale Netze zu schwergewichtig für diese Aufgabe.
- Kein Zwei-Klassen-Klassifikator. Wir nutzen keinen Zwei-Klassen-Klassifikator, daher ist One-vs-All ausgeschlossen.
- Entscheidungsbaum oder logistische Regression sind möglich. Ein Entscheidungsbaum könnte funktionieren oder logistische Regression für Multiclass-Daten.
- Multiclass Boosted Decision Trees lösen ein anderes Problem. Die multiclass boosted decision trees sind eher für nicht-parametrische Aufgaben geeignet, z.B. für Ranglisten und daher für uns nicht nützlich.
Verwendung von Scikit-learn
Wir werden Scikit-learn verwenden, um unsere Daten zu analysieren. Es gibt allerdings viele Möglichkeiten, logistische Regression mit Scikit-learn anzuwenden. Sehen Sie sich die Parameter an, die man übergeben kann.
Im Wesentlichen sind zwei wichtige Parameter - multi_class und solver - festzulegen, wenn wir Scikit-learn bitten, eine logistische Regression durchzuführen. Der Wert von multi_class bestimmt eine bestimmte Verhaltensweise. Der Wert von solver gibt an, welchen Algorithmus man verwenden möchte. Nicht alle Solver sind mit allen multi_class-Werten kompatibel.
Laut der Dokumentation verwendet der Trainingsalgorithmus im Multiclass-Fall:
- das one-vs-rest (OvR) Schema, wenn die Option
multi_classaufovrgesetzt ist - die Kreuzentropie-Verlustfunktion, wenn die Option
multi_classaufmultinomialgesetzt ist. (Die Optionmultinomialwird zurzeit nur von den Solvern ‘lbfgs’, ‘sag’, ‘saga’ und ‘newton-cg’ unterstützt.)"
> 🎓 Das 'Schema' kann entweder 'ovr' (one-vs-rest) oder 'multinomial' sein. Da logistische Regression eigentlich für binäre Klassifikation ausgelegt ist, erlauben diese Schemata eine bessere Handhabung von Multiclass-Aufgaben. Quelle
> 🎓 Der 'Solver' ist definiert als "der Algorithmus zur Lösung des Optimierungsproblems". Quelle.
Scikit-learn bietet diese Tabelle, um zu zeigen, wie die Solvers unterschiedliche Herausforderungen verschiedener Datenstrukturen bewältigen:

Übung – Daten aufteilen
Wir konzentrieren uns bei unserem ersten Trainingsversuch auf die logistische Regression, da Sie diese Methode kürzlich in einer vorherigen Lektion gelernt haben. Teilen Sie Ihre Daten in Trainings- und Testgruppen mittels train_test_split() auf:
X_train, X_test, y_train, y_test = train_test_split(cuisines_feature_df, cuisines_label_df, test_size=0.3)
Übung – logistische Regression anwenden
Da Sie die Multiclass-Variante verwenden, müssen Sie ein Schema wählen und den Solver festlegen. Verwenden Sie LogisticRegression mit einer Multiclass-Konfiguration und dem Solver liblinear, um zu trainieren.
-
Erstellen Sie eine logistische Regression mit
multi_classaufovrund dem Solverliblinear:```python lr = LogisticRegression(multi_class='ovr',solver='liblinear') model = lr.fit(X_train, np.ravel(y_train))
accuracy = model.score(X_test, y_test) print ("Accuracy is {}".format(accuracy)) ```
✅ Probieren Sie einen anderen Solver wie
lbfgsaus, der oft als Standard eingestellt ist.> Hinweis: Verwenden Sie die Pandas-Funktion
ravel, um Ihre Daten bei Bedarf zu glätten.Die Genauigkeit ist gut – über 80%!
-
Sie können dieses Modell in Aktion sehen, indem Sie eine einzelne Datenzeile (#50) testen:
python print(f'ingredients: {X_test.iloc[50][X_test.iloc[50]!=0].keys()}') print(f'cuisine: {y_test.iloc[50]}')Das Ergebnis wird ausgegeben:
output
ingredients: Index(['cilantro', 'onion', 'pea', 'potato', 'tomato', 'vegetable_oil'], dtype='object')
cuisine: indian
✅ Probieren Sie eine andere Zeilennummer und überprüfen Sie die Ergebnisse. 1. Wenn Sie tiefer graben, können Sie die Genauigkeit dieser Vorhersage überprüfen:
```python
test= X_test.iloc[50].values.reshape(-1, 1).T
proba = model.predict_proba(test)
classes = model.classes_
resultdf = pd.DataFrame(data=proba, columns=classes)
topPrediction = resultdf.T.sort_values(by=[0], ascending = [False])
topPrediction.head()
```
Das Ergebnis wird ausgegeben – Indische Küche ist die beste Vermutung mit hoher Wahrscheinlichkeit:
| | 0 |
| -------: | -------: |
| indian | 0.715851 |
| chinese | 0.229475 |
| japanese | 0.029763 |
| korean | 0.017277 |
| thai | 0.007634 |
✅ Können Sie erklären, warum das Modell ziemlich sicher ist, dass es sich um indische Küche handelt?
-
Erhalten Sie weitere Details, indem Sie einen Klassifikationsbericht ausdrucken, wie Sie es in den Regressionslektionen getan haben:
python y_pred = model.predict(X_test) print(classification_report(y_test,y_pred))precision recall f1-score support chinese 0.73 0.71 0.72 229 indian 0.91 0.93 0.92 254 japanese 0.70 0.75 0.72 220 korean 0.86 0.76 0.81 242 thai 0.79 0.85 0.82 254 accuracy 0.80 1199 macro avg 0.80 0.80 0.80 1199 weighted avg 0.80 0.80 0.80 1199
🚀Herausforderung
In dieser Lektion haben Sie Ihre bereinigten Daten verwendet, um ein Machine-Learning-Modell zu erstellen, das basierend auf einer Reihe von Zutaten eine nationale Küche vorhersagen kann. Nehmen Sie sich Zeit, um die vielen Optionen, die Scikit-learn zur Klassifizierung von Daten bietet, zu lesen. Vertiefen Sie sich in das Konzept des 'solvers', um zu verstehen, was hinter den Kulissen passiert.
Post-Lecture Quiz
Rückblick & Selbststudium
Vertiefen Sie sich ein wenig mehr in die Mathematik hinter der logistischen Regression in dieser Lektion
Aufgabe
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir auf Genauigkeit achten, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache ist als maßgebliche Quelle zu betrachten. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Klassifikationsmodelle erstellen
import pandas as pd
cuisines_df = pd.read_csv("../../data/cleaned_cuisines.csv")
cuisines_df.head()
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import accuracy_score,precision_score,confusion_matrix,classification_report, precision_recall_curve
from sklearn.svm import SVC
import numpy as np
cuisines_label_df = cuisines_df['cuisine']
cuisines_label_df.head()
cuisines_feature_df = cuisines_df.drop(['Unnamed: 0', 'cuisine'], axis=1)
cuisines_feature_df.head()
X_train, X_test, y_train, y_test = train_test_split(cuisines_feature_df, cuisines_label_df, test_size=0.3)
lr = LogisticRegression(multi_class='ovr',solver='liblinear')
model = lr.fit(X_train, np.ravel(y_train))
accuracy = model.score(X_test, y_test)
print ("Accuracy is {}".format(accuracy))
# test an item
print(f'ingredients: {X_test.iloc[50][X_test.iloc[50]!=0].keys()}')
print(f'cuisine: {y_test.iloc[50]}')
#rehsape to 2d array and transpose
test= X_test.iloc[50].values.reshape(-1, 1).T
# predict with score
proba = model.predict_proba(test)
classes = model.classes_
# create df with classes and scores
resultdf = pd.DataFrame(data=proba, columns=classes)
# create df to show results
topPrediction = resultdf.T.sort_values(by=[0], ascending = [False])
topPrediction.head()
y_pred = model.predict(X_test)
print(classification_report(y_test,y_pred))
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Erstellen Sie ein Klassifikationsmodell: Köstliche asiatische und indische Küchen
Küchenklassifikatoren 1
In dieser Lektion werden wir eine Vielzahl von Klassifikatoren erkunden, um eine nationale Küche basierend auf einer Gruppe von Zutaten vorherzusagen. Dabei lernen wir mehr über einige der Möglichkeiten, wie Algorithmen für Klassifikationsaufgaben eingesetzt werden können.
Quiz vor der Vorlesung
Vorbereitung
Diese Lektion baut auf unserer vorherigen Lektion auf, in der wir:
-
Eine sanfte Einführung in Klassifikationen anhand eines Datensatzes über die großartigen Küchen Asiens und Indiens 😋 gemacht haben.
-
Einige dplyr-Verben erkundet haben, um unsere Daten vorzubereiten und zu bereinigen.
-
Wunderschöne Visualisierungen mit ggplot2 erstellt haben.
-
Demonstriert haben, wie man mit unausgewogenen Daten umgeht, indem man sie mit recipes vorverarbeitet.
-
Gezeigt haben, wie man unser Rezept
prepundbake, um sicherzustellen, dass es wie vorgesehen funktioniert.
Voraussetzungen
Für diese Lektion benötigen wir die folgenden Pakete, um unsere Daten zu bereinigen, vorzubereiten und zu visualisieren:
-
tidyverse: Das tidyverse ist eine Sammlung von R-Paketen, die darauf abzielt, Datenwissenschaft schneller, einfacher und unterhaltsamer zu machen! -
tidymodels: Das tidymodels Framework ist eine Sammlung von Paketen für Modellierung und maschinelles Lernen. -
themis: Das themis-Paket bietet zusätzliche Rezeptschritte für den Umgang mit unausgewogenen Daten. -
nnet: Das nnet-Paket bietet Funktionen zur Schätzung von Feedforward-Neuronalen Netzen mit einer einzigen versteckten Schicht sowie für multinomiale logistische Regressionsmodelle.
Sie können diese Pakete wie folgt installieren:
install.packages(c("tidyverse", "tidymodels", "DataExplorer", "here"))
Alternativ überprüft das folgende Skript, ob die für dieses Modul benötigten Pakete vorhanden sind, und installiert sie für Sie, falls sie fehlen.
suppressWarnings(if (!require("pacman"))install.packages("pacman"))
pacman::p_load(tidyverse, tidymodels, themis, here)
Jetzt legen wir los!
1. Teile die Daten in Trainings- und Testdatensätze auf.
Wir beginnen mit ein paar Schritten aus unserer vorherigen Lektion.
Entferne die häufigsten Zutaten, die Verwirrung zwischen verschiedenen Küchenstilen stiften, mit dplyr::select().
Jeder liebt Reis, Knoblauch und Ingwer!
# Load the original cuisines data
df <- read_csv(file = "https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/4-Classification/data/cuisines.csv")
# Drop id column, rice, garlic and ginger from our original data set
df_select <- df %>%
select(-c(1, rice, garlic, ginger)) %>%
# Encode cuisine column as categorical
mutate(cuisine = factor(cuisine))
# Display new data set
df_select %>%
slice_head(n = 5)
# Display distribution of cuisines
df_select %>%
count(cuisine) %>%
arrange(desc(n))
Perfekt! Jetzt teilen wir die Daten so auf, dass 70 % der Daten für das Training und 30 % für das Testen verwendet werden. Dabei wenden wir eine Stratifizierung an, um das Verhältnis der einzelnen Küchenarten in den Trainings- und Validierungsdatensätzen beizubehalten.
rsample, ein Paket in Tidymodels, bietet eine Infrastruktur für effizientes Aufteilen und Resampling von Daten:
# Load the core Tidymodels packages into R session
library(tidymodels)
# Create split specification
set.seed(2056)
cuisines_split <- initial_split(data = df_select,
strata = cuisine,
prop = 0.7)
# Extract the data in each split
cuisines_train <- training(cuisines_split)
cuisines_test <- testing(cuisines_split)
# Print the number of cases in each split
cat("Training cases: ", nrow(cuisines_train), "\n",
"Test cases: ", nrow(cuisines_test), sep = "")
# Display the first few rows of the training set
cuisines_train %>%
slice_head(n = 5)
# Display distribution of cuisines in the training set
cuisines_train %>%
count(cuisine) %>%
arrange(desc(n))
2. Umgang mit unausgewogenen Daten
Wie Sie vielleicht im ursprünglichen Datensatz sowie in unserem Trainingssatz bemerkt haben, gibt es eine ziemlich ungleiche Verteilung der Anzahl der Küchen. Koreanische Küchen sind fast dreimal so häufig wie thailändische Küchen. Unaussgewogene Daten haben oft negative Auswirkungen auf die Modellleistung. Viele Modelle funktionieren am besten, wenn die Anzahl der Beobachtungen gleich ist, und haben daher Schwierigkeiten mit unausgewogenen Daten.
Es gibt hauptsächlich zwei Möglichkeiten, mit unausgewogenen Datensätzen umzugehen:
-
Hinzufügen von Beobachtungen zur Minderheitsklasse:
Over-Sampling, z. B. mit einem SMOTE-Algorithmus, der synthetisch neue Beispiele der Minderheitsklasse anhand der nächsten Nachbarn dieser Fälle generiert. -
Entfernen von Beobachtungen aus der Mehrheitsklasse:
Under-Sampling
In unserer vorherigen Lektion haben wir demonstriert, wie man mit unausgewogenen Datensätzen mithilfe eines recipe umgehen kann. Ein Rezept kann als eine Art Blaupause betrachtet werden, die beschreibt, welche Schritte auf einen Datensatz angewendet werden sollten, um ihn für die Datenanalyse vorzubereiten. In unserem Fall möchten wir eine gleichmäßige Verteilung der Anzahl unserer Küchen für unseren training set erreichen. Lassen Sie uns direkt loslegen.
# Load themis package for dealing with imbalanced data
library(themis)
# Create a recipe for preprocessing training data
cuisines_recipe <- recipe(cuisine ~ ., data = cuisines_train) %>%
step_smote(cuisine)
# Print recipe
cuisines_recipe
Du kannst natürlich bestätigen (mithilfe von prep+bake), dass das Rezept wie erwartet funktioniert – alle Küchenlabels haben 559 Beobachtungen.
Da wir dieses Rezept als Vorverarbeitung für das Modellieren verwenden werden, übernimmt ein workflow() den gesamten Vorbereitungs- und Backprozess für uns, sodass wir das Rezept nicht manuell schätzen müssen.
Jetzt sind wir bereit, ein Modell zu trainieren 👩💻👨💻!
3. Auswahl des Klassifikators
<p > <img src="../../images/parsnip.jpg" width="600"/> <figcaption>Kunstwerk von @allison_horst</figcaption>
Jetzt müssen wir entscheiden, welchen Algorithmus wir für die Aufgabe verwenden 🤔.
In Tidymodels bietet das parsnip package eine einheitliche Schnittstelle für die Arbeit mit Modellen über verschiedene Engines (Pakete) hinweg. Bitte sehen Sie sich die parsnip-Dokumentation an, um Modelltypen und Engines sowie deren entsprechende Modellargumente zu erkunden. Die Vielfalt kann auf den ersten Blick ziemlich überwältigend sein. Zum Beispiel umfassen die folgenden Methoden alle Klassifikationstechniken:
-
C5.0 Regelbasierte Klassifikationsmodelle
-
Flexible Diskriminanzmodelle
-
Lineare Diskriminanzmodelle
-
Regularisierte Diskriminanzmodelle
-
Logistische Regressionsmodelle
-
Multinomiale Regressionsmodelle
-
Naive Bayes Modelle
-
Support Vector Machines
-
Nächste Nachbarn
-
Entscheidungsbäume
-
Ensemble-Methoden
-
Neuronale Netze
Die Liste geht weiter!
Welchen Klassifikator wählen?
Welchen Klassifikator sollten Sie also wählen? Oft ist es eine gute Methode, mehrere auszuprobieren und nach einem guten Ergebnis zu suchen.
> AutoML löst dieses Problem elegant, indem es diese Vergleiche in der Cloud durchführt und Ihnen ermöglicht, den besten Algorithmus für Ihre Daten auszuwählen. Probieren Sie es hier aus.
Die Wahl des Klassifikators hängt auch von unserem Problem ab. Wenn das Ergebnis beispielsweise in mehr als zwei Klassen kategorisiert werden kann, wie in unserem Fall, müssen Sie einen Multiklassen-Klassifikationsalgorithmus anstelle eines binären Klassifikationsalgorithmus verwenden.
Ein besserer Ansatz
Ein besserer Ansatz als wildes Raten ist jedoch, die Ideen auf diesem herunterladbaren ML Cheat Sheet zu verfolgen. Hier entdecken wir, dass wir für unser Multiklassenproblem einige Optionen haben:
<p > <img src="../../images/cheatsheet.png" width="500"/> <figcaption>Ein Abschnitt des Algorithmus-Cheat Sheets von Microsoft, der Multiklassen-Klassifikationsoptionen beschreibt</figcaption>
Überlegungen
Schauen wir uns verschiedene Ansätze an, die wir unter den gegebenen Einschränkungen verfolgen können:
-
Tiefe neuronale Netze sind zu aufwendig. Angesichts unseres sauberen, aber minimalen Datensatzes und der Tatsache, dass wir das Training lokal über Notebooks durchführen, sind tiefe neuronale Netze für diese Aufgabe zu schwergewichtig.
-
Kein Zwei-Klassen-Klassifikator. Wir verwenden keinen Zwei-Klassen-Klassifikator, daher scheidet ein One-vs-All-Ansatz aus.
-
Entscheidungsbaum oder logistische Regression könnten funktionieren. Ein Entscheidungsbaum könnte geeignet sein, oder auch eine multinomiale Regression/multiklassige logistische Regression für Daten mit mehreren Klassen.
-
Multiklassige Boosted Decision Trees lösen ein anderes Problem. Der multiklassige Boosted Decision Tree eignet sich am besten für nichtparametrische Aufgaben, z. B. Aufgaben zur Erstellung von Rankings, und ist daher für uns nicht nützlich.
Generell ist es eine gute Idee, vor der Anwendung komplexerer Machine-Learning-Modelle wie Ensemble-Methoden zunächst das einfachste Modell zu erstellen, um ein grundlegendes Verständnis für die Daten zu bekommen. Daher beginnen wir in dieser Lektion mit einem multinomial regression-Modell.
> Logistische Regression ist eine Technik, die verwendet wird, wenn die Zielvariable kategorisch (oder nominal) ist. Bei der binären logistischen Regression gibt es zwei Zielvariablen, während es bei der multinomialen logistischen Regression mehr als zwei Zielvariablen gibt. Weitere Informationen finden Sie unter Advanced Regression Methods.
4. Ein multinomiales logistische Regressionsmodell trainieren und evaluieren
In Tidymodels definiert parsnip::multinom_reg() ein Modell, das lineare Prädiktoren verwendet, um Multiklass-Daten mithilfe der multinomialen Verteilung vorherzusagen. Siehe ?multinom_reg() für die verschiedenen Möglichkeiten/Engines, mit denen Sie dieses Modell anpassen können.
In diesem Beispiel passen wir ein multinomiales Regressionsmodell über die Standard-Engine nnet an.
> Ich habe den Wert für penalty mehr oder weniger zufällig gewählt. Es gibt bessere Methoden, diesen Wert zu bestimmen, z. B. durch Resampling und Tuning des Modells, was wir später besprechen werden.
>
> Siehe Tidymodels: Get Started, falls Sie mehr darüber erfahren möchten, wie man Modell-Hyperparameter optimiert.
# Create a multinomial regression model specification
mr_spec <- multinom_reg(penalty = 1) %>%
set_engine("nnet", MaxNWts = 2086) %>%
set_mode("classification")
# Print model specification
mr_spec
Großartige Arbeit 🥳! Jetzt, da wir ein Rezept und eine Modellspezifikation haben, müssen wir eine Möglichkeit finden, diese zusammen in ein Objekt zu bündeln, das zuerst die Daten vorverarbeitet, dann das Modell auf den vorverarbeiteten Daten anpasst und auch potenzielle Nachbearbeitungsaktivitäten ermöglicht. In Tidymodels wird dieses praktische Objekt workflow genannt und hält bequem deine Modellierungskomponenten! Das ist das, was wir in Python als Pipelines bezeichnen würden.
Also, lass uns alles in einen Workflow bündeln!📦
# Bundle recipe and model specification
mr_wf <- workflow() %>%
add_recipe(cuisines_recipe) %>%
add_model(mr_spec)
# Print out workflow
mr_wf
Workflows 👌👌! Ein workflow() kann auf ähnliche Weise angepasst werden wie ein Modell. Also, Zeit, ein Modell zu trainieren!
# Train a multinomial regression model
mr_fit <- fit(object = mr_wf, data = cuisines_train)
mr_fit
Die Ausgabe zeigt die Koeffizienten, die das Modell während des Trainings gelernt hat.
Das trainierte Modell bewerten
Es ist an der Zeit, die Leistung des Modells 📏 zu überprüfen, indem wir es mit einem Testdatensatz evaluieren! Beginnen wir damit, Vorhersagen für den Testdatensatz zu erstellen.
# Make predictions on the test set
results <- cuisines_test %>% select(cuisine) %>%
bind_cols(mr_fit %>% predict(new_data = cuisines_test))
# Print out results
results %>%
slice_head(n = 5)
Großartige Arbeit! In Tidymodels kann die Bewertung der Modellleistung mit yardstick durchgeführt werden – einem Paket, das verwendet wird, um die Effektivität von Modellen anhand von Leistungsmetriken zu messen. Wie wir es in unserer Lektion zur logistischen Regression gemacht haben, beginnen wir mit der Berechnung einer Konfusionsmatrix.
# Confusion matrix for categorical data
conf_mat(data = results, truth = cuisine, estimate = .pred_class)
Wenn man mit mehreren Klassen arbeitet, ist es in der Regel intuitiver, dies als Heatmap zu visualisieren, wie hier:
update_geom_defaults(geom = "tile", new = list(color = "black", alpha = 0.7))
# Visualize confusion matrix
results %>%
conf_mat(cuisine, .pred_class) %>%
autoplot(type = "heatmap")
Die dunkleren Felder in der Konfusionsmatrix zeigen eine hohe Anzahl von Fällen an, und idealerweise sehen Sie eine diagonale Linie aus dunkleren Feldern, die Fälle markieren, bei denen die vorhergesagte und die tatsächliche Kategorie übereinstimmen.
Lassen Sie uns nun zusammenfassende Statistiken für die Konfusionsmatrix berechnen.
# Summary stats for confusion matrix
conf_mat(data = results, truth = cuisine, estimate = .pred_class) %>%
summary()
Wenn wir uns auf einige Metriken wie Genauigkeit, Sensitivität und PPV konzentrieren, ist das für den Anfang gar nicht so schlecht 🥳!
4. Tiefer eintauchen
Stellen wir uns eine subtile Frage: Nach welchen Kriterien wird eine bestimmte Art von Küche als vorhergesagtes Ergebnis ausgewählt?
Nun, statistische Machine-Learning-Algorithmen, wie die logistische Regression, basieren auf Wahrscheinlichkeit. Das bedeutet, dass ein Klassifikator tatsächlich eine Wahrscheinlichkeitsverteilung über eine Menge möglicher Ergebnisse vorhersagt. Die Klasse mit der höchsten Wahrscheinlichkeit wird dann als das wahrscheinlichste Ergebnis für die gegebenen Beobachtungen ausgewählt.
Schauen wir uns das in der Praxis an, indem wir sowohl harte Klassenentscheidungen als auch Wahrscheinlichkeiten betrachten.
# Make hard class prediction and probabilities
results_prob <- cuisines_test %>%
select(cuisine) %>%
bind_cols(mr_fit %>% predict(new_data = cuisines_test)) %>%
bind_cols(mr_fit %>% predict(new_data = cuisines_test, type = "prob"))
# Print out results
results_prob %>%
slice_head(n = 5)
✅ Können Sie erklären, warum das Modell ziemlich sicher ist, dass die erste Beobachtung thailändisch ist?
🚀Herausforderung
In dieser Lektion haben Sie Ihre bereinigten Daten verwendet, um ein Machine-Learning-Modell zu erstellen, das anhand einer Reihe von Zutaten eine nationale Küche vorhersagen kann. Nehmen Sie sich etwas Zeit, um die vielen Optionen zu erkunden, die Tidymodels zur Klassifizierung von Daten bietet, sowie andere Möglichkeiten, um eine multinomiale Regression anzupassen.
EIN GROSSES DANKESCHÖN AN:
Allison Horst für die Erstellung der großartigen Illustrationen, die R einladender und ansprechender machen. Weitere Illustrationen finden Sie in ihrer Galerie.
Cassie Breviu und Jen Looper für die Erstellung der ursprünglichen Python-Version dieses Moduls ♥️
<br> Hätte gerne ein paar Witze eingebaut, aber ich verstehe keine Food-Wortspiele 😅.
<br>
Viel Spaß beim Lernen,
Eric, Gold Microsoft Learn Student Ambassador.
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Parameter-Spiel
Anweisungen
Es gibt viele Parameter, die standardmäßig festgelegt sind, wenn man mit diesen Klassifikatoren arbeitet. Intellisense in VS Code kann dir helfen, sie genauer zu untersuchen. Wähle eine der ML-Klassifikationstechniken aus dieser Lektion und trainiere die Modelle erneut, indem du verschiedene Parameterwerte anpasst. Erstelle ein Notebook, in dem du erklärst, warum einige Änderungen die Modellqualität verbessern, während andere sie verschlechtern. Sei in deiner Antwort detailliert.
Bewertungskriterien
| Kriterien | Hervorragend | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Notebook wird präsentiert, das einen vollständig aufgebauten Klassifikator enthält, dessen Parameter angepasst und Änderungen in Textfeldern erklärt werden | Ein Notebook wird teilweise präsentiert oder schlecht erklärt | Ein Notebook ist fehlerhaft oder unvollständig |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Klassifikationsmodell erstellen
import pandas as pd
cuisines_df = pd.read_csv("../data/cleaned_cuisines.csv")
cuisines_df.head()
cuisines_label_df = cuisines_df['cuisine']
cuisines_label_df.head()
cuisines_features_df = cuisines_df.drop(['Unnamed: 0', 'cuisine'], axis=1)
cuisines_features_df.head()
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, bitten wir zu beachten, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache ist als maßgebliche Quelle zu betrachten. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Verwendung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Cuisine classifiers 2
In dieser zweiten Klassifikationslektion werden Sie weitere Möglichkeiten zur Klassifikation numerischer Daten erkunden. Außerdem erfahren Sie die Auswirkungen der Wahl eines Klassifikators gegenüber einem anderen.
Pre-lecture quiz
Voraussetzung
Wir gehen davon aus, dass Sie die vorherigen Lektionen abgeschlossen haben und einen bereinigten Datensatz in Ihrem data-Ordner mit dem Namen cleaned_cuisines.csv im Stammverzeichnis dieses 4-Lektionen-Ordners haben.
Vorbereitung
Wir haben Ihre notebook.ipynb-Datei mit dem bereinigten Datensatz geladen und in X- und y-Datenrahmen aufgeteilt, bereit für den Modellierungsprozess.
Eine Klassifikationskarte
Zuvor haben Sie die verschiedenen Optionen kennengelernt, die Sie bei der Klassifikation von Daten anhand des Cheat Sheets von Microsoft haben. Scikit-learn bietet ein ähnliches, aber detaillierteres Cheat Sheet, das Ihnen dabei helfen kann, Ihre Schätzer (ein anderer Begriff für Klassifikatoren) weiter einzugrenzen:
> Tipp: besuchen Sie diese Karte online und klicken Sie dem Pfad entlang, um die Dokumentation zu lesen.
Der Plan
Diese Karte ist sehr hilfreich, sobald Sie ein klares Verständnis Ihrer Daten haben, da Sie den Pfaden zu einer Entscheidung folgen können:
- Wir haben >50 Stichproben
- Wir wollen eine Kategorie vorhersagen
- Wir haben gelabelte Daten
- Wir haben weniger als 100.000 Stichproben
- ✨ Wir können einen Linear SVC wählen
- Falls das nicht funktioniert, da wir numerische Daten haben
- Können wir einen ✨ KNeighbors Classifier ausprobieren
- Wenn das nicht funktioniert, versuchen Sie ✨ SVC und ✨ Ensemble Classifier
Dies ist eine sehr hilfreiche Vorgehensweise.
Übung - Daten aufteilen
Folgen wir diesem Pfad, sollten wir zunächst einige Bibliotheken zum Verwenden importieren.
-
Importieren Sie die benötigten Bibliotheken:
python from sklearn.neighbors import KNeighborsClassifier from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier from sklearn.model_selection import train_test_split, cross_val_score from sklearn.metrics import accuracy_score,precision_score,confusion_matrix,classification_report, precision_recall_curve import numpy as np -
Teilen Sie Ihre Trainings- und Testdaten auf:
python X_train, X_test, y_train, y_test = train_test_split(cuisines_features_df, cuisines_label_df, test_size=0.3)
Linear SVC Klassifikator
Support-Vektor-Clustering (SVC) ist ein Teil der Familie der Support-Vektor-Maschinen (lernen Sie unten mehr über diese kennen). Bei dieser Methode können Sie einen „Kernel“ auswählen, um zu entscheiden, wie die Labels gruppiert werden. Der Parameter „C“ bezieht sich auf „Regularisierung“, also die Regulierung des Einflusses von Parametern. Der Kernel kann einer von mehreren sein; hier setzen wir ihn auf „linear“, um linear SVC zu verwenden. Die Wahrscheinlichkeit ist standardmäßig „false“; hier setzen wir sie auf „true“, um Wahrscheinlichkeitsabschätzungen zu erhalten. Wir setzen den Zufallszustand auf „0“, um die Daten zu mischen und Wahrscheinlichkeiten zu ermitteln.
Übung - Anwenden eines Linear SVC
Beginnen Sie damit, ein Array von Klassifikatoren zu erstellen. Sie werden dieses Array nach und nach erweitern, während wir testen.
-
Beginnen Sie mit einem Linear SVC:
```python C = 10
Erstellen Sie verschiedene Klassifikatoren.
classifiers = { 'Linear SVC': SVC(kernel='linear', C=C, probability=True,random_state=0) } ```
-
Trainieren Sie Ihr Modell mit dem Linear SVC und geben Sie einen Bericht aus:
```python n_classifiers = len(classifiers)
for index, (name, classifier) in enumerate(classifiers.items()): classifier.fit(X_train, np.ravel(y_train))
y_pred = classifier.predict(X_test) accuracy = accuracy_score(y_test, y_pred) print("Accuracy (train) for %s: %0.1f%% " % (name, accuracy * 100)) print(classification_report(y_test,y_pred))```
Das Ergebnis ist recht gut:
```output Accuracy (train) for Linear SVC: 78.6% precision recall f1-score support
chinese 0.71 0.67 0.69 242 indian 0.88 0.86 0.87 234 japanese 0.79 0.74 0.76 254 korean 0.85 0.81 0.83 242 thai 0.71 0.86 0.78 227 accuracy 0.79 1199macro avg 0.79 0.79 0.79 1199 weighted avg 0.79 0.79 0.79 1199 ```
K-Neighbors Klassifikator
K-Neighbors gehört zur Familie der „Nachbarn“-ML-Methoden, die für überwachtes und unüberwachtes Lernen eingesetzt werden können. Bei dieser Methode wird eine vordefinierte Anzahl an Punkten erstellt, und die Daten werden um diese Punkte gruppiert, sodass verallgemeinerte Labels für die Daten vorhergesagt werden können.
Übung - Anwenden des K-Neighbors Klassifikators
Der vorherige Klassifikator war gut und funktionierte gut mit den Daten, aber vielleicht können wir eine bessere Genauigkeit erreichen. Versuchen Sie einen K-Neighbors Klassifikator.
-
Fügen Sie Ihrem Klassifikator-Array eine Linie hinzu (setzen Sie ein Komma nach dem Linear SVC-Element):
python 'KNN classifier': KNeighborsClassifier(C),Das Ergebnis ist etwas schlechter:
```output Accuracy (train) for KNN classifier: 73.8% precision recall f1-score support
chinese 0.64 0.67 0.66 242 indian 0.86 0.78 0.82 234 japanese 0.66 0.83 0.74 254 korean 0.94 0.58 0.72 242 thai 0.71 0.82 0.76 227 accuracy 0.74 1199macro avg 0.76 0.74 0.74 1199 weighted avg 0.76 0.74 0.74 1199 ```
✅ Lernen Sie mehr über K-Neighbors
Support Vector Classifier
Support-Vektor-Klassifikatoren sind Teil der Familie der Support-Vektor-Maschinen, die für Klassifikations- und Regressionsaufgaben eingesetzt werden. SVMs „bilden Trainingsbeispiele als Punkte im Raum ab“, um den Abstand zwischen zwei Kategorien zu maximieren. Nachfolgende Daten werden in diesen Raum abgebildet, sodass ihre Kategorie vorhergesagt werden kann.
Übung - Anwenden eines Support Vector Classifier
Versuchen wir eine etwas bessere Genauigkeit mit einem Support Vector Classifier.
-
Fügen Sie nach dem K-Neighbors-Element ein Komma ein und dann diese Zeile:
python 'SVC': SVC(),Das Ergebnis ist ziemlich gut!
```output Accuracy (train) for SVC: 83.2% precision recall f1-score support
chinese 0.79 0.74 0.76 242 indian 0.88 0.90 0.89 234 japanese 0.87 0.81 0.84 254 korean 0.91 0.82 0.86 242 thai 0.74 0.90 0.81 227 accuracy 0.83 1199macro avg 0.84 0.83 0.83 1199 weighted avg 0.84 0.83 0.83 1199 ```
✅ Lernen Sie mehr über Support-Vektoren
Ensemble-Klassifikatoren
Folgen wir dem Pfad bis zum Ende, obwohl der vorherige Test recht gut war. Versuchen wir einige „Ensemble-Klassifikatoren“, speziell Random Forest und AdaBoost:
'RFST': RandomForestClassifier(n_estimators=100),
'ADA': AdaBoostClassifier(n_estimators=100)
Das Ergebnis ist sehr gut, besonders für Random Forest:
Accuracy (train) for RFST: 84.5%
precision recall f1-score support
chinese 0.80 0.77 0.78 242
indian 0.89 0.92 0.90 234
japanese 0.86 0.84 0.85 254
korean 0.88 0.83 0.85 242
thai 0.80 0.87 0.83 227
accuracy 0.84 1199
macro avg 0.85 0.85 0.84 1199
weighted avg 0.85 0.84 0.84 1199
Accuracy (train) for ADA: 72.4%
precision recall f1-score support
chinese 0.64 0.49 0.56 242
indian 0.91 0.83 0.87 234
japanese 0.68 0.69 0.69 254
korean 0.73 0.79 0.76 242
thai 0.67 0.83 0.74 227
accuracy 0.72 1199
macro avg 0.73 0.73 0.72 1199
weighted avg 0.73 0.72 0.72 1199
✅ Lernen Sie mehr über Ensemble-Klassifikatoren
Diese Methode des Maschinellen Lernens „kombiniert die Vorhersagen mehrerer Basis-Schätzer“, um die Qualität des Modells zu verbessern. In unserem Beispiel verwendeten wir Random Trees und AdaBoost.
-
Random Forest, eine Mittelungsmethode, baut einen „Wald“ aus „Entscheidungsbäumen“, der mit Zufälligkeit versehen ist, um Overfitting zu vermeiden. Der Parameter n_estimators wird auf die Anzahl der Bäume gesetzt.
-
AdaBoost passt einen Klassifikator an einen Datensatz an und passt dann Kopien dieses Klassifikators an denselben Datensatz an. Es fokussiert sich auf die Gewichte falsch klassifizierter Elemente und passt die Gewichtung für den nächsten Klassifikator an, um Fehler zu korrigieren.
🚀Herausforderung
Jede dieser Techniken hat eine große Anzahl von Parametern, die Sie anpassen können. Recherchieren Sie die Standardparameter jedes Verfahrens und denken Sie darüber nach, was die Anpassung dieser Parameter für die Qualität des Modells bedeuten würde.
Post-lecture quiz
Rückblick & Selbststudium
In diesen Lektionen gibt es viele Fachbegriffe, nehmen Sie sich also eine Minute, um diese Liste mit nützlichen Begriffen durchzugehen!
Aufgabe
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache ist als maßgebliche Quelle zu betrachten. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Weitere Klassifikationsmodelle erstellen
Übersicht über den Datensatz
Dieser Datensatz enthält einzelne Proben (zum Beispiel Rezepte), die nach Küchenart gekennzeichnet sind.
Jede Zeile entspricht einer einzelnen Probe/einem Datensatz, und die Spalten repräsentieren Zutaten oder andere Attribute, die für die Klassifizierung verwendet werden, einschließlich des Labels cuisine.
import pandas as pd
# Load dataset containing cuisine features
cuisines_df = pd.read_csv("../../data/cleaned_cuisines.csv")
cuisines_df.head()
cuisines_label_df = cuisines_df['cuisine']
cuisines_label_df.head()
cuisines_features_df = cuisines_df.drop(['Unnamed: 0', 'cuisine'], axis=1)
cuisines_features_df.head()
Verschiedene Klassifikatoren ausprobieren
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import accuracy_score,precision_score,confusion_matrix,classification_report, precision_recall_curve
import numpy as np
X_train, X_test, y_train, y_test = train_test_split(cuisines_features_df, cuisines_label_df, test_size=0.3)
C = 10
# Create different classifiers.
classifiers = {
'Linear SVC': SVC(kernel='linear', C=C, probability=True,random_state=0),
'KNN classifier': KNeighborsClassifier(C),
'SVC': SVC(),
'RFST': RandomForestClassifier(n_estimators=100),
'ADA': AdaBoostClassifier(n_estimators=100)
}
n_classifiers = len(classifiers)
for index, (name, classifier) in enumerate(classifiers.items()):
classifier.fit(X_train, np.ravel(y_train))
y_pred = classifier.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy (train) for %s: %0.1f%% " % (name, accuracy * 100))
print(classification_report(y_test,y_pred))
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Zwar bemühen wir uns um Genauigkeit, bitte beachten Sie jedoch, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache ist als maßgebliche Quelle zu betrachten. Für wichtige Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Erstellen Sie ein Klassifikationsmodell: Köstliche asiatische und indische Küchen
Küchenklassifikatoren 2
In dieser zweiten Lektion zur Klassifikation werden wir weitere Möglichkeiten zur Klassifikation von kategorialen Daten erkunden. Außerdem werden wir die Auswirkungen der Wahl eines Klassifikators gegenüber einem anderen kennenlernen.
Quiz vor der Vorlesung
Voraussetzungen
Wir gehen davon aus, dass Sie die vorherigen Lektionen abgeschlossen haben, da wir einige zuvor erlernte Konzepte weiterführen werden.
Für diese Lektion benötigen wir die folgenden Pakete:
-
tidyverse: Das tidyverse ist eine Sammlung von R-Paketen, die darauf abzielt, Datenwissenschaft schneller, einfacher und unterhaltsamer zu machen! -
tidymodels: Das tidymodels Framework ist eine Sammlung von Paketen für Modellierung und maschinelles Lernen. -
themis: Das themis-Paket bietet zusätzliche Rezeptschritte für den Umgang mit unausgewogenen Daten.
Sie können diese Pakete wie folgt installieren:
install.packages(c("tidyverse", "tidymodels", "kernlab", "themis", "ranger", "xgboost", "kknn"))
Alternativ überprüft das untenstehende Skript, ob Sie die für dieses Modul benötigten Pakete installiert haben, und installiert sie für Sie, falls sie fehlen.
suppressWarnings(if (!require("pacman"))install.packages("pacman"))
pacman::p_load(tidyverse, tidymodels, themis, kernlab, ranger, xgboost, kknn)
1. Eine Klassifikationsübersicht
In unserer vorherigen Lektion haben wir versucht, die Frage zu beantworten: Wie wählt man zwischen mehreren Modellen aus? In hohem Maße hängt dies von den Eigenschaften der Daten und der Art des Problems ab, das wir lösen möchten (zum Beispiel Klassifikation oder Regression?).
Zuvor haben wir die verschiedenen Möglichkeiten kennengelernt, die Ihnen zur Verfügung stehen, wenn Sie Daten mithilfe von Microsofts Spickzettel klassifizieren. Das Machine-Learning-Framework von Python, Scikit-learn, bietet einen ähnlichen, aber detaillierteren Spickzettel, der Ihnen dabei helfen kann, Ihre Auswahl an Schätzern (ein anderer Begriff für Klassifikatoren) weiter einzugrenzen:
<p > <img src="../../images/map.png" width="700"/> <figcaption></figcaption>
> Tipp: Besuchen Sie diese Karte online und klicken Sie entlang des Pfads, um die Dokumentation zu lesen. > > Die Tidymodels-Referenzseite bietet ebenfalls eine hervorragende Dokumentation über verschiedene Modelltypen.
Der Plan 🗺️
Diese Karte ist sehr hilfreich, sobald Sie ein klares Verständnis Ihrer Daten haben, da Sie entlang ihrer Pfade zu einer Entscheidung „gehen“ können:
-
Wir haben \>50 Proben
-
Wir möchten eine Kategorie vorhersagen
-
Wir haben beschriftete Daten
-
Wir haben weniger als 100.000 Proben
-
✨ Wir können einen Linear SVC wählen
-
Wenn das nicht funktioniert, da wir numerische Daten haben
-
Können wir einen ✨ KNeighbors Classifier ausprobieren
- Wenn das nicht funktioniert, probieren Sie ✨ SVC und ✨ Ensemble Classifiers
-
Dies ist ein sehr hilfreicher Pfad, dem man folgen kann. Jetzt legen wir direkt los und nutzen das tidymodels Modellierungs-Framework: eine konsistente und flexible Sammlung von R-Paketen, die entwickelt wurden, um gute statistische Praktiken zu fördern 😊.
2. Daten aufteilen und mit unausgewogenen Datensätzen umgehen.
Aus unseren vorherigen Lektionen haben wir gelernt, dass es eine Reihe von gemeinsamen Zutaten in unseren Küchen gab. Außerdem gab es eine ziemlich ungleiche Verteilung in der Anzahl der Küchen.
Wir werden damit umgehen, indem wir:
-
Die häufigsten Zutaten, die Verwirrung zwischen verschiedenen Küchen schaffen, mit
dplyr::select()entfernen. -
Ein
recipeverwenden, das die Daten vorverarbeitet, um sie für die Modellierung vorzubereiten, indem einover-sampling-Algorithmus angewendet wird.
Wir haben das oben bereits in der vorherigen Lektion behandelt, daher sollte das ein Kinderspiel sein 🥳!
# Load the core Tidyverse and Tidymodels packages
library(tidyverse)
library(tidymodels)
# Load the original cuisines data
df <- read_csv(file = "https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/4-Classification/data/cuisines.csv")
# Drop id column, rice, garlic and ginger from our original data set
df_select <- df %>%
select(-c(1, rice, garlic, ginger)) %>%
# Encode cuisine column as categorical
mutate(cuisine = factor(cuisine))
# Create data split specification
set.seed(2056)
cuisines_split <- initial_split(data = df_select,
strata = cuisine,
prop = 0.7)
# Extract the data in each split
cuisines_train <- training(cuisines_split)
cuisines_test <- testing(cuisines_split)
# Display distribution of cuisines in the training set
cuisines_train %>%
count(cuisine) %>%
arrange(desc(n))
Umgang mit unausgeglichenen Daten
Unausgeglichene Daten haben oft negative Auswirkungen auf die Modellleistung. Viele Modelle erzielen die besten Ergebnisse, wenn die Anzahl der Beobachtungen gleich ist, und haben daher Schwierigkeiten mit unausgeglichenen Daten.
Es gibt im Wesentlichen zwei Ansätze, um mit unausgeglichenen Datensätzen umzugehen:
-
Hinzufügen von Beobachtungen zur Minderheitsklasse:
Over-sampling, z. B. mit einem SMOTE-Algorithmus, der synthetisch neue Beispiele der Minderheitsklasse generiert, indem er die nächsten Nachbarn dieser Fälle verwendet. -
Entfernen von Beobachtungen aus der Mehrheitsklasse:
Under-sampling
In unserer vorherigen Lektion haben wir demonstriert, wie man mit unausgeglichenen Datensätzen mithilfe eines recipe umgeht. Ein Recipe kann als eine Art Blaupause betrachtet werden, die beschreibt, welche Schritte auf einen Datensatz angewendet werden sollten, um ihn für die Datenanalyse vorzubereiten. In unserem Fall möchten wir eine gleichmäßige Verteilung der Anzahl unserer Küchenstile im training set erreichen. Legen wir los.
# Load themis package for dealing with imbalanced data
library(themis)
# Create a recipe for preprocessing training data
cuisines_recipe <- recipe(cuisine ~ ., data = cuisines_train) %>%
step_smote(cuisine)
# Print recipe
cuisines_recipe
Jetzt sind wir bereit, Modelle zu trainieren 👩💻👨💻!
3. Über multinomiale Regressionsmodelle hinaus
In unserer vorherigen Lektion haben wir uns mit multinomialen Regressionsmodellen beschäftigt. Lassen Sie uns einige flexiblere Modelle für die Klassifikation erkunden.
Support Vector Machines
Im Kontext der Klassifikation ist Support Vector Machines eine Technik des maschinellen Lernens, die versucht, eine Hyperebene zu finden, die die Klassen "optimal" trennt. Schauen wir uns ein einfaches Beispiel an:
<p > <img src="../../images/svm.png" width="300"/> <figcaption>https://commons.wikimedia.org/w/index.php?curid=22877598</figcaption>
H1~ trennt die Klassen nicht. H2~ trennt sie, aber nur mit einem kleinen Abstand. H3~ trennt sie mit dem maximalen Abstand.
Linearer Support-Vector-Klassifikator
Support-Vector-Clustering (SVC) ist ein Mitglied der Familie der Support-Vector-Maschinen (SVM), einer Technik des maschinellen Lernens. Beim SVC wird die Hyperebene so gewählt, dass sie die meisten Trainingsbeobachtungen korrekt trennt, aber einige Beobachtungen möglicherweise falsch klassifiziert. Indem einige Punkte auf der falschen Seite erlaubt werden, wird die SVM robuster gegenüber Ausreißern und erzielt dadurch eine bessere Generalisierung auf neue Daten. Der Parameter, der diese Abweichung reguliert, wird als cost bezeichnet und hat standardmäßig den Wert 1 (siehe help("svm_poly")).
Lassen Sie uns einen linearen SVC erstellen, indem wir degree = 1 in einem polynomialen SVM-Modell setzen.
# Make a linear SVC specification
svc_linear_spec <- svm_poly(degree = 1) %>%
set_engine("kernlab") %>%
set_mode("classification")
# Bundle specification and recipe into a worklow
svc_linear_wf <- workflow() %>%
add_recipe(cuisines_recipe) %>%
add_model(svc_linear_spec)
# Print out workflow
svc_linear_wf
Nun, da wir die Vorverarbeitungsschritte und die Modellspezifikation in einem Workflow erfasst haben, können wir fortfahren, den linearen SVC zu trainieren und die Ergebnisse dabei auszuwerten. Für die Leistungskennzahlen erstellen wir ein Metrik-Set, das folgende Werte bewertet: accuracy, sensitivity, Positive Predicted Value und F Measure.
> augment() fügt der angegebenen Datenmenge Spalte(n) für Vorhersagen hinzu.
# Train a linear SVC model
svc_linear_fit <- svc_linear_wf %>%
fit(data = cuisines_train)
# Create a metric set
eval_metrics <- metric_set(ppv, sens, accuracy, f_meas)
# Make predictions and Evaluate model performance
svc_linear_fit %>%
augment(new_data = cuisines_test) %>%
eval_metrics(truth = cuisine, estimate = .pred_class)
Support Vector Machine
Die Support Vector Machine (SVM) ist eine Erweiterung des Support Vector Classifiers, um eine nicht-lineare Grenze zwischen den Klassen zu ermöglichen. Im Wesentlichen nutzen SVMs den Kernel-Trick, um den Merkmalsraum zu erweitern und sich an nichtlineare Beziehungen zwischen den Klassen anzupassen. Eine beliebte und äußerst flexible Kernel-Funktion, die von SVMs verwendet wird, ist die Radial Basis Function. Schauen wir uns an, wie sie sich auf unseren Daten schlägt.
set.seed(2056)
# Make an RBF SVM specification
svm_rbf_spec <- svm_rbf() %>%
set_engine("kernlab") %>%
set_mode("classification")
# Bundle specification and recipe into a worklow
svm_rbf_wf <- workflow() %>%
add_recipe(cuisines_recipe) %>%
add_model(svm_rbf_spec)
# Train an RBF model
svm_rbf_fit <- svm_rbf_wf %>%
fit(data = cuisines_train)
# Make predictions and Evaluate model performance
svm_rbf_fit %>%
augment(new_data = cuisines_test) %>%
eval_metrics(truth = cuisine, estimate = .pred_class)
Viel besser 🤩!
> ✅ Bitte siehe: > > - Support Vector Machines, Hands-on Machine Learning mit R > > - Support Vector Machines, Eine Einführung in Statistisches Lernen mit Anwendungen in R > > für weiterführende Lektüre.
Nächster-Nachbar-Klassifikatoren
Der k-nächste Nachbar (KNN) ist ein Algorithmus, bei dem jede Beobachtung basierend auf ihrer Ähnlichkeit zu anderen Beobachtungen vorhergesagt wird.
Lass uns einen auf unsere Daten anwenden.
# Make a KNN specification
knn_spec <- nearest_neighbor() %>%
set_engine("kknn") %>%
set_mode("classification")
# Bundle recipe and model specification into a workflow
knn_wf <- workflow() %>%
add_recipe(cuisines_recipe) %>%
add_model(knn_spec)
# Train a boosted tree model
knn_wf_fit <- knn_wf %>%
fit(data = cuisines_train)
# Make predictions and Evaluate model performance
knn_wf_fit %>%
augment(new_data = cuisines_test) %>%
eval_metrics(truth = cuisine, estimate = .pred_class)
Es scheint, dass dieses Modell nicht besonders gut abschneidet. Wahrscheinlich wird eine Anpassung der Modellparameter (siehe help("nearest_neighbor")) die Leistung verbessern. Probieren Sie es unbedingt aus.
> ✅ Weitere Informationen finden Sie unter: > > - Hands-on Machine Learning with R > > - An Introduction to Statistical Learning with Applications in R > > um mehr über K-Nearest Neighbors-Klassifikatoren zu erfahren.
Ensemble-Klassifikatoren
Ensemble-Algorithmen funktionieren, indem sie mehrere Basis-Estimatoren kombinieren, um ein optimales Modell zu erstellen, entweder durch:
bagging: Anwenden einer Mittelungsfunktion auf eine Sammlung von Basismodellen
boosting: Erstellen einer Sequenz von Modellen, die aufeinander aufbauen, um die Vorhersageleistung zu verbessern.
Beginnen wir mit einem Random-Forest-Modell, das eine große Sammlung von Entscheidungsbäumen erstellt und dann eine Mittelungsfunktion anwendet, um ein besseres Gesamtmodell zu erhalten.
# Make a random forest specification
rf_spec <- rand_forest() %>%
set_engine("ranger") %>%
set_mode("classification")
# Bundle recipe and model specification into a workflow
rf_wf <- workflow() %>%
add_recipe(cuisines_recipe) %>%
add_model(rf_spec)
# Train a random forest model
rf_wf_fit <- rf_wf %>%
fit(data = cuisines_train)
# Make predictions and Evaluate model performance
rf_wf_fit %>%
augment(new_data = cuisines_test) %>%
eval_metrics(truth = cuisine, estimate = .pred_class)
Gute Arbeit 👏!
Lass uns auch ein Boosted-Tree-Modell ausprobieren.
Boosted Tree definiert eine Ensemble-Methode, die eine Reihe von sequentiellen Entscheidungsbäumen erstellt, bei denen jeder Baum von den Ergebnissen der vorherigen Bäume abhängt, um den Fehler schrittweise zu reduzieren. Der Fokus liegt auf den Gewichten der falsch klassifizierten Elemente, und die Anpassung für den nächsten Klassifikator wird entsprechend korrigiert.
Es gibt verschiedene Möglichkeiten, dieses Modell anzupassen (siehe help("boost_tree")). In diesem Beispiel passen wir Boosted Trees über die xgboost-Engine an.
# Make a boosted tree specification
boost_spec <- boost_tree(trees = 200) %>%
set_engine("xgboost") %>%
set_mode("classification")
# Bundle recipe and model specification into a workflow
boost_wf <- workflow() %>%
add_recipe(cuisines_recipe) %>%
add_model(boost_spec)
# Train a boosted tree model
boost_wf_fit <- boost_wf %>%
fit(data = cuisines_train)
# Make predictions and Evaluate model performance
boost_wf_fit %>%
augment(new_data = cuisines_test) %>%
eval_metrics(truth = cuisine, estimate = .pred_class)
> ✅ Bitte sehen Sie: > > - Machine Learning for Social Scientists > > - Hands-on Machine Learning with R > > - An Introduction to Statistical Learning with Applications in R > > - <https://algotech.netlify.app/blog/xgboost/> - Untersucht das AdaBoost-Modell, das eine gute Alternative zu xgboost darstellt. > > um mehr über Ensemble-Klassifikatoren zu erfahren.
4. Extra - Vergleich mehrerer Modelle
Wir haben in diesem Lab eine ganze Reihe von Modellen angepasst 🙌. Es kann mühsam oder aufwendig werden, viele Workflows aus verschiedenen Sets von Preprozessoren und/oder Modellspezifikationen zu erstellen und dann die Leistungskennzahlen einzeln zu berechnen.
Schauen wir, ob wir das vereinfachen können, indem wir eine Funktion erstellen, die eine Liste von Workflows auf den Trainingssatz anpasst und dann die Leistungskennzahlen basierend auf dem Testsatz zurückgibt. Wir werden map() und map_dfr() aus dem purrr Paket verwenden, um Funktionen auf jedes Element in einer Liste anzuwenden.
> map()-Funktionen ermöglichen es, viele for-Schleifen durch Code zu ersetzen, der sowohl kürzer als auch leichter lesbar ist. Der beste Ort, um mehr über die map()-Funktionen zu lernen, ist das Kapitel über Iteration in "R for Data Science".
set.seed(2056)
# Create a metric set
eval_metrics <- metric_set(ppv, sens, accuracy, f_meas)
# Define a function that returns performance metrics
compare_models <- function(workflow_list, train_set, test_set){
suppressWarnings(
# Fit each model to the train_set
map(workflow_list, fit, data = train_set) %>%
# Make predictions on the test set
map_dfr(augment, new_data = test_set, .id = "model") %>%
# Select desired columns
select(model, cuisine, .pred_class) %>%
# Evaluate model performance
group_by(model) %>%
eval_metrics(truth = cuisine, estimate = .pred_class) %>%
ungroup()
)
} # End of function
# Make a list of workflows
workflow_list <- list(
"svc" = svc_linear_wf,
"svm" = svm_rbf_wf,
"knn" = knn_wf,
"random_forest" = rf_wf,
"xgboost" = boost_wf)
# Call the function
set.seed(2056)
perf_metrics <- compare_models(workflow_list = workflow_list, train_set = cuisines_train, test_set = cuisines_test)
# Print out performance metrics
perf_metrics %>%
group_by(.metric) %>%
arrange(desc(.estimate)) %>%
slice_head(n=7)
# Compare accuracy
perf_metrics %>%
filter(.metric == "accuracy") %>%
arrange(desc(.estimate))
workflowset Paket ermöglicht es Nutzern, eine große Anzahl von Modellen zu erstellen und einfach anzupassen. Es ist jedoch hauptsächlich darauf ausgelegt, mit Resampling-Techniken wie cross-validation zu arbeiten, eine Methode, die wir noch behandeln werden.
🚀Herausforderung
Jede dieser Techniken hat eine Vielzahl von Parametern, die Sie anpassen können, wie zum Beispiel cost bei SVMs, neighbors bei KNN, mtry (zufällig ausgewählte Prädiktoren) bei Random Forest.
Recherchieren Sie die Standardparameter jedes Modells und überlegen Sie, was das Anpassen dieser Parameter für die Qualität des Modells bedeuten würde.
Um mehr über ein bestimmtes Modell und seine Parameter zu erfahren, verwenden Sie: help("model"), z. B. help("rand_forest").
> In der Praxis schätzen wir normalerweise die besten Werte für diese Parameter, indem wir viele Modelle auf einem simulierten Datensatz trainieren und messen, wie gut diese Modelle abschneiden. Dieser Prozess wird Tuning genannt.
Quiz nach der Vorlesung
Überblick & Selbststudium
Es gibt viele Fachbegriffe in diesen Lektionen, nehmen Sie sich daher einen Moment Zeit, um diese Liste nützlicher Begriffe zu überprüfen!
EIN DANKESCHÖN AN:
Allison Horst für die großartigen Illustrationen, die R einladender und ansprechender machen. Weitere Illustrationen finden Sie in ihrer Galerie.
Cassie Breviu und Jen Looper für die Erstellung der ursprünglichen Python-Version dieses Moduls ♥️
Viel Spaß beim Lernen,
Eric, Gold Microsoft Learn Student Ambassador.
<p > <img src="../../images/r_learners_sm.jpeg" width="569"/> <figcaption>Kunstwerk von @allison_horst</figcaption>
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Erstelle einen Empfehlungsdienst
Anweisungen
Basierend auf deinen Übungen in dieser Lektion weißt du nun, wie man eine JavaScript-basierte Webanwendung mit Onnx Runtime und einem konvertierten Onnx-Modell erstellt. Experimentiere mit dem Aufbau eines neuen Empfehlungsdienstes, indem du Daten aus diesen Lektionen oder aus anderen Quellen verwendest (bitte gib die Quelle an). Du könntest beispielsweise einen Haustier-Empfehlungsdienst basierend auf verschiedenen Persönlichkeitsmerkmalen erstellen oder einen Musikgenre-Empfehlungsdienst basierend auf der Stimmung einer Person. Sei kreativ!
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Eine Webanwendung und ein Notebook werden präsentiert, beide gut dokumentiert und funktionierend | Eines von beiden fehlt oder ist fehlerhaft | Beide fehlen oder sind fehlerhaft |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Erstellen einer Web-App zur Empfehlung von Küchen
In dieser Lektion wirst du ein Klassifikationsmodell erstellen, indem du einige der Techniken anwendest, die du in den vorherigen Lektionen gelernt hast, und mit dem köstlichen Küchendatensatz arbeitest, der in dieser Serie verwendet wurde. Außerdem wirst du eine kleine Web-App entwickeln, um ein gespeichertes Modell zu nutzen, indem du die Web-Laufzeit von Onnx einsetzt.
Eine der nützlichsten praktischen Anwendungen des maschinellen Lernens ist der Aufbau von Empfehlungssystemen, und du kannst heute den ersten Schritt in diese Richtung machen!
> 🎥 Klicke auf das Bild oben für ein Video: Jen Looper erstellt eine Web-App mit klassifizierten Küchendaten
Quiz vor der Lektion
In dieser Lektion wirst du lernen:
- Wie man ein Modell erstellt und es als Onnx-Modell speichert
- Wie man Netron verwendet, um das Modell zu inspizieren
- Wie man das Modell in einer Web-App für Inferenz verwendet
Erstelle dein Modell
Der Aufbau angewandter ML-Systeme ist ein wichtiger Teil der Nutzung dieser Technologien für Geschäftssysteme. Du kannst Modelle innerhalb deiner Webanwendungen verwenden (und sie somit bei Bedarf offline nutzen), indem du Onnx einsetzt.
In einer vorherigen Lektion hast du ein Regressionsmodell über UFO-Sichtungen erstellt, es "eingemacht" und in einer Flask-App verwendet. Obwohl diese Architektur sehr nützlich ist, handelt es sich um eine vollständige Python-App, und deine Anforderungen könnten die Nutzung einer JavaScript-Anwendung umfassen.
In dieser Lektion kannst du ein einfaches JavaScript-basiertes System für Inferenz erstellen. Zunächst musst du jedoch ein Modell trainieren und es für die Verwendung mit Onnx konvertieren.
Übung - Klassifikationsmodell trainieren
Trainiere zunächst ein Klassifikationsmodell mit dem bereinigten Küchendatensatz, den wir verwendet haben.
-
Beginne mit dem Import nützlicher Bibliotheken:
python !pip install skl2onnx import pandas as pdDu benötigst 'skl2onnx', um dein Scikit-learn-Modell in das Onnx-Format zu konvertieren.
-
Arbeite dann mit deinen Daten wie in den vorherigen Lektionen, indem du eine CSV-Datei mit
read_csv()liest:python data = pd.read_csv('../data/cleaned_cuisines.csv') data.head() -
Entferne die ersten beiden unnötigen Spalten und speichere die verbleibenden Daten als 'X':
python X = data.iloc[:,2:] X.head() -
Speichere die Labels als 'y':
```python y = data[['cuisine']] y.head()
```
Beginne die Trainingsroutine
Wir werden die 'SVC'-Bibliothek verwenden, die eine gute Genauigkeit bietet.
-
Importiere die entsprechenden Bibliotheken aus Scikit-learn:
python from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.model_selection import cross_val_score from sklearn.metrics import accuracy_score,precision_score,confusion_matrix,classification_report -
Teile die Trainings- und Testdaten:
python X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3) -
Erstelle ein SVC-Klassifikationsmodell wie in der vorherigen Lektion:
python model = SVC(kernel='linear', C=10, probability=True,random_state=0) model.fit(X_train,y_train.values.ravel()) -
Teste nun dein Modell, indem du
predict()aufrufst:python y_pred = model.predict(X_test) -
Gib einen Klassifikationsbericht aus, um die Qualität des Modells zu überprüfen:
python print(classification_report(y_test,y_pred))Wie wir zuvor gesehen haben, ist die Genauigkeit gut:
```output precision recall f1-score support
chinese 0.72 0.69 0.70 257 indian 0.91 0.87 0.89 243 japanese 0.79 0.77 0.78 239 korean 0.83 0.79 0.81 236 thai 0.72 0.84 0.78 224 accuracy 0.79 1199macro avg 0.79 0.79 0.79 1199 weighted avg 0.79 0.79 0.79 1199 ```
Konvertiere dein Modell in Onnx
Stelle sicher, dass die Konvertierung mit der richtigen Tensor-Anzahl erfolgt. Dieser Datensatz enthält 380 aufgelistete Zutaten, daher musst du diese Zahl in FloatTensorType angeben:
-
Konvertiere mit einer Tensor-Anzahl von 380.
```python from skl2onnx import convert_sklearn from skl2onnx.common.data_types import FloatTensorType
initial_type = [('float_input', FloatTensorType([None, 380]))] options = {id(model): {'nocl': True, 'zipmap': False}} ```
-
Erstelle die Onnx-Datei und speichere sie als model.onnx:
python onx = convert_sklearn(model, initial_types=initial_type, options=options) with open("./model.onnx", "wb") as f: f.write(onx.SerializeToString())> Hinweis: Du kannst Optionen in deinem Konvertierungsskript übergeben. In diesem Fall haben wir 'nocl' auf True und 'zipmap' auf False gesetzt. Da es sich um ein Klassifikationsmodell handelt, hast du die Möglichkeit, ZipMap zu entfernen, das eine Liste von Wörterbüchern erzeugt (nicht erforderlich).
noclbezieht sich darauf, ob Klasseninformationen im Modell enthalten sind. Reduziere die Größe deines Modells, indem dunoclauf 'True' setzt.
Wenn du das gesamte Notebook ausführst, wird ein Onnx-Modell erstellt und in diesem Ordner gespeichert.
Betrachte dein Modell
Onnx-Modelle sind in Visual Studio Code nicht sehr sichtbar, aber es gibt eine sehr gute kostenlose Software, die viele Forscher verwenden, um das Modell zu visualisieren und sicherzustellen, dass es korrekt erstellt wurde. Lade Netron herunter und öffne deine model.onnx-Datei. Du kannst dein einfaches Modell visualisiert sehen, mit seinen 380 Eingaben und dem Klassifikator:

Netron ist ein hilfreiches Tool, um deine Modelle zu betrachten.
Jetzt bist du bereit, dieses praktische Modell in einer Web-App zu verwenden. Lass uns eine App erstellen, die nützlich ist, wenn du in deinen Kühlschrank schaust und herausfinden möchtest, welche Kombination deiner übrig gebliebenen Zutaten du verwenden kannst, um eine bestimmte Küche zu kochen, wie von deinem Modell bestimmt.
Erstelle eine Empfehlungs-Webanwendung
Du kannst dein Modell direkt in einer Web-App verwenden. Diese Architektur ermöglicht es dir auch, sie lokal und sogar offline auszuführen, falls erforderlich. Beginne mit der Erstellung einer index.html-Datei im selben Ordner, in dem du deine model.onnx-Datei gespeichert hast.
-
Füge in dieser Datei index.html das folgende Markup hinzu:
html <!DOCTYPE html> <html> <header> <title>Cuisine Matcher</title> </header> <body> ... </body> </html> -
Füge nun innerhalb der
body-Tags ein wenig Markup hinzu, um eine Liste von Kontrollkästchen anzuzeigen, die einige Zutaten widerspiegeln:```html <h1>Check your refrigerator. What can you create?</h1> <div id="wrapper"> <div class="boxCont"> <input type="checkbox" value="4" class="checkbox"> <label>apple</label> </div>
<div class="boxCont"> <input type="checkbox" value="247" class="checkbox"> <label>pear</label> </div> <div class="boxCont"> <input type="checkbox" value="77" class="checkbox"> <label>cherry</label> </div> <div class="boxCont"> <input type="checkbox" value="126" class="checkbox"> <label>fenugreek</label> </div> <div class="boxCont"> <input type="checkbox" value="302" class="checkbox"> <label>sake</label> </div> <div class="boxCont"> <input type="checkbox" value="327" class="checkbox"> <label>soy sauce</label> </div> <div class="boxCont"> <input type="checkbox" value="112" class="checkbox"> <label>cumin</label> </div> </div> <div style="padding-top:10px"> <button onClick="startInference()">What kind of cuisine can you make?</button> </div>```
Beachte, dass jedes Kontrollkästchen einen Wert hat. Dieser spiegelt den Index wider, an dem die Zutat gemäß dem Datensatz gefunden wird. Apfel, zum Beispiel, in dieser alphabetischen Liste, belegt die fünfte Spalte, daher ist sein Wert '4', da wir bei 0 zu zählen beginnen. Du kannst die Zutaten-Tabelle konsultieren, um den Index einer bestimmten Zutat zu finden.
Setze deine Arbeit in der index.html-Datei fort und füge einen Skriptblock hinzu, in dem das Modell nach dem letzten abschließenden
</div>aufgerufen wird. -
Importiere zunächst die Onnx Runtime:
html <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.9.0/dist/ort.min.js"></script>> Onnx Runtime wird verwendet, um die Ausführung deiner Onnx-Modelle auf einer Vielzahl von Hardwareplattformen zu ermöglichen, einschließlich Optimierungen und einer API zur Nutzung.
-
Sobald die Runtime eingerichtet ist, kannst du sie aufrufen:
```html <script> const ingredients = Array(380).fill(0);
const checks = [...document.querySelectorAll('.checkbox')]; checks.forEach(check => { check.addEventListener('change', function() { // toggle the state of the ingredient // based on the checkbox's value (1 or 0) ingredients[check.value] = check.checked ? 1 : 0; }); }); function testCheckboxes() { // validate if at least one checkbox is checked return checks.some(check => check.checked); } async function startInference() { let atLeastOneChecked = testCheckboxes() if (!atLeastOneChecked) { alert('Please select at least one ingredient.'); return; } try { // create a new session and load the model. const session = await ort.InferenceSession.create('./model.onnx'); const input = new ort.Tensor(new Float32Array(ingredients), [1, 380]); const feeds = { float_input: input }; // feed inputs and run const results = await session.run(feeds); // read from results alert('You can enjoy ' + results.label.data[0] + ' cuisine today!') } catch (e) { console.log(`failed to inference ONNX model`); console.error(e); } }</script> ```
In diesem Code passieren mehrere Dinge:
- Du hast ein Array von 380 möglichen Werten (1 oder 0) erstellt, das je nach Auswahl eines Kontrollkästchens gesetzt und an das Modell zur Inferenz gesendet wird.
- Du hast ein Array von Kontrollkästchen erstellt und eine Möglichkeit, festzustellen, ob sie im
init-Funktion aktiviert wurden, die beim Start der Anwendung aufgerufen wird. Wenn ein Kontrollkästchen aktiviert ist, wird dasingredients-Array geändert, um die ausgewählte Zutat widerzuspiegeln. - Du hast eine
testCheckboxes-Funktion erstellt, die überprüft, ob ein Kontrollkästchen aktiviert wurde. - Du verwendest die
startInference-Funktion, wenn die Schaltfläche gedrückt wird, und wenn ein Kontrollkästchen aktiviert ist, startest du die Inferenz. - Die Inferenzroutine umfasst:
- Das Einrichten eines asynchronen Ladevorgangs des Modells
- Das Erstellen einer Tensor-Struktur, die an das Modell gesendet wird
- Das Erstellen von 'feeds', die den
float_input-Eingang widerspiegeln, den du beim Training deines Modells erstellt hast (du kannst Netron verwenden, um diesen Namen zu überprüfen) - Das Senden dieser 'feeds' an das Modell und das Warten auf eine Antwort
Teste deine Anwendung
Öffne eine Terminal-Sitzung in Visual Studio Code im Ordner, in dem sich deine index.html-Datei befindet. Stelle sicher, dass du http-server global installiert hast, und gib http-server an der Eingabeaufforderung ein. Ein localhost sollte sich öffnen und du kannst deine Web-App anzeigen. Überprüfe, welche Küche basierend auf verschiedenen Zutaten empfohlen wird:

Herzlichen Glückwunsch, du hast eine Empfehlungs-Web-App mit einigen Feldern erstellt. Nimm dir etwas Zeit, um dieses System weiter auszubauen!
🚀 Herausforderung
Deine Web-App ist sehr minimal, also baue sie weiter aus, indem du Zutaten und ihre Indizes aus den ingredient_indexes-Daten verwendest. Welche Geschmacksrichtungen funktionieren, um ein bestimmtes Nationalgericht zu kreieren?
Quiz nach der Lektion
Überprüfung & Selbststudium
Während diese Lektion nur kurz die Nützlichkeit der Erstellung eines Empfehlungssystems für Lebensmittelzutaten berührt hat, ist dieser Bereich der ML-Anwendungen sehr reich an Beispielen. Lies mehr darüber, wie diese Systeme aufgebaut werden:
- https://www.sciencedirect.com/topics/computer-science/recommendation-engine
- https://www.technologyreview.com/2014/08/25/171547/the-ultimate-challenge-for-recommendation-engines/
- https://www.technologyreview.com/2015/03/23/168831/everything-is-a-recommendation/
Aufgabe
Erstelle einen neuen Empfehlungsalgorithmus
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
!pip install skl2onnx
import pandas as pd
data = pd.read_csv('../../data/cleaned_cuisines.csv')
data.head()
X = data.iloc[:,2:]
X.head()
y = data[['cuisine']]
y.head()
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
from sklearn.metrics import accuracy_score,precision_score,confusion_matrix,classification_report
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3)
model = SVC(kernel='linear', C=10, probability=True,random_state=0)
model.fit(X_train,y_train.values.ravel())
y_pred = model.predict(X_test)
print(classification_report(y_test,y_pred))
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
initial_type = [('float_input', FloatTensorType([None, 380]))]
options = {id(model): {'nocl': True, 'zipmap': False}}
onx = convert_sklearn(model, initial_types=initial_type, options=options)
with open("./model.onnx", "wb") as f:
f.write(onx.SerializeToString())
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einstieg in die Klassifikation
Regionales Thema: Köstliche asiatische und indische Küchen 🍜
In Asien und Indien sind die Essensgewohnheiten äußerst vielfältig und sehr lecker! Schauen wir uns Daten über regionale Küchen an, um ihre Zutaten besser zu verstehen.
> Foto von <a href="https://unsplash.com/@changlisheng?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Lisheng Chang</a> auf <a href="https://unsplash.com/s/photos/asian-food?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
Was Sie lernen werden
In diesem Abschnitt bauen Sie auf Ihrem früheren Studium der Regression auf und lernen andere Klassifikatoren kennen, die Sie verwenden können, um die Daten besser zu verstehen.
> Es gibt nützliche Low-Code-Tools, die Ihnen helfen können, mehr über die Arbeit mit Klassifikationsmodellen zu lernen. Probieren Sie Azure ML für diese Aufgabe aus.
Lektionen
- Einführung in die Klassifikation
- Weitere Klassifikatoren
- Noch andere Klassifikatoren
- Angewandtes ML: eine Web-App erstellen
Credits
"Einstieg in die Klassifikation" wurde mit ♥️ geschrieben von Cassie Breviu und Jen Looper
Der Datensatz zu den köstlichen Küchen stammt von Kaggle.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Recherchiere andere Visualisierungen für Clustering
Anweisungen
In dieser Lektion hast du einige Visualisierungstechniken kennengelernt, um deine Daten für das Clustering vorzubereiten. Insbesondere Streudiagramme sind nützlich, um Gruppen von Objekten zu identifizieren. Recherchiere verschiedene Möglichkeiten und Bibliotheken, um Streudiagramme zu erstellen, und dokumentiere deine Arbeit in einem Notizbuch. Du kannst die Daten aus dieser Lektion, anderen Lektionen oder selbst beschaffte Daten verwenden (bitte gib in deinem Notizbuch die Quelle der Daten an). Erstelle einige Streudiagramme und erkläre, was du dabei entdeckst.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Notizbuch wird mit fünf gut dokumentierten Streudiagrammen präsentiert | Ein Notizbuch wird mit weniger als fünf Streudiagrammen präsentiert und ist weniger gut dokumentiert | Ein unvollständiges Notizbuch wird präsentiert |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in Clustering
Clustering ist eine Art des Unüberwachten Lernens, die davon ausgeht, dass ein Datensatz unbeschriftet ist oder seine Eingaben nicht mit vordefinierten Ausgaben abgeglichen werden. Es verwendet verschiedene Algorithmen, um unbeschriftete Daten zu sortieren und Gruppen gemäß den Mustern bereitzustellen, die es in den Daten erkennt.
> 🎥 Klicke auf das obige Bild für ein Video. Während du dich mit maschinellem Lernen und Clustering beschäftigst, genieße einige Nigerian Dance Hall Tracks – dies ist ein hoch bewertetes Lied von 2014 von PSquare.
Vorlesungsquiz
Einführung
Clustering ist sehr nützlich zur Datenexploration. Schauen wir, ob es helfen kann, Trends und Muster in der Art und Weise zu entdecken, wie nigerianische Zuhörer Musik konsumieren.
✅ Nimm dir eine Minute Zeit, um über die Verwendungsmöglichkeiten von Clustering nachzudenken. Im wirklichen Leben findet Clustering statt, wenn du einen Wäscheberg hast und die Kleidung deiner Familienmitglieder sortieren musst 🧦👕👖🩲. In der Datenwissenschaft findet Clustering statt, wenn versucht wird, die Vorlieben eines Nutzers zu analysieren oder die Eigenschaften eines unbeschrifteten Datensatzes zu bestimmen. Clustering hilft gewissermaßen dabei, Chaos zu verstehen, wie eine Sockenschublade.
> 🎥 Klicke auf das obige Bild für ein Video: John Guttag vom MIT stellt Clustering vor.
In einem professionellen Umfeld kann Clustering verwendet werden, um Dinge wie Marktsegmentierung zu bestimmen, zum Beispiel welche Altersgruppen welche Artikel kaufen. Eine weitere Anwendung wäre die Anomalieerkennung, z.B. um Betrug anhand eines Datensatzes von Kreditkartentransaktionen zu erkennen. Oder du könntest Clustering verwenden, um Tumore in einer Reihe medizinischer Scans zu bestimmen.
✅ Überlege eine Minute, wie du Clusterings „in freier Wildbahn“ in einem Bank-, E-Commerce- oder Geschäftsumfeld begegnet bist.
> 🎓 Interessanterweise stammt die Clusteranalyse aus den Bereichen Anthropologie und Psychologie in den 1930ern. Kannst du dir vorstellen, wie sie damals verwendet worden sein könnte?
Alternativ kannst du es zur Gruppierung von Suchergebnissen verwenden – zum Beispiel nach Einkaufslinks, Bildern oder Rezensionen. Clustering ist nützlich, wenn du einen großen Datensatz hast, den du reduzieren und auf dem du eine detailliertere Analyse durchführen möchtest. So kann die Technik verwendet werden, um Daten kennenzulernen, bevor andere Modelle erstellt werden.
✅ Sobald deine Daten in Clustern organisiert sind, weist du ihnen eine Cluster-ID zu, und diese Technik kann nützlich sein, um die Privatsphäre eines Datensatzes zu wahren; du kannst stattdessen auf einen Datenpunkt durch seine Cluster-ID verweisen, anstatt durch offenlegende identifizierende Daten. Fallen dir weitere Gründe ein, warum du zur Identifikation eines Clusters lieber die Cluster-ID statt anderer Cluster-Elemente verwenden würdest?
Vertiefe dein Verständnis von Clustering-Techniken in diesem Learn-Modul
Einstieg in Clustering
Scikit-learn bietet eine große Auswahl an Methoden zur Durchführung von Clustering. Die Wahl hängt von deinem Anwendungsfall ab. Laut Dokumentation hat jede Methode verschiedene Vorteile. Hier ist eine vereinfachte Tabelle der von Scikit-learn unterstützten Methoden und ihrer geeigneten Anwendungsfälle:
| Methodenname | Anwendungsfall |
|---|---|
| K-Means | Allgemeiner Zweck, induktiv |
| Affinity propagation | viele, ungleichmäßige Cluster, induktiv |
| Mean-shift | viele, ungleichmäßige Cluster, induktiv |
| Spectral clustering | wenige, gleichmäßige Cluster, transduktiv |
| Ward hierarchisches Clustering | viele, eingeschränkte Cluster, transduktiv |
| Agglomeratives Clustering | viele, eingeschränkt, nicht-euklidische Distanzen, transduktiv |
| DBSCAN | nicht-flache Geometrie, ungleichmäßige Cluster, transduktiv |
| OPTICS | nicht-flache Geometrie, ungleichmäßige Cluster mit variabler Dichte, transduktiv |
| Gaussian mixtures | flache Geometrie, induktiv |
| BIRCH | großer Datensatz mit Ausreißern, induktiv |
> 🎓 Wie wir Cluster erstellen, hat viel damit zu tun, wie wir die Datenpunkte in Gruppen zusammenfassen. Lass uns etwas Vokabular aufschlüsseln:
>
> 🎓 'Transduktiv' vs. 'induktiv'
>
> Transduktive Inferenz wird von beobachteten Trainingsfällen abgeleitet, die spezifische Testfälle abbilden. Induktive Inferenz wird von Trainingsfällen abgeleitet, die allgemeine Regeln bilden, die dann erst auf Testfälle angewendet werden.
>
> Ein Beispiel: Stell dir vor, du hast einen Datensatz, der nur teilweise beschriftet ist. Manche Dinge sind „Schallplatten“, manche „CDs“ und manche sind leer. Deine Aufgabe ist es, die leeren Elemente zu beschriften. Wenn du einen induktiven Ansatz wählst, trainierst du ein Modell, das nach „Schallplatten“ und „CDs“ sucht, und wendest diese Beschriftungen auf deine unbeschrifteten Daten an. Dieser Ansatz wird Schwierigkeiten haben, Dinge zu klassifizieren, die tatsächlich „Kassetten“ sind. Ein transduktiver Ansatz hingegen behandelt unbekannte Daten effektiver, weil er ähnliche Elemente zusammenführt und dann einer Gruppe eine Bezeichnung zuweist. In diesem Fall könnten Cluster „runde Musiksachen“ und „quadratische Musiksachen“ reflektieren.
>
> 🎓 'Nicht-flache' vs. 'flache' Geometrie
>
> Abgeleitet aus der mathematischen Terminologie bezieht sich „nicht-flache“ vs. „flache“ Geometrie auf die Maßnahme der Abstände zwischen Punkten durch entweder „flache“ (euklidische) oder „nicht-flache“ (nicht-euklidische) geometrische Methoden.
>
> „Flach“ bezieht sich in diesem Kontext auf die euklidische Geometrie (Teile davon werden als „ebene“ Geometrie gelehrt) und „nicht-flach“ auf nicht-euklidische Geometrie. Was hat Geometrie mit maschinellem Lernen zu tun? Nun, da beide Bereiche in der Mathematik verankert sind, muss es eine gemeinsame Möglichkeit geben, Abstände zwischen Punkten in Clustern zu messen, und dies kann „flach“ oder „nicht-flach“ erfolgen, abhängig von der Natur der Daten. Euklidische Abstände werden als Länge eines Liniensegments zwischen zwei Punkten gemessen. Nicht-euklidische Abstände werden entlang einer Kurve gemessen. Wenn deine Daten visualisiert zu sein scheinen, als existierten sie nicht auf einer Ebene, brauchst du möglicherweise einen spezialisierten Algorithmus, um sie zu handhaben.
>
> Infografik von Dasani Madipalli
>
> 🎓 'Abstände'
>
> Cluster werden durch ihre Distanzmatrix definiert, z.B. die Abstände zwischen Punkten. Dieser Abstand kann auf verschiedene Weise gemessen werden. Euklidische Cluster werden durch den Durchschnitt der Punktwerte definiert und enthalten einen „Zentrumspunkt“ oder Zentroid. Entsprechend werden Abstände durch die Distanz zu diesem Zentroid gemessen. Nicht-euklidische Abstände beziehen sich auf „Clustroide“, den Punkt, der anderen Punkten am nächsten ist. Clustroide können wiederum auf verschiedene Weise definiert werden.
>
> 🎓 'Eingeschränkt'
>
> Constrained Clustering führt „semi-supervised“ Lernen in diese unüberwachte Methode ein. Die Beziehungen zwischen Punkten werden als „darf nicht verbunden“ oder „muss verbunden sein“ markiert, sodass einige Regeln für den Datensatz erzwungen werden.
>
>Ein Beispiel: Wenn ein Algorithmus auf eine Menge unbeschrifteter oder halb-beschrifteter Daten losgelassen wird, können die erzeugten Cluster von minderer Qualität sein. Im obigen Beispiel könnten die Cluster „runde Musiksachen“ und „quadratische Musiksachen“ und „dreieckige Dinge“ und „Kekse“ gruppieren. Werden einige Einschränkungen oder Regeln („der Artikel muss aus Plastik sein“, „der Artikel muss in der Lage sein, Musik zu produzieren“) vorgegeben, kann dies helfen, den Algorithmus zu zwingen, bessere Entscheidungen zu treffen.
>
> 🎓 'Dichte'
>
> Daten, die „rauschbehaftet“ sind, gelten als „dicht“. Die Abstände zwischen Punkten in jedem ihrer Cluster können bei genauer Betrachtung mehr oder weniger dicht oder „überfüllt“ sein, weshalb diese Daten mit der geeigneten Clustering-Methode analysiert werden müssen. Dieser Artikel zeigt den Unterschied zwischen K-Means Clustering und HDBSCAN Algorithmen bei der Untersuchung eines verrauschten Datensatzes mit ungleichmäßiger Clusterdichte.
Clustering-Algorithmen
Es gibt über 100 Clustering-Algorithmen, und ihr Einsatz hängt von der Natur der vorliegenden Daten ab. Lass uns einige der wichtigsten besprechen:
- Hierarchisches Clustering. Wenn ein Objekt nach seiner Nähe zu einem benachbarten Objekt klassifiziert wird, statt zu einem weiter entfernten, werden Cluster auf Basis der Entfernung ihrer Mitglieder zu und von anderen Objekten gebildet. Das Agglomerative Clustering von Scikit-learn ist hierarchisch.
> Infografik von Dasani Madipalli
- Zentroid-basiertes Clustering. Dieser populäre Algorithmus erfordert die Wahl von „k“, also der Anzahl der zu bildenden Cluster, wonach der Algorithmus den Mittelpunkt eines Clusters bestimmt und Daten um diesen Punkt gruppiert. K-means Clustering ist eine beliebte Version des zentroid-basierten Clustering. Der Mittelpunkt wird durch den nächstgelegenen Mittelwert bestimmt, daher der Name. Die quadratische Distanz vom Cluster wird minimiert.
> Infografik von Dasani Madipalli
-
Verteilungsbasiertes Clustering. Basierend auf statistischen Modellen konzentriert sich das verteilungsbasierte Clustering darauf, die Wahrscheinlichkeit zu bestimmen, dass ein Datenpunkt zu einem Cluster gehört, und ordnet ihn entsprechend zu. Gaussian Mixture-Methoden gehören zu diesem Typ.
-
Dichte-basiertes Clustering. Datenpunkte werden Clustern basierend auf ihrer Dichte oder ihrer Gruppierung um einander zugeordnet. Datenpunkte, die weit entfernt von der Gruppe liegen, gelten als Ausreißer oder Rauschen. DBSCAN, Mean-shift und OPTICS gehören zu diesem Clustering-Typ.
-
Raster-basiertes Clustering. Für mehrdimensionale Datensätze wird ein Raster erstellt und die Daten auf die Zellen des Rasters verteilt, wodurch Cluster entstehen.
Übung - Clustere deine Daten
Clustering als Technik wird durch eine gute Visualisierung stark unterstützt, also lasst uns mit der Visualisierung unserer Musikdaten beginnen. Diese Übung hilft uns dabei zu entscheiden, welche der Clustering-Methoden wir für die Art dieser Daten am effektivsten einsetzen sollten.
-
Öffne die Datei notebook.ipynb in diesem Ordner.
-
Importiere das
SeabornPaket für gute Datenvisualisierung.python !pip install seaborn -
Füge die Lieddaten aus nigerian-songs.csv hinzu. Lade einen Dataframe mit einigen Daten über die Songs. Mache dich bereit, diese Daten zu erkunden, indem du die Bibliotheken importierst und die Daten ausgibst:
```python import matplotlib.pyplot as plt import pandas as pd
df = pd.read_csv("../data/nigerian-songs.csv") df.head() ```
Überprüfe die ersten Zeilen der Daten:
name album artist artist_top_genre release_date length popularity danceability acousticness energy instrumentalness liveness loudness speechiness tempo time_signature 0 Sparky Mandy & The Jungle Cruel Santino alternative r&b 2019 144000 48 0.666 0.851 0.42 0.534 0.11 -6.699 0.0829 133.015 5 1 shuga rush EVERYTHING YOU HEARD IS TRUE Odunsi (The Engine) afropop 2020 89488 30 0.71 0.0822 0.683 0.000169 0.101 -5.64 0.36 129.993 3 2 LITT! LITT! AYLØ Indie R&B 2018 207758 40 0.836 0.272 0.564 0.000537 0.11 -7.127 0.0424 130.005 4 3 Confident / Feeling Cool Enjoy Your Life Lady Donli Nigerian Pop 2019 175135 14 0.894 0.798 0.611 0.000187 0.0964 -4.961 0.113 111.087 4 4 wanted you rare. Odunsi (The Engine) Afropop 2018 152049 25 0.702 0.116 0.833 0.91 0.348 -6.044 0.0447 105.115 4 -
Holen Sie sich einige Informationen über das DataFrame, indem Sie
info()aufrufen:python df.info()
Die Ausgabe sieht so aus:
```output
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 530 entries, 0 to 529
Data columns (total 16 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 name 530 non-null object
1 album 530 non-null object
2 artist 530 non-null object
3 artist_top_genre 530 non-null object
4 release_date 530 non-null int64
5 length 530 non-null int64
6 popularity 530 non-null int64
7 danceability 530 non-null float64
8 acousticness 530 non-null float64
9 energy 530 non-null float64
10 instrumentalness 530 non-null float64
11 liveness 530 non-null float64
12 loudness 530 non-null float64
13 speechiness 530 non-null float64
14 tempo 530 non-null float64
15 time_signature 530 non-null int64
dtypes: float64(8), int64(4), object(4)
memory usage: 66.4+ KB
```
-
Überprüfen Sie doppelt auf Nullwerte, indem Sie
isnull()aufrufen und die Summe 0 bestätigen:python df.isnull().sum()Sieht gut aus:
output name 0 album 0 artist 0 artist_top_genre 0 release_date 0 length 0 popularity 0 danceability 0 acousticness 0 energy 0 instrumentalness 0 liveness 0 loudness 0 speechiness 0 tempo 0 time_signature 0 dtype: int64 -
Beschreiben Sie die Daten:
python df.describe()release_date length popularity danceability acousticness energy instrumentalness liveness loudness speechiness tempo time_signature count 530 530 530 530 530 530 530 530 530 530 530 530 mean 2015.390566 222298.1698 17.507547 0.741619 0.265412 0.760623 0.016305 0.147308 -4.953011 0.130748 116.487864 3.986792 std 3.131688 39696.82226 18.992212 0.117522 0.208342 0.148533 0.090321 0.123588 2.464186 0.092939 23.518601 0.333701 min 1998 89488 0 0.255 0.000665 0.111 0 0.0283 -19.362 0.0278 61.695 3 25% 2014 199305 0 0.681 0.089525 0.669 0 0.07565 -6.29875 0.0591 102.96125 4 50% 2016 218509 13 0.761 0.2205 0.7845 0.000004 0.1035 -4.5585 0.09795 112.7145 4 75% 2017 242098.5 31 0.8295 0.403 0.87575 0.000234 0.164 -3.331 0.177 125.03925 4 max 2020 511738 73 0.966 0.954 0.995 0.91 0.811 0.582 0.514 206.007 5
> 🤔 Wenn wir mit Clustering arbeiten, einer unüberwachten Methode, die keine gelabelten Daten benötigt, warum zeigen wir diese Daten mit Labels? In der Datenexplorationsphase sind sie nützlich, aber sie sind für das Funktionieren der Clustering-Algorithmen nicht erforderlich. Sie könnten auch einfach die Spaltenüberschriften entfernen und sich auf die Daten mit Spaltennummern beziehen.
Sehen Sie sich die allgemeinen Werte der Daten an. Beachten Sie, dass Popularität '0' sein kann, was Songs zeigt, die keine Rangfolge haben. Lassen Sie uns diese bald entfernen.
-
Verwenden Sie ein Balkendiagramm, um die beliebtesten Genres herauszufinden:
```python import seaborn as sns
top = df['artist_top_genre'].value_counts() plt.figure(figsize=(10,7)) sns.barplot(x=top[:5].index,y=top[:5].values) plt.xticks(rotation=45) plt.title('Top genres',color = 'blue') ```

✅ Wenn Sie mehr Top-Werte sehen möchten, ändern Sie [:5] auf einen größeren Wert oder entfernen Sie es, um alle zu sehen.
Beachten Sie, wenn das Top-Genre als 'Missing' beschrieben wird, bedeutet dies, dass Spotify es nicht klassifiziert hat, also lassen wir es weg.
-
Entfernen Sie fehlende Daten, indem Sie sie herausfiltern
python df = df[df['artist_top_genre'] != 'Missing'] top = df['artist_top_genre'].value_counts() plt.figure(figsize=(10,7)) sns.barplot(x=top.index,y=top.values) plt.xticks(rotation=45) plt.title('Top genres',color = 'blue')Überprüfen Sie jetzt erneut die Genres:

-
Bei weitem dominieren die drei Top-Genres diesen Datensatz. Konzentrieren wir uns auf
afro dancehall,afropopundnigerian popund filtern zusätzlich den Datensatz, um alles mit einem Popularitätswert von 0 zu entfernen (was bedeutet, dass es im Datensatz keine Popularitätsklassifizierung gab und für unsere Zwecke als Rauschen betrachtet werden kann):python df = df[(df['artist_top_genre'] == 'afro dancehall') | (df['artist_top_genre'] == 'afropop') | (df['artist_top_genre'] == 'nigerian pop')] df = df[(df['popularity'] > 0)] top = df['artist_top_genre'].value_counts() plt.figure(figsize=(10,7)) sns.barplot(x=top.index,y=top.values) plt.xticks(rotation=45) plt.title('Top genres',color = 'blue') -
Führen Sie einen kurzen Test durch, um zu sehen, ob die Daten in irgendeiner besonders starken Weise korrelieren:
python corrmat = df.corr(numeric_only=True) f, ax = plt.subplots(figsize=(12, 9)) sns.heatmap(corrmat, vmax=.8, square=True)
Die einzige starke Korrelation besteht zwischen
energyundloudness, was nicht allzu überraschend ist, da laute Musik in der Regel ziemlich energetisch ist. Ansonsten sind die Korrelationen relativ schwach. Es wird interessant sein zu sehen, was ein Clustering-Algorithmus aus diesen Daten machen kann.> 🎓 Beachten Sie, dass Korrelation keine Kausalität impliziert! Wir haben den Beweis für eine Korrelation, aber keinen Beweis für eine Kausalität. Eine amüsante Webseite zeigt einige Visualisierungen, die diesen Punkt hervorheben.
Gibt es eine Konvergenz in diesem Datensatz bezüglich der wahrgenommenen Popularität und Tanzbarkeit eines Songs? Ein FacetGrid zeigt konzentrische Kreise, die unabhängig vom Genre übereinstimmen. Könnte es sein, dass sich der nigerianische Geschmack auf ein bestimmtes Maß an Tanzbarkeit für dieses Genre einpendelt?
✅ Probieren Sie verschiedene Datenpunkte (energy, loudness, speechiness) und mehr oder andere Musikgenres aus. Was können Sie entdecken? Schauen Sie sich die Tabelle df.describe() an, um die allgemeine Verteilung der Datenpunkte zu sehen.
Übung - Datenverteilung
Unterscheiden sich diese drei Genres signifikant in der Wahrnehmung ihrer Tanzbarkeit, basierend auf ihrer Popularität?
-
Untersuchen Sie die Verteilung der Daten der drei Top-Genres hinsichtlich Popularität und Tanzbarkeit entlang einer gegebenen x- und y-Achse.
```python sns.set_theme(style="ticks")
g = sns.jointplot( data=df, x="popularity", y="danceability", hue="artist_top_genre", kind="kde", ) ```
Sie können konzentrische Kreise um einen allgemeinen Konvergenzpunkt entdecken, die die Verteilung der Punkte zeigen.
> 🎓 Beachten Sie, dass dieses Beispiel ein KDE (Kernel Density Estimate) Diagramm verwendet, das die Daten mittels einer kontinuierlichen Wahrscheinlichkeitsdichtekurve darstellt. Dies ermöglicht uns die Interpretation von Daten bei der Arbeit mit mehreren Verteilungen.
Im Allgemeinen stimmen die drei Genres lose in Bezug auf ihre Popularität und Tanzbarkeit überein. Die Bestimmung von Clustern in diesen lose ausgerichteten Daten wird eine Herausforderung sein:

-
Erstellen Sie ein Streudiagramm:
python sns.FacetGrid(df, hue="artist_top_genre", height=5) \ .map(plt.scatter, "popularity", "danceability") \ .add_legend()Ein Streudiagramm mit denselben Achsen zeigt ein ähnliches Konvergenzmuster

Im Allgemeinen können Sie für Clustering Streudiagramme verwenden, um Cluster von Daten zu zeigen, daher ist das Beherrschen dieser Art der Visualisierung sehr nützlich. In der nächsten Lektion werden wir diese gefilterten Daten verwenden und k-Means-Clustering anwenden, um Gruppen in diesen Daten zu entdecken, die sich auf interessante Weise überschneiden.
🚀 Herausforderung
Bereiten Sie für die nächste Lektion ein Diagramm über die verschiedenen Clustering-Algorithmen vor, die Sie entdecken und in einer Produktionsumgebung verwenden könnten. Welche Arten von Problemen versucht das Clustering zu lösen?
Post-Lecture-Quiz
Rückblick & Selbststudium
Bevor Sie Clustering-Algorithmen anwenden, ist es, wie wir gelernt haben, eine gute Idee, die Natur Ihres Datensatzes zu verstehen. Lesen Sie mehr zu diesem Thema hier
Dieser hilfreiche Artikel führt Sie durch die verschiedenen Verhaltensweisen der Clustering-Algorithmen, abhängig von unterschiedlichen Datenformen.
Aufgabe
Forschen Sie nach weiteren Visualisierungen für Clustering
<!-- CO-OP TRANSLATOR DISCLAIMER START --> Haftungsausschluss: Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache gilt als maßgebliche Quelle. Bei kritischen Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Verwendung dieser Übersetzung entstehen. <!-- CO-OP TRANSLATOR DISCLAIMER END -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
!pip install seaborn
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv("../../data/nigerian-songs.csv")
df.head()
Erhalte Informationen über das DataFrame
df.info()
df.isnull().sum()
Schauen Sie sich die allgemeinen Werte der Daten an. Beachten Sie, dass die Beliebtheit '0' sein kann – und es gibt viele Zeilen mit diesem Wert.
df.describe()
Lass uns die Genres untersuchen. Einige sind als 'Fehlend' aufgeführt, was bedeutet, dass sie im Datensatz keinem Genre zugeordnet sind.
import seaborn as sns
top = df['artist_top_genre'].value_counts()
plt.figure(figsize=(10,7))
sns.barplot(x=top[:5].index,y=top[:5].values)
plt.xticks(rotation=45)
plt.title('Top genres',color = 'blue')
Wichtige Regeln: 1. Übersetze die Datei ins Deutsche, ohne dabei zu wörtlich zu sein. 2. Kommentare sollten ebenfalls übersetzt werden. 3. Markdown-Formatierung muss beibehalten werden. 4. Die folgenden Elemente dürfen nicht übersetzt werden: - [!NOTE], [!WARNING], [!TIP], [!IMPORTANT], [!CAUTION] - Variablennamen, Funktionsnamen, Klassennamen - Platzhalter wie @@INLINE_CODE_x@@ oder @@CODE_BLOCK_x@@ - URLs oder Pfade 5. Entferne Genres, die als "Missing" gekennzeichnet sind, da sie auf Spotify nicht klassifiziert sind.
Einführung
Dieses Dokument bietet eine Übersicht über die wichtigsten Funktionen und Best Practices für die Nutzung der API. Bitte lesen Sie die folgenden Abschnitte sorgfältig durch, um das Beste aus der API herauszuholen.
Voraussetzungen
Bevor Sie beginnen, stellen Sie sicher, dass Sie die folgenden Anforderungen erfüllen:
- Ein gültiger API-Schlüssel
- Grundlegende Kenntnisse in der Programmierung
- Zugriff auf die Dokumentation unter API-Dokumentation
Erste Schritte
Um die API zu verwenden, folgen Sie diesen Schritten:
- Registrieren Sie sich für einen API-Schlüssel.
- Richten Sie Ihre Entwicklungsumgebung ein.
- Testen Sie die Verbindung mit einem einfachen API-Aufruf.
[!NOTE] Weitere Details finden Sie im Abschnitt "Häufige Fragen".
Häufige Fehler
Fehler 401: Nicht autorisiert
Dieser Fehler tritt auf, wenn der API-Schlüssel fehlt oder ungültig ist. Überprüfen Sie, ob Sie den richtigen Schlüssel verwenden.
[!WARNING] Teilen Sie Ihren API-Schlüssel niemals öffentlich.
Fehler 404: Nicht gefunden
Dieser Fehler bedeutet, dass die angeforderte Ressource nicht existiert. Stellen Sie sicher, dass die URL korrekt ist.
Best Practices
- Verwenden Sie Caching: Reduzieren Sie die Anzahl der API-Aufrufe, indem Sie Ergebnisse zwischenspeichern.
- Überwachen Sie die Nutzung: Behalten Sie Ihre API-Nutzung im Auge, um die Limits nicht zu überschreiten.
- Fehlerbehandlung: Implementieren Sie eine robuste Fehlerbehandlung, um Ausfallzeiten zu minimieren.
[!TIP] Nutzen Sie die Debugging-Tools, die in der Dokumentation beschrieben sind.
Genres
Die API unterstützt eine Vielzahl von Musikgenres. Hier sind einige Beispiele:
- Pop
- Rock
- Jazz
- Klassik
- Hip-Hop
- Elektronisch
Fazit
Die API bietet leistungsstarke Funktionen, die Ihnen helfen, Ihre Anwendungen zu verbessern. Befolgen Sie die Best Practices und konsultieren Sie die Dokumentation, um das Beste aus der API herauszuholen.
[!IMPORTANT] Bei Fragen oder Problemen wenden Sie sich bitte an den Support.
df = df[df['artist_top_genre'] != 'Missing']
top = df['artist_top_genre'].value_counts()
plt.figure(figsize=(10,7))
sns.barplot(x=top.index,y=top.values)
plt.xticks(rotation=45)
plt.title('Top genres',color = 'blue')
df = df[(df['artist_top_genre'] == 'afro dancehall') | (df['artist_top_genre'] == 'afropop') | (df['artist_top_genre'] == 'nigerian pop')]
df = df[(df['popularity'] > 0)]
top = df['artist_top_genre'].value_counts()
plt.figure(figsize=(10,7))
sns.barplot(x=top.index,y=top.values)
plt.xticks(rotation=45)
plt.title('Top genres',color = 'blue')
corrmat = df.corr()
f, ax = plt.subplots(figsize=(12, 9))
sns.heatmap(corrmat, vmax=.8, square=True);
sns.set_theme(style="ticks")
# Show the joint distribution using kernel density estimation
g = sns.jointplot(
data=df,
x="popularity", y="danceability", hue="artist_top_genre",
kind="kde",
)
Im Allgemeinen stimmen die drei Genres in Bezug auf ihre Beliebtheit und Tanzbarkeit überein. Ein Streudiagramm mit denselben Achsen zeigt ein ähnliches Muster der Konvergenz. Versuchen Sie ein Streudiagramm, um die Verteilung der Daten pro Genre zu überprüfen.
sns.FacetGrid(df, hue="artist_top_genre", size=5) \
.map(plt.scatter, "popularity", "danceability") \
.add_legend()
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Nigerianische Musik von Spotify extrahiert - eine Analyse
Clustering ist eine Art des Unsupervised Learning, das davon ausgeht, dass ein Datensatz nicht beschriftet ist oder dass seine Eingaben nicht mit vordefinierten Ausgaben übereinstimmen. Es verwendet verschiedene Algorithmen, um unbeschriftete Daten zu sortieren und Gruppierungen basierend auf Mustern zu erstellen, die es in den Daten erkennt.
Einleitung
Clustering ist sehr nützlich für die Datenexploration. Schauen wir, ob es dabei helfen kann, Trends und Muster im Musikgeschmack des nigerianischen Publikums zu entdecken.
> ✅ Nehmen Sie sich eine Minute Zeit, um über die Einsatzmöglichkeiten von Clustering nachzudenken. Im Alltag passiert Clustering, wenn Sie einen Wäschehaufen haben und die Kleidung Ihrer Familienmitglieder sortieren müssen 🧦👕👖🩲. In der Datenwissenschaft passiert Clustering, wenn versucht wird, die Vorlieben eines Nutzers zu analysieren oder die Eigenschaften eines unbeschrifteten Datensatzes zu bestimmen. Clustering hilft gewissermaßen, Chaos zu ordnen, wie eine Sockenschublade.
Im beruflichen Umfeld kann Clustering beispielsweise für die Marktsegmentierung verwendet werden, um herauszufinden, welche Altersgruppen welche Artikel kaufen. Ein weiterer Anwendungsfall wäre die Anomalieerkennung, etwa um Betrug in einem Datensatz mit Kreditkartentransaktionen aufzudecken. Oder Sie könnten Clustering verwenden, um Tumore in einer Reihe medizinischer Scans zu identifizieren.
✅ Denken Sie eine Minute darüber nach, wie Sie Clustering „in freier Wildbahn“ erlebt haben könnten, etwa im Bankwesen, E-Commerce oder Geschäftsbereich.
> 🎓 Interessanterweise stammt die Clusteranalyse aus den Bereichen Anthropologie und Psychologie der 1930er Jahre. Können Sie sich vorstellen, wie sie damals eingesetzt wurde?
Alternativ könnten Sie Clustering verwenden, um Suchergebnisse zu gruppieren – beispielsweise nach Einkaufslinks, Bildern oder Bewertungen. Clustering ist nützlich, wenn Sie einen großen Datensatz haben, den Sie reduzieren und auf dem Sie eine detailliertere Analyse durchführen möchten. Die Technik kann also genutzt werden, um Daten zu verstehen, bevor andere Modelle erstellt werden.
✅ Sobald Ihre Daten in Clustern organisiert sind, weisen Sie ihnen eine Cluster-ID zu. Diese Technik kann nützlich sein, um die Privatsphäre eines Datensatzes zu wahren; Sie können sich stattdessen auf einen Datenpunkt durch seine Cluster-ID beziehen, anstatt durch aufschlussreichere identifizierbare Daten. Können Sie sich andere Gründe vorstellen, warum Sie sich auf eine Cluster-ID anstelle anderer Elemente des Clusters beziehen würden, um sie zu identifizieren?
Einstieg ins Clustering
> 🎓 Wie wir Cluster erstellen, hängt stark davon ab, wie wir die Datenpunkte in Gruppen zusammenfassen. Lassen Sie uns einige Begriffe klären: > > 🎓 'Transduktiv' vs. 'induktiv' > > Transduktive Inferenz wird aus beobachteten Trainingsfällen abgeleitet, die auf spezifische Testfälle abgebildet werden. Induktive Inferenz wird aus Trainingsfällen abgeleitet, die auf allgemeine Regeln abgebildet werden, die dann auf Testfälle angewendet werden. > > Ein Beispiel: Stellen Sie sich vor, Sie haben einen Datensatz, der nur teilweise beschriftet ist. Einige Dinge sind „Schallplatten“, einige „CDs“ und einige sind leer. Ihre Aufgabe ist es, die leeren Felder zu beschriften. Wenn Sie einen induktiven Ansatz wählen, würden Sie ein Modell trainieren, das nach „Schallplatten“ und „CDs“ sucht, und diese Beschriftungen auf Ihre unbeschrifteten Daten anwenden. Dieser Ansatz hätte Schwierigkeiten, Dinge zu klassifizieren, die tatsächlich „Kassetten“ sind. Ein transduktiver Ansatz hingegen geht mit diesen unbekannten Daten effektiver um, da er ähnliche Elemente gruppiert und dann einer Gruppe ein Label zuweist. In diesem Fall könnten Cluster „runde Musikdinge“ und „eckige Musikdinge“ widerspiegeln. > > 🎓 'Nicht-flache' vs. 'flache' Geometrie > > Abgeleitet aus der mathematischen Terminologie, bezieht sich nicht-flache vs. flache Geometrie auf die Messung von Abständen zwischen Punkten entweder durch „flache“ (euklidische) oder „nicht-flache“ (nicht-euklidische) geometrische Methoden. > > „Flach“ bezieht sich in diesem Kontext auf die euklidische Geometrie (Teile davon werden als „Ebene Geometrie“ gelehrt), und nicht-flach auf die nicht-euklidische Geometrie. Was hat Geometrie mit maschinellem Lernen zu tun? Nun, als zwei Felder, die in der Mathematik verwurzelt sind, muss es eine gemeinsame Methode geben, um Abstände zwischen Punkten in Clustern zu messen, und das kann auf eine „flache“ oder „nicht-flache“ Weise geschehen, abhängig von der Natur der Daten. Euklidische Abstände werden als die Länge eines Liniensegments zwischen zwei Punkten gemessen. Nicht-euklidische Abstände werden entlang einer Kurve gemessen. Wenn Ihre Daten, visualisiert, nicht auf einer Ebene zu existieren scheinen, müssen Sie möglicherweise einen spezialisierten Algorithmus verwenden, um sie zu verarbeiten.
<p > <img src="../../images/flat-nonflat.png" width="600"/> <figcaption>Infografik von Dasani Madipalli</figcaption>
> 🎓 'Abstände' > > Cluster werden durch ihre Distanzmatrix definiert, z. B. die Abstände zwischen Punkten. Diese Abstände können auf verschiedene Weise gemessen werden. Euklidische Cluster werden durch den Durchschnitt der Punktwerte definiert und enthalten einen „Zentroid“ oder Mittelpunkt. Abstände werden somit durch die Entfernung zu diesem Zentroid gemessen. Nicht-euklidische Abstände beziehen sich auf „Clustroids“, den Punkt, der anderen Punkten am nächsten liegt. Clustroids können wiederum auf verschiedene Arten definiert werden. > > 🎓 'Eingeschränkt' > > Eingeschränktes Clustering führt „semi-supervised“ Lernen in diese unüberwachte Methode ein. Die Beziehungen zwischen Punkten werden als „kann nicht verknüpft werden“ oder „muss verknüpft werden“ markiert, sodass einige Regeln auf den Datensatz angewendet werden. > > Ein Beispiel: Wenn ein Algorithmus auf einen Stapel unbeschrifteter oder halb beschrifteter Daten losgelassen wird, könnten die Cluster, die er erzeugt, von schlechter Qualität sein. In dem obigen Beispiel könnten die Cluster „runde Musikdinge“, „eckige Musikdinge“, „dreieckige Dinge“ und „Kekse“ gruppieren. Wenn einige Einschränkungen oder Regeln vorgegeben werden („das Element muss aus Plastik sein“, „das Element muss Musik produzieren können“), kann dies helfen, den Algorithmus zu besseren Entscheidungen zu führen. > > 🎓 'Dichte' > > Daten, die „rauschhaft“ sind, werden als „dicht“ betrachtet. Die Abstände zwischen Punkten in jedem ihrer Cluster können sich bei der Untersuchung als mehr oder weniger dicht oder „gedrängt“ erweisen, und daher müssen diese Daten mit der geeigneten Clustering-Methode analysiert werden. Dieser Artikel zeigt den Unterschied zwischen der Verwendung von K-Means-Clustering und HDBSCAN-Algorithmen zur Untersuchung eines rauschhaften Datensatzes mit ungleichmäßiger Clusterdichte.
Vertiefen Sie Ihr Verständnis von Clustering-Techniken in diesem Learn-Modul
Clustering-Algorithmen
Es gibt über 100 Clustering-Algorithmen, und ihre Verwendung hängt von der Art der vorliegenden Daten ab. Lassen Sie uns einige der wichtigsten besprechen:
- Hierarchisches Clustering. Wenn ein Objekt basierend auf seiner Nähe zu einem nahegelegenen Objekt klassifiziert wird, anstatt zu einem weiter entfernten, werden Cluster basierend auf den Abständen ihrer Mitglieder zu anderen Objekten gebildet. Hierarchisches Clustering zeichnet sich dadurch aus, dass zwei Cluster wiederholt kombiniert werden.
<p > <img src="../../images/hierarchical.png" width="600"/> <figcaption>Infografik von Dasani Madipalli</figcaption>
- Zentroid-Clustering. Dieser beliebte Algorithmus erfordert die Wahl von „k“, oder der Anzahl der zu bildenden Cluster, wonach der Algorithmus den Mittelpunkt eines Clusters bestimmt und Daten um diesen Punkt sammelt. K-Means-Clustering ist eine beliebte Version des Zentroid-Clustering, die einen Datensatz in vordefinierte K-Gruppen unterteilt. Der Mittelpunkt wird durch den nächstgelegenen Mittelwert bestimmt, daher der Name. Der quadrierte Abstand vom Cluster wird minimiert.
<p > <img src="../../images/centroid.png" width="600"/> <figcaption>Infografik von Dasani Madipalli</figcaption>
-
Verteilungsbasiertes Clustering. Basierend auf statistischen Modellen konzentriert sich das verteilungsbasierte Clustering darauf, die Wahrscheinlichkeit zu bestimmen, dass ein Datenpunkt zu einem Cluster gehört, und ihn entsprechend zuzuweisen. Gaussian-Mischmethoden gehören zu diesem Typ.
-
Dichtebasiertes Clustering. Datenpunkte werden basierend auf ihrer Dichte oder ihrer Gruppierung um andere Punkte herum Clustern zugewiesen. Datenpunkte, die weit von der Gruppe entfernt sind, werden als Ausreißer oder Rauschen betrachtet. DBSCAN, Mean-Shift und OPTICS gehören zu diesem Typ des Clustering.
-
Rasterbasiertes Clustering. Für mehrdimensionale Datensätze wird ein Raster erstellt, und die Daten werden auf die Zellen des Rasters verteilt, wodurch Cluster entstehen.
Der beste Weg, Clustering zu lernen, ist, es selbst auszuprobieren. Genau das werden Sie in dieser Übung tun.
Wir benötigen einige Pakete, um dieses Modul abzuschließen. Sie können sie wie folgt installieren: install.packages(c('tidyverse', 'tidymodels', 'DataExplorer', 'summarytools', 'plotly', 'paletteer', 'corrplot', 'patchwork'))
Alternativ überprüft das folgende Skript, ob Sie die für dieses Modul erforderlichen Pakete haben, und installiert sie für Sie, falls einige fehlen.
suppressWarnings(if(!require("pacman")) install.packages("pacman"))
pacman::p_load('tidyverse', 'tidymodels', 'DataExplorer', 'summarytools', 'plotly', 'paletteer', 'corrplot', 'patchwork')
Übung - Daten clustern
Clustering als Technik wird durch eine geeignete Visualisierung erheblich erleichtert, also beginnen wir damit, unsere Musikdaten zu visualisieren. Diese Übung wird uns helfen zu entscheiden, welche der Clustering-Methoden wir am effektivsten für die Art dieser Daten verwenden sollten.
Legen wir direkt los und importieren die Daten.
# Load the core tidyverse and make it available in your current R session
library(tidyverse)
# Import the data into a tibble
df <- read_csv(file = "https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/5-Clustering/data/nigerian-songs.csv")
# View the first 5 rows of the data set
df %>%
slice_head(n = 5)
Manchmal möchten wir etwas mehr Informationen über unsere Daten erhalten. Wir können uns die Daten und deren Struktur mit der Funktion glimpse() ansehen:
# Glimpse into the data set
df %>%
glimpse()
Gute Arbeit!💪
Wir können sehen, dass glimpse() die Gesamtanzahl der Zeilen (Beobachtungen) und Spalten (Variablen) anzeigt, gefolgt von den ersten Einträgen jeder Variable in einer Zeile nach dem Variablennamen. Zusätzlich wird der Datentyp der Variable direkt nach dem Variablennamen in < > angegeben.
DataExplorer::introduce() kann diese Informationen übersichtlich zusammenfassen:
# Describe basic information for our data
df %>%
introduce()
# A visual display of the same
df %>%
plot_intro()
Super! Wir haben gerade festgestellt, dass unsere Daten keine fehlenden Werte enthalten.
Während wir dabei sind, können wir gängige Statistiken zur zentralen Tendenz (z. B. Mittelwert und Median) sowie Streuungsmaße (z. B. Standardabweichung) mit summarytools::descr() untersuchen.
# Describe common statistics
df %>%
descr(stats = "common")
Schauen wir uns die allgemeinen Werte der Daten an. Beachten Sie, dass die Beliebtheit 0 sein kann, was Songs ohne Ranking zeigt. Diese werden wir gleich entfernen.
> 🤔 Wenn wir mit Clustering arbeiten, einer unüberwachten Methode, die keine gelabelten Daten benötigt, warum zeigen wir dann diese Daten mit Labels? In der Phase der Datenexploration sind sie hilfreich, aber für die Funktion der Clustering-Algorithmen sind sie nicht notwendig.
1. Beliebte Genres erkunden
Lassen Sie uns die beliebtesten Genres 🎶 herausfinden, indem wir die Häufigkeit ihrer Vorkommen zählen.
# Popular genres
top_genres <- df %>%
count(artist_top_genre, sort = TRUE) %>%
# Encode to categorical and reorder the according to count
mutate(artist_top_genre = factor(artist_top_genre) %>% fct_inorder())
# Print the top genres
top_genres
Das hat gut geklappt! Man sagt, ein Bild sagt mehr als tausend Zeilen eines Dataframes (eigentlich sagt das niemand 😅). Aber du verstehst, was ich meine, oder?
Eine Möglichkeit, kategoriale Daten (Zeichen- oder Faktorvariablen) zu visualisieren, ist die Verwendung von Balkendiagrammen. Lass uns ein Balkendiagramm der Top 10 Genres erstellen:
# Change the default gray theme
theme_set(theme_light())
# Visualize popular genres
top_genres %>%
slice(1:10) %>%
ggplot(mapping = aes(x = artist_top_genre, y = n,
fill = artist_top_genre)) +
geom_col(alpha = 0.8) +
paletteer::scale_fill_paletteer_d("rcartocolor::Vivid") +
ggtitle("Top genres") +
theme(plot.title = element_text(hjust = 0.5),
# Rotates the X markers (so we can read them)
axis.text.x = element_text(angle = 90))
Jetzt ist es viel einfacher zu erkennen, dass wir fehlende Genres haben 🧐!
> Eine gute Visualisierung zeigt dir Dinge, die du nicht erwartet hast, oder wirft neue Fragen zu den Daten auf - Hadley Wickham und Garrett Grolemund, R For Data Science
Beachte: Wenn das Top-Genre als Missing beschrieben wird, bedeutet das, dass Spotify es nicht klassifiziert hat. Also lass uns das entfernen.
# Visualize popular genres
top_genres %>%
filter(artist_top_genre != "Missing") %>%
slice(1:10) %>%
ggplot(mapping = aes(x = artist_top_genre, y = n,
fill = artist_top_genre)) +
geom_col(alpha = 0.8) +
paletteer::scale_fill_paletteer_d("rcartocolor::Vivid") +
ggtitle("Top genres") +
theme(plot.title = element_text(hjust = 0.5),
# Rotates the X markers (so we can read them)
axis.text.x = element_text(angle = 90))
Aus der kleinen Datenexploration lernen wir, dass die drei führenden Genres dieses Dataset dominieren. Konzentrieren wir uns auf afro dancehall, afropop und nigerian pop, und filtern zusätzlich das Dataset, um alles mit einem Popularitätswert von 0 zu entfernen (das bedeutet, es wurde im Dataset nicht mit einer Popularität klassifiziert und kann für unsere Zwecke als Rauschen betrachtet werden):
nigerian_songs <- df %>%
# Concentrate on top 3 genres
filter(artist_top_genre %in% c("afro dancehall", "afropop","nigerian pop")) %>%
# Remove unclassified observations
filter(popularity != 0)
# Visualize popular genres
nigerian_songs %>%
count(artist_top_genre) %>%
ggplot(mapping = aes(x = artist_top_genre, y = n,
fill = artist_top_genre)) +
geom_col(alpha = 0.8) +
paletteer::scale_fill_paletteer_d("ggsci::category10_d3") +
ggtitle("Top genres") +
theme(plot.title = element_text(hjust = 0.5))
Lassen Sie uns prüfen, ob es eine offensichtliche lineare Beziehung zwischen den numerischen Variablen in unserem Datensatz gibt. Diese Beziehung wird mathematisch durch die Korrelationsstatistik quantifiziert.
Die Korrelationsstatistik ist ein Wert zwischen -1 und 1, der die Stärke einer Beziehung angibt. Werte über 0 weisen auf eine positive Korrelation hin (hohe Werte einer Variablen gehen tendenziell mit hohen Werten der anderen einher), während Werte unter 0 auf eine negative Korrelation hinweisen (hohe Werte einer Variablen gehen tendenziell mit niedrigen Werten der anderen einher).
# Narrow down to numeric variables and fid correlation
corr_mat <- nigerian_songs %>%
select(where(is.numeric)) %>%
cor()
# Visualize correlation matrix
corrplot(corr_mat, order = 'AOE', col = c('white', 'black'), bg = 'gold2')
Die Daten sind nicht stark korreliert, außer zwischen energy und loudness, was Sinn ergibt, da laute Musik normalerweise ziemlich energiegeladen ist. Popularity hat eine Verbindung zu release date, was ebenfalls Sinn ergibt, da neuere Songs wahrscheinlich beliebter sind. Länge und Energie scheinen ebenfalls eine Korrelation zu haben.
Es wird interessant sein zu sehen, was ein Clustering-Algorithmus aus diesen Daten machen kann!
> 🎓 Beachten Sie, dass Korrelation keine Kausalität impliziert! Wir haben einen Beweis für Korrelation, aber keinen Beweis für Kausalität. Eine amüsante Webseite bietet einige Visualisierungen, die diesen Punkt verdeutlichen.
2. Verteilung der Daten erkunden
Lassen Sie uns einige subtilere Fragen stellen. Unterscheiden sich die Genres signifikant in ihrer Wahrnehmung der Tanzbarkeit, basierend auf ihrer Beliebtheit? Untersuchen wir die Datenverteilung unserer drei beliebtesten Genres hinsichtlich Beliebtheit und Tanzbarkeit entlang einer gegebenen x- und y-Achse mithilfe von Dichteplots.
# Perform 2D kernel density estimation
density_estimate_2d <- nigerian_songs %>%
ggplot(mapping = aes(x = popularity, y = danceability, color = artist_top_genre)) +
geom_density_2d(bins = 5, size = 1) +
paletteer::scale_color_paletteer_d("RSkittleBrewer::wildberry") +
xlim(-20, 80) +
ylim(0, 1.2)
# Density plot based on the popularity
density_estimate_pop <- nigerian_songs %>%
ggplot(mapping = aes(x = popularity, fill = artist_top_genre, color = artist_top_genre)) +
geom_density(size = 1, alpha = 0.5) +
paletteer::scale_fill_paletteer_d("RSkittleBrewer::wildberry") +
paletteer::scale_color_paletteer_d("RSkittleBrewer::wildberry") +
theme(legend.position = "none")
# Density plot based on the danceability
density_estimate_dance <- nigerian_songs %>%
ggplot(mapping = aes(x = danceability, fill = artist_top_genre, color = artist_top_genre)) +
geom_density(size = 1, alpha = 0.5) +
paletteer::scale_fill_paletteer_d("RSkittleBrewer::wildberry") +
paletteer::scale_color_paletteer_d("RSkittleBrewer::wildberry")
# Patch everything together
library(patchwork)
density_estimate_2d / (density_estimate_pop + density_estimate_dance)
Wir sehen, dass es konzentrische Kreise gibt, die sich unabhängig vom Genre ausrichten. Könnte es sein, dass sich die nigerianischen Vorlieben bei einem bestimmten Grad an Tanzbarkeit für dieses Genre treffen?
Im Allgemeinen stimmen die drei Genres in Bezug auf ihre Beliebtheit und Tanzbarkeit überein. Es wird eine Herausforderung sein, Cluster in diesen lose ausgerichteten Daten zu identifizieren. Schauen wir, ob ein Streudiagramm dabei helfen kann.
# A scatter plot of popularity and danceability
scatter_plot <- nigerian_songs %>%
ggplot(mapping = aes(x = popularity, y = danceability, color = artist_top_genre, shape = artist_top_genre)) +
geom_point(size = 2, alpha = 0.8) +
paletteer::scale_color_paletteer_d("futurevisions::mars")
# Add a touch of interactivity
ggplotly(scatter_plot)
Ein Streudiagramm der gleichen Achsen zeigt ein ähnliches Muster der Konvergenz.
Im Allgemeinen können Streudiagramme für das Clustering verwendet werden, um Datencluster darzustellen. Daher ist es sehr nützlich, diese Art der Visualisierung zu beherrschen. In der nächsten Lektion werden wir diese gefilterten Daten verwenden und k-means Clustering einsetzen, um Gruppen in diesen Daten zu entdecken, die auf interessante Weise überlappen.
🚀 Herausforderung
Zur Vorbereitung auf die nächste Lektion erstelle ein Diagramm über die verschiedenen Clustering-Algorithmen, die du möglicherweise entdecken und in einer Produktionsumgebung verwenden könntest. Welche Arten von Problemen versucht das Clustering zu lösen?
Quiz nach der Vorlesung
Überblick & Selbststudium
Bevor du Clustering-Algorithmen anwendest, wie wir gelernt haben, ist es eine gute Idee, die Natur deines Datensatzes zu verstehen. Lies mehr zu diesem Thema hier.
Vertiefe dein Verständnis von Clustering-Techniken:
-
Trainiere und evaluiere Clustering-Modelle mit Tidymodels und Freunden
-
Bradley Boehmke & Brandon Greenwell, Hands-On Machine Learning with R.
Aufgabe
Recherchiere andere Visualisierungen für Clustering
DANKE AN:
Jen Looper für die Erstellung der ursprünglichen Python-Version dieses Moduls ♥️
Dasani Madipalli für die Erstellung der großartigen Illustrationen, die maschinelle Lernkonzepte verständlicher und leichter nachvollziehbar machen.
Viel Spaß beim Lernen,
Eric, Gold Microsoft Learn Student Ambassador.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Probieren Sie verschiedene Clustering-Methoden aus
Anweisungen
In dieser Lektion haben Sie etwas über K-Means-Clustering gelernt. Manchmal ist K-Means für Ihre Daten nicht geeignet. Erstellen Sie ein Notebook mit Daten entweder aus diesen Lektionen oder aus einer anderen Quelle (geben Sie die Quelle an) und zeigen Sie eine andere Clustering-Methode, die NICHT K-Means verwendet. Was haben Sie gelernt?
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Notebook wird mit einem gut dokumentierten Clustering-Modell präsentiert | Ein Notebook wird ohne gute Dokumentation und/oder unvollständig präsentiert | Unvollständige Arbeit wird eingereicht |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
pip install seaborn
Beginnen Sie dort, wo wir in der letzten Lektion aufgehört haben, mit importierten und gefilterten Daten.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
df = pd.read_csv("../data/nigerian-songs.csv")
df.head()
Wir werden uns nur auf 3 Genres konzentrieren. Vielleicht können wir 3 Cluster erstellen!
df = df[(df['artist_top_genre'] == 'afro dancehall') | (df['artist_top_genre'] == 'afropop') | (df['artist_top_genre'] == 'nigerian pop')]
df = df[(df['popularity'] > 0)]
top = df['artist_top_genre'].value_counts()
plt.figure(figsize=(10,7))
sns.barplot(x=top.index,y=top.values)
plt.xticks(rotation=45)
plt.title('Top genres',color = 'blue')
df.head()
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
K-Means Clustering
Quiz vor der Lektion
In dieser Lektion lernst du, wie man mit Scikit-learn und dem nigerianischen Musikdatensatz, den du zuvor importiert hast, Cluster erstellt. Wir behandeln die Grundlagen von K-Means für das Clustering. Denke daran, dass es, wie du in der vorherigen Lektion gelernt hast, viele Möglichkeiten gibt, mit Clustern zu arbeiten, und die Methode, die du wählst, hängt von deinen Daten ab. Wir werden K-Means ausprobieren, da es die gängigste Clustering-Technik ist. Los geht's!
Begriffe, die du kennenlernen wirst:
- Silhouette-Score
- Elbow-Methode
- Trägheit (Inertia)
- Varianz
Einführung
K-Means Clustering ist eine Methode aus dem Bereich der Signalverarbeitung. Sie wird verwendet, um Datengruppen in 'k' Cluster zu unterteilen, basierend auf einer Reihe von Beobachtungen. Jede Beobachtung dient dazu, einen bestimmten Datenpunkt dem nächstgelegenen 'Mittelwert' oder dem Mittelpunkt eines Clusters zuzuordnen.
Die Cluster können als Voronoi-Diagramme visualisiert werden, die einen Punkt (oder 'Seed') und dessen zugehörige Region umfassen.

> Infografik von Jen Looper
Der K-Means-Clustering-Prozess läuft in einem dreistufigen Verfahren ab:
- Der Algorithmus wählt eine Anzahl von k-Mittelpunkten aus, indem er Stichproben aus dem Datensatz zieht. Danach wiederholt er:
- Er ordnet jede Stichprobe dem nächstgelegenen Schwerpunkt zu.
- Er erstellt neue Schwerpunkte, indem er den Mittelwert aller Stichproben berechnet, die den vorherigen Schwerpunkten zugeordnet wurden.
- Dann berechnet er die Differenz zwischen den neuen und alten Schwerpunkten und wiederholt den Vorgang, bis die Schwerpunkte stabilisiert sind.
Ein Nachteil der Verwendung von K-Means ist, dass du 'k', also die Anzahl der Schwerpunkte, festlegen musst. Glücklicherweise hilft die 'Elbow-Methode', einen guten Ausgangswert für 'k' zu schätzen. Du wirst sie gleich ausprobieren.
Voraussetzung
Du wirst in der Datei notebook.ipynb arbeiten, die den Datenimport und die vorläufige Bereinigung enthält, die du in der letzten Lektion durchgeführt hast.
Übung - Vorbereitung
Beginne damit, die Song-Daten noch einmal anzusehen.
-
Erstelle ein Boxplot, indem du
boxplot()für jede Spalte aufrufst:```python plt.figure(figsize=(20,20), dpi=200)
plt.subplot(4,3,1) sns.boxplot(x = 'popularity', data = df)
plt.subplot(4,3,2) sns.boxplot(x = 'acousticness', data = df)
plt.subplot(4,3,3) sns.boxplot(x = 'energy', data = df)
plt.subplot(4,3,4) sns.boxplot(x = 'instrumentalness', data = df)
plt.subplot(4,3,5) sns.boxplot(x = 'liveness', data = df)
plt.subplot(4,3,6) sns.boxplot(x = 'loudness', data = df)
plt.subplot(4,3,7) sns.boxplot(x = 'speechiness', data = df)
plt.subplot(4,3,8) sns.boxplot(x = 'tempo', data = df)
plt.subplot(4,3,9) sns.boxplot(x = 'time_signature', data = df)
plt.subplot(4,3,10) sns.boxplot(x = 'danceability', data = df)
plt.subplot(4,3,11) sns.boxplot(x = 'length', data = df)
plt.subplot(4,3,12) sns.boxplot(x = 'release_date', data = df) ```
Diese Daten sind etwas verrauscht: Wenn du jede Spalte als Boxplot betrachtest, kannst du Ausreißer erkennen.

Du könntest den Datensatz durchgehen und diese Ausreißer entfernen, aber das würde die Daten ziemlich minimieren.
-
Wähle vorerst aus, welche Spalten du für deine Clustering-Übung verwenden möchtest. Wähle solche mit ähnlichen Bereichen und kodiere die Spalte
artist_top_genreals numerische Daten:```python from sklearn.preprocessing import LabelEncoder le = LabelEncoder()
X = df.loc[:, ('artist_top_genre','popularity','danceability','acousticness','loudness','energy')]
y = df['artist_top_genre']
X['artist_top_genre'] = le.fit_transform(X['artist_top_genre'])
y = le.transform(y) ```
-
Jetzt musst du festlegen, wie viele Cluster du anstreben möchtest. Du weißt, dass es 3 Song-Genres gibt, die wir aus dem Datensatz herausgearbeitet haben, also probiere es mit 3:
```python from sklearn.cluster import KMeans
nclusters = 3 seed = 0
km = KMeans(n_clusters=nclusters, random_state=seed) km.fit(X)
Predict the cluster for each data point
y_cluster_kmeans = km.predict(X) y_cluster_kmeans ```
Du siehst ein Array, das die vorhergesagten Cluster (0, 1 oder 2) für jede Zeile des Dataframes ausgibt.
-
Verwende dieses Array, um einen 'Silhouette-Score' zu berechnen:
python from sklearn import metrics score = metrics.silhouette_score(X, y_cluster_kmeans) score
Silhouette-Score
Suche nach einem Silhouette-Score, der näher bei 1 liegt. Dieser Score variiert zwischen -1 und 1, und wenn der Score 1 ist, ist das Cluster dicht und gut von anderen Clustern getrennt. Ein Wert nahe 0 repräsentiert sich überlappende Cluster mit Stichproben, die sehr nahe an der Entscheidungsgrenze der benachbarten Cluster liegen. (Quelle)
Unser Score ist 0,53, also genau in der Mitte. Das zeigt, dass unsere Daten nicht besonders gut für diese Art von Clustering geeignet sind, aber lass uns weitermachen.
Übung - Ein Modell erstellen
-
Importiere
KMeansund starte den Clustering-Prozess.```python from sklearn.cluster import KMeans wcss = []
for i in range(1, 11): kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42) kmeans.fit(X) wcss.append(kmeans.inertia_)
```
Es gibt einige Teile, die einer Erklärung bedürfen.
> 🎓 range: Dies sind die Iterationen des Clustering-Prozesses.
> 🎓 random_state: "Bestimmt die Zufallszahlengenerierung für die Initialisierung der Schwerpunkte." Quelle
> 🎓 WCSS: "within-cluster sums of squares" misst den quadrierten durchschnittlichen Abstand aller Punkte innerhalb eines Clusters zum Cluster-Schwerpunkt. Quelle.
> 🎓 Trägheit (Inertia): K-Means-Algorithmen versuchen, Schwerpunkte so zu wählen, dass die 'Trägheit' minimiert wird, "ein Maß dafür, wie intern kohärent Cluster sind." Quelle. Der Wert wird bei jeder Iteration zur WCSS-Variablen hinzugefügt.
> 🎓 k-means++: In Scikit-learn kannst du die 'k-means++'-Optimierung verwenden, die "die Schwerpunkte so initialisiert, dass sie (im Allgemeinen) weit voneinander entfernt sind, was wahrscheinlich bessere Ergebnisse als eine zufällige Initialisierung liefert."
Elbow-Methode
Zuvor hast du angenommen, dass du 3 Cluster wählen solltest, da du 3 Song-Genres anvisiert hast. Aber ist das wirklich der Fall?
-
Verwende die 'Elbow-Methode', um sicherzugehen.
python plt.figure(figsize=(10,5)) sns.lineplot(x=range(1, 11), y=wcss, marker='o', color='red') plt.title('Elbow') plt.xlabel('Number of clusters') plt.ylabel('WCSS') plt.show()Verwende die
wcss-Variable, die du im vorherigen Schritt erstellt hast, um ein Diagramm zu erstellen, das zeigt, wo der 'Knick' im Ellbogen liegt, der die optimale Anzahl von Clustern anzeigt. Vielleicht sind es tatsächlich 3!
Übung - Die Cluster anzeigen
-
Wiederhole den Prozess, diesmal mit drei Clustern, und zeige die Cluster als Streudiagramm an:
python from sklearn.cluster import KMeans kmeans = KMeans(n_clusters = 3) kmeans.fit(X) labels = kmeans.predict(X) plt.scatter(df['popularity'],df['danceability'],c = labels) plt.xlabel('popularity') plt.ylabel('danceability') plt.show() -
Überprüfe die Genauigkeit des Modells:
```python labels = kmeans.labels_
correct_labels = sum(y == labels)
print("Result: %d out of %d samples were correctly labeled." % (correct_labels, y.size))
print('Accuracy score: {0:0.2f}'. format(correct_labels/float(y.size))) ```
Die Genauigkeit dieses Modells ist nicht sehr gut, und die Form der Cluster gibt dir einen Hinweis, warum.

Diese Daten sind zu unausgewogen, zu wenig korreliert, und es gibt zu viel Varianz zwischen den Spaltenwerten, um gut zu clustern. Tatsächlich werden die Cluster, die sich bilden, wahrscheinlich stark von den drei Genre-Kategorien beeinflusst, die wir oben definiert haben. Das war ein Lernprozess!
In der Dokumentation von Scikit-learn kannst du sehen, dass ein Modell wie dieses, bei dem die Cluster nicht sehr gut abgegrenzt sind, ein 'Varianz'-Problem hat:
> Infografik von Scikit-learn
Varianz
Varianz wird definiert als "der Durchschnitt der quadrierten Abweichungen vom Mittelwert" (Quelle). Im Kontext dieses Clustering-Problems bezieht sich dies darauf, dass die Zahlen unseres Datensatzes dazu neigen, sich etwas zu stark vom Mittelwert zu entfernen.
✅ Dies ist ein guter Moment, um über alle Möglichkeiten nachzudenken, wie du dieses Problem beheben könntest. Die Daten etwas mehr anpassen? Andere Spalten verwenden? Einen anderen Algorithmus ausprobieren? Tipp: Versuche, deine Daten zu skalieren, um sie zu normalisieren, und teste andere Spalten.
> Probiere diesen 'Varianzrechner' aus, um das Konzept besser zu verstehen.
🚀Herausforderung
Verbringe etwas Zeit mit diesem Notebook und passe die Parameter an. Kannst du die Genauigkeit des Modells verbessern, indem du die Daten weiter bereinigst (z. B. Ausreißer entfernst)? Du kannst Gewichte verwenden, um bestimmten Datenproben mehr Gewicht zu geben. Was kannst du sonst noch tun, um bessere Cluster zu erstellen?
Tipp: Versuche, deine Daten zu skalieren. Im Notebook gibt es auskommentierten Code, der eine Standard-Skalierung hinzufügt, um die Daten-Spalten in Bezug auf den Bereich einander ähnlicher zu machen. Du wirst feststellen, dass der Silhouette-Score zwar sinkt, aber der 'Knick' im Ellbogen-Diagramm glatter wird. Das liegt daran, dass unskalierte Daten es Daten mit weniger Varianz erlauben, mehr Gewicht zu tragen. Lies mehr über dieses Problem hier.
Quiz nach der Lektion
Rückblick & Selbststudium
Schau dir einen K-Means-Simulator wie diesen hier an. Mit diesem Tool kannst du Beispieldatenpunkte visualisieren und deren Schwerpunkte bestimmen. Du kannst die Zufälligkeit der Daten, die Anzahl der Cluster und die Anzahl der Schwerpunkte bearbeiten. Hilft dir das, eine Vorstellung davon zu bekommen, wie die Daten gruppiert werden können?
Sieh dir auch dieses Handout zu K-Means von Stanford an.
Aufgabe
Probiere verschiedene Clustering-Methoden aus
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
pip install seaborn
Beginnen Sie dort, wo wir in der letzten Lektion aufgehört haben, mit importierten und gefilterten Daten.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
df = pd.read_csv("../../data/nigerian-songs.csv")
df.head()
Wir werden uns nur auf 3 Genres konzentrieren. Vielleicht können wir 3 Cluster erstellen!
df = df[(df['artist_top_genre'] == 'afro dancehall') | (df['artist_top_genre'] == 'afropop') | (df['artist_top_genre'] == 'nigerian pop')]
df = df[(df['popularity'] > 0)]
top = df['artist_top_genre'].value_counts()
plt.figure(figsize=(10,7))
sns.barplot(x=top.index,y=top.values)
plt.xticks(rotation=45)
plt.title('Top genres',color = 'blue')
df.head()
Wie sauber sind diese Daten? Überprüfen Sie Ausreißer mithilfe von Boxplots. Wir werden uns auf Spalten mit weniger Ausreißern konzentrieren (obwohl Sie die Ausreißer bereinigen könnten). Boxplots können den Bereich der Daten anzeigen und helfen, auszuwählen, welche Spalten verwendet werden sollen. Beachten Sie, dass Boxplots keine Varianz zeigen, ein wichtiges Element für gut clusterbare Daten (https://stats.stackexchange.com/questions/91536/deduce-variance-from-boxplot).
plt.figure(figsize=(20,20), dpi=200)
plt.subplot(4,3,1)
sns.boxplot(x = 'popularity', data = df)
plt.subplot(4,3,2)
sns.boxplot(x = 'acousticness', data = df)
plt.subplot(4,3,3)
sns.boxplot(x = 'energy', data = df)
plt.subplot(4,3,4)
sns.boxplot(x = 'instrumentalness', data = df)
plt.subplot(4,3,5)
sns.boxplot(x = 'liveness', data = df)
plt.subplot(4,3,6)
sns.boxplot(x = 'loudness', data = df)
plt.subplot(4,3,7)
sns.boxplot(x = 'speechiness', data = df)
plt.subplot(4,3,8)
sns.boxplot(x = 'tempo', data = df)
plt.subplot(4,3,9)
sns.boxplot(x = 'time_signature', data = df)
plt.subplot(4,3,10)
sns.boxplot(x = 'danceability', data = df)
plt.subplot(4,3,11)
sns.boxplot(x = 'length', data = df)
plt.subplot(4,3,12)
sns.boxplot(x = 'release_date', data = df)
Wählen Sie mehrere Spalten mit ähnlichen Bereichen aus. Stellen Sie sicher, dass die Spalte artist_top_genre enthalten ist, um unsere Genres beizubehalten.
from sklearn.preprocessing import LabelEncoder, StandardScaler
le = LabelEncoder()
# scaler = StandardScaler()
X = df.loc[:, ('artist_top_genre','popularity','danceability','acousticness','loudness','energy')]
y = df['artist_top_genre']
X['artist_top_genre'] = le.fit_transform(X['artist_top_genre'])
# X = scaler.fit_transform(X)
y = le.transform(y)
from sklearn.cluster import KMeans
nclusters = 3
seed = 0
km = KMeans(n_clusters=nclusters, random_state=seed)
km.fit(X)
# Predict the cluster for each data point
y_cluster_kmeans = km.predict(X)
y_cluster_kmeans
Diese Zahlen bedeuten uns nicht viel, also lassen Sie uns einen 'Silhouette-Score' holen, um die Genauigkeit zu überprüfen. Unser Score liegt im Mittelfeld.
from sklearn import metrics
score = metrics.silhouette_score(X, y_cluster_kmeans)
score
Importieren Sie KMeans und erstellen Sie ein Modell
from sklearn.cluster import KMeans
wcss = []
for i in range(1, 11):
kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42)
kmeans.fit(X)
wcss.append(kmeans.inertia_)
Verwenden Sie dieses Modell, um mit der Elbow-Methode die beste Anzahl von Clustern zu bestimmen.
plt.figure(figsize=(10,5))
sns.lineplot(range(1, 11), wcss,marker='o',color='red')
plt.title('Elbow')
plt.xlabel('Number of clusters')
plt.ylabel('WCSS')
plt.show()
Looks like 3 is a good number after all. Fit the model again and create a scatterplot of your clusters. They do group in bunches, but they are pretty close together.
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters = 3)
kmeans.fit(X)
labels = kmeans.predict(X)
plt.scatter(df['popularity'],df['danceability'],c = labels)
plt.xlabel('popularity')
plt.ylabel('danceability')
plt.show()
Die Genauigkeit dieses Modells ist nicht schlecht, aber auch nicht großartig. Es könnte sein, dass sich die Daten nicht gut für K-Means-Clustering eignen. Sie könnten eine andere Methode ausprobieren.
labels = kmeans.labels_
correct_labels = sum(y == labels)
print("Result: %d out of %d samples were correctly labeled." % (correct_labels, y.size))
print('Accuracy score: {0:0.2f}'. format(correct_labels/float(y.size)))
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erkunde K-Means-Clustering mit R und den Prinzipien von Tidy Data.
Quiz vor der Lektion
In dieser Lektion lernst du, wie du mit dem Tidymodels-Paket und anderen Paketen aus dem R-Ökosystem (wir nennen sie Freunde 🧑🤝🧑) sowie dem nigerianischen Musikdatensatz, den du zuvor importiert hast, Cluster erstellen kannst. Wir behandeln die Grundlagen von K-Means für das Clustering. Denke daran, dass es, wie du in der vorherigen Lektion gelernt hast, viele Möglichkeiten gibt, mit Clustern zu arbeiten, und die Methode, die du wählst, von deinen Daten abhängt. Wir werden K-Means ausprobieren, da es die am häufigsten verwendete Clustering-Technik ist. Los geht's!
Begriffe, die du kennenlernen wirst:
-
Silhouettenbewertung
-
Elbow-Methode
-
Trägheit
-
Varianz
Einführung
K-Means-Clustering ist eine Methode, die aus dem Bereich der Signalverarbeitung stammt. Sie wird verwendet, um Gruppen von Daten basierend auf Ähnlichkeiten ihrer Merkmale in k Cluster zu unterteilen und zu partitionieren.
Die Cluster können als Voronoi-Diagramme visualisiert werden, die einen Punkt (oder 'Seed') und dessen entsprechende Region enthalten.
<p > <img src="../../images/voronoi.png" width="500"/> <figcaption>Infografik von Jen Looper</figcaption>
Die Schritte des K-Means-Clustering sind wie folgt:
-
Der Datenwissenschaftler beginnt damit, die gewünschte Anzahl von Clustern festzulegen, die erstellt werden sollen.
-
Anschließend wählt der Algorithmus zufällig K Beobachtungen aus dem Datensatz aus, die als anfängliche Zentren der Cluster (d. h. Zentroiden) dienen.
-
Danach wird jede der verbleibenden Beobachtungen ihrem nächstgelegenen Zentroiden zugewiesen.
-
Anschließend werden die neuen Mittelwerte jedes Clusters berechnet und der Zentroid wird zum Mittelwert verschoben.
-
Nun, da die Zentren neu berechnet wurden, wird jede Beobachtung erneut überprüft, um festzustellen, ob sie möglicherweise näher an einem anderen Cluster liegt. Alle Objekte werden erneut unter Verwendung der aktualisierten Cluster-Mittelwerte zugewiesen. Die Schritte der Clusterzuweisung und der Aktualisierung der Zentroiden werden iterativ wiederholt, bis sich die Clusterzuweisungen nicht mehr ändern (d. h. wenn Konvergenz erreicht ist). Typischerweise endet der Algorithmus, wenn jede neue Iteration zu einer vernachlässigbaren Bewegung der Zentroiden führt und die Cluster statisch werden.
<div>
> Beachte, dass aufgrund der Zufälligkeit der anfänglichen k Beobachtungen, die als Startzentroiden verwendet werden, jedes Mal, wenn wir das Verfahren anwenden, leicht unterschiedliche Ergebnisse erzielt werden können. Aus diesem Grund verwenden die meisten Algorithmen mehrere zufällige Starts und wählen die Iteration mit dem niedrigsten WCSS. Daher wird dringend empfohlen, K-Means immer mit mehreren Werten von nstart auszuführen, um ein unerwünschtes lokales Optimum zu vermeiden.
</div>
Diese kurze Animation, die die Illustrationen von Allison Horst verwendet, erklärt den Clustering-Prozess:
<p > <img src="../../images/kmeans.gif" width="550"/> <figcaption>Illustration von @allison_horst</figcaption>
Eine grundlegende Frage, die beim Clustering aufkommt, ist: Wie weißt du, in wie viele Cluster du deine Daten aufteilen sollst? Ein Nachteil der Verwendung von K-Means ist, dass du k, also die Anzahl der Zentroiden, festlegen musst. Glücklicherweise hilft die Elbow-Methode, einen guten Ausgangswert für k zu schätzen. Du wirst es gleich ausprobieren.
Voraussetzung
Wir machen genau dort weiter, wo wir in der vorherigen Lektion aufgehört haben, in der wir den Datensatz analysiert, viele Visualisierungen erstellt und den Datensatz auf interessante Beobachtungen gefiltert haben. Schau sie dir unbedingt an!
Wir benötigen einige Pakete, um dieses Modul abzuschließen. Du kannst sie wie folgt installieren: install.packages(c('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork'))
Alternativ überprüft das folgende Skript, ob du die für dieses Modul erforderlichen Pakete hast, und installiert sie für dich, falls einige fehlen.
suppressWarnings(if(!require("pacman")) install.packages("pacman"))
pacman::p_load('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork')
Los geht's!
1. Ein Tanz mit Daten: Eingrenzen auf die 3 beliebtesten Musikgenres
Dies ist eine Zusammenfassung dessen, was wir in der vorherigen Lektion gemacht haben. Lass uns ein paar Daten analysieren!
# Load the core tidyverse and make it available in your current R session
library(tidyverse)
# Import the data into a tibble
df <- read_csv(file = "https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/5-Clustering/data/nigerian-songs.csv", show_col_types = FALSE)
# Narrow down to top 3 popular genres
nigerian_songs <- df %>%
# Concentrate on top 3 genres
filter(artist_top_genre %in% c("afro dancehall", "afropop","nigerian pop")) %>%
# Remove unclassified observations
filter(popularity != 0)
# Visualize popular genres using bar plots
theme_set(theme_light())
nigerian_songs %>%
count(artist_top_genre) %>%
ggplot(mapping = aes(x = artist_top_genre, y = n,
fill = artist_top_genre)) +
geom_col(alpha = 0.8) +
paletteer::scale_fill_paletteer_d("ggsci::category10_d3") +
ggtitle("Top genres") +
theme(plot.title = element_text(hjust = 0.5))
🤩 Das lief gut!
2. Mehr Datenexploration.
Wie sauber sind diese Daten? Lassen Sie uns Ausreißer mithilfe von Boxplots überprüfen. Wir konzentrieren uns auf numerische Spalten mit weniger Ausreißern (auch wenn Sie die Ausreißer bereinigen könnten). Boxplots können den Wertebereich der Daten zeigen und helfen, auszuwählen, welche Spalten verwendet werden sollen. Beachten Sie, dass Boxplots keine Varianz darstellen, ein wichtiger Aspekt für gut clustbare Daten. Weitere Informationen finden Sie in dieser Diskussion.
Boxplots werden verwendet, um die Verteilung von numerischen Daten grafisch darzustellen. Beginnen wir also damit, alle numerischen Spalten zusammen mit den beliebten Musikgenres auszuwählen.
# Select top genre column and all other numeric columns
df_numeric <- nigerian_songs %>%
select(artist_top_genre, where(is.numeric))
# Display the data
df_numeric %>%
slice_head(n = 5)
Sehen Sie, wie der Auswahlhelfer where das so einfach macht 💁? Entdecken Sie weitere solche Funktionen hier.
Da wir für jede numerische Eigenschaft ein Boxplot erstellen werden und Schleifen vermeiden möchten, formatieren wir unsere Daten in ein längeres Format um. Dadurch können wir facets nutzen – Unterdiagramme, die jeweils einen Teil der Daten anzeigen.
# Pivot data from wide to long
df_numeric_long <- df_numeric %>%
pivot_longer(!artist_top_genre, names_to = "feature_names", values_to = "values")
# Print out data
df_numeric_long %>%
slice_head(n = 15)
Viel länger! Jetzt ist es Zeit für einige ggplots! Welches geom werden wir verwenden?
# Make a box plot
df_numeric_long %>%
ggplot(mapping = aes(x = feature_names, y = values, fill = feature_names)) +
geom_boxplot() +
facet_wrap(~ feature_names, ncol = 4, scales = "free") +
theme(legend.position = "none")
Easy-gg!
Jetzt können wir sehen, dass diese Daten etwas unruhig sind: Wenn man jede Spalte als Boxplot betrachtet, erkennt man Ausreißer. Man könnte den Datensatz durchgehen und diese Ausreißer entfernen, aber das würde die Daten ziemlich minimal machen.
Für den Moment wählen wir aus, welche Spalten wir für unsere Cluster-Übung verwenden werden. Lassen Sie uns die numerischen Spalten mit ähnlichen Bereichen auswählen. Wir könnten artist_top_genre als numerisch codieren, aber wir lassen es vorerst weg.
# Select variables with similar ranges
df_numeric_select <- df_numeric %>%
select(popularity, danceability, acousticness, loudness, energy)
# Normalize data
# df_numeric_select <- scale(df_numeric_select)
3. Berechnung von k-means Clustering in R
Wir können k-means in R mit der integrierten Funktion kmeans berechnen, siehe help("kmeans()"). Die Funktion kmeans() akzeptiert als Hauptargument einen Data Frame mit ausschließlich numerischen Spalten.
Der erste Schritt bei der Verwendung von k-means Clustering besteht darin, die Anzahl der Cluster (k) festzulegen, die in der endgültigen Lösung erzeugt werden sollen. Wir wissen, dass es 3 Musikgenres gibt, die wir aus dem Datensatz herausgearbeitet haben, also probieren wir es mit 3:
set.seed(2056)
# Kmeans clustering for 3 clusters
kclust <- kmeans(
df_numeric_select,
# Specify the number of clusters
centers = 3,
# How many random initial configurations
nstart = 25
)
# Display clustering object
kclust
Das kmeans-Objekt enthält mehrere Informationen, die in help("kmeans()") gut erklärt werden. Für den Moment konzentrieren wir uns auf einige davon. Wir sehen, dass die Daten in 3 Cluster mit den Größen 65, 110, 111 gruppiert wurden. Die Ausgabe enthält außerdem die Clusterzentren (Mittelwerte) für die 3 Gruppen über die 5 Variablen.
Der Clustering-Vektor ist die Clusterzuweisung für jede Beobachtung. Nutzen wir die Funktion augment, um die Clusterzuweisung dem ursprünglichen Datensatz hinzuzufügen.
# Add predicted cluster assignment to data set
augment(kclust, df_numeric_select) %>%
relocate(.cluster) %>%
slice_head(n = 10)
Perfekt, wir haben gerade unseren Datensatz in 3 Gruppen aufgeteilt. Aber wie gut ist unser Clustering 🤷? Schauen wir uns den Silhouette-Score an.
Silhouette-Score
Silhouette-Analyse kann verwendet werden, um die Trennungsdistanz zwischen den resultierenden Clustern zu untersuchen. Dieser Score variiert zwischen -1 und 1. Wenn der Score nahe bei 1 liegt, ist das Cluster dicht und gut von anderen Clustern getrennt. Ein Wert nahe 0 repräsentiert sich überlappende Cluster, bei denen die Datenpunkte sehr nah an der Entscheidungsgrenze der benachbarten Cluster liegen. Quelle.
Die Methode des durchschnittlichen Silhouette-Scores berechnet den durchschnittlichen Silhouette-Wert der Beobachtungen für verschiedene Werte von k. Ein hoher durchschnittlicher Silhouette-Score deutet auf ein gutes Clustering hin.
Die silhouette-Funktion im Cluster-Paket wird verwendet, um die durchschnittliche Silhouette-Breite zu berechnen.
> Der Silhouette-Score kann mit jeder Distanz-Metrik berechnet werden, wie z. B. der euklidischen Distanz oder der Manhattan-Distanz, die wir in der vorherigen Lektion besprochen haben.
# Load cluster package
library(cluster)
# Compute average silhouette score
ss <- silhouette(kclust$cluster,
# Compute euclidean distance
dist = dist(df_numeric_select))
mean(ss[, 3])
Unser Score ist 0,549, also genau in der Mitte. Das deutet darauf hin, dass unsere Daten nicht besonders gut für diese Art der Clusterbildung geeignet sind. Schauen wir, ob wir diese Vermutung visuell bestätigen können. Das factoextra-Paket stellt Funktionen (fviz_cluster()) zur Verfügung, um Cluster visuell darzustellen.
library(factoextra)
# Visualize clustering results
fviz_cluster(kclust, df_numeric_select)
Die Überlappung der Cluster zeigt, dass unsere Daten für diese Art der Clusterbildung nicht besonders gut geeignet sind, aber lassen Sie uns trotzdem weitermachen.
4. Bestimmung der optimalen Anzahl von Clustern
Eine grundlegende Frage, die bei der K-Means-Clusterbildung häufig auftritt, lautet: Ohne bekannte Klassenlabels, wie wissen wir, in wie viele Cluster die Daten unterteilt werden sollen?
Eine Möglichkeit, dies herauszufinden, besteht darin, eine Datenprobe zu verwenden, um eine Reihe von Clustering-Modellen mit einer steigenden Anzahl von Clustern zu erstellen (z. B. von 1 bis 10) und Clustering-Metriken wie den Silhouette-Score zu bewerten.
Lassen Sie uns die optimale Anzahl von Clustern bestimmen, indem wir den Clustering-Algorithmus für verschiedene Werte von k berechnen und die Summe der Quadrate innerhalb der Cluster (WCSS) bewerten. Die gesamte Summe der Quadrate innerhalb der Cluster (WCSS) misst die Kompaktheit der Clusterbildung, und wir möchten, dass sie so klein wie möglich ist. Niedrigere Werte bedeuten, dass die Datenpunkte näher beieinander liegen.
Lassen Sie uns die Auswirkungen verschiedener Werte von k, von 1 bis 10, auf diese Clusterbildung untersuchen.
# Create a series of clustering models
kclusts <- tibble(k = 1:10) %>%
# Perform kmeans clustering for 1,2,3 ... ,10 clusters
mutate(model = map(k, ~ kmeans(df_numeric_select, centers = .x, nstart = 25)),
# Farm out clustering metrics eg WCSS
glanced = map(model, ~ glance(.x))) %>%
unnest(cols = glanced)
# View clustering rsulsts
kclusts
Nun, da wir die gesamte innerhalb-Cluster-Summe der Quadrate (tot.withinss) für jeden Clustering-Algorithmus mit Zentrum k haben, verwenden wir die Elbow-Methode, um die optimale Anzahl von Clustern zu finden. Die Methode besteht darin, die WCSS als Funktion der Anzahl der Cluster zu plotten und den Knick der Kurve als die Anzahl der zu verwendenden Cluster auszuwählen.
set.seed(2056)
# Use elbow method to determine optimum number of clusters
kclusts %>%
ggplot(mapping = aes(x = k, y = tot.withinss)) +
geom_line(size = 1.2, alpha = 0.8, color = "#FF7F0EFF") +
geom_point(size = 2, color = "#FF7F0EFF")
Die Grafik zeigt eine deutliche Reduktion des WCSS (also eine größere Kompaktheit), wenn die Anzahl der Cluster von eins auf zwei steigt, sowie eine weitere merkliche Reduktion von zwei auf drei Cluster. Danach wird die Reduktion weniger ausgeprägt, was zu einem Knick 💪 im Diagramm bei etwa drei Clustern führt. Dies ist ein guter Hinweis darauf, dass es zwei bis drei einigermaßen gut getrennte Cluster von Datenpunkten gibt.
Wir können nun das Clustering-Modell extrahieren, bei dem k = 3 ist:
> pull(): wird verwendet, um eine einzelne Spalte zu extrahieren
>
> pluck(): wird verwendet, um Datenstrukturen wie Listen zu indexieren
# Extract k = 3 clustering
final_kmeans <- kclusts %>%
filter(k == 3) %>%
pull(model) %>%
pluck(1)
final_kmeans
Super! Lassen Sie uns die erhaltenen Cluster visualisieren. Lust auf etwas Interaktivität mit plotly?
# Add predicted cluster assignment to data set
results <- augment(final_kmeans, df_numeric_select) %>%
bind_cols(df_numeric %>% select(artist_top_genre))
# Plot cluster assignments
clust_plt <- results %>%
ggplot(mapping = aes(x = popularity, y = danceability, color = .cluster, shape = artist_top_genre)) +
geom_point(size = 2, alpha = 0.8) +
paletteer::scale_color_paletteer_d("ggthemes::Tableau_10")
ggplotly(clust_plt)
Vielleicht hätten wir erwartet, dass jeder Cluster (repräsentiert durch verschiedene Farben) unterschiedliche Genres (repräsentiert durch verschiedene Formen) aufweist.
Werfen wir einen Blick auf die Genauigkeit des Modells.
# Assign genres to predefined integers
label_count <- results %>%
group_by(artist_top_genre) %>%
mutate(id = cur_group_id()) %>%
ungroup() %>%
summarise(correct_labels = sum(.cluster == id))
# Print results
cat("Result:", label_count$correct_labels, "out of", nrow(results), "samples were correctly labeled.")
cat("\nAccuracy score:", label_count$correct_labels/nrow(results))
Die Genauigkeit dieses Modells ist nicht schlecht, aber auch nicht besonders gut. Es könnte daran liegen, dass die Daten sich nicht gut für K-Means-Clustering eignen. Die Daten sind zu unausgewogen, zu wenig korreliert, und es gibt zu viel Varianz zwischen den Spaltenwerten, um gut zu clustern. Tatsächlich werden die gebildeten Cluster wahrscheinlich stark von den drei oben definierten Genre-Kategorien beeinflusst oder verzerrt.
Nichtsdestotrotz war das ein ziemlich lehrreicher Prozess!
In der Dokumentation von Scikit-learn kann man sehen, dass ein Modell wie dieses, bei dem die Cluster nicht klar abgegrenzt sind, ein 'Varianz'-Problem hat:
<p > <img src="../../images/problems.png" width="500"/> <figcaption>Infografik von Scikit-learn</figcaption>
Varianz
Varianz wird definiert als "der Durchschnitt der quadrierten Abweichungen vom Mittelwert" Quelle. Im Kontext dieses Clustering-Problems bezieht sich dies darauf, dass die Zahlen in unserem Datensatz dazu neigen, sich zu stark vom Mittelwert zu entfernen.
✅ Dies ist ein großartiger Moment, um über alle Möglichkeiten nachzudenken, wie man dieses Problem beheben könnte. Die Daten noch etwas anpassen? Andere Spalten verwenden? Einen anderen Algorithmus ausprobieren? Tipp: Versuchen Sie, Ihre Daten zu skalieren, um sie zu normalisieren, und testen Sie andere Spalten.
> Probieren Sie diesen 'Varianzrechner' aus, um das Konzept besser zu verstehen.
🚀Herausforderung
Verbringen Sie etwas Zeit mit diesem Notebook und passen Sie die Parameter an. Können Sie die Genauigkeit des Modells verbessern, indem Sie die Daten weiter bereinigen (z. B. Ausreißer entfernen)? Sie können Gewichte verwenden, um bestimmten Datenproben mehr Gewicht zu geben. Was können Sie sonst noch tun, um bessere Cluster zu erstellen?
Tipp: Versuchen Sie, Ihre Daten zu skalieren. Im Notebook gibt es auskommentierten Code, der eine Standard-Skalierung hinzufügt, um die Daten-Spalten in Bezug auf den Wertebereich einander ähnlicher zu machen. Sie werden feststellen, dass der Silhouetten-Score zwar sinkt, aber der 'Knick' im Elbogen-Diagramm geglättet wird. Das liegt daran, dass unskalierte Daten es Daten mit weniger Varianz ermöglichen, mehr Gewicht zu tragen. Lesen Sie mehr über dieses Problem hier.
Quiz nach der Vorlesung
Überblick & Selbststudium
-
Schauen Sie sich einen K-Means-Simulator wie diesen hier an. Mit diesem Tool können Sie Beispieldatenpunkte visualisieren und deren Zentroiden bestimmen. Sie können die Zufälligkeit der Daten, die Anzahl der Cluster und die Anzahl der Zentroiden bearbeiten. Hilft Ihnen das, eine Vorstellung davon zu bekommen, wie die Daten gruppiert werden können?
-
Werfen Sie auch einen Blick auf dieses Handout zu K-Means von Stanford.
Möchten Sie Ihre neu erworbenen Clustering-Fähigkeiten an Datensätzen ausprobieren, die sich gut für K-Means-Clustering eignen? Schauen Sie sich Folgendes an:
-
Train and Evaluate Clustering Models mit Tidymodels und Co.
-
K-means Cluster Analysis, UC Business Analytics R Programming Guide
Aufgabe
Probieren Sie verschiedene Clustering-Methoden aus
EIN GROSSES DANKESCHÖN AN:
Jen Looper für die Erstellung der ursprünglichen Python-Version dieses Moduls ♥️
Allison Horst für die Erstellung der großartigen Illustrationen, die R einladender und ansprechender machen. Weitere Illustrationen finden Sie in ihrer Galerie.
Viel Spaß beim Lernen,
Eric, Gold Microsoft Learn Student Ambassador.
<p > <img src="../../images/r_learners_sm.jpeg" width="500"/> <figcaption>Kunstwerk von @allison_horst</figcaption>
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
pip install seaborn
Beginnen Sie dort, wo wir in der letzten Lektion aufgehört haben, mit importierten und gefilterten Daten.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
import numpy as np
df = pd.read_csv("../../data/nigerian-songs.csv")
df.head()
Wir werden uns nur auf 3 Genres konzentrieren. Vielleicht können wir 3 Cluster erstellen!
df = df[(df['artist_top_genre'] == 'afro dancehall') | (df['artist_top_genre'] == 'afropop') | (df['artist_top_genre'] == 'nigerian pop')]
df = df[(df['popularity'] > 0)]
top = df['artist_top_genre'].value_counts()
plt.figure(figsize=(10,7))
sns.barplot(x=top.index,y=top.values)
plt.xticks(rotation=45)
plt.title('Top genres',color = 'blue')
df.head()
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
# X = df.loc[:, ('danceability','energy')]
from sklearn.svm import SVC
from sklearn.semi_supervised import LabelSpreading
from sklearn.semi_supervised import SelfTrainingClassifier
from sklearn import datasets
X = df[['danceability','acousticness']].values
y = df['energy'].values
# X = scaler.fit_transform(X)
# step size in the mesh
h = .02
rng = np.random.RandomState(0)
y_rand = rng.rand(y.shape[0])
y_30 = np.copy(y)
y_30[y_rand < 0.3] = -1 # set random samples to be unlabeled
y_50 = np.copy(y)
y_50[y_rand < 0.5] = -1
# we create an instance of SVM and fit out data. We do not scale our
# data since we want to plot the support vectors
ls30 = (LabelSpreading().fit(X, y_30), y_30, 'Label Spreading 30% data')
ls50 = (LabelSpreading().fit(X, y_50), y_50, 'Label Spreading 50% data')
ls100 = (LabelSpreading().fit(X, y), y, 'Label Spreading 100% data')
# the base classifier for self-training is identical to the SVC
base_classifier = SVC(kernel='rbf', gamma=.5, probability=True)
st30 = (SelfTrainingClassifier(base_classifier).fit(X, y_30),
y_30, 'Self-training 30% data')
st50 = (SelfTrainingClassifier(base_classifier).fit(X, y_50),
y_50, 'Self-training 50% data')
rbf_svc = (SVC(kernel='rbf', gamma=.5).fit(X, y), y, 'SVC with rbf kernel')
# create a mesh to plot in
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
color_map = {-1: (1, 1, 1), 0: (0, 0, .9), 1: (1, 0, 0), 2: (.8, .6, 0)}
classifiers = (ls30, st30, ls50, st50, ls100, rbf_svc)
for i, (clf, y_train, title) in enumerate(classifiers):
# Plot the decision boundary. For that, we will assign a color to each
# point in the mesh [x_min, x_max]x[y_min, y_max].
plt.subplot(3, 2, i + 1)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
# Put the result into a color plot
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.Paired)
plt.axis('off')
# Plot also the training points
colors = [color_map[y] for y in y_train]
plt.scatter(X[:, 0], X[:, 1], c=colors, edgecolors='black')
plt.title(title)
plt.suptitle("Unlabeled points are colored white", y=0.1)
plt.show()
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Clustering-Modelle für maschinelles Lernen
Clustering ist eine Aufgabe des maschinellen Lernens, bei der versucht wird, Objekte zu finden, die einander ähneln, und diese in Gruppen, sogenannte Cluster, zu unterteilen. Was Clustering von anderen Ansätzen im maschinellen Lernen unterscheidet, ist, dass alles automatisch geschieht. Tatsächlich kann man sagen, dass es das Gegenteil von überwachten Lernmethoden ist.
Regionales Thema: Clustering-Modelle für den Musikgeschmack eines nigerianischen Publikums 🎧
Das vielfältige Publikum in Nigeria hat ebenso vielfältige musikalische Vorlieben. Mithilfe von Daten, die von Spotify gesammelt wurden (inspiriert von diesem Artikel), werfen wir einen Blick auf einige beliebte Musikstücke in Nigeria. Dieses Datenset enthält Informationen über verschiedene Songs, wie deren 'Danceability'-Score, 'Acousticness', Lautstärke, 'Speechiness', Popularität und Energie. Es wird spannend sein, Muster in diesen Daten zu entdecken!

> Foto von <a href="https://unsplash.com/@marcelalaskoski?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Marcela Laskoski</a> auf <a href="https://unsplash.com/s/photos/nigerian-music?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
In dieser Reihe von Lektionen wirst du neue Wege entdecken, Daten mithilfe von Clustering-Techniken zu analysieren. Clustering ist besonders nützlich, wenn dein Datensatz keine Labels enthält. Falls Labels vorhanden sind, könnten Klassifikationstechniken, wie die, die du in früheren Lektionen gelernt hast, hilfreicher sein. Aber in Fällen, in denen du unbeschriftete Daten gruppieren möchtest, ist Clustering eine großartige Methode, um Muster zu erkennen.
> Es gibt nützliche Low-Code-Tools, die dir helfen können, mit Clustering-Modellen zu arbeiten. Probiere Azure ML für diese Aufgabe aus.
Lektionen
Credits
Diese Lektionen wurden mit 🎶 von Jen Looper geschrieben, mit hilfreichen Reviews von Rishit Dagli und Muhammad Sakib Khan Inan.
Das Nigerian Songs-Datenset wurde von Kaggle bezogen und von Spotify gesammelt.
Nützliche K-Means-Beispiele, die bei der Erstellung dieser Lektion geholfen haben, umfassen diese Iris-Analyse, dieses einführende Notebook und dieses hypothetische NGO-Beispiel.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Suche nach einem Bot
Anweisungen
Bots sind überall. Deine Aufgabe: Finde einen und adoptiere ihn! Du kannst sie auf Websites, in Banking-Anwendungen und am Telefon finden, zum Beispiel wenn du Finanzdienstleistungsunternehmen für Beratung oder Kontoinformationen anrufst. Analysiere den Bot und versuche, ihn zu verwirren. Wenn es dir gelingt, den Bot zu verwirren, warum glaubst du, dass das passiert ist? Schreibe eine kurze Arbeit über deine Erfahrungen.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Eine vollständige Seite wird geschrieben, die die vermutete Bot-Architektur erklärt und deine Erfahrungen beschreibt | Die Arbeit ist unvollständig oder nicht gut recherchiert | Keine Arbeit wird eingereicht |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in die Verarbeitung natürlicher Sprache
Diese Lektion behandelt eine kurze Geschichte und wichtige Konzepte der Verarbeitung natürlicher Sprache, einem Teilbereich der Computerlinguistik.
Quiz vor der Vorlesung
Einführung
NLP, wie es allgemein bekannt ist, ist eines der bekanntesten Gebiete, in denen maschinelles Lernen angewendet und in Produktionssoftware eingesetzt wurde.
✅ Können Sie sich Software vorstellen, die Sie täglich nutzen und die wahrscheinlich NLP integriert hat? Was ist mit Ihren Textverarbeitungsprogrammen oder mobilen Apps, die Sie regelmäßig verwenden?
Sie werden lernen:
- Die Idee von Sprachen. Wie Sprachen entstanden sind und welche Hauptbereiche untersucht wurden.
- Definition und Konzepte. Sie werden auch Definitionen und Konzepte darüber lernen, wie Computer Text verarbeiten, einschließlich Parsing, Grammatik und der Identifizierung von Nomen und Verben. In dieser Lektion gibt es einige Programmieraufgaben, und es werden mehrere wichtige Konzepte eingeführt, die Sie später in den nächsten Lektionen programmieren lernen werden.
Computerlinguistik
Die Computerlinguistik ist ein Forschungs- und Entwicklungsbereich, der sich über viele Jahrzehnte erstreckt und untersucht, wie Computer mit Sprachen arbeiten, sie verstehen, übersetzen und sogar kommunizieren können. Die Verarbeitung natürlicher Sprache (NLP) ist ein verwandtes Gebiet, das sich darauf konzentriert, wie Computer 'natürliche', also menschliche, Sprachen verarbeiten können.
Beispiel - Telefon-Diktat
Wenn Sie jemals Ihrem Telefon etwas diktiert haben, anstatt zu tippen, oder einem virtuellen Assistenten eine Frage gestellt haben, wurde Ihre Sprache in eine Textform umgewandelt und dann verarbeitet oder geparst aus der Sprache, die Sie gesprochen haben. Die erkannten Schlüsselwörter wurden dann in ein Format verarbeitet, das das Telefon oder der Assistent verstehen und darauf reagieren konnte.
> Echtes sprachliches Verständnis ist schwierig! Bild von Jen Looper
Wie wird diese Technologie möglich gemacht?
Dies ist möglich, weil jemand ein Computerprogramm geschrieben hat, um dies zu tun. Vor einigen Jahrzehnten haben einige Science-Fiction-Autoren vorausgesagt, dass Menschen hauptsächlich mit ihren Computern sprechen würden und die Computer immer genau verstehen würden, was sie meinten. Leider stellte sich heraus, dass dies ein schwierigeres Problem war, als viele sich vorgestellt hatten, und obwohl es heute viel besser verstanden wird, gibt es erhebliche Herausforderungen, um ein 'perfektes' Verständnis der natürlichen Sprache zu erreichen, insbesondere wenn es darum geht, den Sinn eines Satzes zu verstehen. Dies ist ein besonders schwieriges Problem, wenn es darum geht, Humor zu verstehen oder Emotionen wie Sarkasmus in einem Satz zu erkennen.
Vielleicht erinnern Sie sich jetzt an Schulstunden, in denen der Lehrer die Teile der Grammatik in einem Satz behandelt hat. In einigen Ländern wird Grammatik und Linguistik als eigenständiges Fach unterrichtet, in vielen anderen sind diese Themen jedoch Teil des Sprachenlernens: entweder Ihrer Erstsprache in der Grundschule (Lesen und Schreiben lernen) und möglicherweise einer Zweitsprache in der weiterführenden Schule. Machen Sie sich keine Sorgen, wenn Sie kein Experte darin sind, Nomen von Verben oder Adverbien von Adjektiven zu unterscheiden!
Wenn Sie Schwierigkeiten haben, den Unterschied zwischen dem einfachen Präsens und dem Präsens Progressiv zu erkennen, sind Sie nicht allein. Dies ist für viele Menschen eine Herausforderung, selbst für Muttersprachler einer Sprache. Die gute Nachricht ist, dass Computer sehr gut darin sind, formale Regeln anzuwenden, und Sie werden lernen, Code zu schreiben, der einen Satz genauso gut wie ein Mensch parsen kann. Die größere Herausforderung, die Sie später untersuchen werden, besteht darin, die Bedeutung und Stimmung eines Satzes zu verstehen.
Voraussetzungen
Für diese Lektion ist die Hauptvoraussetzung, die Sprache dieser Lektion lesen und verstehen zu können. Es gibt keine mathematischen Probleme oder Gleichungen zu lösen. Während der ursprüngliche Autor diese Lektion auf Englisch geschrieben hat, ist sie auch in andere Sprachen übersetzt, sodass Sie möglicherweise eine Übersetzung lesen. Es gibt Beispiele, in denen eine Reihe verschiedener Sprachen verwendet wird (um die unterschiedlichen Grammatikregeln verschiedener Sprachen zu vergleichen). Diese werden nicht übersetzt, aber der erläuternde Text wird übersetzt, sodass die Bedeutung klar sein sollte.
Für die Programmieraufgaben verwenden Sie Python, und die Beispiele basieren auf Python 3.8.
In diesem Abschnitt benötigen und verwenden Sie:
- Python 3 Verständnis. Verständnis der Programmiersprache Python 3, diese Lektion verwendet Eingaben, Schleifen, Dateilesen, Arrays.
- Visual Studio Code + Erweiterung. Wir verwenden Visual Studio Code und dessen Python-Erweiterung. Sie können auch eine Python-IDE Ihrer Wahl verwenden.
- TextBlob. TextBlob ist eine vereinfachte Textverarbeitungsbibliothek für Python. Folgen Sie den Anweisungen auf der TextBlob-Website, um es auf Ihrem System zu installieren (installieren Sie auch die Corpora, wie unten gezeigt):
bash
pip install -U textblob
python -m textblob.download_corpora
> 💡 Tipp: Sie können Python direkt in VS Code-Umgebungen ausführen. Weitere Informationen finden Sie in den Dokumentationen.
Mit Maschinen sprechen
Die Geschichte, Computer dazu zu bringen, menschliche Sprache zu verstehen, reicht Jahrzehnte zurück, und einer der frühesten Wissenschaftler, der sich mit der Verarbeitung natürlicher Sprache beschäftigte, war Alan Turing.
Der 'Turing-Test'
Als Turing in den 1950er Jahren künstliche Intelligenz erforschte, überlegte er, ob ein Gesprächstest durchgeführt werden könnte, bei dem ein Mensch und ein Computer (über schriftliche Korrespondenz) miteinander kommunizieren, und der Mensch im Gespräch nicht sicher ist, ob er mit einem anderen Menschen oder einem Computer kommuniziert.
Wenn der Mensch nach einer bestimmten Gesprächsdauer nicht feststellen konnte, ob die Antworten von einem Computer stammen oder nicht, könnte man dann sagen, dass der Computer denkt?
Die Inspiration - 'Das Imitationsspiel'
Die Idee dazu kam von einem Partyspiel namens Das Imitationsspiel, bei dem ein Fragesteller allein in einem Raum ist und herausfinden soll, welche der beiden Personen (in einem anderen Raum) männlich und weiblich sind. Der Fragesteller kann Notizen senden und muss versuchen, Fragen zu stellen, bei denen die schriftlichen Antworten das Geschlecht der mysteriösen Person offenbaren. Natürlich versuchen die Spieler im anderen Raum, den Fragesteller zu täuschen, indem sie Fragen so beantworten, dass sie den Fragesteller in die Irre führen oder verwirren, während sie gleichzeitig den Anschein erwecken, ehrlich zu antworten.
Entwicklung von Eliza
In den 1960er Jahren entwickelte ein MIT-Wissenschaftler namens Joseph Weizenbaum Eliza, eine Computer-'Therapeutin', die dem Menschen Fragen stellte und den Eindruck erweckte, seine Antworten zu verstehen. Während Eliza einen Satz parsen und bestimmte grammatikalische Konstrukte und Schlüsselwörter identifizieren konnte, um eine vernünftige Antwort zu geben, konnte man nicht sagen, dass sie den Satz verstand. Wenn Eliza beispielsweise ein Satz im Format "Ich bin <u>traurig</u>" präsentiert wurde, könnte sie Wörter im Satz umstellen und ersetzen, um die Antwort "Wie lange sind Sie <u>traurig</u>" zu bilden.
Dies erweckte den Eindruck, dass Eliza die Aussage verstand und eine Anschlussfrage stellte, während sie in Wirklichkeit die Zeitform änderte und einige Wörter hinzufügte. Wenn Eliza ein Schlüsselwort nicht identifizieren konnte, für das sie eine Antwort hatte, gab sie stattdessen eine zufällige Antwort, die auf viele verschiedene Aussagen anwendbar sein könnte. Eliza konnte leicht ausgetrickst werden, zum Beispiel wenn ein Benutzer schrieb "Du bist ein <u>Fahrrad</u>", könnte sie mit "Wie lange bin ich ein <u>Fahrrad</u>?" antworten, anstatt mit einer vernünftigeren Antwort.
> 🎥 Klicken Sie auf das Bild oben für ein Video über das ursprüngliche ELIZA-Programm
> Hinweis: Sie können die ursprüngliche Beschreibung von Eliza lesen, die 1966 veröffentlicht wurde, wenn Sie ein ACM-Konto haben. Alternativ können Sie über Eliza auf Wikipedia lesen.
Übung - Programmieren eines einfachen Konversationsbots
Ein Konversationsbot wie Eliza ist ein Programm, das Benutzereingaben entgegennimmt und scheinbar intelligent darauf reagiert. Im Gegensatz zu Eliza wird unser Bot keine Vielzahl von Regeln haben, die den Eindruck einer intelligenten Konversation erwecken. Stattdessen wird unser Bot nur eine Fähigkeit haben: die Konversation mit zufälligen Antworten fortzusetzen, die in fast jeder trivialen Unterhaltung funktionieren könnten.
Der Plan
Ihre Schritte beim Erstellen eines Konversationsbots:
- Drucken Sie Anweisungen, die den Benutzer darüber informieren, wie er mit dem Bot interagieren soll.
- Starten Sie eine Schleife:
- Akzeptieren Sie Benutzereingaben.
- Wenn der Benutzer den Wunsch äußert, zu beenden, dann beenden Sie.
- Verarbeiten Sie die Benutzereingaben und bestimmen Sie die Antwort (in diesem Fall ist die Antwort eine zufällige Auswahl aus einer Liste möglicher allgemeiner Antworten).
- Drucken Sie die Antwort.
- Kehren Sie zu Schritt 2 zurück.
Den Bot erstellen
Lassen Sie uns den Bot erstellen. Wir beginnen mit der Definition einiger Phrasen.
-
Erstellen Sie diesen Bot selbst in Python mit den folgenden zufälligen Antworten:
python random_responses = ["That is quite interesting, please tell me more.", "I see. Do go on.", "Why do you say that?", "Funny weather we've been having, isn't it?", "Let's change the subject.", "Did you catch the game last night?"]Hier ist eine Beispielausgabe zur Orientierung (Benutzereingaben beginnen mit
>):output Hello, I am Marvin, the simple robot. You can end this conversation at any time by typing 'bye' After typing each answer, press 'enter' How are you today? > I am good thanks That is quite interesting, please tell me more. > today I went for a walk Did you catch the game last night? > I did, but my team lost Funny weather we've been having, isn't it? > yes but I hope next week is better Let's change the subject. > ok, lets talk about music Why do you say that? > because I like music! Why do you say that? > bye It was nice talking to you, goodbye!Eine mögliche Lösung für die Aufgabe finden Sie hier
✅ Halten Sie inne und überlegen Sie:
- Glauben Sie, dass die zufälligen Antworten jemanden dazu bringen könnten, zu denken, dass der Bot sie tatsächlich versteht?
- Welche Funktionen müsste der Bot haben, um effektiver zu sein?
- Wenn ein Bot wirklich die Bedeutung eines Satzes verstehen könnte, müsste er dann auch die Bedeutung vorheriger Sätze in einem Gespräch merken?
🚀 Herausforderung
Wählen Sie eines der oben genannten "Halten Sie inne und überlegen Sie"-Elemente aus und versuchen Sie entweder, es in Code umzusetzen, oder schreiben Sie eine Lösung auf Papier mit Pseudocode.
In der nächsten Lektion lernen Sie eine Reihe anderer Ansätze zur Verarbeitung natürlicher Sprache und maschinellem Lernen kennen.
Quiz nach der Vorlesung
Überprüfung & Selbststudium
Sehen Sie sich die unten stehenden Referenzen als weitere Lesemöglichkeiten an.
Referenzen
- Schubert, Lenhart, "Computational Linguistics", The Stanford Encyclopedia of Philosophy (Spring 2020 Edition), Edward N. Zalta (ed.), URL = <https://plato.stanford.edu/archives/spr2020/entries/computational-linguistics/>.
- Princeton University "About WordNet." WordNet. Princeton University. 2010.
Aufgabe
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Einen Bot zum Antworten bringen
Anweisungen
In den letzten Lektionen hast du einen einfachen Bot programmiert, mit dem du chatten kannst. Dieser Bot gibt zufällige Antworten, bis du 'bye' sagst. Kannst du die Antworten etwas weniger zufällig machen und Antworten auslösen, wenn du bestimmte Dinge sagst, wie 'warum' oder 'wie'? Überlege, wie maschinelles Lernen diese Art von Arbeit weniger manuell machen könnte, während du deinen Bot erweiterst. Du kannst die Bibliotheken NLTK oder TextBlob verwenden, um deine Aufgaben zu erleichtern.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Eine neue bot.py-Datei wird präsentiert und dokumentiert | Eine neue Bot-Datei wird präsentiert, enthält jedoch Fehler | Es wird keine Datei präsentiert |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Häufige Aufgaben und Techniken der Verarbeitung natürlicher Sprache
Für die meisten Aufgaben der Verarbeitung natürlicher Sprache muss der zu verarbeitende Text in kleinere Einheiten zerlegt, analysiert und die Ergebnisse gespeichert oder mit Regeln und Datensätzen abgeglichen werden. Diese Aufgaben ermöglichen es dem Programmierer, die Bedeutung oder Absicht oder lediglich die Häufigkeit von Begriffen und Wörtern in einem Text abzuleiten.
Quiz vor der Vorlesung
Lassen Sie uns gängige Techniken zur Verarbeitung von Texten entdecken. In Kombination mit maschinellem Lernen helfen diese Techniken, große Mengen an Text effizient zu analysieren. Bevor wir jedoch ML auf diese Aufgaben anwenden, sollten wir die Probleme verstehen, mit denen ein NLP-Spezialist konfrontiert ist.
Häufige Aufgaben in der NLP
Es gibt verschiedene Möglichkeiten, einen Text zu analysieren, an dem Sie arbeiten. Es gibt Aufgaben, die Sie durchführen können, und durch diese Aufgaben können Sie ein Verständnis für den Text gewinnen und Schlussfolgerungen ziehen. Diese Aufgaben werden in der Regel in einer bestimmten Reihenfolge durchgeführt.
Tokenisierung
Wahrscheinlich ist das Erste, was die meisten NLP-Algorithmen tun müssen, den Text in Token oder Wörter zu zerlegen. Obwohl dies einfach klingt, kann es durch die Berücksichtigung von Satzzeichen und unterschiedlichen Wort- und Satzgrenzen in verschiedenen Sprachen kompliziert werden. Es kann erforderlich sein, verschiedene Methoden anzuwenden, um die Abgrenzungen zu bestimmen.
> Tokenisierung eines Satzes aus Stolz und Vorurteil. Infografik von Jen Looper
Einbettungen
Wort-Einbettungen sind eine Möglichkeit, Ihre Textdaten numerisch darzustellen. Einbettungen werden so durchgeführt, dass Wörter mit ähnlicher Bedeutung oder Wörter, die zusammen verwendet werden, in Clustern gruppiert werden.
> "Ich habe den größten Respekt vor Ihren Nerven, sie sind meine alten Freunde." - Wort-Einbettungen für einen Satz aus Stolz und Vorurteil. Infografik von Jen Looper
✅ Probieren Sie dieses interessante Tool aus, um mit Wort-Einbettungen zu experimentieren. Wenn Sie auf ein Wort klicken, werden Cluster ähnlicher Wörter angezeigt: 'Spielzeug' gruppiert sich mit 'Disney', 'Lego', 'Playstation' und 'Konsole'.
Parsing & Part-of-Speech-Tagging
Jedes tokenisierte Wort kann als Wortart (Part of Speech) markiert werden – z. B. als Substantiv, Verb oder Adjektiv. Der Satz der schnelle rote Fuchs sprang über den faulen braunen Hund könnte beispielsweise wie folgt markiert werden: Fuchs = Substantiv, sprang = Verb.

> Parsing eines Satzes aus Stolz und Vorurteil. Infografik von Jen Looper
Parsing bedeutet, zu erkennen, welche Wörter in einem Satz miteinander in Beziehung stehen – zum Beispiel ist der schnelle rote Fuchs sprang eine Adjektiv-Substantiv-Verb-Sequenz, die von der Sequenz fauler brauner Hund getrennt ist.
Wort- und Phrasenhäufigkeiten
Ein nützliches Verfahren bei der Analyse eines großen Textkorpus ist der Aufbau eines Wörterbuchs mit allen interessanten Wörtern oder Phrasen und deren Häufigkeit. Die Phrase der schnelle rote Fuchs sprang über den faulen braunen Hund hat beispielsweise eine Wortfrequenz von 2 für das Wort "der".
Schauen wir uns einen Beispieltext an, in dem wir die Häufigkeit von Wörtern zählen. Rudyard Kiplings Gedicht "The Winners" enthält die folgende Strophe:
What the moral? Who rides may read.
When the night is thick and the tracks are blind
A friend at a pinch is a friend, indeed,
But a fool to wait for the laggard behind.
Down to Gehenna or up to the Throne,
He travels the fastest who travels alone.
Da die Häufigkeit von Phrasen je nach Bedarf groß- und kleinschreibungsempfindlich sein kann, hat die Phrase a friend eine Häufigkeit von 2, the eine Häufigkeit von 6 und travels eine Häufigkeit von 2.
N-Gramme
Ein Text kann in Sequenzen von Wörtern einer bestimmten Länge aufgeteilt werden: ein einzelnes Wort (Unigramm), zwei Wörter (Bigramme), drei Wörter (Trigramme) oder eine beliebige Anzahl von Wörtern (N-Gramme).
Zum Beispiel ergibt der schnelle rote Fuchs sprang über den faulen braunen Hund mit einem N-Gramm-Wert von 2 die folgenden N-Gramme:
- der schnelle
- schnelle rote
- rote Fuchs
- Fuchs sprang
- sprang über
- über den
- den faulen
- faulen braunen
- braunen Hund
Es könnte einfacher sein, dies als ein gleitendes Fenster über den Satz zu visualisieren. Hier ist es für N-Gramme mit 3 Wörtern, wobei das N-Gramm in jedem Satz hervorgehoben ist:
- <u>der schnelle rote</u> Fuchs sprang über den faulen braunen Hund
- der <u>schnelle rote Fuchs</u> sprang über den faulen braunen Hund
- der schnelle <u>rote Fuchs sprang</u> über den faulen braunen Hund
- der schnelle rote <u>Fuchs sprang über</u> den faulen braunen Hund
- der schnelle rote Fuchs <u>sprang über den</u> faulen braunen Hund
- der schnelle rote Fuchs sprang <u>über den faulen</u> braunen Hund
- der schnelle rote Fuchs sprang über <u>den faulen braunen</u> Hund
- der schnelle rote Fuchs sprang über den <u>faulen braunen Hund</u>

> N-Gramm-Wert von 3: Infografik von Jen Looper
Extraktion von Nominalphrasen
In den meisten Sätzen gibt es ein Substantiv, das das Subjekt oder Objekt des Satzes ist. Im Englischen ist es oft daran erkennbar, dass ihm 'a', 'an' oder 'the' vorangestellt ist. Das Identifizieren des Subjekts oder Objekts eines Satzes durch die 'Extraktion der Nominalphrase' ist eine gängige Aufgabe in der NLP, wenn versucht wird, die Bedeutung eines Satzes zu verstehen.
✅ Im Satz "I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation. It is too long ago. I was in the middle before I knew that I had begun.", können Sie die Nominalphrasen identifizieren?
Im Satz der schnelle rote Fuchs sprang über den faulen braunen Hund gibt es 2 Nominalphrasen: schneller roter Fuchs und fauler brauner Hund.
Sentiment-Analyse
Ein Satz oder Text kann auf seine Stimmung analysiert werden, also wie positiv oder negativ er ist. Die Stimmung wird in Polarität und Objektivität/Subjektivität gemessen. Die Polarität wird von -1,0 bis 1,0 (negativ bis positiv) und die Objektivität von 0,0 bis 1,0 (am objektivsten bis am subjektivsten) gemessen.
✅ Später lernen Sie, dass es verschiedene Möglichkeiten gibt, die Stimmung mithilfe von maschinellem Lernen zu bestimmen. Eine Möglichkeit besteht jedoch darin, eine Liste von Wörtern und Phrasen zu haben, die von einem menschlichen Experten als positiv oder negativ kategorisiert wurden, und dieses Modell auf Text anzuwenden, um einen Polaritätswert zu berechnen. Können Sie sehen, wie dies in einigen Fällen funktioniert und in anderen weniger gut?
Flexion
Die Flexion ermöglicht es Ihnen, ein Wort zu nehmen und die Einzahl oder Mehrzahl des Wortes zu erhalten.
Lemmatisierung
Ein Lemma ist die Grundform oder das Stammwort für eine Gruppe von Wörtern, zum Beispiel haben flog, fliegt, fliegend das Lemma des Verbs fliegen.
Es gibt auch nützliche Datenbanken für NLP-Forscher, insbesondere:
WordNet
WordNet ist eine Datenbank von Wörtern, Synonymen, Antonymen und vielen anderen Details für jedes Wort in vielen verschiedenen Sprachen. Es ist unglaublich nützlich beim Erstellen von Übersetzungen, Rechtschreibprüfungen oder Sprachwerkzeugen jeglicher Art.
NLP-Bibliotheken
Glücklicherweise müssen Sie nicht alle diese Techniken selbst entwickeln, da es ausgezeichnete Python-Bibliotheken gibt, die Entwicklern, die nicht auf die Verarbeitung natürlicher Sprache oder maschinelles Lernen spezialisiert sind, den Zugang erleichtern. In den nächsten Lektionen werden Sie mehr Beispiele dazu sehen, aber hier lernen Sie einige nützliche Beispiele kennen, die Ihnen bei der nächsten Aufgabe helfen.
Übung - Verwendung der TextBlob-Bibliothek
Lassen Sie uns eine Bibliothek namens TextBlob verwenden, da sie hilfreiche APIs für diese Arten von Aufgaben enthält. TextBlob "steht auf den Schultern von NLTK und pattern und arbeitet gut mit beiden zusammen." Es enthält eine beträchtliche Menge an ML in seiner API.
> Hinweis: Ein nützlicher Quick Start-Leitfaden ist für TextBlob verfügbar und wird erfahrenen Python-Entwicklern empfohlen.
Wenn Sie versuchen, Nominalphrasen zu identifizieren, bietet TextBlob mehrere Optionen für Extraktoren, um Nominalphrasen zu finden.
-
Schauen Sie sich
ConllExtractoran.```python from textblob import TextBlob from textblob.np_extractors import ConllExtractor
import and create a Conll extractor to use later
extractor = ConllExtractor()
later when you need a noun phrase extractor:
user_input = input("> ") user_input_blob = TextBlob(user_input, np_extractor=extractor) # note non-default extractor specified np = user_input_blob.noun_phrases
```> Was passiert hier? ConllExtractor ist "Ein Nominalphrasen-Extraktor, der Chunk-Parsing verwendet, das mit dem ConLL-2000-Trainingskorpus trainiert wurde." ConLL-2000 bezieht sich auf die Konferenz zur computergestützten Verarbeitung natürlicher Sprache im Jahr 2000. Jedes Jahr veranstaltete die Konferenz einen Workshop, um ein schwieriges NLP-Problem zu lösen, und 2000 war es das Chunking von Nominalphrasen. Ein Modell wurde auf dem Wall Street Journal trainiert, mit "Abschnitten 15-18 als Trainingsdaten (211727 Token) und Abschnitt 20 als Testdaten (47377 Token)". Sie können die verwendeten Verfahren hier und die Ergebnisse einsehen.
Herausforderung - Verbesserung Ihres Bots mit NLP
In der vorherigen Lektion haben Sie einen sehr einfachen Q&A-Bot erstellt. Jetzt machen Sie Marvin etwas einfühlsamer, indem Sie Ihre Eingabe auf Stimmung analysieren und eine passende Antwort ausgeben. Sie müssen auch eine noun_phrase identifizieren und dazu weitere Eingaben anfordern.
Ihre Schritte beim Erstellen eines besseren Konversationsbots:
- Anweisungen ausgeben, die den Benutzer darüber informieren, wie er mit dem Bot interagieren soll.
- Schleife starten
- Benutzereingabe akzeptieren
- Wenn der Benutzer um Beendigung bittet, dann beenden
- Benutzereingabe verarbeiten und passende Stimmungsantwort bestimmen
- Wenn eine Nominalphrase in der Stimmung erkannt wird, diese pluralisieren und weitere Eingaben zu diesem Thema anfordern
- Antwort ausgeben
- Zurück zu Schritt 2
Hier ist der Codeausschnitt, um die Stimmung mit TextBlob zu bestimmen. Beachten Sie, dass es nur vier Abstufungen der Stimmungsantwort gibt (Sie könnten mehr hinzufügen, wenn Sie möchten):
if user_input_blob.polarity <= -0.5:
response = "Oh dear, that sounds bad. "
elif user_input_blob.polarity <= 0:
response = "Hmm, that's not great. "
elif user_input_blob.polarity <= 0.5:
response = "Well, that sounds positive. "
elif user_input_blob.polarity <= 1:
response = "Wow, that sounds great. "
Hier ist eine Beispielausgabe zur Orientierung (Benutzereingaben beginnen mit >):
Hello, I am Marvin, the friendly robot.
You can end this conversation at any time by typing 'bye'
After typing each answer, press 'enter'
How are you today?
> I am ok
Well, that sounds positive. Can you tell me more?
> I went for a walk and saw a lovely cat
Well, that sounds positive. Can you tell me more about lovely cats?
> cats are the best. But I also have a cool dog
Wow, that sounds great. Can you tell me more about cool dogs?
> I have an old hounddog but he is sick
Hmm, that's not great. Can you tell me more about old hounddogs?
> bye
It was nice talking to you, goodbye!
Eine mögliche Lösung für die Aufgabe finden Sie hier
✅ Wissensüberprüfung
- Glauben Sie, dass die einfühlsamen Antworten jemanden dazu bringen könnten, zu denken, dass der Bot sie tatsächlich versteht?
- Macht das Identifizieren der Nominalphrase den Bot glaubwürdiger?
- Warum könnte das Extrahieren einer 'Nominalphrase' aus einem Satz nützlich sein?
Implementieren Sie den Bot aus der vorherigen Wissensüberprüfung und testen Sie ihn mit einem Freund. Kann er sie täuschen? Können Sie Ihren Bot glaubwürdiger machen?
🚀Herausforderung
Nehmen Sie eine Aufgabe aus der vorherigen Wissensüberprüfung und versuchen Sie, sie zu implementieren. Testen Sie den Bot mit einem Freund. Kann er sie täuschen? Können Sie Ihren Bot glaubwürdiger machen?
Quiz nach der Vorlesung
Rückblick & Selbststudium
In den nächsten Lektionen werden Sie mehr über Sentiment-Analyse erfahren. Recherchieren Sie diese interessante Technik in Artikeln wie diesen auf KDNuggets.
Aufgabe
Bringen Sie einen Bot zum Antworten
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Poetische Freiheit
Anweisungen
In diesem Notebook findest du über 500 Gedichte von Emily Dickinson, die zuvor mit Azure Text Analytics auf ihre Stimmung analysiert wurden. Nutze dieses Datenset und analysiere es mit den in der Lektion beschriebenen Techniken. Entspricht die vorgeschlagene Stimmung eines Gedichts der Entscheidung des fortschrittlicheren Azure-Dienstes? Warum oder warum nicht, deiner Meinung nach? Gibt es etwas, das dich überrascht?
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Notebook wird mit einer soliden Analyse der Beispielausgabe eines Autors präsentiert | Das Notebook ist unvollständig oder führt keine Analyse durch | Es wird kein Notebook präsentiert |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Übersetzung und Sentiment-Analyse mit ML
In den vorherigen Lektionen hast du gelernt, wie man einen einfachen Bot mit TextBlob erstellt, einer Bibliothek, die maschinelles Lernen im Hintergrund nutzt, um grundlegende NLP-Aufgaben wie die Extraktion von Nominalphrasen durchzuführen. Eine weitere wichtige Herausforderung in der Computerlinguistik ist die präzise Übersetzung eines Satzes von einer gesprochenen oder geschriebenen Sprache in eine andere.
Quiz vor der Vorlesung
Übersetzung ist ein sehr schwieriges Problem, das durch die Tatsache erschwert wird, dass es Tausende von Sprachen gibt, die jeweils sehr unterschiedliche Grammatikregeln haben können. Ein Ansatz besteht darin, die formalen Grammatikregeln einer Sprache, wie Englisch, in eine sprachunabhängige Struktur umzuwandeln und diese dann durch Rückübersetzung in eine andere Sprache zu übersetzen. Dieser Ansatz umfasst folgende Schritte:
- Identifikation. Identifiziere oder markiere die Wörter in der Eingabesprache als Substantive, Verben usw.
- Übersetzung erstellen. Erstelle eine direkte Übersetzung jedes Wortes im Format der Zielsprache.
Beispielsatz, Englisch zu Irisch
Im 'Englischen' lautet der Satz I feel happy aus drei Wörtern in der Reihenfolge:
- Subjekt (I)
- Verb (feel)
- Adjektiv (happy)
Im 'Irischen' hat derselbe Satz jedoch eine ganz andere grammatikalische Struktur – Emotionen wie "happy" oder "sad" werden als etwas auf dir ausgedrückt.
Die englische Phrase I feel happy würde im Irischen Tá athas orm lauten. Eine wörtliche Übersetzung wäre Happy is upon me.
Ein irischer Sprecher, der ins Englische übersetzt, würde sagen I feel happy, nicht Happy is upon me, weil er die Bedeutung des Satzes versteht, auch wenn die Wörter und die Satzstruktur unterschiedlich sind.
Die formale Reihenfolge des Satzes im Irischen lautet:
- Verb (Tá oder is)
- Adjektiv (athas, oder happy)
- Subjekt (orm, oder upon me)
Übersetzung
Ein naives Übersetzungsprogramm könnte nur Wörter übersetzen und die Satzstruktur ignorieren.
✅ Wenn du als Erwachsener eine zweite (oder dritte oder weitere) Sprache gelernt hast, hast du vielleicht damit begonnen, in deiner Muttersprache zu denken, ein Konzept Wort für Wort im Kopf in die zweite Sprache zu übersetzen und dann deine Übersetzung auszusprechen. Dies ähnelt dem, was naive Übersetzungsprogramme tun. Es ist wichtig, diese Phase zu überwinden, um fließend zu werden!
Naive Übersetzungen führen zu schlechten (und manchmal urkomischen) Fehlübersetzungen: I feel happy wird wörtlich zu Mise bhraitheann athas ins Irische übersetzt. Das bedeutet (wörtlich) me feel happy und ist kein gültiger irischer Satz. Obwohl Englisch und Irisch Sprachen sind, die auf zwei eng benachbarten Inseln gesprochen werden, sind sie sehr unterschiedliche Sprachen mit unterschiedlichen Grammatikstrukturen.
> Du kannst dir einige Videos über irische Sprachtraditionen ansehen, wie dieses hier
Ansätze mit maschinellem Lernen
Bisher hast du den Ansatz der formalen Regeln für die Verarbeitung natürlicher Sprache kennengelernt. Ein anderer Ansatz besteht darin, die Bedeutung der Wörter zu ignorieren und stattdessen maschinelles Lernen zu verwenden, um Muster zu erkennen. Dies kann bei der Übersetzung funktionieren, wenn du viele Texte (ein Corpus) oder Texte (Corpora) in der Ausgangs- und Zielsprache hast.
Betrachte beispielsweise den Fall von Stolz und Vorurteil, einem bekannten englischen Roman, der 1813 von Jane Austen geschrieben wurde. Wenn du das Buch auf Englisch und eine menschliche Übersetzung des Buches ins Französische konsultierst, könntest du Phrasen in einem erkennen, die idiomatisch in das andere übersetzt wurden. Das wirst du gleich ausprobieren.
Wenn beispielsweise eine englische Phrase wie I have no money wörtlich ins Französische übersetzt wird, könnte sie Je n'ai pas de monnaie werden. "Monnaie" ist ein schwieriges französisches 'falsches Freund', da 'money' und 'monnaie' nicht synonym sind. Eine bessere Übersetzung, die ein Mensch machen könnte, wäre Je n'ai pas d'argent, da sie besser vermittelt, dass du kein Geld hast (statt 'Kleingeld', was die Bedeutung von 'monnaie' ist).

> Bild von Jen Looper
Wenn ein ML-Modell genügend menschliche Übersetzungen hat, um ein Modell darauf aufzubauen, kann es die Genauigkeit von Übersetzungen verbessern, indem es häufige Muster in Texten identifiziert, die zuvor von Experten, die beide Sprachen sprechen, übersetzt wurden.
Übung - Übersetzung
Du kannst TextBlob verwenden, um Sätze zu übersetzen. Probiere die berühmte erste Zeile von Stolz und Vorurteil:
from textblob import TextBlob
blob = TextBlob(
"It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife!"
)
print(blob.translate(to="fr"))
TextBlob macht einen ziemlich guten Job bei der Übersetzung: "C'est une vérité universellement reconnue, qu'un homme célibataire en possession d'une bonne fortune doit avoir besoin d'une femme!".
Man könnte argumentieren, dass die Übersetzung von TextBlob tatsächlich viel genauer ist als die französische Übersetzung des Buches von 1932 durch V. Leconte und Ch. Pressoir:
"C'est une vérité universelle qu'un célibataire pourvu d'une belle fortune doit avoir envie de se marier, et, si peu que l'on sache de son sentiment à cet egard, lorsqu'il arrive dans une nouvelle résidence, cette idée est si bien fixée dans l'esprit de ses voisins qu'ils le considèrent sur-le-champ comme la propriété légitime de l'une ou l'autre de leurs filles."
In diesem Fall macht die durch ML informierte Übersetzung einen besseren Job als der menschliche Übersetzer, der unnötigerweise Worte in den Mund der ursprünglichen Autorin legt, um 'Klarheit' zu schaffen.
> Was passiert hier? Und warum ist TextBlob so gut in der Übersetzung? Nun, im Hintergrund verwendet es Google Translate, eine ausgeklügelte KI, die Millionen von Phrasen analysieren kann, um die besten Strings für die jeweilige Aufgabe vorherzusagen. Hier passiert nichts manuell, und du benötigst eine Internetverbindung, um blob.translate zu verwenden.
✅ Probiere einige weitere Sätze aus. Was ist besser, ML oder menschliche Übersetzung? In welchen Fällen?
Sentiment-Analyse
Ein weiteres Gebiet, in dem maschinelles Lernen sehr gut funktionieren kann, ist die Sentiment-Analyse. Ein nicht-ML-Ansatz für Sentiment besteht darin, Wörter und Phrasen zu identifizieren, die 'positiv' und 'negativ' sind. Dann wird bei einem neuen Textstück der Gesamtwert der positiven, negativen und neutralen Wörter berechnet, um das Gesamtsentiment zu identifizieren.
Dieser Ansatz lässt sich leicht täuschen, wie du vielleicht in der Marvin-Aufgabe gesehen hast – der Satz Great, that was a wonderful waste of time, I'm glad we are lost on this dark road ist ein sarkastischer, negativer Sentiment-Satz, aber der einfache Algorithmus erkennt 'great', 'wonderful', 'glad' als positiv und 'waste', 'lost' und 'dark' als negativ. Das Gesamtsentiment wird durch diese widersprüchlichen Wörter beeinflusst.
✅ Halte einen Moment inne und denke darüber nach, wie wir als menschliche Sprecher Sarkasmus vermitteln. Tonfall spielt eine große Rolle. Versuche, die Phrase "Well, that film was awesome" auf verschiedene Arten zu sagen, um herauszufinden, wie deine Stimme Bedeutung vermittelt.
ML-Ansätze
Der ML-Ansatz würde darin bestehen, manuell negative und positive Textkörper zu sammeln – Tweets, Filmkritiken oder alles, bei dem der Mensch eine Bewertung und eine schriftliche Meinung abgegeben hat. Dann können NLP-Techniken auf Meinungen und Bewertungen angewendet werden, sodass Muster entstehen (z. B. positive Filmkritiken enthalten häufiger die Phrase 'Oscar worthy' als negative Filmkritiken, oder positive Restaurantkritiken sagen 'gourmet' viel häufiger als 'disgusting').
> ⚖️ Beispiel: Wenn du in einem Büro eines Politikers arbeiten würdest und ein neues Gesetz diskutiert würde, könnten Bürger E-Mails schreiben, die das Gesetz unterstützen oder ablehnen. Angenommen, du wirst beauftragt, die E-Mails zu lesen und in zwei Stapel zu sortieren, dafür und dagegen. Wenn es viele E-Mails gäbe, könntest du überfordert sein, sie alle zu lesen. Wäre es nicht schön, wenn ein Bot sie alle für dich lesen, verstehen und dir sagen könnte, in welchen Stapel jede E-Mail gehört? > > Eine Möglichkeit, dies zu erreichen, besteht darin, maschinelles Lernen zu verwenden. Du würdest das Modell mit einem Teil der dagegen-E-Mails und einem Teil der dafür-E-Mails trainieren. Das Modell würde dazu neigen, Phrasen und Wörter mit der dagegen-Seite und der dafür-Seite zu assoziieren, aber es würde keinen der Inhalte verstehen, sondern nur, dass bestimmte Wörter und Muster eher in einer dagegen- oder einer dafür-E-Mail erscheinen. Du könntest es mit einigen E-Mails testen, die du nicht zum Trainieren des Modells verwendet hast, und sehen, ob es zu denselben Schlussfolgerungen kommt wie du. Sobald du mit der Genauigkeit des Modells zufrieden bist, könntest du zukünftige E-Mails verarbeiten, ohne jede einzeln lesen zu müssen.
✅ Klingt dieser Prozess wie Prozesse, die du in früheren Lektionen verwendet hast?
Übung - sentimentale Sätze
Sentiment wird mit einer Polarität von -1 bis 1 gemessen, wobei -1 das negativste Sentiment und 1 das positivste ist. Sentiment wird auch mit einem Wert von 0 - 1 für Objektivität (0) und Subjektivität (1) gemessen.
Betrachte erneut Jane Austens Stolz und Vorurteil. Der Text ist hier bei Project Gutenberg verfügbar. Das folgende Beispiel zeigt ein kurzes Programm, das das Sentiment der ersten und letzten Sätze des Buches analysiert und dessen Polarität sowie Subjektivitäts-/Objektivitätswert anzeigt.
Du solltest die TextBlob-Bibliothek (oben beschrieben) verwenden, um sentiment zu bestimmen (du musst keinen eigenen Sentiment-Rechner schreiben) in der folgenden Aufgabe.
from textblob import TextBlob
quote1 = """It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife."""
quote2 = """Darcy, as well as Elizabeth, really loved them; and they were both ever sensible of the warmest gratitude towards the persons who, by bringing her into Derbyshire, had been the means of uniting them."""
sentiment1 = TextBlob(quote1).sentiment
sentiment2 = TextBlob(quote2).sentiment
print(quote1 + " has a sentiment of " + str(sentiment1))
print(quote2 + " has a sentiment of " + str(sentiment2))
Du siehst die folgende Ausgabe:
It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want # of a wife. has a sentiment of Sentiment(polarity=0.20952380952380953, subjectivity=0.27142857142857146)
Darcy, as well as Elizabeth, really loved them; and they were
both ever sensible of the warmest gratitude towards the persons
who, by bringing her into Derbyshire, had been the means of
uniting them. has a sentiment of Sentiment(polarity=0.7, subjectivity=0.8)
Herausforderung - Sentiment-Polarität überprüfen
Deine Aufgabe ist es, mithilfe der Sentiment-Polarität zu bestimmen, ob Stolz und Vorurteil mehr absolut positive Sätze als absolut negative hat. Für diese Aufgabe kannst du davon ausgehen, dass ein Polaritätswert von 1 oder -1 absolut positiv bzw. negativ ist.
Schritte:
- Lade eine Kopie von Stolz und Vorurteil von Project Gutenberg als .txt-Datei herunter. Entferne die Metadaten am Anfang und Ende der Datei, sodass nur der Originaltext übrig bleibt.
- Öffne die Datei in Python und extrahiere den Inhalt als String.
- Erstelle ein TextBlob mit dem Buch-String.
- Analysiere jeden Satz im Buch in einer Schleife.
- Wenn die Polarität 1 oder -1 ist, speichere den Satz in einer Liste oder einem Array von positiven oder negativen Nachrichten.
- Am Ende gib alle positiven und negativen Sätze (separat) und die Anzahl von jedem aus.
Hier ist eine Beispiel-Lösung.
✅ Wissensüberprüfung
- Das Sentiment basiert auf den im Satz verwendeten Wörtern, aber versteht der Code die Wörter?
- Denkst du, dass die Sentiment-Polarität genau ist, oder mit anderen Worten, stimmst du den Bewertungen zu?
- Insbesondere, stimmst du der absoluten positiven Polarität der folgenden Sätze zu?
- “What an excellent father you have, girls!” said she, when the door was shut.
- “Your examination of Mr. Darcy is over, I presume,” said Miss Bingley; “and pray what is the result?” “I am perfectly convinced by it that Mr. Darcy has no defect.
- How wonderfully these sort of things occur!
- I have the greatest dislike in the world to that sort of thing.
- Charlotte is an excellent manager, I dare say.
- “This is delightful indeed!
- I am so happy!
- Your idea of the ponies is delightful.
- Die nächsten 3 Sätze wurden mit einer absolut positiven Sentiment-Bewertung bewertet, aber bei genauer Betrachtung sind sie keine positiven Sätze. Warum dachte die Sentiment-Analyse, dass sie positive Sätze seien?
- Happy shall I be, when his stay at Netherfield is over!” “I wish I could say anything to comfort you,” replied Elizabeth; “but it is wholly out of my power.
- If I could but see you as happy!
- Our distress, my dear Lizzy, is very great.
- Stimmst du der absoluten negativen Polarität der folgenden Sätze zu?
- Everybody is disgusted with his pride.
- “I should like to know how he behaves among strangers.” “You shall hear then—but prepare yourself for something very dreadful.
- The pause was to Elizabeth’s feelings dreadful.
- It would be dreadful!
✅ Jeder Jane-Austen-Liebhaber wird verstehen, dass sie ihre Bücher oft nutzt, um die lächerlicheren Aspekte der englischen Regency-Gesellschaft zu kritisieren. Elizabeth Bennett, die Hauptfigur in Stolz und Vorurteil, ist eine scharfsinnige soziale Beobachterin (wie die Autorin), und ihre Sprache ist oft stark nuanciert. Selbst Mr. Darcy (der Liebesinteressent in der Geschichte) bemerkt Elizabeths spielerischen und neckenden Sprachgebrauch: "I have had the pleasure of your acquaintance long enough to know that you find great enjoyment in occasionally professing opinions which in fact are not your own."
🚀Herausforderung
Kannst du Marvin noch besser machen, indem du andere Merkmale aus der Benutzereingabe extrahierst?
Quiz nach der Vorlesung
Rückblick & Selbststudium
Es gibt viele Möglichkeiten, Sentiment aus Texten zu extrahieren. Denke an die geschäftlichen Anwendungen, die von dieser Technik profitieren könnten. Überlege, wie sie auch schiefgehen kann. Lies mehr über ausgeklügelte, unternehmensgerechte Systeme zur Sentiment-Analyse, wie zum Beispiel Azure Text Analysis. Teste einige der oben genannten Sätze aus "Stolz und Vorurteil" und prüfe, ob sie Nuancen erkennen können.
Aufgabe
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
from textblob import TextBlob
# You should download the book text, clean it, and import it here
with open("pride.txt", encoding="utf8") as f:
file_contents = f.read()
book_pride = TextBlob(file_contents)
positive_sentiment_sentences = []
negative_sentiment_sentences = []
for sentence in book_pride.sentences:
if sentence.sentiment.polarity == 1:
positive_sentiment_sentences.append(sentence)
if sentence.sentiment.polarity == -1:
negative_sentiment_sentences.append(sentence)
print("The " + str(len(positive_sentiment_sentences)) + " most positive sentences:")
for sentence in positive_sentiment_sentences:
print("+ " + str(sentence.replace("\n", "").replace(" ", " ")))
print("The " + str(len(negative_sentiment_sentences)) + " most negative sentences:")
for sentence in negative_sentiment_sentences:
print("- " + str(sentence.replace("\n", "").replace(" ", " ")))
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
dies ist ein temporärer Platzhalter
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
NLTK
Anweisungen
NLTK ist eine bekannte Bibliothek für die Anwendung in der Computerlinguistik und NLP. Nutzen Sie diese Gelegenheit, um das 'NLTK-Buch' durchzulesen und die Übungen auszuprobieren. In dieser nicht bewerteten Aufgabe werden Sie die Bibliothek genauer kennenlernen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Sentimentanalyse mit Hotelbewertungen - Datenverarbeitung
In diesem Abschnitt verwenden Sie die Techniken aus den vorherigen Lektionen, um eine explorative Datenanalyse eines großen Datensatzes durchzuführen. Sobald Sie ein gutes Verständnis für die Nützlichkeit der verschiedenen Spalten haben, lernen Sie:
- wie man unnötige Spalten entfernt
- wie man neue Daten basierend auf den vorhandenen Spalten berechnet
- wie man den resultierenden Datensatz speichert, um ihn in der finalen Herausforderung zu verwenden
Quiz vor der Lektion
Einführung
Bisher haben Sie gelernt, dass Textdaten sich stark von numerischen Datentypen unterscheiden. Wenn es sich um Text handelt, der von einem Menschen geschrieben oder gesprochen wurde, kann er analysiert werden, um Muster, Häufigkeiten, Stimmungen und Bedeutungen zu erkennen. Diese Lektion führt Sie in einen realen Datensatz mit einer echten Herausforderung ein: 515K Hotel Reviews Data in Europe, der unter einer CC0: Public Domain Lizenz steht. Er wurde von Booking.com aus öffentlichen Quellen extrahiert. Der Ersteller des Datensatzes ist Jiashen Liu.
Vorbereitung
Sie benötigen:
- Die Fähigkeit, .ipynb-Notebooks mit Python 3 auszuführen
- pandas
- NLTK, das Sie lokal installieren sollten
- Den Datensatz, der auf Kaggle verfügbar ist: 515K Hotel Reviews Data in Europe. Er ist etwa 230 MB groß, wenn er entpackt ist. Laden Sie ihn in den Root-Ordner
/dataherunter, der mit diesen NLP-Lektionen verbunden ist.
Explorative Datenanalyse
Diese Herausforderung geht davon aus, dass Sie einen Hotel-Empfehlungsbot mit Sentimentanalyse und Gästebewertungen erstellen. Der Datensatz, den Sie verwenden, enthält Bewertungen von 1493 verschiedenen Hotels in 6 Städten.
Mit Python, einem Datensatz von Hotelbewertungen und der Sentimentanalyse von NLTK könnten Sie herausfinden:
- Welche Wörter und Phrasen werden in Bewertungen am häufigsten verwendet?
- Korrelieren die offiziellen Tags, die ein Hotel beschreiben, mit den Bewertungsergebnissen (z. B. gibt es mehr negative Bewertungen für ein bestimmtes Hotel von Familien mit kleinen Kindern als von Alleinreisenden, was darauf hindeuten könnte, dass es besser für Alleinreisende geeignet ist)?
- Stimmen die Sentiment-Scores von NLTK mit den numerischen Bewertungen der Hotelgäste überein?
Datensatz
Lassen Sie uns den Datensatz, den Sie heruntergeladen und lokal gespeichert haben, erkunden. Öffnen Sie die Datei in einem Editor wie VS Code oder sogar Excel.
Die Kopfzeilen des Datensatzes sind wie folgt:
Hotel_Address, Additional_Number_of_Scoring, Review_Date, Average_Score, Hotel_Name, Reviewer_Nationality, Negative_Review, Review_Total_Negative_Word_Counts, Total_Number_of_Reviews, Positive_Review, Review_Total_Positive_Word_Counts, Total_Number_of_Reviews_Reviewer_Has_Given, Reviewer_Score, Tags, days_since_review, lat, lng
Hier sind sie gruppiert, um sie leichter zu untersuchen:
Hotel-Spalten
Hotel_Name,Hotel_Address,lat(Breitengrad),lng(Längengrad)- Mit lat und lng könnten Sie eine Karte mit Python erstellen, die die Hotelstandorte anzeigt (vielleicht farblich codiert für negative und positive Bewertungen).
- Hotel_Address ist für uns nicht offensichtlich nützlich und wir werden es wahrscheinlich durch ein Land ersetzen, um die Sortierung und Suche zu erleichtern.
Hotel-Meta-Bewertungsspalten
Average_Score- Laut dem Ersteller des Datensatzes ist diese Spalte der Durchschnittliche Score des Hotels, berechnet basierend auf dem neuesten Kommentar im letzten Jahr. Dies scheint eine ungewöhnliche Methode zur Berechnung des Scores zu sein, aber es sind die extrahierten Daten, daher nehmen wir sie zunächst so hin.
✅ Basierend auf den anderen Spalten in diesen Daten: Können Sie sich eine andere Methode vorstellen, um den Durchschnittsscore zu berechnen?
Total_Number_of_Reviews- Die Gesamtanzahl der Bewertungen, die dieses Hotel erhalten hat – es ist unklar (ohne Code zu schreiben), ob sich dies auf die Bewertungen im Datensatz bezieht.
Additional_Number_of_Scoring- Dies bedeutet, dass eine Bewertung abgegeben wurde, aber keine positive oder negative Bewertung vom Bewerter geschrieben wurde.
Bewertungsspalten
Reviewer_Score- Dies ist ein numerischer Wert mit maximal einer Dezimalstelle zwischen den Minimal- und Maximalwerten 2,5 und 10.
- Es wird nicht erklärt, warum 2,5 der niedrigste mögliche Score ist.
Negative_Review- Wenn ein Bewerter nichts geschrieben hat, enthält dieses Feld "No Negative".
- Beachten Sie, dass ein Bewerter möglicherweise eine positive Bewertung in der Spalte Negative Review schreibt (z. B. "there is nothing bad about this hotel").
Review_Total_Negative_Word_Counts- Höhere negative Wortanzahlen deuten auf einen niedrigeren Score hin (ohne die Sentimentalität zu überprüfen).
Positive_Review- Wenn ein Bewerter nichts geschrieben hat, enthält dieses Feld "No Positive".
- Beachten Sie, dass ein Bewerter möglicherweise eine negative Bewertung in der Spalte Positive Review schreibt (z. B. "there is nothing good about this hotel at all").
Review_Total_Positive_Word_Counts- Höhere positive Wortanzahlen deuten auf einen höheren Score hin (ohne die Sentimentalität zu überprüfen).
Review_Dateunddays_since_review- Eine Frische- oder Veraltungsmaßnahme könnte auf eine Bewertung angewendet werden (ältere Bewertungen könnten weniger genau sein als neuere, da sich das Hotelmanagement geändert hat, Renovierungen durchgeführt wurden oder ein Pool hinzugefügt wurde usw.).
Tags- Dies sind kurze Beschreibungen, die ein Bewerter möglicherweise auswählt, um die Art des Gastes zu beschreiben, der er war (z. B. allein oder Familie), die Art des Zimmers, die Aufenthaltsdauer und wie die Bewertung eingereicht wurde.
- Leider ist die Verwendung dieser Tags problematisch. Siehe den Abschnitt unten, der ihre Nützlichkeit diskutiert.
Bewerterspalten
Total_Number_of_Reviews_Reviewer_Has_Given- Dies könnte ein Faktor in einem Empfehlungsmodell sein, z. B. wenn Sie feststellen könnten, dass produktivere Bewerter mit Hunderten von Bewertungen eher negativ als positiv sind. Der Bewerter einer bestimmten Bewertung wird jedoch nicht mit einem eindeutigen Code identifiziert und kann daher nicht mit einer Reihe von Bewertungen verknüpft werden. Es gibt 30 Bewerter mit 100 oder mehr Bewertungen, aber es ist schwer zu erkennen, wie dies das Empfehlungsmodell unterstützen könnte.
Reviewer_Nationality- Manche Leute könnten denken, dass bestimmte Nationalitäten eher positive oder negative Bewertungen abgeben, basierend auf einer nationalen Neigung. Seien Sie vorsichtig, solche anekdotischen Ansichten in Ihre Modelle einzubauen. Dies sind nationale (und manchmal rassistische) Stereotypen, und jeder Bewerter war eine Einzelperson, die eine Bewertung basierend auf ihrer Erfahrung geschrieben hat. Diese könnte durch viele Filter wie frühere Hotelaufenthalte, die zurückgelegte Entfernung und ihr persönliches Temperament beeinflusst worden sein. Zu denken, dass ihre Nationalität der Grund für eine Bewertung war, ist schwer zu rechtfertigen.
Beispiele
| Durchschnittlicher Score | Gesamtanzahl Bewertungen | Bewerter-Score | Negative <br />Bewertung | Positive Bewertung | Tags |
|---|---|---|---|---|---|
| 7.8 | 1945 | 2.5 | This is currently not a hotel but a construction site I was terrorized from early morning and all day with unacceptable building noise while resting after a long trip and working in the room People were working all day i e with jackhammers in the adjacent rooms I asked for a room change but no silent room was available To make things worse I was overcharged I checked out in the evening since I had to leave very early flight and received an appropriate bill A day later the hotel made another charge without my consent in excess of booked price It's a terrible place Don't punish yourself by booking here | Nothing Terrible place Stay away | Business trip Couple Standard Double Room Stayed 2 nights |
Wie Sie sehen können, hatte dieser Gast keinen angenehmen Aufenthalt in diesem Hotel. Das Hotel hat einen guten Durchschnittsscore von 7,8 und 1945 Bewertungen, aber dieser Bewerter gab ihm 2,5 und schrieb 115 Wörter darüber, wie negativ sein Aufenthalt war. Wenn sie überhaupt nichts in der Spalte Positive_Review geschrieben hätten, könnten Sie vermuten, dass es nichts Positives gab, aber sie schrieben 7 Worte der Warnung. Wenn wir nur Wörter zählen würden, anstatt die Bedeutung oder Stimmung der Wörter zu berücksichtigen, könnten wir eine verzerrte Sicht auf die Absicht des Bewerters haben. Seltsamerweise ist ihre Bewertung von 2,5 verwirrend, denn wenn der Hotelaufenthalt so schlecht war, warum überhaupt Punkte vergeben? Wenn Sie den Datensatz genau untersuchen, werden Sie feststellen, dass der niedrigste mögliche Score 2,5 und nicht 0 ist. Der höchste mögliche Score ist 10.
Tags
Wie oben erwähnt, scheint die Idee, Tags zur Kategorisierung der Daten zu verwenden, auf den ersten Blick sinnvoll. Leider sind diese Tags nicht standardisiert, was bedeutet, dass in einem bestimmten Hotel die Optionen Single room, Twin room und Double room sein könnten, während sie im nächsten Hotel Deluxe Single Room, Classic Queen Room und Executive King Room sind. Dies könnten dieselben Dinge sein, aber es gibt so viele Variationen, dass die Wahl besteht zwischen:
-
Der Versuch, alle Begriffe auf einen einzigen Standard zu ändern, was sehr schwierig ist, da nicht klar ist, wie der Konvertierungspfad in jedem Fall aussehen würde (z. B. Classic single room wird zu Single room, aber Superior Queen Room with Courtyard Garden or City View ist viel schwieriger zuzuordnen).
-
Wir können einen NLP-Ansatz verfolgen und die Häufigkeit bestimmter Begriffe wie Solo, Business Traveller oder Family with young kids messen, wie sie auf jedes Hotel angewendet werden, und dies in das Empfehlungsmodell einfließen lassen.
Tags sind normalerweise (aber nicht immer) ein einzelnes Feld, das eine Liste von 5 bis 6 durch Kommas getrennten Werten enthält, die sich auf Art der Reise, Art der Gäste, Art des Zimmers, Anzahl der Nächte und Art des Geräts, auf dem die Bewertung eingereicht wurde beziehen. Da jedoch einige Bewerter nicht jedes Feld ausfüllen (sie könnten eines leer lassen), sind die Werte nicht immer in derselben Reihenfolge.
Ein Beispiel: Nehmen Sie Art der Gruppe. Es gibt 1025 einzigartige Möglichkeiten in diesem Feld in der Spalte Tags, und leider beziehen sich nur einige davon auf eine Gruppe (einige sind die Art des Zimmers usw.). Wenn Sie nur die Ergebnisse filtern, die Familie erwähnen, enthalten die Ergebnisse viele Family room-Typen. Wenn Sie den Begriff with einbeziehen, d. h. die Family with-Werte zählen, sind die Ergebnisse besser, mit über 80.000 der 515.000 Ergebnisse, die die Phrase "Family with young children" oder "Family with older children" enthalten.
Das bedeutet, dass die Tags-Spalte für uns nicht völlig nutzlos ist, aber es wird einige Arbeit erfordern, sie nützlich zu machen.
Durchschnittlicher Hotelscore
Es gibt eine Reihe von Unstimmigkeiten oder Diskrepanzen im Datensatz, die ich nicht erklären kann, die aber hier illustriert werden, damit Sie sich ihrer bewusst sind, wenn Sie Ihre Modelle erstellen. Wenn Sie es herausfinden, lassen Sie es uns bitte im Diskussionsbereich wissen!
Der Datensatz enthält die folgenden Spalten, die sich auf den Durchschnittsscore und die Anzahl der Bewertungen beziehen:
- Hotel_Name
- Additional_Number_of_Scoring
- Average_Score
- Total_Number_of_Reviews
- Reviewer_Score
Das einzelne Hotel mit den meisten Bewertungen in diesem Datensatz ist Britannia International Hotel Canary Wharf mit 4789 Bewertungen von insgesamt 515.000. Wenn wir jedoch den Wert Total_Number_of_Reviews für dieses Hotel betrachten, beträgt er 9086. Sie könnten vermuten, dass es viele weitere Scores ohne Bewertungen gibt, daher sollten wir vielleicht den Wert der Spalte Additional_Number_of_Scoring hinzufügen. Dieser Wert beträgt 2682, und wenn wir ihn zu 4789 addieren, erhalten wir 7471, was immer noch 1615 weniger ist als der Wert von Total_Number_of_Reviews.
Wenn Sie die Spalte Average_Score betrachten, könnten Sie vermuten, dass es sich um den Durchschnitt der Bewertungen im Datensatz handelt, aber die Beschreibung von Kaggle lautet: "Durchschnittlicher Score des Hotels, berechnet basierend auf dem neuesten Kommentar im letzten Jahr". Das scheint nicht sehr nützlich zu sein, aber wir können unseren eigenen Durchschnitt basierend auf den Bewertungsscores im Datensatz berechnen. Am Beispiel desselben Hotels wird der durchschnittliche Hotelscore mit 7,1 angegeben, aber der berechnete Score (durchschnittlicher Bewerterscore im Datensatz) beträgt 6,8. Das ist nah dran, aber nicht derselbe Wert, und wir können nur vermuten, dass die in den Additional_Number_of_Scoring-Bewertungen angegebenen Scores den Durchschnitt auf 7,1 erhöht haben. Leider ist es ohne Möglichkeit, diese Annahme zu testen oder zu beweisen, schwierig, Average_Score, Additional_Number_of_Scoring und Total_Number_of_Reviews zu verwenden oder ihnen zu vertrauen, wenn sie auf Daten basieren oder sich auf Daten beziehen, die wir nicht haben.
Um die Sache weiter zu verkomplizieren, hat das Hotel mit der zweithöchsten Anzahl an Bewertungen einen berechneten Durchschnittsscore von 8,12, und der Average_Score im Datensatz beträgt 8,1. Ist dieser korrekte Score ein Zufall, oder ist das erste Hotel eine Diskrepanz?
In der Annahme, dass dieses Hotel ein Ausreißer sein könnte und dass vielleicht die meisten Werte übereinstimmen (aber einige aus irgendeinem Grund nicht), werden wir als Nächstes ein kurzes Programm schreiben, um die Werte im Datensatz zu untersuchen und die korrekte Verwendung (oder Nichtverwendung) der Werte zu bestimmen. > 🚨 Ein Hinweis zur Vorsicht > > Bei der Arbeit mit diesem Datensatz werden Sie Code schreiben, der etwas aus dem Text berechnet, ohne dass Sie den Text selbst lesen oder analysieren müssen. Das ist das Wesen von NLP: Bedeutung oder Stimmung zu interpretieren, ohne dass ein Mensch dies tun muss. Es ist jedoch möglich, dass Sie einige der negativen Bewertungen lesen. Ich möchte Sie dringend bitten, dies nicht zu tun, da es nicht notwendig ist. Einige davon sind albern oder irrelevante negative Hotelbewertungen, wie zum Beispiel: "Das Wetter war nicht gut" – etwas, das außerhalb der Kontrolle des Hotels oder überhaupt irgendjemandes liegt. Aber es gibt auch eine dunkle Seite bei einigen Bewertungen. Manchmal sind die negativen Bewertungen rassistisch, sexistisch oder altersdiskriminierend. Das ist bedauerlich, aber zu erwarten, wenn ein Datensatz von einer öffentlichen Website extrahiert wird. Einige Rezensenten hinterlassen Bewertungen, die Sie geschmacklos, unangenehm oder verstörend finden könnten. Es ist besser, den Code die Stimmung messen zu lassen, als sie selbst zu lesen und sich darüber aufzuregen. Das gesagt, es ist nur eine Minderheit, die solche Dinge schreibt, aber sie existiert dennoch.
Übung – Datenexploration
Daten laden
Genug mit der visuellen Untersuchung der Daten – jetzt wirst du etwas Code schreiben und Antworten finden! In diesem Abschnitt verwenden wir die Bibliothek pandas. Deine erste Aufgabe ist sicherzustellen, dass du die CSV-Daten laden und lesen kannst. Die pandas-Bibliothek verfügt über einen schnellen CSV-Loader, und das Ergebnis wird, wie in den vorherigen Lektionen, in einem DataFrame gespeichert. Die CSV-Datei, die wir laden, enthält über eine halbe Million Zeilen, aber nur 17 Spalten. Pandas bietet dir viele leistungsstarke Möglichkeiten, mit einem DataFrame zu interagieren, einschließlich der Möglichkeit, Operationen auf jeder Zeile auszuführen.
Ab hier enthält diese Lektion Code-Snippets, Erklärungen zum Code und Diskussionen darüber, was die Ergebnisse bedeuten. Verwende das beigefügte notebook.ipynb für deinen Code.
Beginnen wir mit dem Laden der Datendatei, die du verwenden wirst:
# Load the hotel reviews from CSV
import pandas as pd
import time
# importing time so the start and end time can be used to calculate file loading time
print("Loading data file now, this could take a while depending on file size")
start = time.time()
# df is 'DataFrame' - make sure you downloaded the file to the data folder
df = pd.read_csv('../../data/Hotel_Reviews.csv')
end = time.time()
print("Loading took " + str(round(end - start, 2)) + " seconds")
Sobald die Daten geladen sind, können wir einige Operationen darauf ausführen. Halte diesen Code für den nächsten Abschnitt oben in deinem Programm.
Daten erkunden
In diesem Fall sind die Daten bereits sauber, das bedeutet, dass sie bereit zur Verarbeitung sind und keine Zeichen in anderen Sprachen enthalten, die Algorithmen, die nur englische Zeichen erwarten, verwirren könnten.
✅ Es könnte sein, dass du mit Daten arbeiten musst, die eine anfängliche Verarbeitung erfordern, um sie zu formatieren, bevor du NLP-Techniken anwendest – aber diesmal nicht. Wenn du es müsstest, wie würdest du mit nicht-englischen Zeichen umgehen?
Nimm dir einen Moment Zeit, um sicherzustellen, dass du die Daten nach dem Laden mit Code erkunden kannst. Es ist sehr verlockend, sich auf die Spalten Negative_Review und Positive_Review zu konzentrieren. Diese enthalten natürlichen Text, den deine NLP-Algorithmen verarbeiten können. Aber warte! Bevor du mit NLP und Sentiment-Analyse beginnst, solltest du den folgenden Code verwenden, um sicherzustellen, dass die im Datensatz angegebenen Werte mit den Werten übereinstimmen, die du mit pandas berechnest.
DataFrame-Operationen
Die erste Aufgabe in dieser Lektion besteht darin, zu überprüfen, ob die folgenden Annahmen korrekt sind, indem du Code schreibst, der den DataFrame untersucht (ohne ihn zu ändern).
> Wie bei vielen Programmieraufgaben gibt es mehrere Möglichkeiten, dies zu lösen. Ein guter Rat ist jedoch, es auf die einfachste und verständlichste Weise zu tun, insbesondere wenn es einfacher zu verstehen ist, wenn du später zu diesem Code zurückkehrst. Mit DataFrames gibt es eine umfassende API, die oft eine effiziente Möglichkeit bietet, das zu tun, was du möchtest.
Behandle die folgenden Fragen als Programmieraufgaben und versuche, sie zu beantworten, ohne die Lösung anzusehen.
- Gib die Form des gerade geladenen DataFrames aus (die Form ist die Anzahl der Zeilen und Spalten).
- Berechne die Häufigkeit der Rezensenten-Nationalitäten:
- Wie viele unterschiedliche Werte gibt es in der Spalte
Reviewer_Nationalityund welche sind das? - Welche Nationalität der Rezensenten ist im Datensatz am häufigsten (Land und Anzahl der Bewertungen ausgeben)?
- Was sind die nächsten 10 am häufigsten vorkommenden Nationalitäten und deren Häufigkeit?
- Welches Hotel wurde für jede der 10 häufigsten Rezensenten-Nationalitäten am häufigsten bewertet?
- Wie viele Bewertungen gibt es pro Hotel (Häufigkeit der Bewertungen pro Hotel im Datensatz)?
- Obwohl es im Datensatz eine Spalte
Average_Scorefür jedes Hotel gibt, kannst du auch einen Durchschnittswert berechnen (indem du den Durchschnitt aller Rezensentenbewertungen im Datensatz für jedes Hotel berechnest). Füge deinem DataFrame eine neue Spalte mit der ÜberschriftCalc_Average_Scorehinzu, die diesen berechneten Durchschnitt enthält. - Haben einige Hotels denselben (auf eine Dezimalstelle gerundeten)
Average_ScoreundCalc_Average_Score? - Versuche, eine Python-Funktion zu schreiben, die eine Series (Zeile) als Argument nimmt und die Werte vergleicht. Gib eine Nachricht aus, wenn die Werte nicht übereinstimmen. Verwende dann die
.apply()-Methode, um jede Zeile mit der Funktion zu verarbeiten. - Berechne und gib aus, wie viele Zeilen in der Spalte
Negative_Reviewden Wert "No Negative" haben. - Berechne und gib aus, wie viele Zeilen in der Spalte
Positive_Reviewden Wert "No Positive" haben. - Berechne und gib aus, wie viele Zeilen in der Spalte
Positive_Reviewden Wert "No Positive" und in der SpalteNegative_Reviewden Wert "No Negative" haben.
Code-Antworten
- Gib die Form des gerade geladenen DataFrames aus (die Form ist die Anzahl der Zeilen und Spalten).
python
print("The shape of the data (rows, cols) is " + str(df.shape))
> The shape of the data (rows, cols) is (515738, 17)
-
Berechne die Häufigkeit der Rezensenten-Nationalitäten:
-
Wie viele unterschiedliche Werte gibt es in der Spalte
Reviewer_Nationalityund welche sind das? - Welche Nationalität der Rezensenten ist im Datensatz am häufigsten (Land und Anzahl der Bewertungen ausgeben)?
```python # value_counts() creates a Series object that has index and values in this case, the country and the frequency they occur in reviewer nationality nationality_freq = df["Reviewer_Nationality"].value_counts() print("There are " + str(nationality_freq.size) + " different nationalities") # print first and last rows of the Series. Change to nationality_freq.to_string() to print all of the data print(nationality_freq)
There are 227 different nationalities
United Kingdom 245246
United States of America 35437
Australia 21686
Ireland 14827
United Arab Emirates 10235
...
Comoros 1
Palau 1
Northern Mariana Islands 1
Cape Verde 1
Guinea 1
Name: Reviewer_Nationality, Length: 227, dtype: int64
```
-
Was sind die nächsten 10 am häufigsten vorkommenden Nationalitäten und deren Häufigkeit?
```python print("The highest frequency reviewer nationality is " + str(nationality_freq.index[0]).strip() + " with " + str(nationality_freq[0]) + " reviews.") # Notice there is a leading space on the values, strip() removes that for printing # What is the top 10 most common nationalities and their frequencies? print("The next 10 highest frequency reviewer nationalities are:") print(nationality_freq[1:11].to_string())
The highest frequency reviewer nationality is United Kingdom with 245246 reviews. The next 10 highest frequency reviewer nationalities are: United States of America 35437 Australia 21686 Ireland 14827 United Arab Emirates 10235 Saudi Arabia 8951 Netherlands 8772 Switzerland 8678 Germany 7941 Canada 7894 France 7296 ```
-
Welches Hotel wurde für jede der 10 häufigsten Rezensenten-Nationalitäten am häufigsten bewertet?
```python
# What was the most frequently reviewed hotel for the top 10 nationalities
# Normally with pandas you will avoid an explicit loop, but wanted to show creating a new dataframe using criteria (don't do this with large amounts of data because it could be very slow)
for nat in nationality_freq[:10].index:
# First, extract all the rows that match the criteria into a new dataframe
nat_df = df[df["Reviewer_Nationality"] == nat]
# Now get the hotel freq
freq = nat_df["Hotel_Name"].value_counts()
print("The most reviewed hotel for " + str(nat).strip() + " was " + str(freq.index[0]) + " with " + str(freq[0]) + " reviews.")
The most reviewed hotel for United Kingdom was Britannia International Hotel Canary Wharf with 3833 reviews. The most reviewed hotel for United States of America was Hotel Esther a with 423 reviews. The most reviewed hotel for Australia was Park Plaza Westminster Bridge London with 167 reviews. The most reviewed hotel for Ireland was Copthorne Tara Hotel London Kensington with 239 reviews. The most reviewed hotel for United Arab Emirates was Millennium Hotel London Knightsbridge with 129 reviews. The most reviewed hotel for Saudi Arabia was The Cumberland A Guoman Hotel with 142 reviews. The most reviewed hotel for Netherlands was Jaz Amsterdam with 97 reviews. The most reviewed hotel for Switzerland was Hotel Da Vinci with 97 reviews. The most reviewed hotel for Germany was Hotel Da Vinci with 86 reviews. The most reviewed hotel for Canada was St James Court A Taj Hotel London with 61 reviews. ```
- Wie viele Bewertungen gibt es pro Hotel (Häufigkeit der Bewertungen pro Hotel im Datensatz)?
```python # First create a new dataframe based on the old one, removing the uneeded columns hotel_freq_df = df.drop(["Hotel_Address", "Additional_Number_of_Scoring", "Review_Date", "Average_Score", "Reviewer_Nationality", "Negative_Review", "Review_Total_Negative_Word_Counts", "Positive_Review", "Review_Total_Positive_Word_Counts", "Total_Number_of_Reviews_Reviewer_Has_Given", "Reviewer_Score", "Tags", "days_since_review", "lat", "lng"], axis = 1)
# Group the rows by Hotel_Name, count them and put the result in a new column Total_Reviews_Found hotel_freq_df['Total_Reviews_Found'] = hotel_freq_df.groupby('Hotel_Name').transform('count')
# Get rid of all the duplicated rows hotel_freq_df = hotel_freq_df.drop_duplicates(subset = ["Hotel_Name"]) display(hotel_freq_df) ``` | Hotel_Name | Total_Number_of_Reviews | Total_Reviews_Found | | :----------------------------------------: | :---------------------: | :-----------------: | | Britannia International Hotel Canary Wharf | 9086 | 4789 | | Park Plaza Westminster Bridge London | 12158 | 4169 | | Copthorne Tara Hotel London Kensington | 7105 | 3578 | | ... | ... | ... | | Mercure Paris Porte d Orleans | 110 | 10 | | Hotel Wagner | 135 | 10 | | Hotel Gallitzinberg | 173 | 8 |
Du wirst feststellen, dass die im Datensatz gezählten Ergebnisse nicht mit dem Wert in Total_Number_of_Reviews übereinstimmen. Es ist unklar, ob dieser Wert im Datensatz die Gesamtzahl der Bewertungen des Hotels darstellt, von denen nicht alle erfasst wurden, oder ob eine andere Berechnung vorliegt. Total_Number_of_Reviews wird aufgrund dieser Unklarheit nicht im Modell verwendet.
- Obwohl es im Datensatz eine Spalte
Average_Scorefür jedes Hotel gibt, kannst du auch einen Durchschnittswert berechnen (indem du den Durchschnitt aller Rezensentenbewertungen im Datensatz für jedes Hotel berechnest). Füge deinem DataFrame eine neue Spalte mit der ÜberschriftCalc_Average_Scorehinzu, die diesen berechneten Durchschnitt enthält. Gib die SpaltenHotel_Name,Average_ScoreundCalc_Average_Scoreaus.
```python # define a function that takes a row and performs some calculation with it def get_difference_review_avg(row): return row["Average_Score"] - row["Calc_Average_Score"]
# 'mean' is mathematical word for 'average' df['Calc_Average_Score'] = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
# Add a new column with the difference between the two average scores df["Average_Score_Difference"] = df.apply(get_difference_review_avg, axis = 1)
# Create a df without all the duplicates of Hotel_Name (so only 1 row per hotel) review_scores_df = df.drop_duplicates(subset = ["Hotel_Name"])
# Sort the dataframe to find the lowest and highest average score difference review_scores_df = review_scores_df.sort_values(by=["Average_Score_Difference"])
display(review_scores_df[["Average_Score_Difference", "Average_Score", "Calc_Average_Score", "Hotel_Name"]]) ```
Du fragst dich vielleicht, warum der Wert in Average_Score manchmal vom berechneten Durchschnittswert abweicht. Da wir nicht wissen, warum einige Werte übereinstimmen, andere jedoch abweichen, ist es in diesem Fall sicherer, die Bewertungswerte zu verwenden, die wir haben, um den Durchschnitt selbst zu berechnen. Die Abweichungen sind jedoch in der Regel sehr gering. Hier sind die Hotels mit der größten Abweichung zwischen dem Datensatzdurchschnitt und dem berechneten Durchschnitt:
| Average_Score_Difference | Average_Score | Calc_Average_Score | Hotel_Name |
|---|---|---|---|
| -0.8 | 7.7 | 8.5 | Best Western Hotel Astoria |
| -0.7 | 8.8 | 9.5 | Hotel Stendhal Place Vend me Paris MGallery |
| -0.7 | 7.5 | 8.2 | Mercure Paris Porte d Orleans |
| -0.7 | 7.9 | 8.6 | Renaissance Paris Vendome Hotel |
| -0.5 | 7.0 | 7.5 | Hotel Royal Elys es |
| ... | ... | ... | ... |
| 0.7 | 7.5 | 6.8 | Mercure Paris Op ra Faubourg Montmartre |
| 0.8 | 7.1 | 6.3 | Holiday Inn Paris Montparnasse Pasteur |
| 0.9 | 6.8 | 5.9 | Villa Eugenie |
| 0.9 | 8.6 | 7.7 | MARQUIS Faubourg St Honor Relais Ch teaux |
| 1.3 | 7.2 | 5.9 | Kube Hotel Ice Bar |
Da nur ein Hotel eine Abweichung von mehr als 1 Punkt hat, können wir die Abweichung wahrscheinlich ignorieren und den berechneten Durchschnittswert verwenden.
-
Berechne und gib aus, wie viele Zeilen in der Spalte
Negative_Reviewden Wert "No Negative" haben. -
Berechne und gib aus, wie viele Zeilen in der Spalte
Positive_Reviewden Wert "No Positive" haben. -
Berechne und gib aus, wie viele Zeilen in der Spalte
Positive_Reviewden Wert "No Positive" und in der SpalteNegative_Reviewden Wert "No Negative" haben.
```python # with lambdas: start = time.time() no_negative_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" else False , axis=1) print("Number of No Negative reviews: " + str(len(no_negative_reviews[no_negative_reviews == True].index)))
no_positive_reviews = df.apply(lambda x: True if x['Positive_Review'] == "No Positive" else False , axis=1) print("Number of No Positive reviews: " + str(len(no_positive_reviews[no_positive_reviews == True].index)))
both_no_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" and x['Positive_Review'] == "No Positive" else False , axis=1) print("Number of both No Negative and No Positive reviews: " + str(len(both_no_reviews[both_no_reviews == True].index))) end = time.time() print("Lambdas took " + str(round(end - start, 2)) + " seconds")
Number of No Negative reviews: 127890 Number of No Positive reviews: 35946 Number of both No Negative and No Positive reviews: 127 Lambdas took 9.64 seconds ```
Eine andere Methode
Eine andere Möglichkeit, Elemente ohne Lambdas zu zählen, ist die Verwendung von sum, um die Zeilen zu zählen:
```python # without lambdas (using a mixture of notations to show you can use both) start = time.time() no_negative_reviews = sum(df.Negative_Review == "No Negative") print("Number of No Negative reviews: " + str(no_negative_reviews))
no_positive_reviews = sum(df["Positive_Review"] == "No Positive") print("Number of No Positive reviews: " + str(no_positive_reviews))
both_no_reviews = sum((df.Negative_Review == "No Negative") & (df.Positive_Review == "No Positive")) print("Number of both No Negative and No Positive reviews: " + str(both_no_reviews))
end = time.time() print("Sum took " + str(round(end - start, 2)) + " seconds")
Number of No Negative reviews: 127890 Number of No Positive reviews: 35946 Number of both No Negative and No Positive reviews: 127 Sum took 0.19 seconds ```
Du hast vielleicht bemerkt, dass es 127 Zeilen gibt, die sowohl "No Negative" als auch "No Positive" in den Spalten Negative_Review und Positive_Review enthalten. Das bedeutet, dass der Rezensent dem Hotel eine numerische Bewertung gegeben hat, aber darauf verzichtet hat, eine positive oder negative Bewertung zu schreiben. Glücklicherweise handelt es sich hierbei um eine kleine Anzahl von Zeilen (127 von 515738, also 0,02 %), sodass dies unser Modell oder die Ergebnisse wahrscheinlich nicht in eine bestimmte Richtung verzerren wird. Dennoch hättest du vielleicht nicht erwartet, dass ein Datensatz mit Bewertungen Zeilen ohne Bewertungen enthält. Es lohnt sich also, die Daten zu erkunden, um solche Zeilen zu entdecken.
Nachdem du den Datensatz erkundet hast, wirst du in der nächsten Lektion die Daten filtern und eine Sentiment-Analyse hinzufügen.
🚀 Herausforderung
Diese Lektion zeigt, wie wir bereits in früheren Lektionen gesehen haben, wie wichtig es ist, die Daten und ihre Eigenheiten genau zu verstehen, bevor man Operationen darauf ausführt. Insbesondere textbasierte Daten erfordern eine sorgfältige Prüfung. Durchsuche verschiedene textlastige Datensätze und finde heraus, ob du Bereiche entdecken kannst, die Vorurteile oder verzerrte Stimmungen in ein Modell einbringen könnten.
Quiz nach der Vorlesung
Überprüfung & Selbststudium
Nimm an diesem Lernpfad zu NLP teil, um Werkzeuge zu entdecken, die du beim Erstellen von sprach- und textlastigen Modellen ausprobieren kannst.
Aufgabe
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
# EDA
import pandas as pd
import time
def get_difference_review_avg(row):
return row["Average_Score"] - row["Calc_Average_Score"]
# Load the hotel reviews from CSV
print("Loading data file now, this could take a while depending on file size")
start = time.time()
df = pd.read_csv('../../data/Hotel_Reviews.csv')
end = time.time()
print("Loading took " + str(round(end - start, 2)) + " seconds")
# What shape is the data (rows, columns)?
print("The shape of the data (rows, cols) is " + str(df.shape))
# value_counts() creates a Series object that has index and values
# in this case, the country and the frequency they occur in reviewer nationality
nationality_freq = df["Reviewer_Nationality"].value_counts()
# What reviewer nationality is the most common in the dataset?
print("The highest frequency reviewer nationality is " + str(nationality_freq.index[0]).strip() + " with " + str(nationality_freq[0]) + " reviews.")
# What is the top 10 most common nationalities and their frequencies?
print("The top 10 highest frequency reviewer nationalities are:")
print(nationality_freq[0:10].to_string())
# How many unique nationalities are there?
print("There are " + str(nationality_freq.index.size) + " unique nationalities in the dataset")
# What was the most frequently reviewed hotel for the top 10 nationalities - print the hotel and number of reviews
for nat in nationality_freq[:10].index:
# First, extract all the rows that match the criteria into a new dataframe
nat_df = df[df["Reviewer_Nationality"] == nat]
# Now get the hotel freq
freq = nat_df["Hotel_Name"].value_counts()
print("The most reviewed hotel for " + str(nat).strip() + " was " + str(freq.index[0]) + " with " + str(freq[0]) + " reviews.")
# How many reviews are there per hotel (frequency count of hotel) and do the results match the value in `Total_Number_of_Reviews`?
# First create a new dataframe based on the old one, removing the uneeded columns
hotel_freq_df = df.drop(["Hotel_Address", "Additional_Number_of_Scoring", "Review_Date", "Average_Score", "Reviewer_Nationality", "Negative_Review", "Review_Total_Negative_Word_Counts", "Positive_Review", "Review_Total_Positive_Word_Counts", "Total_Number_of_Reviews_Reviewer_Has_Given", "Reviewer_Score", "Tags", "days_since_review", "lat", "lng"], axis = 1)
# Group the rows by Hotel_Name, count them and put the result in a new column Total_Reviews_Found
hotel_freq_df['Total_Reviews_Found'] = hotel_freq_df.groupby('Hotel_Name').transform('count')
# Get rid of all the duplicated rows
hotel_freq_df = hotel_freq_df.drop_duplicates(subset = ["Hotel_Name"])
print()
print(hotel_freq_df.to_string())
print(str(hotel_freq_df.shape))
# While there is an `Average_Score` for each hotel according to the dataset,
# you can also calculate an average score (getting the average of all reviewer scores in the dataset for each hotel)
# Add a new column to your dataframe with the column header `Calc_Average_Score` that contains that calculated average.
df['Calc_Average_Score'] = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
# Add a new column with the difference between the two average scores
df["Average_Score_Difference"] = df.apply(get_difference_review_avg, axis = 1)
# Create a df without all the duplicates of Hotel_Name (so only 1 row per hotel)
review_scores_df = df.drop_duplicates(subset = ["Hotel_Name"])
# Sort the dataframe to find the lowest and highest average score difference
review_scores_df = review_scores_df.sort_values(by=["Average_Score_Difference"])
print(review_scores_df[["Average_Score_Difference", "Average_Score", "Calc_Average_Score", "Hotel_Name"]])
# Do any hotels have the same (rounded to 1 decimal place) `Average_Score` and `Calc_Average_Score`?
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
dies ist ein temporärer Platzhalter
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Probieren Sie ein anderes Dataset aus
Anweisungen
Nachdem Sie gelernt haben, wie man mit NLTK Sentiment-Analysen auf Texte anwendet, probieren Sie ein anderes Dataset aus. Sie werden wahrscheinlich einige Datenverarbeitungen durchführen müssen, also erstellen Sie ein Notebook und dokumentieren Sie Ihren Denkprozess. Was entdecken Sie?
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein vollständiges Notebook und Dataset werden präsentiert, mit gut dokumentierten Zellen, die erklären, wie das Sentiment zugewiesen wird | Das Notebook enthält keine ausreichenden Erklärungen | Das Notebook ist fehlerhaft |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Sentiment-Analyse mit Hotelbewertungen
Nachdem Sie den Datensatz im Detail untersucht haben, ist es an der Zeit, die Spalten zu filtern und dann NLP-Techniken auf den Datensatz anzuwenden, um neue Einblicke in die Hotels zu gewinnen.
Quiz vor der Lektion
Filter- und Sentiment-Analyse-Operationen
Wie Sie wahrscheinlich bemerkt haben, weist der Datensatz einige Probleme auf. Einige Spalten enthalten nutzlose Informationen, andere scheinen fehlerhaft zu sein. Selbst wenn sie korrekt sind, ist unklar, wie sie berechnet wurden, und die Ergebnisse können nicht unabhängig durch eigene Berechnungen überprüft werden.
Übung: Etwas mehr Datenverarbeitung
Bereinigen Sie die Daten noch ein wenig mehr. Fügen Sie Spalten hinzu, die später nützlich sein werden, ändern Sie die Werte in anderen Spalten und entfernen Sie bestimmte Spalten vollständig.
-
Erste Spaltenverarbeitung
-
Entfernen Sie
latundlng. -
Ersetzen Sie die Werte in
Hotel_Addressdurch die folgenden Werte (wenn die Adresse den Namen der Stadt und des Landes enthält, ändern Sie sie so, dass nur die Stadt und das Land angegeben sind).Dies sind die einzigen Städte und Länder im Datensatz:
Amsterdam, Niederlande
Barcelona, Spanien
London, Vereinigtes Königreich
Mailand, Italien
Paris, Frankreich
Wien, Österreich
```python def replace_address(row): if "Netherlands" in row["Hotel_Address"]: return "Amsterdam, Netherlands" elif "Barcelona" in row["Hotel_Address"]: return "Barcelona, Spain" elif "United Kingdom" in row["Hotel_Address"]: return "London, United Kingdom" elif "Milan" in row["Hotel_Address"]:
return "Milan, Italy" elif "France" in row["Hotel_Address"]: return "Paris, France" elif "Vienna" in row["Hotel_Address"]: return "Vienna, Austria"# Replace all the addresses with a shortened, more useful form df["Hotel_Address"] = df.apply(replace_address, axis = 1) # The sum of the value_counts() should add up to the total number of reviews print(df["Hotel_Address"].value_counts()) ```
Nun können Sie Daten auf Länderebene abfragen:
python display(df.groupby("Hotel_Address").agg({"Hotel_Name": "nunique"}))Hotel_Address Hotel_Name Amsterdam, Niederlande 105 Barcelona, Spanien 211 London, Vereinigtes Königreich 400 Mailand, Italien 162 Paris, Frankreich 458 Wien, Österreich 158 -
Verarbeitung der Hotel-Meta-Review-Spalten
-
Entfernen Sie
Additional_Number_of_Scoring. -
Ersetzen Sie
Total_Number_of_Reviewsdurch die tatsächliche Anzahl der Bewertungen für das jeweilige Hotel, die im Datensatz enthalten sind. -
Ersetzen Sie
Average_Scoredurch einen selbst berechneten Durchschnittswert.
python
# Drop `Additional_Number_of_Scoring`
df.drop(["Additional_Number_of_Scoring"], axis = 1, inplace=True)
# Replace `Total_Number_of_Reviews` and `Average_Score` with our own calculated values
df.Total_Number_of_Reviews = df.groupby('Hotel_Name').transform('count')
df.Average_Score = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
-
Verarbeitung der Bewertungs-Spalten
-
Entfernen Sie
Review_Total_Negative_Word_Counts,Review_Total_Positive_Word_Counts,Review_Dateunddays_since_review. -
Behalten Sie
Reviewer_Score,Negative_ReviewundPositive_Reviewbei. -
Behalten Sie
Tagsvorerst bei.- Wir werden im nächsten Abschnitt einige zusätzliche Filteroperationen auf die Tags anwenden und sie dann entfernen.
-
Verarbeitung der Rezensenten-Spalten
-
Entfernen Sie
Total_Number_of_Reviews_Reviewer_Has_Given. -
Behalten Sie
Reviewer_Nationality.
Tag-Spalten
Die Tag-Spalte ist problematisch, da sie eine Liste (im Textformat) enthält, die in der Spalte gespeichert ist. Leider sind die Reihenfolge und die Anzahl der Unterabschnitte in dieser Spalte nicht immer gleich. Es ist für einen Menschen schwierig, die richtigen Phrasen zu identifizieren, die von Interesse sind, da es 515.000 Zeilen und 1427 Hotels gibt und jede Bewertung leicht unterschiedliche Optionen bietet, die ein Rezensent auswählen könnte. Hier kommt NLP ins Spiel. Sie können den Text scannen, die häufigsten Phrasen finden und diese zählen.
Leider interessieren uns keine einzelnen Wörter, sondern mehrwortige Phrasen (z. B. Geschäftsreise). Das Ausführen eines Algorithmus zur Häufigkeitsverteilung von Mehrwortphrasen auf so vielen Daten (6.762.646 Wörter) könnte außergewöhnlich viel Zeit in Anspruch nehmen. Ohne die Daten anzusehen, scheint dies jedoch notwendig zu sein. Hier ist explorative Datenanalyse nützlich, denn nachdem Sie eine Stichprobe der Tags wie [' Geschäftsreise ', ' Alleinreisender ', ' Einzelzimmer ', ' Aufenthalt 5 Nächte ', ' Übermittelt von einem mobilen Gerät '] gesehen haben, können Sie beginnen zu fragen, ob es möglich ist, die Verarbeitung erheblich zu reduzieren. Glücklicherweise ist das möglich – aber zuerst müssen Sie einige Schritte befolgen, um die interessanten Tags zu ermitteln.
Filtern der Tags
Denken Sie daran, dass das Ziel des Datensatzes darin besteht, Sentiment und Spalten hinzuzufügen, die Ihnen helfen, das beste Hotel auszuwählen (für sich selbst oder vielleicht für einen Kunden, der Sie beauftragt, einen Hotel-Empfehlungsbot zu erstellen). Sie müssen sich fragen, ob die Tags im endgültigen Datensatz nützlich sind oder nicht. Hier ist eine Interpretation (wenn Sie den Datensatz aus anderen Gründen benötigen, könnten andere Tags in der Auswahl bleiben oder entfernt werden):
- Die Art der Reise ist relevant und sollte bleiben.
- Die Art der Gästegruppe ist wichtig und sollte bleiben.
- Die Art des Zimmers, der Suite oder des Studios, in dem der Gast übernachtet hat, ist irrelevant (alle Hotels haben im Grunde die gleichen Zimmer).
- Das Gerät, mit dem die Bewertung übermittelt wurde, ist irrelevant.
- Die Anzahl der Nächte, die der Rezensent geblieben ist, könnte relevant sein, wenn Sie längere Aufenthalte mit einer höheren Zufriedenheit des Hotels in Verbindung bringen, aber das ist eher unwahrscheinlich und wahrscheinlich irrelevant.
Zusammenfassend: Behalten Sie 2 Arten von Tags und entfernen Sie die anderen.
Zuerst möchten Sie die Tags nicht zählen, bis sie in einem besseren Format vorliegen. Das bedeutet, dass Sie die eckigen Klammern und Anführungszeichen entfernen müssen. Es gibt mehrere Möglichkeiten, dies zu tun, aber Sie möchten die schnellste Methode, da die Verarbeitung viel Zeit in Anspruch nehmen könnte. Glücklicherweise bietet pandas eine einfache Möglichkeit, jeden dieser Schritte auszuführen.
# Remove opening and closing brackets
df.Tags = df.Tags.str.strip("[']")
# remove all quotes too
df.Tags = df.Tags.str.replace(" ', '", ",", regex = False)
Jedes Tag wird zu etwas wie: Geschäftsreise, Alleinreisender, Einzelzimmer, Aufenthalt 5 Nächte, Übermittelt von einem mobilen Gerät.
Als Nächstes stoßen wir auf ein Problem. Einige Bewertungen oder Zeilen haben 5 Spalten, andere 3, wieder andere 6. Dies ist ein Ergebnis der Art und Weise, wie der Datensatz erstellt wurde, und schwer zu beheben. Sie möchten eine Häufigkeitszählung jeder Phrase erhalten, aber sie sind in jeder Bewertung in unterschiedlicher Reihenfolge, sodass die Zählung möglicherweise ungenau ist und ein Hotel möglicherweise keinen Tag zugewiesen bekommt, den es verdient hätte.
Stattdessen nutzen Sie die unterschiedliche Reihenfolge zu Ihrem Vorteil, da jedes Tag mehrwörtig ist, aber auch durch ein Komma getrennt! Der einfachste Weg, dies zu tun, besteht darin, 6 temporäre Spalten zu erstellen, wobei jedes Tag in die Spalte eingefügt wird, die seiner Reihenfolge im Tag entspricht. Sie können dann die 6 Spalten zu einer großen Spalte zusammenführen und die Methode value_counts() auf die resultierende Spalte anwenden. Wenn Sie das ausgeben, sehen Sie, dass es 2428 einzigartige Tags gab. Hier ist eine kleine Stichprobe:
| Tag | Anzahl |
|---|---|
| Freizeitreise | 417778 |
| Übermittelt von einem mobilen Gerät | 307640 |
| Paar | 252294 |
| Aufenthalt 1 Nacht | 193645 |
| Aufenthalt 2 Nächte | 133937 |
| Alleinreisender | 108545 |
| Aufenthalt 3 Nächte | 95821 |
| Geschäftsreise | 82939 |
| Gruppe | 65392 |
| Familie mit kleinen Kindern | 61015 |
| Aufenthalt 4 Nächte | 47817 |
| Doppelzimmer | 35207 |
| Standard Doppelzimmer | 32248 |
| Superior Doppelzimmer | 31393 |
| Familie mit älteren Kindern | 26349 |
| Deluxe Doppelzimmer | 24823 |
| Doppel- oder Zweibettzimmer | 22393 |
| Aufenthalt 5 Nächte | 20845 |
| Standard Doppel- oder Zweibettzimmer | 17483 |
| Klassisches Doppelzimmer | 16989 |
| Superior Doppel- oder Zweibettzimmer | 13570 |
| 2 Zimmer | 12393 |
Einige der häufigen Tags wie Übermittelt von einem mobilen Gerät sind für uns nutzlos, daher könnte es sinnvoll sein, sie vor der Zählung der Phrasenhäufigkeit zu entfernen. Da dies jedoch eine so schnelle Operation ist, können Sie sie auch belassen und ignorieren.
Entfernen der Aufenthaltsdauer-Tags
Das Entfernen dieser Tags ist Schritt 1, es reduziert die Gesamtzahl der zu berücksichtigenden Tags leicht. Beachten Sie, dass Sie sie nicht aus dem Datensatz entfernen, sondern nur entscheiden, sie bei der Zählung/Beibehaltung im Bewertungsdatensatz nicht zu berücksichtigen.
| Aufenthaltsdauer | Anzahl |
|---|---|
| Aufenthalt 1 Nacht | 193645 |
| Aufenthalt 2 Nächte | 133937 |
| Aufenthalt 3 Nächte | 95821 |
| Aufenthalt 4 Nächte | 47817 |
| Aufenthalt 5 Nächte | 20845 |
| Aufenthalt 6 Nächte | 9776 |
| Aufenthalt 7 Nächte | 7399 |
| Aufenthalt 8 Nächte | 2502 |
| Aufenthalt 9 Nächte | 1293 |
| ... | ... |
Es gibt eine große Vielfalt an Zimmern, Suiten, Studios, Apartments und so weiter. Sie bedeuten alle ungefähr dasselbe und sind für Sie nicht relevant, daher entfernen Sie sie aus der Betrachtung.
| Zimmertyp | Anzahl |
|---|---|
| Doppelzimmer | 35207 |
| Standard Doppelzimmer | 32248 |
| Superior Doppelzimmer | 31393 |
| Deluxe Doppelzimmer | 24823 |
| Doppel- oder Zweibettzimmer | 22393 |
| Standard Doppel- oder Zweibettzimmer | 17483 |
| Klassisches Doppelzimmer | 16989 |
| Superior Doppel- oder Zweibettzimmer | 13570 |
Schließlich, und das ist erfreulich (weil es kaum Verarbeitung erforderte), bleiben Ihnen die folgenden nützlichen Tags:
| Tag | Anzahl |
|---|---|
| Freizeitreise | 417778 |
| Paar | 252294 |
| Alleinreisender | 108545 |
| Geschäftsreise | 82939 |
| Gruppe (kombiniert mit Reisende mit Freunden) | 67535 |
| Familie mit kleinen Kindern | 61015 |
| Familie mit älteren Kindern | 26349 |
| Mit einem Haustier | 1405 |
Man könnte argumentieren, dass Reisende mit Freunden mehr oder weniger dasselbe ist wie Gruppe, und es wäre sinnvoll, die beiden wie oben zu kombinieren. Der Code zur Identifizierung der richtigen Tags befindet sich im Tags-Notebook.
Der letzte Schritt besteht darin, neue Spalten für jedes dieser Tags zu erstellen. Dann fügen Sie für jede Bewertungszeile eine 1 hinzu, wenn die Tag-Spalte mit einer der neuen Spalten übereinstimmt, andernfalls eine 0. Das Endergebnis ist eine Zählung, wie viele Rezensenten dieses Hotel (in der Gesamtheit) beispielsweise für Geschäftsreisen oder Freizeit ausgewählt haben oder um ein Haustier mitzubringen. Dies sind nützliche Informationen, wenn Sie ein Hotel empfehlen möchten.
# Process the Tags into new columns
# The file Hotel_Reviews_Tags.py, identifies the most important tags
# Leisure trip, Couple, Solo traveler, Business trip, Group combined with Travelers with friends,
# Family with young children, Family with older children, With a pet
df["Leisure_trip"] = df.Tags.apply(lambda tag: 1 if "Leisure trip" in tag else 0)
df["Couple"] = df.Tags.apply(lambda tag: 1 if "Couple" in tag else 0)
df["Solo_traveler"] = df.Tags.apply(lambda tag: 1 if "Solo traveler" in tag else 0)
df["Business_trip"] = df.Tags.apply(lambda tag: 1 if "Business trip" in tag else 0)
df["Group"] = df.Tags.apply(lambda tag: 1 if "Group" in tag or "Travelers with friends" in tag else 0)
df["Family_with_young_children"] = df.Tags.apply(lambda tag: 1 if "Family with young children" in tag else 0)
df["Family_with_older_children"] = df.Tags.apply(lambda tag: 1 if "Family with older children" in tag else 0)
df["With_a_pet"] = df.Tags.apply(lambda tag: 1 if "With a pet" in tag else 0)
Speichern Sie Ihre Datei
Speichern Sie schließlich den Datensatz, wie er jetzt ist, unter einem neuen Namen.
df.drop(["Review_Total_Negative_Word_Counts", "Review_Total_Positive_Word_Counts", "days_since_review", "Total_Number_of_Reviews_Reviewer_Has_Given"], axis = 1, inplace=True)
# Saving new data file with calculated columns
print("Saving results to Hotel_Reviews_Filtered.csv")
df.to_csv(r'../data/Hotel_Reviews_Filtered.csv', index = False)
Sentiment-Analyse-Operationen
In diesem letzten Abschnitt wenden Sie Sentiment-Analyse auf die Bewertungs-Spalten an und speichern die Ergebnisse in einem Datensatz.
Übung: Laden und Speichern der gefilterten Daten
Beachten Sie, dass Sie jetzt den gefilterten Datensatz laden, der im vorherigen Abschnitt gespeichert wurde, nicht den ursprünglichen Datensatz.
import time
import pandas as pd
import nltk as nltk
from nltk.corpus import stopwords
from nltk.sentiment.vader import SentimentIntensityAnalyzer
nltk.download('vader_lexicon')
# Load the filtered hotel reviews from CSV
df = pd.read_csv('../../data/Hotel_Reviews_Filtered.csv')
# You code will be added here
# Finally remember to save the hotel reviews with new NLP data added
print("Saving results to Hotel_Reviews_NLP.csv")
df.to_csv(r'../data/Hotel_Reviews_NLP.csv', index = False)
Entfernen von Stoppwörtern
Wenn Sie die Sentiment-Analyse auf die Spalten für negative und positive Bewertungen anwenden würden, könnte dies viel Zeit in Anspruch nehmen. Auf einem leistungsstarken Test-Laptop mit schnellem Prozessor dauerte es 12–14 Minuten, je nachdem, welche Sentiment-Bibliothek verwendet wurde. Das ist eine (relativ) lange Zeit, daher lohnt es sich zu untersuchen, ob dies beschleunigt werden kann.
Das Entfernen von Stoppwörtern, also häufigen englischen Wörtern, die das Sentiment eines Satzes nicht verändern, ist der erste Schritt. Durch das Entfernen dieser Wörter sollte die Sentiment-Analyse schneller laufen, ohne an Genauigkeit zu verlieren (da die Stoppwörter das Sentiment nicht beeinflussen, aber die Analyse verlangsamen).
Die längste negative Bewertung hatte 395 Wörter, aber nach dem Entfernen der Stoppwörter sind es nur noch 195 Wörter.
Das Entfernen der Stoppwörter ist ebenfalls eine schnelle Operation. Das Entfernen der Stoppwörter aus 2 Bewertungs-Spalten über 515.000 Zeilen dauerte auf dem Testgerät 3,3 Sekunden. Es könnte bei Ihnen etwas mehr oder weniger Zeit in Anspruch nehmen, abhängig von der Geschwindigkeit Ihrer CPU, dem RAM, ob Sie eine SSD haben oder nicht, und einigen anderen Faktoren. Die relativ kurze Dauer dieser Operation bedeutet, dass es sich lohnt, sie durchzuführen, wenn sie die Zeit für die Sentiment-Analyse verbessert.
from nltk.corpus import stopwords
# Load the hotel reviews from CSV
df = pd.read_csv("../../data/Hotel_Reviews_Filtered.csv")
# Remove stop words - can be slow for a lot of text!
# Ryan Han (ryanxjhan on Kaggle) has a great post measuring performance of different stop words removal approaches
# https://www.kaggle.com/ryanxjhan/fast-stop-words-removal # using the approach that Ryan recommends
start = time.time()
cache = set(stopwords.words("english"))
def remove_stopwords(review):
text = " ".join([word for word in review.split() if word not in cache])
return text
# Remove the stop words from both columns
df.Negative_Review = df.Negative_Review.apply(remove_stopwords)
df.Positive_Review = df.Positive_Review.apply(remove_stopwords)
Durchführung der Sentiment-Analyse
Nun sollten Sie die Sentiment-Analyse sowohl für die Spalten mit negativen als auch mit positiven Bewertungen berechnen und das Ergebnis in 2 neuen Spalten speichern. Der Test der Sentiment-Analyse wird darin bestehen, sie mit der Bewertung des Rezensenten für dieselbe Bewertung zu vergleichen. Wenn beispielsweise die Sentiment-Analyse ergibt, dass die negative Bewertung ein Sentiment von 1 (extrem positives Sentiment) und die positive Bewertung ebenfalls ein Sentiment von 1 hat, der Rezensent dem Hotel jedoch die niedrigste mögliche Bewertung gegeben hat, dann stimmt entweder der Bewertungstext nicht mit der Bewertung überein oder der Sentiment-Analysator konnte das Sentiment nicht korrekt erkennen. Sie sollten erwarten, dass einige Sentiment-Werte völlig falsch sind, und oft wird das erklärbar sein, z. B. könnte die Bewertung extrem sarkastisch sein: "Natürlich LIEBTE ich es, in einem Zimmer ohne Heizung zu schlafen", und der Sentiment-Analysator denkt, das sei ein positives Sentiment, obwohl ein Mensch beim Lesen erkennen würde, dass es sich um Sarkasmus handelt. NLTK bietet verschiedene Sentiment-Analysetools, mit denen man arbeiten kann, und Sie können diese austauschen, um zu sehen, ob die Sentimentanalyse genauer oder weniger genau ist. Hier wird die VADER-Sentimentanalyse verwendet.
> Hutto, C.J. & Gilbert, E.E. (2014). VADER: Ein sparsames regelbasiertes Modell zur Sentimentanalyse von Social-Media-Texten. Achte Internationale Konferenz über Weblogs und Social Media (ICWSM-14). Ann Arbor, MI, Juni 2014.
from nltk.sentiment.vader import SentimentIntensityAnalyzer
# Create the vader sentiment analyser (there are others in NLTK you can try too)
vader_sentiment = SentimentIntensityAnalyzer()
# Hutto, C.J. & Gilbert, E.E. (2014). VADER: A Parsimonious Rule-based Model for Sentiment Analysis of Social Media Text. Eighth International Conference on Weblogs and Social Media (ICWSM-14). Ann Arbor, MI, June 2014.
# There are 3 possibilities of input for a review:
# It could be "No Negative", in which case, return 0
# It could be "No Positive", in which case, return 0
# It could be a review, in which case calculate the sentiment
def calc_sentiment(review):
if review == "No Negative" or review == "No Positive":
return 0
return vader_sentiment.polarity_scores(review)["compound"]
Später im Programm, wenn Sie bereit sind, die Sentimentanalyse durchzuführen, können Sie sie auf jede Bewertung wie folgt anwenden:
# Add a negative sentiment and positive sentiment column
print("Calculating sentiment columns for both positive and negative reviews")
start = time.time()
df["Negative_Sentiment"] = df.Negative_Review.apply(calc_sentiment)
df["Positive_Sentiment"] = df.Positive_Review.apply(calc_sentiment)
end = time.time()
print("Calculating sentiment took " + str(round(end - start, 2)) + " seconds")
Dies dauert auf meinem Computer etwa 120 Sekunden, kann jedoch je nach Computer variieren. Wenn Sie die Ergebnisse ausdrucken und überprüfen möchten, ob das Sentiment mit der Bewertung übereinstimmt:
df = df.sort_values(by=["Negative_Sentiment"], ascending=True)
print(df[["Negative_Review", "Negative_Sentiment"]])
df = df.sort_values(by=["Positive_Sentiment"], ascending=True)
print(df[["Positive_Review", "Positive_Sentiment"]])
Das Allerletzte, was Sie mit der Datei tun sollten, bevor Sie sie in der Challenge verwenden, ist, sie zu speichern! Sie sollten auch in Betracht ziehen, alle neuen Spalten neu anzuordnen, damit sie einfacher zu bearbeiten sind (für einen Menschen ist dies eine kosmetische Änderung).
# Reorder the columns (This is cosmetic, but to make it easier to explore the data later)
df = df.reindex(["Hotel_Name", "Hotel_Address", "Total_Number_of_Reviews", "Average_Score", "Reviewer_Score", "Negative_Sentiment", "Positive_Sentiment", "Reviewer_Nationality", "Leisure_trip", "Couple", "Solo_traveler", "Business_trip", "Group", "Family_with_young_children", "Family_with_older_children", "With_a_pet", "Negative_Review", "Positive_Review"], axis=1)
print("Saving results to Hotel_Reviews_NLP.csv")
df.to_csv(r"../data/Hotel_Reviews_NLP.csv", index = False)
Sie sollten den gesamten Code für das Analyse-Notebook ausführen (nachdem Sie Ihr Filter-Notebook ausgeführt haben, um die Datei Hotel_Reviews_Filtered.csv zu generieren).
Zusammengefasst sind die Schritte:
- Die ursprüngliche Datensatzdatei Hotel_Reviews.csv wird in der vorherigen Lektion mit dem Explorer-Notebook untersucht.
- Hotel_Reviews.csv wird mit dem Filter-Notebook gefiltert, was zu Hotel_Reviews_Filtered.csv führt.
- Hotel_Reviews_Filtered.csv wird mit dem Sentiment-Analyse-Notebook verarbeitet, was zu Hotel_Reviews_NLP.csv führt.
- Verwenden Sie Hotel_Reviews_NLP.csv in der untenstehenden NLP-Challenge.
Fazit
Zu Beginn hatten Sie einen Datensatz mit Spalten und Daten, aber nicht alle davon konnten überprüft oder verwendet werden. Sie haben die Daten untersucht, herausgefiltert, was Sie nicht benötigen, Tags in etwas Nützliches umgewandelt, eigene Durchschnittswerte berechnet, einige Sentiment-Spalten hinzugefügt und hoffentlich interessante Dinge über die Verarbeitung natürlicher Texte gelernt.
Quiz nach der Vorlesung
Challenge
Jetzt, da Sie Ihren Datensatz auf Sentiment analysiert haben, versuchen Sie, Strategien anzuwenden, die Sie in diesem Lehrplan gelernt haben (zum Beispiel Clustering?), um Muster rund um das Sentiment zu erkennen.
Überprüfung & Selbststudium
Nehmen Sie dieses Lernmodul, um mehr zu erfahren und verschiedene Tools zu verwenden, um Sentiment in Texten zu erkunden.
Aufgabe
Probieren Sie einen anderen Datensatz aus
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
import pandas as pd
import time
import ast
def replace_address(row):
if "Netherlands" in row["Hotel_Address"]:
return "Amsterdam, Netherlands"
elif "Barcelona" in row["Hotel_Address"]:
return "Barcelona, Spain"
elif "United Kingdom" in row["Hotel_Address"]:
return "London, United Kingdom"
elif "Milan" in row["Hotel_Address"]:
return "Milan, Italy"
elif "France" in row["Hotel_Address"]:
return "Paris, France"
elif "Vienna" in row["Hotel_Address"]:
return "Vienna, Austria"
else:
return row.Hotel_Address
# Load the hotel reviews from CSV
start = time.time()
df = pd.read_csv('../../data/Hotel_Reviews.csv')
# dropping columns we will not use:
df.drop(["lat", "lng"], axis = 1, inplace=True)
# Replace all the addresses with a shortened, more useful form
df["Hotel_Address"] = df.apply(replace_address, axis = 1)
# Drop `Additional_Number_of_Scoring`
df.drop(["Additional_Number_of_Scoring"], axis = 1, inplace=True)
# Replace `Total_Number_of_Reviews` and `Average_Score` with our own calculated values
df.Total_Number_of_Reviews = df.groupby('Hotel_Name').transform('count')
df.Average_Score = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
# Process the Tags into new columns
# The file Hotel_Reviews_Tags.py, identifies the most important tags
# Leisure trip, Couple, Solo traveler, Business trip, Group combined with Travelers with friends,
# Family with young children, Family with older children, With a pet
df["Leisure_trip"] = df.Tags.apply(lambda tag: 1 if "Leisure trip" in tag else 0)
df["Couple"] = df.Tags.apply(lambda tag: 1 if "Couple" in tag else 0)
df["Solo_traveler"] = df.Tags.apply(lambda tag: 1 if "Solo traveler" in tag else 0)
df["Business_trip"] = df.Tags.apply(lambda tag: 1 if "Business trip" in tag else 0)
df["Group"] = df.Tags.apply(lambda tag: 1 if "Group" in tag or "Travelers with friends" in tag else 0)
df["Family_with_young_children"] = df.Tags.apply(lambda tag: 1 if "Family with young children" in tag else 0)
df["Family_with_older_children"] = df.Tags.apply(lambda tag: 1 if "Family with older children" in tag else 0)
df["With_a_pet"] = df.Tags.apply(lambda tag: 1 if "With a pet" in tag else 0)
# No longer need any of these columns
df.drop(["Review_Date", "Review_Total_Negative_Word_Counts", "Review_Total_Positive_Word_Counts", "days_since_review", "Total_Number_of_Reviews_Reviewer_Has_Given"], axis = 1, inplace=True)
# Saving new data file with calculated columns
print("Saving results to Hotel_Reviews_Filtered.csv")
df.to_csv(r'../../data/Hotel_Reviews_Filtered.csv', index = False)
end = time.time()
print("Filtering took " + str(round(end - start, 2)) + " seconds")
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
# Load the hotel reviews from CSV (you can )
import pandas as pd
df = pd.read_csv('../../data/Hotel_Reviews_Filtered.csv')
# We want to find the most useful tags to keep
# Remove opening and closing brackets
df.Tags = df.Tags.str.strip("[']")
# remove all quotes too
df.Tags = df.Tags.str.replace(" ', '", ",", regex = False)
# removing this to take advantage of the 'already a phrase' fact of the dataset
# Now split the strings into a list
tag_list_df = df.Tags.str.split(',', expand = True)
# Remove leading and trailing spaces
df["Tag_1"] = tag_list_df[0].str.strip()
df["Tag_2"] = tag_list_df[1].str.strip()
df["Tag_3"] = tag_list_df[2].str.strip()
df["Tag_4"] = tag_list_df[3].str.strip()
df["Tag_5"] = tag_list_df[4].str.strip()
df["Tag_6"] = tag_list_df[5].str.strip()
# Merge the 6 columns into one with melt
df_tags = df.melt(value_vars=["Tag_1", "Tag_2", "Tag_3", "Tag_4", "Tag_5", "Tag_6"])
# Get the value counts
tag_vc = df_tags.value.value_counts()
# print(tag_vc)
print("The shape of the tags with no filtering:", str(df_tags.shape))
# Drop rooms, suites, and length of stay, mobile device and anything with less count than a 1000
df_tags = df_tags[~df_tags.value.str.contains("Standard|room|Stayed|device|Beds|Suite|Studio|King|Superior|Double", na=False, case=False)]
tag_vc = df_tags.value.value_counts().reset_index(name="count").query("count > 1000")
# Print the top 10 (there should only be 9 and we'll use these in the filtering section)
print(tag_vc[:10])
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
import time
import pandas as pd
import nltk as nltk
from nltk.corpus import stopwords
from nltk.sentiment.vader import SentimentIntensityAnalyzer
nltk.download('vader_lexicon')
vader_sentiment = SentimentIntensityAnalyzer()
# There are 3 possibilities of input for a review:
# It could be "No Negative", in which case, return 0
# It could be "No Positive", in which case, return 0
# It could be a review, in which case calculate the sentiment
def calc_sentiment(review):
if review == "No Negative" or review == "No Positive":
return 0
return vader_sentiment.polarity_scores(review)["compound"]
# Load the hotel reviews from CSV
df = pd.read_csv("../../data/Hotel_Reviews_Filtered.csv")
# Remove stop words - can be slow for a lot of text!
# Ryan Han (ryanxjhan on Kaggle) has a great post measuring performance of different stop words removal approaches
# https://www.kaggle.com/ryanxjhan/fast-stop-words-removal # using the approach that Ryan recommends
start = time.time()
cache = set(stopwords.words("english"))
def remove_stopwords(review):
text = " ".join([word for word in review.split() if word not in cache])
return text
# Remove the stop words from both columns
df.Negative_Review = df.Negative_Review.apply(remove_stopwords)
df.Positive_Review = df.Positive_Review.apply(remove_stopwords)
end = time.time()
print("Removing stop words took " + str(round(end - start, 2)) + " seconds")
# Add a negative sentiment and positive sentiment column
print("Calculating sentiment columns for both positive and negative reviews")
start = time.time()
df["Negative_Sentiment"] = df.Negative_Review.apply(calc_sentiment)
df["Positive_Sentiment"] = df.Positive_Review.apply(calc_sentiment)
end = time.time()
print("Calculating sentiment took " + str(round(end - start, 2)) + " seconds")
df = df.sort_values(by=["Negative_Sentiment"], ascending=True)
print(df[["Negative_Review", "Negative_Sentiment"]])
df = df.sort_values(by=["Positive_Sentiment"], ascending=True)
print(df[["Positive_Review", "Positive_Sentiment"]])
# Reorder the columns (This is cosmetic, but to make it easier to explore the data later)
df = df.reindex(["Hotel_Name", "Hotel_Address", "Total_Number_of_Reviews", "Average_Score", "Reviewer_Score", "Negative_Sentiment", "Positive_Sentiment", "Reviewer_Nationality", "Leisure_trip", "Couple", "Solo_traveler", "Business_trip", "Group", "Family_with_young_children", "Family_with_older_children", "With_a_pet", "Negative_Review", "Positive_Review"], axis=1)
print("Saving results to Hotel_Reviews_NLP.csv")
df.to_csv(r"../../data/Hotel_Reviews_NLP.csv", index = False)
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
dies ist ein temporärer Platzhalter
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Laden Sie die Hotelbewertungsdaten in diesen Ordner herunter.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einstieg in die Verarbeitung natürlicher Sprache
Die Verarbeitung natürlicher Sprache (Natural Language Processing, NLP) ist die Fähigkeit eines Computerprogramms, die menschliche Sprache so zu verstehen, wie sie gesprochen und geschrieben wird – bezeichnet als natürliche Sprache. Sie ist ein Bestandteil der künstlichen Intelligenz (KI). NLP existiert seit mehr als 50 Jahren und hat ihre Wurzeln in der Linguistik. Das gesamte Fachgebiet zielt darauf ab, Maschinen dabei zu helfen, die menschliche Sprache zu verstehen und zu verarbeiten. Dies kann dann genutzt werden, um Aufgaben wie Rechtschreibprüfung oder maschinelle Übersetzung auszuführen. Es hat eine Vielzahl von Anwendungen in der realen Welt in verschiedenen Bereichen, darunter medizinische Forschung, Suchmaschinen und Business Intelligence.
Regionales Thema: Europäische Sprachen und Literatur sowie romantische Hotels in Europa ❤️
In diesem Abschnitt des Lehrplans wirst du in eine der am weitesten verbreiteten Anwendungen des maschinellen Lernens eingeführt: die Verarbeitung natürlicher Sprache (NLP). Abgeleitet aus der Computerlinguistik ist diese Kategorie der künstlichen Intelligenz die Brücke zwischen Menschen und Maschinen durch sprachliche oder textbasierte Kommunikation.
In diesen Lektionen lernen wir die Grundlagen von NLP, indem wir kleine Konversationsbots erstellen, um zu verstehen, wie maschinelles Lernen dazu beiträgt, diese Gespräche immer „intelligenter“ zu machen. Du wirst in der Zeit zurückreisen und mit Elizabeth Bennett und Mr. Darcy aus Jane Austens klassischem Roman Stolz und Vorurteil, veröffentlicht im Jahr 1813, chatten. Anschließend vertiefst du dein Wissen, indem du mehr über Sentiment-Analyse anhand von Hotelbewertungen in Europa lernst.
> Foto von <a href="https://unsplash.com/@elaineh?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Elaine Howlin</a> auf <a href="https://unsplash.com/s/photos/pride-and-prejudice?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
Lektionen
- Einführung in die Verarbeitung natürlicher Sprache
- Häufige NLP-Aufgaben und Techniken
- Übersetzung und Sentiment-Analyse mit maschinellem Lernen
- Datenvorbereitung
- NLTK für Sentiment-Analyse
Credits
Diese Lektionen zur Verarbeitung natürlicher Sprache wurden mit ☕ von Stephen Howell geschrieben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Visualisiere weitere Zeitreihen
Anweisungen
Du hast begonnen, etwas über Zeitreihenprognosen zu lernen, indem du dir die Art von Daten angesehen hast, die dieses spezielle Modellieren erfordern. Du hast einige Daten rund um Energie visualisiert. Jetzt suche nach anderen Daten, die von Zeitreihenprognosen profitieren könnten. Finde drei Beispiele (versuche Kaggle und Azure Open Datasets) und erstelle ein Notebook, um sie zu visualisieren. Notiere in dem Notebook alle besonderen Merkmale, die sie aufweisen (Saisonalität, abrupte Änderungen oder andere Trends).
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Drei Datensätze werden in einem Notebook geplottet und erklärt | Zwei Datensätze werden in einem Notebook geplottet und erklärt | Wenige Datensätze werden geplottet oder erklärt, oder die präsentierten Daten sind unzureichend |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in die Zeitreihenprognose

> Sketchnote von Tomomi Imura
In dieser und der nächsten Lektion wirst du etwas über Zeitreihenprognosen lernen, ein interessantes und wertvolles Werkzeug im Repertoire eines ML-Wissenschaftlers, das weniger bekannt ist als andere Themen. Zeitreihenprognosen sind eine Art „Kristallkugel“: Basierend auf der bisherigen Entwicklung einer Variablen, wie z. B. einem Preis, kannst du ihren potenziellen zukünftigen Wert vorhersagen.
> 🎥 Klicke auf das Bild oben, um ein Video über Zeitreihenprognosen anzusehen
Quiz vor der Vorlesung
Es ist ein nützliches und interessantes Feld mit echtem Mehrwert für Unternehmen, da es direkt auf Probleme wie Preisgestaltung, Bestandsmanagement und Lieferkettenfragen angewendet werden kann. Während Deep-Learning-Techniken zunehmend eingesetzt werden, um bessere Einblicke zu gewinnen und zukünftige Entwicklungen besser vorherzusagen, bleibt die Zeitreihenprognose ein Bereich, der stark von klassischen ML-Techniken geprägt ist.
> Das nützliche Zeitreihen-Curriculum der Penn State University findest du hier
Einführung
Angenommen, du verwaltest eine Reihe von intelligenten Parkuhren, die Daten darüber liefern, wie oft und wie lange sie im Laufe der Zeit genutzt werden.
> Was wäre, wenn du basierend auf der bisherigen Nutzung der Parkuhr ihren zukünftigen Wert gemäß den Gesetzen von Angebot und Nachfrage vorhersagen könntest?
Die genaue Vorhersage, wann gehandelt werden muss, um ein Ziel zu erreichen, ist eine Herausforderung, die mit Zeitreihenprognosen angegangen werden kann. Es würde die Leute zwar nicht glücklich machen, in Stoßzeiten mehr zahlen zu müssen, wenn sie einen Parkplatz suchen, aber es wäre eine sichere Möglichkeit, Einnahmen zu generieren, um die Straßen zu reinigen!
Lass uns einige Arten von Zeitreihenalgorithmen erkunden und ein Notebook starten, um einige Daten zu bereinigen und vorzubereiten. Die Daten, die du analysieren wirst, stammen aus dem GEFCom2014-Vorhersagewettbewerb. Sie umfassen 3 Jahre stündliche Daten zu Stromverbrauch und Temperatur zwischen 2012 und 2014. Anhand der historischen Muster des Stromverbrauchs und der Temperatur kannst du zukünftige Werte des Stromverbrauchs vorhersagen.
In diesem Beispiel lernst du, wie man einen Zeitschritt in die Zukunft vorhersagt, indem nur historische Verbrauchsdaten verwendet werden. Bevor du jedoch beginnst, ist es hilfreich, zu verstehen, was im Hintergrund passiert.
Einige Definitionen
Wenn du auf den Begriff „Zeitreihe“ stößt, musst du verstehen, wie er in verschiedenen Kontexten verwendet wird.
🎓 Zeitreihe
In der Mathematik ist eine „Zeitreihe eine Reihe von Datenpunkten, die in zeitlicher Reihenfolge indiziert (oder aufgelistet oder grafisch dargestellt) sind. Am häufigsten ist eine Zeitreihe eine Sequenz, die in gleichmäßigen zeitlichen Abständen aufgenommen wurde.“ Ein Beispiel für eine Zeitreihe ist der tägliche Schlusswert des Dow Jones Industrial Average. Zeitreihendiagramme und statistische Modellierung werden häufig in der Signalverarbeitung, Wettervorhersage, Erdbebenvorhersage und anderen Bereichen verwendet, in denen Ereignisse auftreten und Datenpunkte über die Zeit hinweg dargestellt werden können.
🎓 Zeitreihenanalyse
Die Zeitreihenanalyse ist die Analyse der oben genannten Zeitreihendaten. Zeitreihendaten können unterschiedliche Formen annehmen, einschließlich „unterbrochener Zeitreihen“, die Muster in der Entwicklung einer Zeitreihe vor und nach einem unterbrechenden Ereignis erkennen. Die Art der Analyse, die für die Zeitreihe erforderlich ist, hängt von der Natur der Daten ab. Zeitreihendaten selbst können in Form von Zahlen- oder Zeichenfolgen vorliegen.
Die durchzuführende Analyse verwendet eine Vielzahl von Methoden, einschließlich Frequenz- und Zeitbereich, linear und nichtlinear und mehr. Erfahre mehr über die vielen Möglichkeiten, diese Art von Daten zu analysieren.
🎓 Zeitreihenprognose
Die Zeitreihenprognose ist die Verwendung eines Modells, um zukünftige Werte basierend auf Mustern vorherzusagen, die aus zuvor gesammelten Daten abgeleitet wurden. Während es möglich ist, Regressionsmodelle zu verwenden, um Zeitreihendaten zu untersuchen, bei denen Zeitindizes als x-Variablen in einem Diagramm dargestellt werden, werden solche Daten am besten mit speziellen Modelltypen analysiert.
Zeitreihendaten sind eine Liste geordneter Beobachtungen, im Gegensatz zu Daten, die durch lineare Regression analysiert werden können. Das am häufigsten verwendete Modell ist ARIMA, ein Akronym für „Autoregressive Integrated Moving Average“.
ARIMA-Modelle „beziehen den aktuellen Wert einer Serie auf vergangene Werte und frühere Vorhersagefehler.“ Sie eignen sich am besten zur Analyse von Zeitbereichsdaten, bei denen Daten in zeitlicher Reihenfolge angeordnet sind.
> Es gibt verschiedene Arten von ARIMA-Modellen, über die du hier mehr erfahren kannst und die in der nächsten Lektion behandelt werden.
In der nächsten Lektion wirst du ein ARIMA-Modell mit Univariaten Zeitreihen erstellen, das sich auf eine Variable konzentriert, deren Wert sich im Laufe der Zeit ändert. Ein Beispiel für diese Art von Daten ist dieser Datensatz, der die monatliche CO2-Konzentration am Mauna Loa Observatory aufzeichnet:
| CO2 | YearMonth | Year | Month |
|---|---|---|---|
| 330.62 | 1975.04 | 1975 | 1 |
| 331.40 | 1975.13 | 1975 | 2 |
| 331.87 | 1975.21 | 1975 | 3 |
| 333.18 | 1975.29 | 1975 | 4 |
| 333.92 | 1975.38 | 1975 | 5 |
| 333.43 | 1975.46 | 1975 | 6 |
| 331.85 | 1975.54 | 1975 | 7 |
| 330.01 | 1975.63 | 1975 | 8 |
| 328.51 | 1975.71 | 1975 | 9 |
| 328.41 | 1975.79 | 1975 | 10 |
| 329.25 | 1975.88 | 1975 | 11 |
| 330.97 | 1975.96 | 1975 | 12 |
✅ Identifiziere die Variable, die sich in diesem Datensatz im Laufe der Zeit ändert.
Zu berücksichtigende Eigenschaften von Zeitreihendaten
Wenn du Zeitreihendaten betrachtest, wirst du möglicherweise feststellen, dass sie bestimmte Eigenschaften aufweisen, die du berücksichtigen und mildern musst, um ihre Muster besser zu verstehen. Wenn du Zeitreihendaten als potenzielles „Signal“ betrachtest, das du analysieren möchtest, können diese Eigenschaften als „Rauschen“ angesehen werden. Oft musst du dieses „Rauschen“ reduzieren, indem du einige statistische Techniken anwendest.
Hier sind einige Konzepte, die du kennen solltest, um mit Zeitreihen zu arbeiten:
🎓 Trends
Trends sind messbare Zunahmen und Abnahmen im Laufe der Zeit. Lies mehr. Im Kontext von Zeitreihen geht es darum, wie man Trends nutzt und, falls erforderlich, aus den Zeitreihen entfernt.
Saisonalität ist definiert als periodische Schwankungen, wie z. B. Feiertagsanstürme, die sich auf den Umsatz auswirken könnten. Schau dir an, wie verschiedene Diagrammtypen Saisonalität in Daten darstellen.
🎓 Ausreißer
Ausreißer sind Datenpunkte, die weit außerhalb der Standardvarianz liegen.
🎓 Langfristige Zyklen
Unabhängig von der Saisonalität können Daten langfristige Zyklen aufweisen, wie z. B. eine wirtschaftliche Rezession, die länger als ein Jahr dauert.
🎓 Konstante Varianz
Im Laufe der Zeit zeigen einige Daten konstante Schwankungen, wie z. B. der tägliche und nächtliche Energieverbrauch.
🎓 Abrupte Änderungen
Die Daten können abrupte Änderungen aufweisen, die einer weiteren Analyse bedürfen. Die plötzliche Schließung von Unternehmen aufgrund von COVID führte beispielsweise zu Veränderungen in den Daten.
✅ Hier ist ein Beispiel für ein Zeitreihendiagramm, das die täglichen Ausgaben für In-Game-Währung über einige Jahre zeigt. Kannst du eine der oben genannten Eigenschaften in diesen Daten erkennen?

Übung – Einstieg in Stromverbrauchsdaten
Lass uns beginnen, ein Zeitreihenmodell zu erstellen, um den zukünftigen Stromverbrauch basierend auf vergangenen Verbrauchsdaten vorherzusagen.
> Die Daten in diesem Beispiel stammen aus dem GEFCom2014-Vorhersagewettbewerb. Sie umfassen 3 Jahre stündliche Daten zu Stromverbrauch und Temperaturwerten zwischen 2012 und 2014. > > Tao Hong, Pierre Pinson, Shu Fan, Hamidreza Zareipour, Alberto Troccoli und Rob J. Hyndman, „Probabilistic energy forecasting: Global Energy Forecasting Competition 2014 and beyond“, International Journal of Forecasting, vol.32, no.3, pp 896-913, Juli-September, 2016.
-
Öffne im Ordner
workingdieser Lektion die Datei notebook.ipynb. Beginne damit, Bibliotheken hinzuzufügen, die dir beim Laden und Visualisieren von Daten helfen:python import os import matplotlib.pyplot as plt from common.utils import load_data %matplotlib inlineBeachte, dass du die Dateien aus dem enthaltenen Ordner
commonverwendest, die deine Umgebung einrichten und das Herunterladen der Daten übernehmen. -
Untersuche als Nächstes die Daten als DataFrame, indem du
load_data()undhead()aufrufst:python data_dir = './data' energy = load_data(data_dir)[['load']] energy.head()Du kannst sehen, dass es zwei Spalten gibt, die Datum und Verbrauch darstellen:
load 2012-01-01 00:00:00 2698.0 2012-01-01 01:00:00 2558.0 2012-01-01 02:00:00 2444.0 2012-01-01 03:00:00 2402.0 2012-01-01 04:00:00 2403.0 -
Zeichne nun die Daten, indem du
plot()aufrufst:python energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12) plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()
-
Zeichne nun die erste Juliwoche 2014, indem du sie als Eingabe im Muster
[von Datum]:[bis Datum]anenergyübergibst:python energy['2014-07-01':'2014-07-07'].plot(y='load', subplots=True, figsize=(15, 8), fontsize=12) plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()
Ein wunderschönes Diagramm! Sieh dir diese Diagramme an und überlege, ob du eine der oben genannten Eigenschaften erkennen kannst. Was können wir durch die Visualisierung der Daten ableiten?
In der nächsten Lektion wirst du ein ARIMA-Modell erstellen, um einige Vorhersagen zu treffen.
🚀 Herausforderung
Erstelle eine Liste aller Branchen und Forschungsbereiche, die deiner Meinung nach von Zeitreihenprognosen profitieren könnten. Kannst du dir eine Anwendung dieser Techniken in den Künsten vorstellen? In der Ökonometrie? In der Ökologie? Im Einzelhandel? In der Industrie? In der Finanzwelt? Wo noch?
Quiz nach der Vorlesung
Rückblick & Selbststudium
Obwohl wir sie hier nicht behandeln, werden neuronale Netze manchmal verwendet, um klassische Methoden der Zeitreihenprognose zu verbessern. Lies mehr darüber in diesem Artikel.
Aufgabe
Visualisiere weitere Zeitreihen
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Dateneinrichtung
In diesem Notebook zeigen wir, wie man: - Zeitreihendaten für dieses Modul einrichtet - die Daten visualisiert
Die Daten in diesem Beispiel stammen aus dem GEFCom2014-Vorhersagewettbewerb. Sie bestehen aus 3 Jahren stündlicher Stromlast- und Temperaturwerte zwischen 2012 und 2014.
Tao Hong, Pierre Pinson, Shu Fan, Hamidreza Zareipour, Alberto Troccoli und Rob J. Hyndman, "Probabilistic energy forecasting: Global Energy Forecasting Competition 2014 and beyond", International Journal of Forecasting, Bd. 32, Nr. 3, S. 896-913, Juli-September, 2016.
import os
import matplotlib.pyplot as plt
from common.utils import load_data
%matplotlib inline
Laden Sie die Daten aus der CSV-Datei in ein Pandas-DataFrame.
data_dir = './data'
energy = load_data(data_dir)[['load']]
energy.head()
Zeichnen Sie alle verfügbaren Lastdaten (Januar 2012 bis Dezember 2014)
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
energy['2014-07-01':'2014-07-07'].plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
dies ist ein temporärer Platzhalter
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Datenvorbereitung
In diesem Notebook zeigen wir, wie man:
Zeitreihendaten für dieses Modul einrichtet
die Daten visualisiert
Die Daten in diesem Beispiel stammen aus dem GEFCom2014-Vorhersagewettbewerb1. Sie umfassen 3 Jahre stündliche Stromlast- und Temperaturwerte zwischen 2012 und 2014.
1Tao Hong, Pierre Pinson, Shu Fan, Hamidreza Zareipour, Alberto Troccoli und Rob J. Hyndman, "Probabilistische Energievorhersage: Global Energy Forecasting Competition 2014 und darüber hinaus", International Journal of Forecasting, Bd.32, Nr.3, S. 896-913, Juli-September, 2016.
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Ein neues ARIMA-Modell
Anweisungen
Nachdem Sie ein ARIMA-Modell erstellt haben, erstellen Sie ein neues mit frischen Daten (probieren Sie eines von diesen Datensätzen von Duke). Kommentieren Sie Ihre Arbeit in einem Notebook, visualisieren Sie die Daten und Ihr Modell, und testen Sie die Genauigkeit mit MAPE.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Notebook wird präsentiert, in dem ein neues ARIMA-Modell erstellt, getestet und mit Visualisierungen sowie Genauigkeitsangaben erklärt wird. | Das präsentierte Notebook ist nicht kommentiert oder enthält Fehler | Ein unvollständiges Notebook wird präsentiert |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Zeitreihenprognose mit ARIMA
In der vorherigen Lektion haben Sie etwas über Zeitreihenprognosen gelernt und einen Datensatz geladen, der die Schwankungen der elektrischen Last über einen bestimmten Zeitraum zeigt.
> 🎥 Klicken Sie auf das Bild oben, um ein Video anzusehen: Eine kurze Einführung in ARIMA-Modelle. Das Beispiel wird in R durchgeführt, aber die Konzepte sind universell.
Quiz vor der Lektion
Einführung
In dieser Lektion lernen Sie eine spezifische Methode kennen, um Modelle mit ARIMA: AutoRegressive Integrated Moving Average zu erstellen. ARIMA-Modelle eignen sich besonders gut für Daten, die Nicht-Stationarität aufweisen.
Allgemeine Konzepte
Um mit ARIMA arbeiten zu können, müssen Sie einige grundlegende Konzepte kennen:
-
🎓 Stationarität. Im statistischen Kontext bezieht sich Stationarität auf Daten, deren Verteilung sich nicht ändert, wenn sie in der Zeit verschoben werden. Nicht-stationäre Daten zeigen hingegen Schwankungen aufgrund von Trends, die transformiert werden müssen, um analysiert werden zu können. Saisonalität kann beispielsweise Schwankungen in den Daten verursachen, die durch einen Prozess des „saisonalen Differenzierens“ eliminiert werden können.
-
🎓 Differenzieren. Das Differenzieren von Daten bezieht sich auf den Prozess, nicht-stationäre Daten zu transformieren, um sie stationär zu machen, indem der nicht-konstante Trend entfernt wird. „Differenzieren entfernt die Änderungen im Niveau einer Zeitreihe, eliminiert Trends und Saisonalität und stabilisiert dadurch den Mittelwert der Zeitreihe.“ Paper von Shixiong et al
ARIMA im Kontext von Zeitreihen
Lassen Sie uns die Bestandteile von ARIMA genauer betrachten, um besser zu verstehen, wie es uns hilft, Zeitreihen zu modellieren und Vorhersagen zu treffen.
-
AR - für AutoRegressiv. Autoregressive Modelle analysieren, wie der Name schon sagt, frühere Werte in Ihren Daten, um Annahmen über sie zu treffen. Diese früheren Werte werden als „Lags“ bezeichnet. Ein Beispiel wären Daten, die monatliche Verkaufszahlen von Bleistiften zeigen. Die Verkaufszahlen jedes Monats würden als „entwickelnde Variable“ im Datensatz betrachtet. Dieses Modell wird erstellt, indem „die interessierende Variable auf ihre eigenen verzögerten (d. h. vorherigen) Werte regressiert wird.“ Wikipedia
-
I - für Integriert. Im Gegensatz zu den ähnlichen 'ARMA'-Modellen bezieht sich das 'I' in ARIMA auf den integrierten Aspekt. Die Daten werden „integriert“, wenn Differenzierungsschritte angewendet werden, um Nicht-Stationarität zu eliminieren.
-
MA - für Gleitender Durchschnitt. Der gleitende Durchschnitt in diesem Modell bezieht sich auf die Ausgangsvariable, die durch die Beobachtung der aktuellen und vergangenen Werte der Lags bestimmt wird.
Fazit: ARIMA wird verwendet, um ein Modell so genau wie möglich an die spezielle Form von Zeitreihendaten anzupassen.
Übung - Ein ARIMA-Modell erstellen
Öffnen Sie den /working-Ordner in dieser Lektion und suchen Sie die Datei notebook.ipynb.
-
Führen Sie das Notebook aus, um die Python-Bibliothek
statsmodelszu laden; diese benötigen Sie für ARIMA-Modelle. -
Laden Sie die notwendigen Bibliotheken.
-
Laden Sie nun weitere Bibliotheken, die für die Datenvisualisierung nützlich sind:
```python import os import warnings import matplotlib.pyplot as plt import numpy as np import pandas as pd import datetime as dt import math
from pandas.plotting import autocorrelation_plot from statsmodels.tsa.statespace.sarimax import SARIMAX from sklearn.preprocessing import MinMaxScaler from common.utils import load_data, mape from IPython.display import Image
%matplotlib inline pd.options.display.float_format = '{:,.2f}'.format np.set_printoptions(precision=2) warnings.filterwarnings("ignore") # specify to ignore warning messages ```
-
Laden Sie die Daten aus der Datei
/data/energy.csvin ein Pandas-DataFrame und werfen Sie einen Blick darauf:python energy = load_data('./data')[['load']] energy.head(10) -
Visualisieren Sie alle verfügbaren Energiedaten von Januar 2012 bis Dezember 2014. Es sollte keine Überraschungen geben, da wir diese Daten in der letzten Lektion gesehen haben:
python energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12) plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()Jetzt erstellen wir ein Modell!
Erstellen von Trainings- und Testdatensätzen
Nachdem Ihre Daten geladen sind, können Sie sie in Trainings- und Testdatensätze aufteilen. Sie trainieren Ihr Modell mit dem Trainingsdatensatz. Wie üblich bewerten Sie nach Abschluss des Trainings die Genauigkeit des Modells mit dem Testdatensatz. Sie müssen sicherstellen, dass der Testdatensatz einen späteren Zeitraum als der Trainingsdatensatz abdeckt, um sicherzustellen, dass das Modell keine Informationen aus zukünftigen Zeiträumen erhält.
-
Weisen Sie dem Trainingsdatensatz einen Zeitraum von zwei Monaten vom 1. September bis zum 31. Oktober 2014 zu. Der Testdatensatz umfasst den Zeitraum vom 1. November bis zum 31. Dezember 2014:
python train_start_dt = '2014-11-01 00:00:00' test_start_dt = '2014-12-30 00:00:00'Da diese Daten den täglichen Energieverbrauch widerspiegeln, gibt es ein starkes saisonales Muster, aber der Verbrauch ähnelt am meisten dem Verbrauch in den letzten Tagen.
-
Visualisieren Sie die Unterschiede:
python energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \ .join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \ .plot(y=['train', 'test'], figsize=(15, 8), fontsize=12) plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()
Daher sollte ein relativ kleines Zeitfenster für das Training der Daten ausreichen.
> Hinweis: Da die Funktion, die wir zum Anpassen des ARIMA-Modells verwenden, während des Anpassens eine Validierung innerhalb des Datensatzes durchführt, werden wir auf Validierungsdaten verzichten.
Daten für das Training vorbereiten
Nun müssen Sie die Daten für das Training vorbereiten, indem Sie die Daten filtern und skalieren. Filtern Sie Ihren Datensatz, um nur die benötigten Zeiträume und Spalten einzuschließen, und skalieren Sie die Daten, um sicherzustellen, dass sie im Intervall 0,1 projiziert werden.
-
Filtern Sie den ursprünglichen Datensatz, um nur die oben genannten Zeiträume pro Datensatz und nur die benötigte Spalte 'load' sowie das Datum einzuschließen:
```python train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']] test = energy.copy()[energy.index >= test_start_dt][['load']]
print('Training data shape: ', train.shape) print('Test data shape: ', test.shape) ```
Sie können die Form der Daten sehen:
output Training data shape: (1416, 1) Test data shape: (48, 1) -
Skalieren Sie die Daten, um sie in den Bereich (0, 1) zu bringen.
python scaler = MinMaxScaler() train['load'] = scaler.fit_transform(train) train.head(10) -
Visualisieren Sie die ursprünglichen vs. skalierten Daten:
python energy[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']].rename(columns={'load':'original load'}).plot.hist(bins=100, fontsize=12) train.rename(columns={'load':'scaled load'}).plot.hist(bins=100, fontsize=12) plt.show()
> Die ursprünglichen Daten

> Die skalierten Daten
-
Nachdem Sie die skalierten Daten kalibriert haben, können Sie die Testdaten skalieren:
python test['load'] = scaler.transform(test) test.head()
ARIMA implementieren
Es ist Zeit, ARIMA zu implementieren! Sie verwenden jetzt die zuvor installierte statsmodels-Bibliothek.
Nun müssen Sie mehrere Schritte ausführen:
- Definieren Sie das Modell, indem Sie
SARIMAX()aufrufen und die Modellparameter p, d und q sowie P, D und Q übergeben. - Bereiten Sie das Modell für die Trainingsdaten vor, indem Sie die Funktion
fit()aufrufen. - Treffen Sie Vorhersagen, indem Sie die Funktion
forecast()aufrufen und die Anzahl der Schritte (denHorizont) angeben, die vorhergesagt werden sollen.
> 🎓 Wofür stehen all diese Parameter? In einem ARIMA-Modell gibt es 3 Parameter, die verwendet werden, um die Hauptaspekte einer Zeitreihe zu modellieren: Saisonalität, Trend und Rauschen. Diese Parameter sind:
p: Der Parameter, der mit dem autoregressiven Aspekt des Modells verbunden ist und vergangene Werte einbezieht.
d: Der Parameter, der mit dem integrierten Teil des Modells verbunden ist und die Menge an Differenzierung (🎓 erinnern Sie sich an Differenzierung 👆?) beeinflusst, die auf eine Zeitreihe angewendet wird.
q: Der Parameter, der mit dem gleitenden Durchschnitt des Modells verbunden ist.
> Hinweis: Wenn Ihre Daten einen saisonalen Aspekt haben – was hier der Fall ist –, verwenden wir ein saisonales ARIMA-Modell (SARIMA). In diesem Fall müssen Sie ein weiteres Set von Parametern verwenden: P, D und Q, die dieselben Assoziationen wie p, d und q beschreiben, aber den saisonalen Komponenten des Modells entsprechen.
-
Beginnen Sie mit der Festlegung Ihres bevorzugten Horizontwerts. Versuchen wir es mit 3 Stunden:
```python
Specify the number of steps to forecast ahead
HORIZON = 3 print('Forecasting horizon:', HORIZON, 'hours') ```
Die Auswahl der besten Werte für die Parameter eines ARIMA-Modells kann herausfordernd sein, da sie subjektiv und zeitaufwändig ist. Sie könnten die Funktion
auto_arima()aus derpyramid-Bibliothek in Betracht ziehen. -
Versuchen Sie vorerst einige manuelle Auswahlmöglichkeiten, um ein gutes Modell zu finden.
```python order = (4, 1, 0) seasonal_order = (1, 1, 0, 24)
model = SARIMAX(endog=train, order=order, seasonal_order=seasonal_order) results = model.fit()
print(results.summary()) ```
Eine Ergebnistabelle wird ausgegeben.
Sie haben Ihr erstes Modell erstellt! Nun müssen wir eine Möglichkeit finden, es zu bewerten.
Modell bewerten
Um Ihr Modell zu bewerten, können Sie die sogenannte walk forward-Validierung durchführen. In der Praxis werden Zeitreihenmodelle jedes Mal neu trainiert, wenn neue Daten verfügbar werden. Dies ermöglicht es dem Modell, die beste Vorhersage zu jedem Zeitpunkt zu treffen.
Beginnen Sie am Anfang der Zeitreihe mit dieser Technik, trainieren Sie das Modell mit dem Trainingsdatensatz. Treffen Sie dann eine Vorhersage für den nächsten Zeitpunkt. Die Vorhersage wird mit dem bekannten Wert verglichen. Der Trainingsdatensatz wird dann erweitert, um den bekannten Wert einzuschließen, und der Prozess wird wiederholt.
> Hinweis: Sie sollten das Fenster des Trainingsdatensatzes fixieren, um effizienter zu trainieren, sodass jedes Mal, wenn Sie eine neue Beobachtung zum Trainingsdatensatz hinzufügen, die Beobachtung vom Anfang des Datensatzes entfernt wird.
Dieser Prozess bietet eine robustere Schätzung, wie das Modell in der Praxis abschneiden wird. Allerdings entstehen dadurch höhere Rechenkosten, da so viele Modelle erstellt werden. Dies ist akzeptabel, wenn die Daten klein oder das Modell einfach ist, könnte jedoch bei größeren Datenmengen problematisch sein.
Die Walk-Forward-Validierung ist der Goldstandard für die Bewertung von Zeitreihenmodellen und wird für Ihre eigenen Projekte empfohlen.
-
Erstellen Sie zunächst einen Testdatenpunkt für jeden HORIZON-Schritt.
```python test_shifted = test.copy()
for t in range(1, HORIZON+1): test_shifted['load+'+str(t)] = test_shifted['load'].shift(-t, freq='H')
test_shifted = test_shifted.dropna(how='any') test_shifted.head(5) ```
load load+1 load+2 2014-12-30 00:00:00 0.33 0.29 0.27 2014-12-30 01:00:00 0.29 0.27 0.27 2014-12-30 02:00:00 0.27 0.27 0.30 2014-12-30 03:00:00 0.27 0.30 0.41 2014-12-30 04:00:00 0.30 0.41 0.57 Die Daten werden horizontal entsprechend ihrem Horizontpunkt verschoben.
-
Treffen Sie Vorhersagen für Ihre Testdaten mit diesem gleitenden Fensteransatz in einer Schleife, die der Länge der Testdaten entspricht:
```python %%time training_window = 720 # dedicate 30 days (720 hours) for training
train_ts = train['load'] test_ts = test_shifted
history = [x for x in train_ts] history = history[(-training_window):]
predictions = list()
order = (2, 1, 0) seasonal_order = (1, 1, 0, 24)
for t in range(test_ts.shape[0]): model = SARIMAX(endog=history, order=order, seasonal_order=seasonal_order) model_fit = model.fit() yhat = model_fit.forecast(steps = HORIZON) predictions.append(yhat) obs = list(test_ts.iloc[t]) # move the training window history.append(obs[0]) history.pop(0) print(test_ts.index[t]) print(t+1, ': predicted =', yhat, 'expected =', obs) ```
Sie können das Training beobachten:
```output 2014-12-30 00:00:00 1 : predicted = [0.32 0.29 0.28] expected = [0.32945389435989236, 0.2900626678603402, 0.2739480752014323]
2014-12-30 01:00:00 2 : predicted = [0.3 0.29 0.3 ] expected = [0.2900626678603402, 0.2739480752014323, 0.26812891674127126]
2014-12-30 02:00:00 3 : predicted = [0.27 0.28 0.32] expected = [0.2739480752014323, 0.26812891674127126, 0.3025962399283795] ```
-
Vergleichen Sie die Vorhersagen mit der tatsächlichen Last:
python eval_df = pd.DataFrame(predictions, columns=['t+'+str(t) for t in range(1, HORIZON+1)]) eval_df['timestamp'] = test.index[0:len(test.index)-HORIZON+1] eval_df = pd.melt(eval_df, id_vars='timestamp', value_name='prediction', var_name='h') eval_df['actual'] = np.array(np.transpose(test_ts)).ravel() eval_df[['prediction', 'actual']] = scaler.inverse_transform(eval_df[['prediction', 'actual']]) eval_df.head()Ausgabe
| | | timestamp | h | prediction | actual | | --- | ---------- | --------- | --- | ---------- | -------- | | 0 | 2014-12-30 | 00:00:00 | t+1 | 3,008.74 | 3,023.00 | | 1 | 2014-12-30 | 01:00:00 | t+1 | 2,955.53 | 2,935.00 | | 2 | 2014-12-30 | 02:00:00 | t+1 | 2,900.17 | 2,899.00 | | 3 | 2014-12-30 | 03:00:00 | t+1 | 2,917.69 | 2,886.00 | | 4 | 2014-12-30 | 04:00:00 | t+1 | 2,946.99 | 2,963.00 |Beobachten Sie die stündlichen Vorhersagen im Vergleich zur tatsächlichen Last. Wie genau ist das?
Modellgenauigkeit überprüfen
Überprüfen Sie die Genauigkeit Ihres Modells, indem Sie den mittleren absoluten prozentualen Fehler (MAPE) über alle Vorhersagen testen.
> 🧮 Zeig mir die Mathematik
>
>
>
> MAPE wird verwendet, um die Vorhersagegenauigkeit als Verhältnis darzustellen, das durch die obige Formel definiert ist. Die Differenz zwischen tatsächlichem und vorhergesagtem Wert wird durch den tatsächlichen Wert geteilt. "Der Absolutwert dieser Berechnung wird für jeden prognostizierten Zeitpunkt summiert und durch die Anzahl der angepassten Punkte n geteilt." wikipedia
1. Ausdruck der Gleichung im Code:
```python
if(HORIZON > 1):
eval_df['APE'] = (eval_df['prediction'] - eval_df['actual']).abs() / eval_df['actual']
print(eval_df.groupby('h')['APE'].mean())
```
-
Berechnung des MAPE für einen Schritt:
python print('One step forecast MAPE: ', (mape(eval_df[eval_df['h'] == 't+1']['prediction'], eval_df[eval_df['h'] == 't+1']['actual']))*100, '%')MAPE der Ein-Schritt-Vorhersage: 0.5570581332313952 %
-
Ausgabe des MAPE für die Mehrschritt-Vorhersage:
python print('Multi-step forecast MAPE: ', mape(eval_df['prediction'], eval_df['actual'])*100, '%')output Multi-step forecast MAPE: 1.1460048657704118 %Eine niedrige Zahl ist am besten: Beachten Sie, dass eine Vorhersage mit einem MAPE von 10 um 10 % abweicht.
-
Aber wie immer ist es einfacher, diese Art von Genauigkeitsmessung visuell zu sehen. Lassen Sie uns das plotten:
```python if(HORIZON == 1): ## Plotting single step forecast eval_df.plot(x='timestamp', y=['actual', 'prediction'], style=['r', 'b'], figsize=(15, 8))
else: ## Plotting multi step forecast plot_df = eval_df[(eval_df.h=='t+1')][['timestamp', 'actual']] for t in range(1, HORIZON+1): plot_df['t+'+str(t)] = eval_df[(eval_df.h=='t+'+str(t))]['prediction'].values
fig = plt.figure(figsize=(15, 8)) ax = plt.plot(plot_df['timestamp'], plot_df['actual'], color='red', linewidth=4.0) ax = fig.add_subplot(111) for t in range(1, HORIZON+1): x = plot_df['timestamp'][(t-1):] y = plot_df['t+'+str(t)][0:len(x)] ax.plot(x, y, color='blue', linewidth=4*math.pow(.9,t), alpha=math.pow(0.8,t)) ax.legend(loc='best')plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show() ```

🏆 Ein sehr schöner Plot, der ein Modell mit guter Genauigkeit zeigt. Gut gemacht!
🚀Herausforderung
Tauchen Sie in die verschiedenen Möglichkeiten ein, die Genauigkeit eines Zeitreihenmodells zu testen. In dieser Lektion sprechen wir über MAPE, aber gibt es andere Methoden, die Sie verwenden könnten? Recherchieren Sie diese und kommentieren Sie sie. Ein hilfreiches Dokument finden Sie hier.
Quiz nach der Vorlesung
Rückblick & Selbststudium
Diese Lektion behandelt nur die Grundlagen der Zeitreihenprognose mit ARIMA. Nehmen Sie sich Zeit, Ihr Wissen zu vertiefen, indem Sie dieses Repository und seine verschiedenen Modelltypen durchstöbern, um andere Möglichkeiten zur Erstellung von Zeitreihenmodellen zu lernen.
Aufgabe
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Zeitreihenprognose mit ARIMA
In diesem Notebook zeigen wir, wie man: - Zeitreihendaten für das Training eines ARIMA-Zeitreihenprognosemodells vorbereitet - ein einfaches ARIMA-Modell implementiert, um die nächsten HORIZON-Schritte vorauszusagen (Zeit t+1 bis t+HORIZON) in der Zeitreihe - das Modell bewertet
Die Daten in diesem Beispiel stammen aus dem GEFCom2014 Prognosewettbewerb. Sie umfassen 3 Jahre stündliche Werte des Stromverbrauchs und der Temperatur zwischen 2012 und 2014. Die Aufgabe besteht darin, zukünftige Werte des Stromverbrauchs vorherzusagen. In diesem Beispiel zeigen wir, wie man einen Zeitschritt im Voraus prognostiziert, wobei nur historische Verbrauchsdaten verwendet werden.
Tao Hong, Pierre Pinson, Shu Fan, Hamidreza Zareipour, Alberto Troccoli und Rob J. Hyndman, "Probabilistic energy forecasting: Global Energy Forecasting Competition 2014 and beyond", International Journal of Forecasting, Bd. 32, Nr. 3, S. 896-913, Juli-September, 2016.
Abhängigkeiten installieren
Beginnen Sie mit der Installation einiger erforderlicher Abhängigkeiten. Diese Bibliotheken mit den entsprechenden Versionen sind bekannt dafür, mit der Lösung zu funktionieren:
statsmodels == 0.12.2matplotlib == 3.4.2scikit-learn == 0.24.2
!pip install statsmodels
import os
import warnings
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import datetime as dt
import math
from pandas.plotting import autocorrelation_plot
from statsmodels.tsa.statespace.sarimax import SARIMAX
from sklearn.preprocessing import MinMaxScaler
from common.utils import load_data, mape
from IPython.display import Image
%matplotlib inline
pd.options.display.float_format = '{:,.2f}'.format
np.set_printoptions(precision=2)
warnings.filterwarnings("ignore") # specify to ignore warning messages
energy = load_data('./data')[['load']]
energy.head(10)
Zeichnen Sie alle verfügbaren Lastdaten (Januar 2012 bis Dezember 2014) auf.
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
Erstellen von Trainings- und Testdatensätzen
Einführung
Das Erstellen von Trainings- und Testdatensätzen ist ein entscheidender Schritt im maschinellen Lernen. Ein gut aufgeteilter Datensatz stellt sicher, dass das Modell sowohl trainiert als auch unabhängig evaluiert werden kann.
Warum ist die Aufteilung wichtig?
[!NOTE] Die Aufteilung der Daten in Trainings- und Testdatensätze hilft dabei, Überanpassung zu vermeiden und die Generalisierungsfähigkeit des Modells zu bewerten.
- Trainingsdatensatz: Wird verwendet, um das Modell zu trainieren.
- Testdatensatz: Wird verwendet, um die Leistung des Modells auf neuen, unsichtbaren Daten zu bewerten.
Wie man die Daten aufteilt
-
Zufällige Aufteilung: Verwenden Sie eine zufällige Methode, um die Daten in zwei Gruppen zu teilen. Ein typisches Verhältnis ist 80% für das Training und 20% für das Testen.
-
Stratifizierte Aufteilung: Wenn Ihre Daten ungleichmäßig verteilt sind (z. B. bei Klassifikationsproblemen mit unbalancierten Klassen), stellen Sie sicher, dass die Verteilung der Klassen in beiden Datensätzen ähnlich bleibt.
Beispielcode
from sklearn.model_selection import train_test_split
# Daten und Labels laden
X, y = load_data()
# Aufteilen der Daten
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print("Trainingsdaten:", len(X_train))
print("Testdaten:", len(X_test))
Häufige Fehler vermeiden
[!WARNING] Vermeiden Sie es, die Testdaten während des Trainingsprozesses zu verwenden. Dies kann zu einer verzerrten Bewertung der Modellleistung führen.
- Datenleckage: Stellen Sie sicher, dass keine Informationen aus den Testdaten in den Trainingsprozess einfließen.
- Unzureichende Testdaten: Verwenden Sie genügend Daten für den Testdatensatz, um eine zuverlässige Bewertung zu gewährleisten.
Fazit
Das richtige Aufteilen der Daten ist ein grundlegender Schritt, um ein robustes maschinelles Lernmodell zu entwickeln. Achten Sie darauf, die Daten sorgfältig zu behandeln, um genaue und verlässliche Ergebnisse zu erzielen.
train_start_dt = '2014-11-01 00:00:00'
test_start_dt = '2014-12-30 00:00:00'
energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \
.join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \
.plot(y=['train', 'test'], figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']]
test = energy.copy()[energy.index >= test_start_dt][['load']]
print('Training data shape: ', train.shape)
print('Test data shape: ', test.shape)
scaler = MinMaxScaler()
train['load'] = scaler.fit_transform(train)
train.head(10)
Original vs skalierte Daten:
energy[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']].rename(columns={'load':'original load'}).plot.hist(bins=100, fontsize=12)
train.rename(columns={'load':'scaled load'}).plot.hist(bins=100, fontsize=12)
plt.show()
Lassen Sie uns auch die Testdaten skalieren
test['load'] = scaler.transform(test)
test.head()
# Specify the number of steps to forecast ahead
HORIZON = 3
print('Forecasting horizon:', HORIZON, 'hours')
order = (4, 1, 0)
seasonal_order = (1, 1, 0, 24)
model = SARIMAX(endog=train, order=order, seasonal_order=seasonal_order)
results = model.fit()
print(results.summary())
Bewerten Sie das Modell
Erstellen Sie einen Testdatenpunkt für jeden HORIZON-Schritt.
test_shifted = test.copy()
for t in range(1, HORIZON):
test_shifted['load+'+str(t)] = test_shifted['load'].shift(-t, freq='H')
test_shifted = test_shifted.dropna(how='any')
test_shifted.head(5)
Machen Sie Vorhersagen für die Testdaten
%%time
training_window = 720 # dedicate 30 days (720 hours) for training
train_ts = train['load']
test_ts = test_shifted
history = [x for x in train_ts]
history = history[(-training_window):]
predictions = list()
# let's user simpler model for demonstration
order = (2, 1, 0)
seasonal_order = (1, 1, 0, 24)
for t in range(test_ts.shape[0]):
model = SARIMAX(endog=history, order=order, seasonal_order=seasonal_order)
model_fit = model.fit()
yhat = model_fit.forecast(steps = HORIZON)
predictions.append(yhat)
obs = list(test_ts.iloc[t])
# move the training window
history.append(obs[0])
history.pop(0)
print(test_ts.index[t])
print(t+1, ': predicted =', yhat, 'expected =', obs)
Vergleiche Vorhersagen mit der tatsächlichen Last
eval_df = pd.DataFrame(predictions, columns=['t+'+str(t) for t in range(1, HORIZON+1)])
eval_df['timestamp'] = test.index[0:len(test.index)-HORIZON+1]
eval_df = pd.melt(eval_df, id_vars='timestamp', value_name='prediction', var_name='h')
eval_df['actual'] = np.array(np.transpose(test_ts)).ravel()
eval_df[['prediction', 'actual']] = scaler.inverse_transform(eval_df[['prediction', 'actual']])
eval_df.head()
Berechne den mittleren absoluten prozentualen Fehler (MAPE) für alle Vorhersagen
$$MAPE = \frac{1}{n} \sum_{t=1}^{n}|\frac{actual_t - predicted_t}{actual_t}|$$
if(HORIZON > 1):
eval_df['APE'] = (eval_df['prediction'] - eval_df['actual']).abs() / eval_df['actual']
print(eval_df.groupby('h')['APE'].mean())
print('One step forecast MAPE: ', (mape(eval_df[eval_df['h'] == 't+1']['prediction'], eval_df[eval_df['h'] == 't+1']['actual']))*100, '%')
print('Multi-step forecast MAPE: ', mape(eval_df['prediction'], eval_df['actual'])*100, '%')
Zeichnen Sie die Vorhersagen gegenüber den tatsächlichen Werten für die erste Woche des Testdatensatzes.
if(HORIZON == 1):
## Plotting single step forecast
eval_df.plot(x='timestamp', y=['actual', 'prediction'], style=['r', 'b'], figsize=(15, 8))
else:
## Plotting multi step forecast
plot_df = eval_df[(eval_df.h=='t+1')][['timestamp', 'actual']]
for t in range(1, HORIZON+1):
plot_df['t+'+str(t)] = eval_df[(eval_df.h=='t+'+str(t))]['prediction'].values
fig = plt.figure(figsize=(15, 8))
ax = plt.plot(plot_df['timestamp'], plot_df['actual'], color='red', linewidth=4.0)
ax = fig.add_subplot(111)
for t in range(1, HORIZON+1):
x = plot_df['timestamp'][(t-1):]
y = plot_df['t+'+str(t)][0:len(x)]
ax.plot(x, y, color='blue', linewidth=4*math.pow(.9,t), alpha=math.pow(0.8,t))
ax.legend(loc='best')
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
dies ist ein temporärer Platzhalter
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Zeitreihenprognose mit ARIMA
In diesem Notebook zeigen wir, wie man: - Zeitreihendaten für das Training eines ARIMA-Zeitreihenprognosemodells vorbereitet - ein einfaches ARIMA-Modell implementiert, um die nächsten HORIZON-Schritte vorauszusagen (Zeit t+1 bis t+HORIZON) in der Zeitreihe - das Modell bewertet
Die Daten in diesem Beispiel stammen aus dem GEFCom2014 Prognosewettbewerb. Sie umfassen 3 Jahre stündliche Werte des Stromverbrauchs und der Temperatur zwischen 2012 und 2014. Die Aufgabe besteht darin, zukünftige Werte des Stromverbrauchs vorherzusagen. In diesem Beispiel zeigen wir, wie man einen Zeitschritt im Voraus prognostiziert, wobei nur historische Verbrauchsdaten verwendet werden.
Tao Hong, Pierre Pinson, Shu Fan, Hamidreza Zareipour, Alberto Troccoli und Rob J. Hyndman, "Probabilistic energy forecasting: Global Energy Forecasting Competition 2014 and beyond", International Journal of Forecasting, Bd. 32, Nr. 3, S. 896-913, Juli-September, 2016.
pip install statsmodels
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Ein neues SVR-Modell
Anweisungen [^1]
Nachdem Sie ein SVR-Modell erstellt haben, erstellen Sie ein neues mit frischen Daten (probieren Sie eines dieser Datensätze von Duke aus). Kommentieren Sie Ihre Arbeit in einem Notebook, visualisieren Sie die Daten und Ihr Modell und testen Sie dessen Genauigkeit mit geeigneten Diagrammen und MAPE. Probieren Sie auch aus, die verschiedenen Hyperparameter anzupassen und unterschiedliche Werte für die Zeitstufen zu verwenden.
Bewertungskriterien [^1]
| Kriterien | Hervorragend | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Notebook wird präsentiert, in dem ein SVR-Modell erstellt, getestet und mit Visualisierungen sowie Genauigkeitsangaben erklärt wird. | Das präsentierte Notebook ist nicht kommentiert oder enthält Fehler. | Ein unvollständiges Notebook wird präsentiert. |
[^1]: Der Text in diesem Abschnitt basiert auf der Aufgabe von ARIMA
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Zeitreihenprognose mit Support Vector Regressor
In der vorherigen Lektion hast du gelernt, wie man das ARIMA-Modell zur Vorhersage von Zeitreihen verwendet. Jetzt wirst du das Support Vector Regressor-Modell kennenlernen, ein Regressionsmodell, das zur Vorhersage kontinuierlicher Daten verwendet wird.
Quiz vor der Lektion
Einführung
In dieser Lektion wirst du eine spezifische Methode entdecken, um Modelle mit SVM: Support Vector Machine für Regressionen zu erstellen, oder SVR: Support Vector Regressor.
SVR im Kontext von Zeitreihen [^1]
Bevor du die Bedeutung von SVR für die Vorhersage von Zeitreihen verstehst, hier einige wichtige Konzepte, die du kennen solltest:
- Regression: Überwachtes Lernverfahren zur Vorhersage kontinuierlicher Werte aus einem gegebenen Satz von Eingaben. Die Idee ist, eine Kurve (oder Linie) im Merkmalsraum zu finden, die die maximale Anzahl von Datenpunkten enthält. Hier klicken für weitere Informationen.
- Support Vector Machine (SVM): Ein Typ von überwachten Machine-Learning-Modellen, die für Klassifikation, Regression und Ausreißererkennung verwendet werden. Das Modell ist eine Hyperebene im Merkmalsraum, die im Fall der Klassifikation als Grenze und im Fall der Regression als Best-Fit-Linie fungiert. In SVM wird häufig eine Kernel-Funktion verwendet, um den Datensatz in einen Raum mit höherer Dimension zu transformieren, sodass sie leichter trennbar sind. Hier klicken für weitere Informationen zu SVMs.
- Support Vector Regressor (SVR): Ein Typ von SVM, der die Best-Fit-Linie (die im Fall von SVM eine Hyperebene ist) findet, die die maximale Anzahl von Datenpunkten enthält.
Warum SVR? [^1]
In der letzten Lektion hast du ARIMA kennengelernt, ein sehr erfolgreiches statistisches lineares Verfahren zur Vorhersage von Zeitreihendaten. In vielen Fällen weisen Zeitreihendaten jedoch Nichtlinearitäten auf, die von linearen Modellen nicht abgebildet werden können. In solchen Fällen macht die Fähigkeit von SVM, Nichtlinearitäten in den Daten für Regressionsaufgaben zu berücksichtigen, SVR erfolgreich bei der Vorhersage von Zeitreihen.
Übung - Erstelle ein SVR-Modell
Die ersten Schritte zur Datenvorbereitung sind dieselben wie in der vorherigen Lektion über ARIMA.
Öffne den /working-Ordner in dieser Lektion und finde die Datei notebook.ipynb. [^2]
- Führe das Notebook aus und importiere die notwendigen Bibliotheken: [^2]
python
import sys
sys.path.append('../../')
```python import os import warnings import matplotlib.pyplot as plt import numpy as np import pandas as pd import datetime as dt import math
from sklearn.svm import SVR from sklearn.preprocessing import MinMaxScaler from common.utils import load_data, mape ```
- Lade die Daten aus der Datei
/data/energy.csvin ein Pandas-DataFrame und schaue sie dir an: [^2]
python
energy = load_data('../../data')[['load']]
- Plotte alle verfügbaren Energiedaten von Januar 2012 bis Dezember 2014: [^2]
python
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()

Jetzt lass uns unser SVR-Modell erstellen.
Erstelle Trainings- und Testdatensätze
Nachdem deine Daten geladen sind, kannst du sie in Trainings- und Testdatensätze aufteilen. Anschließend formst du die Daten um, um einen zeitbasierten Datensatz zu erstellen, der für das SVR benötigt wird. Du trainierst dein Modell mit dem Trainingsdatensatz. Nachdem das Modell trainiert wurde, bewertest du seine Genauigkeit anhand des Trainingsdatensatzes, des Testdatensatzes und dann des vollständigen Datensatzes, um die Gesamtleistung zu sehen. Du musst sicherstellen, dass der Testdatensatz einen späteren Zeitraum als der Trainingsdatensatz abdeckt, um sicherzustellen, dass das Modell keine Informationen aus zukünftigen Zeiträumen erhält [^2] (eine Situation, die als Overfitting bekannt ist).
- Weise dem Trainingsdatensatz einen Zeitraum von zwei Monaten vom 1. September bis 31. Oktober 2014 zu. Der Testdatensatz umfasst den Zeitraum vom 1. November bis 31. Dezember 2014: [^2]
python
train_start_dt = '2014-11-01 00:00:00'
test_start_dt = '2014-12-30 00:00:00'
- Visualisiere die Unterschiede: [^2]
python
energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \
.join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \
.plot(y=['train', 'test'], figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()

Bereite die Daten für das Training vor
Jetzt musst du die Daten für das Training vorbereiten, indem du die Daten filterst und skalierst. Filtere deinen Datensatz, um nur die benötigten Zeiträume und Spalten einzuschließen, und skaliere die Daten, um sicherzustellen, dass sie im Intervall 0,1 liegen.
- Filtere den ursprünglichen Datensatz, um nur die oben genannten Zeiträume pro Satz und nur die benötigte Spalte 'load' sowie das Datum einzuschließen: [^2]
```python train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']] test = energy.copy()[energy.index >= test_start_dt][['load']]
print('Training data shape: ', train.shape) print('Test data shape: ', test.shape) ```
output
Training data shape: (1416, 1)
Test data shape: (48, 1)
- Skaliere die Trainingsdaten, um sie in den Bereich (0, 1) zu bringen: [^2]
python
scaler = MinMaxScaler()
train['load'] = scaler.fit_transform(train)
- Skaliere nun die Testdaten: [^2]
python
test['load'] = scaler.transform(test)
Erstelle Daten mit Zeitschritten [^1]
Für das SVR transformierst du die Eingabedaten in die Form [batch, timesteps]. Du formst also die vorhandenen train_data und test_data so um, dass eine neue Dimension entsteht, die sich auf die Zeitschritte bezieht.
# Converting to numpy arrays
train_data = train.values
test_data = test.values
Für dieses Beispiel nehmen wir timesteps = 5. Die Eingaben für das Modell sind also die Daten der ersten 4 Zeitschritte, und die Ausgabe sind die Daten des 5. Zeitschritts.
timesteps=5
Umwandlung der Trainingsdaten in einen 2D-Tensor mithilfe von verschachtelten Listenkomprehensionen:
train_data_timesteps=np.array([[j for j in train_data[i:i+timesteps]] for i in range(0,len(train_data)-timesteps+1)])[:,:,0]
train_data_timesteps.shape
(1412, 5)
Umwandlung der Testdaten in einen 2D-Tensor:
test_data_timesteps=np.array([[j for j in test_data[i:i+timesteps]] for i in range(0,len(test_data)-timesteps+1)])[:,:,0]
test_data_timesteps.shape
(44, 5)
Auswahl von Eingaben und Ausgaben aus Trainings- und Testdaten:
x_train, y_train = train_data_timesteps[:,:timesteps-1],train_data_timesteps[:,[timesteps-1]]
x_test, y_test = test_data_timesteps[:,:timesteps-1],test_data_timesteps[:,[timesteps-1]]
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
(1412, 4) (1412, 1)
(44, 4) (44, 1)
Implementiere SVR [^1]
Jetzt ist es an der Zeit, SVR zu implementieren. Um mehr über diese Implementierung zu erfahren, kannst du diese Dokumentation lesen. Für unsere Implementierung folgen wir diesen Schritten:
- Definiere das Modell, indem du
SVR()aufrufst und die Modell-Hyperparameter übergibst: Kernel, Gamma, C und Epsilon. - Bereite das Modell für die Trainingsdaten vor, indem du die Funktion
fit()aufrufst. - Erstelle Vorhersagen, indem du die Funktion
predict()aufrufst.
Jetzt erstellen wir ein SVR-Modell. Hier verwenden wir den RBF-Kernel und setzen die Hyperparameter Gamma, C und Epsilon auf 0,5, 10 bzw. 0,05.
model = SVR(kernel='rbf',gamma=0.5, C=10, epsilon = 0.05)
Trainiere das Modell mit den Trainingsdaten [^1]
model.fit(x_train, y_train[:,0])
SVR(C=10, cache_size=200, coef0=0.0, degree=3, epsilon=0.05, gamma=0.5,
kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
Erstelle Modellvorhersagen [^1]
y_train_pred = model.predict(x_train).reshape(-1,1)
y_test_pred = model.predict(x_test).reshape(-1,1)
print(y_train_pred.shape, y_test_pred.shape)
(1412, 1) (44, 1)
Du hast dein SVR erstellt! Jetzt müssen wir es bewerten.
Bewerte dein Modell [^1]
Für die Bewertung skalieren wir zuerst die Daten zurück auf unsere ursprüngliche Skala. Um die Leistung zu überprüfen, plotten wir die ursprüngliche und vorhergesagte Zeitreihe und geben auch das MAPE-Ergebnis aus.
Skaliere die vorhergesagten und ursprünglichen Ausgaben:
# Scaling the predictions
y_train_pred = scaler.inverse_transform(y_train_pred)
y_test_pred = scaler.inverse_transform(y_test_pred)
print(len(y_train_pred), len(y_test_pred))
# Scaling the original values
y_train = scaler.inverse_transform(y_train)
y_test = scaler.inverse_transform(y_test)
print(len(y_train), len(y_test))
Überprüfe die Modellleistung bei Trainings- und Testdaten [^1]
Wir extrahieren die Zeitstempel aus dem Datensatz, um sie auf der x-Achse unseres Plots anzuzeigen. Beachte, dass wir die ersten timesteps-1 Werte als Eingabe für die erste Ausgabe verwenden, sodass die Zeitstempel für die Ausgabe danach beginnen.
train_timestamps = energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)].index[timesteps-1:]
test_timestamps = energy[test_start_dt:].index[timesteps-1:]
print(len(train_timestamps), len(test_timestamps))
1412 44
Plotte die Vorhersagen für die Trainingsdaten:
plt.figure(figsize=(25,6))
plt.plot(train_timestamps, y_train, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(train_timestamps, y_train_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.title("Training data prediction")
plt.show()

Gib MAPE für die Trainingsdaten aus:
print('MAPE for training data: ', mape(y_train_pred, y_train)*100, '%')
MAPE for training data: 1.7195710200875551 %
Plotte die Vorhersagen für die Testdaten:
plt.figure(figsize=(10,3))
plt.plot(test_timestamps, y_test, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(test_timestamps, y_test_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.show()

Gib MAPE für die Testdaten aus:
print('MAPE for testing data: ', mape(y_test_pred, y_test)*100, '%')
MAPE for testing data: 1.2623790187854018 %
🏆 Du hast ein sehr gutes Ergebnis auf dem Testdatensatz!
Überprüfe die Modellleistung auf dem vollständigen Datensatz [^1]
# Extracting load values as numpy array
data = energy.copy().values
# Scaling
data = scaler.transform(data)
# Transforming to 2D tensor as per model input requirement
data_timesteps=np.array([[j for j in data[i:i+timesteps]] for i in range(0,len(data)-timesteps+1)])[:,:,0]
print("Tensor shape: ", data_timesteps.shape)
# Selecting inputs and outputs from data
X, Y = data_timesteps[:,:timesteps-1],data_timesteps[:,[timesteps-1]]
print("X shape: ", X.shape,"\nY shape: ", Y.shape)
Tensor shape: (26300, 5)
X shape: (26300, 4)
Y shape: (26300, 1)
# Make model predictions
Y_pred = model.predict(X).reshape(-1,1)
# Inverse scale and reshape
Y_pred = scaler.inverse_transform(Y_pred)
Y = scaler.inverse_transform(Y)
plt.figure(figsize=(30,8))
plt.plot(Y, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(Y_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.show()

print('MAPE: ', mape(Y_pred, Y)*100, '%')
MAPE: 2.0572089029888656 %
🏆 Sehr schöne Plots, die ein Modell mit guter Genauigkeit zeigen. Gut gemacht!
🚀Herausforderung
- Versuche, die Hyperparameter (Gamma, C, Epsilon) beim Erstellen des Modells anzupassen und die Daten zu bewerten, um herauszufinden, welche Hyperparameter die besten Ergebnisse auf den Testdaten liefern. Weitere Informationen zu diesen Hyperparametern findest du in der Dokumentation hier.
- Versuche, verschiedene Kernel-Funktionen für das Modell zu verwenden und analysiere deren Leistung auf dem Datensatz. Eine hilfreiche Dokumentation findest du hier.
- Versuche, verschiedene Werte für
timestepszu verwenden, damit das Modell zurückblicken kann, um Vorhersagen zu treffen.
Quiz nach der Lektion
Rückblick & Selbststudium
Diese Lektion sollte die Anwendung von SVR für die Zeitreihenprognose einführen. Um mehr über SVR zu erfahren, kannst du diesen Blog lesen. Diese Dokumentation zu scikit-learn bietet eine umfassendere Erklärung zu SVMs im Allgemeinen, SVRs und auch andere Implementierungsdetails wie die verschiedenen Kernel-Funktionen, die verwendet werden können, und deren Parameter.
Aufgabe
Credits
[^1]: Der Text, Code und die Ausgabe in diesem Abschnitt wurden von @AnirbanMukherjeeXD beigetragen.
[^2]: Der Text, Code und die Ausgabe in diesem Abschnitt wurden aus ARIMA übernommen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
In diesem Notebook zeigen wir, wie man:
- 2D-Zeitreihendaten für das Training eines SVM-Regressormodells vorbereitet
- SVR mit RBF-Kernel implementiert
- das Modell mithilfe von Diagrammen und MAPE bewertet
Module importieren
import sys
sys.path.append('../../')
import os
import warnings
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import datetime as dt
import math
from sklearn.svm import SVR
from sklearn.preprocessing import MinMaxScaler
from common.utils import load_data, mape
Daten vorbereiten
Daten laden
energy = load_data('../../data')[['load']]
energy.head(5)
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
train_start_dt = '2014-11-01 00:00:00'
test_start_dt = '2014-12-30 00:00:00'
energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \
.join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \
.plot(y=['train', 'test'], figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
Nun müssen Sie die Daten für das Training vorbereiten, indem Sie Ihre Daten filtern und skalieren.
train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']]
test = energy.copy()[energy.index >= test_start_dt][['load']]
print('Training data shape: ', train.shape)
print('Test data shape: ', test.shape)
Skalieren Sie die Daten, um im Bereich (0, 1) zu liegen.
scaler = MinMaxScaler()
train['load'] = scaler.fit_transform(train)
train.head(5)
test['load'] = scaler.transform(test)
test.head(5)
Erstellen von Daten mit Zeitstufen
Für unser SVR transformieren wir die Eingabedaten in die Form [batch, timesteps]. Daher formen wir die bestehenden train_data und test_data so um, dass eine neue Dimension hinzugefügt wird, die sich auf die Timesteps bezieht. In unserem Beispiel nehmen wir timesteps = 5. Die Eingaben für das Modell sind also die Daten der ersten 4 Timesteps, und die Ausgabe wird die Daten des 5. Timesteps sein.
# Converting to numpy arrays
train_data = train.values
test_data = test.values
# Selecting the timesteps
timesteps=5
# Converting data to 2D tensor
train_data_timesteps=np.array([[j for j in train_data[i:i+timesteps]] for i in range(0,len(train_data)-timesteps+1)])[:,:,0]
train_data_timesteps.shape
# Converting test data to 2D tensor
test_data_timesteps=np.array([[j for j in test_data[i:i+timesteps]] for i in range(0,len(test_data)-timesteps+1)])[:,:,0]
test_data_timesteps.shape
x_train, y_train = train_data_timesteps[:,:timesteps-1],train_data_timesteps[:,[timesteps-1]]
x_test, y_test = test_data_timesteps[:,:timesteps-1],test_data_timesteps[:,[timesteps-1]]
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
# Create model using RBF kernel
model = SVR(kernel='rbf',gamma=0.5, C=10, epsilon = 0.05)
# Fit model on training data
model.fit(x_train, y_train[:,0])
Modellvorhersage
# Making predictions
y_train_pred = model.predict(x_train).reshape(-1,1)
y_test_pred = model.predict(x_test).reshape(-1,1)
print(y_train_pred.shape, y_test_pred.shape)
# Scaling the predictions
y_train_pred = scaler.inverse_transform(y_train_pred)
y_test_pred = scaler.inverse_transform(y_test_pred)
print(len(y_train_pred), len(y_test_pred))
# Scaling the original values
y_train = scaler.inverse_transform(y_train)
y_test = scaler.inverse_transform(y_test)
print(len(y_train), len(y_test))
# Extract the timesteps for x-axis
train_timestamps = energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)].index[timesteps-1:]
test_timestamps = energy[test_start_dt:].index[timesteps-1:]
print(len(train_timestamps), len(test_timestamps))
plt.figure(figsize=(25,6))
plt.plot(train_timestamps, y_train, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(train_timestamps, y_train_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.title("Training data prediction")
plt.show()
print('MAPE for training data: ', mape(y_train_pred, y_train)*100, '%')
plt.figure(figsize=(10,3))
plt.plot(test_timestamps, y_test, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(test_timestamps, y_test_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.show()
print('MAPE for testing data: ', mape(y_test_pred, y_test)*100, '%')
Vollständige Datensatzvorhersage
# Extracting load values as numpy array
data = energy.copy().values
# Scaling
data = scaler.transform(data)
# Transforming to 2D tensor as per model input requirement
data_timesteps=np.array([[j for j in data[i:i+timesteps]] for i in range(0,len(data)-timesteps+1)])[:,:,0]
print("Tensor shape: ", data_timesteps.shape)
# Selecting inputs and outputs from data
X, Y = data_timesteps[:,:timesteps-1],data_timesteps[:,[timesteps-1]]
print("X shape: ", X.shape,"\nY shape: ", Y.shape)
# Make model predictions
Y_pred = model.predict(X).reshape(-1,1)
# Inverse scale and reshape
Y_pred = scaler.inverse_transform(Y_pred)
Y = scaler.inverse_transform(Y)
plt.figure(figsize=(30,8))
plt.plot(Y, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(Y_pred, color = 'blue', linewidth=1)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.show()
print('MAPE: ', mape(Y_pred, Y)*100, '%')
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
In diesem Notebook zeigen wir, wie man:
- 2D-Zeitreihendaten für das Training eines SVM-Regressormodells vorbereitet
- SVR mit einem RBF-Kernel implementiert
- das Modell mithilfe von Diagrammen und MAPE bewertet
Module importieren
import sys
sys.path.append('../../')
import os
import warnings
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import datetime as dt
import math
from sklearn.svm import SVR
from sklearn.preprocessing import MinMaxScaler
from common.utils import load_data, mape
Daten vorbereiten
Daten laden
energy = load_data('../../data')[['load']]
energy.head(5)
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
train_start_dt = '2014-11-01 00:00:00'
test_start_dt = '2014-12-30 00:00:00'
energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \
.join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \
.plot(y=['train', 'test'], figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
Nun müssen Sie die Daten für das Training vorbereiten, indem Sie Ihre Daten filtern und skalieren.
train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']]
test = energy.copy()[energy.index >= test_start_dt][['load']]
print('Training data shape: ', train.shape)
print('Test data shape: ', test.shape)
Skalieren Sie die Daten, um im Bereich (0, 1) zu liegen.
scaler = MinMaxScaler()
train['load'] = scaler.fit_transform(train)
train.head(5)
test['load'] = scaler.transform(test)
test.head(5)
Erstellen von Daten mit Zeitstufen
Für unser SVR transformieren wir die Eingabedaten in die Form [batch, timesteps]. Daher formen wir die bestehenden train_data und test_data so um, dass eine neue Dimension entsteht, die sich auf die Timesteps bezieht. In unserem Beispiel nehmen wir timesteps = 5. Die Eingaben für das Modell sind also die Daten der ersten 4 Timesteps, und die Ausgabe werden die Daten des 5. Timesteps sein.
# Converting to numpy arrays
train_data = train.values
test_data = test.values
# Selecting the timesteps
timesteps=None
# Converting data to 2D tensor
train_data_timesteps=None
# Converting test data to 2D tensor
test_data_timesteps=None
x_train, y_train = None
x_test, y_test = None
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
# Create model using RBF kernel
model = None
# Fit model on training data
Modellvorhersage
# Making predictions
y_train_pred = None
y_test_pred = None
# Scaling the predictions
y_train_pred = scaler.inverse_transform(y_train_pred)
y_test_pred = scaler.inverse_transform(y_test_pred)
# Scaling the original values
y_train = scaler.inverse_transform(y_train)
y_test = scaler.inverse_transform(y_test)
# Extract the timesteps for x-axis
train_timestamps = None
test_timestamps = None
plt.figure(figsize=(25,6))
# plot original output
# plot predicted output
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.title("Training data prediction")
plt.show()
print('MAPE for training data: ', mape(y_train_pred, y_train)*100, '%')
plt.figure(figsize=(10,3))
# plot original output
# plot predicted output
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.show()
print('MAPE for testing data: ', mape(y_test_pred, y_test)*100, '%')
Vollständige Datensatzvorhersage
# Extracting load values as numpy array
data = None
# Scaling
data = None
# Transforming to 2D tensor as per model input requirement
data_timesteps=None
# Selecting inputs and outputs from data
X, Y = None, None
# Make model predictions
# Inverse scale and reshape
Y_pred = None
Y = None
plt.figure(figsize=(30,8))
# plot original output
# plot predicted output
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.show()
print('MAPE: ', mape(Y_pred, Y)*100, '%')
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Einführung in die Zeitreihenprognose
Was ist Zeitreihenprognose? Es geht darum, zukünftige Ereignisse vorherzusagen, indem Trends aus der Vergangenheit analysiert werden.
Regionales Thema: weltweiter Stromverbrauch ✨
In diesen zwei Lektionen wirst du in die Zeitreihenprognose eingeführt, ein etwas weniger bekanntes Gebiet des maschinellen Lernens, das dennoch äußerst wertvoll für Industrie- und Geschäftsanwendungen sowie andere Bereiche ist. Obwohl neuronale Netzwerke verwendet werden können, um den Nutzen dieser Modelle zu steigern, werden wir sie im Kontext des klassischen maschinellen Lernens untersuchen, da Modelle helfen, die zukünftige Leistung basierend auf der Vergangenheit vorherzusagen.
Unser regionaler Fokus liegt auf dem weltweiten Stromverbrauch, einem interessanten Datensatz, um zu lernen, wie man den zukünftigen Energieverbrauch basierend auf Mustern der vergangenen Last vorhersagen kann. Du wirst sehen, wie diese Art der Prognose in einem geschäftlichen Umfeld äußerst hilfreich sein kann.

Foto von Peddi Sai hrithik von Strommasten auf einer Straße in Rajasthan auf Unsplash
Lektionen
- Einführung in die Zeitreihenprognose
- ARIMA-Zeitreihenmodelle erstellen
- Support Vector Regressor für Zeitreihenprognosen erstellen
Credits
"Einführung in die Zeitreihenprognose" wurde mit ⚡️ geschrieben von Francesca Lazzeri und Jen Looper. Die Notebooks erschienen erstmals online im Azure "Deep Learning For Time Series"-Repo, ursprünglich geschrieben von Francesca Lazzeri. Die SVR-Lektion wurde von Anirban Mukherjee verfasst.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Eine realistischere Welt
In unserer Situation konnte Peter sich fast ohne Müdigkeit oder Hunger bewegen. In einer realistischeren Welt muss er sich von Zeit zu Zeit hinsetzen und ausruhen sowie sich ernähren. Lassen Sie uns unsere Welt realistischer gestalten, indem wir die folgenden Regeln umsetzen:
- Durch das Bewegen von einem Ort zum anderen verliert Peter Energie und sammelt Müdigkeit.
- Peter kann mehr Energie gewinnen, indem er Äpfel isst.
- Peter kann Müdigkeit loswerden, indem er sich unter einem Baum oder auf dem Gras ausruht (d. h. indem er auf ein Feld mit einem Baum oder Gras - grünes Feld - geht).
- Peter muss den Wolf finden und töten.
- Um den Wolf zu töten, muss Peter bestimmte Energie- und Müdigkeitslevel haben, andernfalls verliert er den Kampf.
Anweisungen
Verwenden Sie das ursprüngliche notebook.ipynb Notebook als Ausgangspunkt für Ihre Lösung.
Modifizieren Sie die Belohnungsfunktion gemäß den Spielregeln, führen Sie den Reinforcement-Learning-Algorithmus aus, um die beste Strategie zum Gewinnen des Spiels zu erlernen, und vergleichen Sie die Ergebnisse des Zufallswegs mit Ihrem Algorithmus in Bezug auf die Anzahl der gewonnenen und verlorenen Spiele.
> Note: In Ihrer neuen Welt ist der Zustand komplexer und umfasst neben der menschlichen Position auch Müdigkeits- und Energielevel. Sie können den Zustand als ein Tupel (Board, Energie, Müdigkeit) darstellen oder eine Klasse für den Zustand definieren (Sie können diese auch von Board ableiten) oder sogar die ursprüngliche Board-Klasse in rlboard.py modifizieren.
In Ihrer Lösung behalten Sie bitte den Code für die Zufallsweg-Strategie bei und vergleichen die Ergebnisse Ihres Algorithmus am Ende mit dem Zufallsweg.
> Note: Sie müssen möglicherweise Hyperparameter anpassen, damit es funktioniert, insbesondere die Anzahl der Epochen. Da der Erfolg des Spiels (Kampf gegen den Wolf) ein seltenes Ereignis ist, können Sie mit einer deutlich längeren Trainingszeit rechnen.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Notebook wird präsentiert mit der Definition der neuen Weltregeln, Q-Learning-Algorithmus und einigen textlichen Erklärungen. Q-Learning kann die Ergebnisse im Vergleich zum Zufallsweg deutlich verbessern. | Ein Notebook wird präsentiert, Q-Learning ist implementiert und verbessert die Ergebnisse im Vergleich zum Zufallsweg, jedoch nicht signifikant; oder das Notebook ist schlecht dokumentiert und der Code ist nicht gut strukturiert. | Es wurden einige Versuche unternommen, die Regeln der Welt neu zu definieren, aber der Q-Learning-Algorithmus funktioniert nicht oder die Belohnungsfunktion ist nicht vollständig definiert. |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Peter und der Wolf: Einführung in Reinforcement Learning
In diesem Tutorial lernen wir, wie man Reinforcement Learning auf ein Problem der Wegfindung anwendet. Das Szenario ist inspiriert von Peter und der Wolf, einem musikalischen Märchen des russischen Komponisten Sergei Prokofjew. Es ist die Geschichte des jungen Pioniers Peter, der mutig sein Haus verlässt, um auf der Waldlichtung einen Wolf zu jagen. Wir werden maschinelle Lernalgorithmen trainieren, die Peter dabei helfen, die Umgebung zu erkunden und eine optimale Navigationskarte zu erstellen.
Zuerst importieren wir eine Reihe nützlicher Bibliotheken:
import matplotlib.pyplot as plt
import numpy as np
import random
import math
Überblick über Reinforcement Learning
Reinforcement Learning (RL) ist eine Lerntechnik, die es uns ermöglicht, das optimale Verhalten eines Agenten in einer bestimmten Umgebung durch viele Experimente zu erlernen. Ein Agent in dieser Umgebung sollte ein Ziel haben, das durch eine Belohnungsfunktion definiert ist.
Die Umgebung
Der Einfachheit halber betrachten wir Peters Welt als ein quadratisches Spielfeld der Größe width x height. Jede Zelle auf diesem Spielfeld kann entweder sein:
* Boden, auf dem Peter und andere Kreaturen laufen können
* Wasser, auf dem man offensichtlich nicht laufen kann
* ein Baum oder Gras – ein Ort, an dem man sich ausruhen kann
* ein Apfel, der etwas darstellt, das Peter gerne finden würde, um sich zu ernähren
* ein Wolf, der gefährlich ist und vermieden werden sollte
Um mit der Umgebung zu arbeiten, definieren wir eine Klasse namens Board. Um dieses Notebook nicht zu überladen, haben wir den gesamten Code, der mit dem Spielfeld arbeitet, in ein separates Modul namens rlboard ausgelagert, das wir nun importieren. Sie können einen Blick in dieses Modul werfen, um mehr Details über die interne Implementierung zu erfahren.
Lassen Sie uns nun ein zufälliges Brett erstellen und sehen, wie es aussieht:
# code block 1
Aktionen und Richtlinien
In unserem Beispiel besteht Peters Ziel darin, einen Apfel zu finden, während er den Wolf und andere Hindernisse vermeidet. Definiere diese Aktionen als ein Wörterbuch und ordne sie Paaren von entsprechenden Koordinatenänderungen zu.
# code block 2
Die Strategie unseres Agenten (Peter) wird durch eine sogenannte Policy definiert. Betrachten wir zunächst die einfachste Policy, die als Random Walk bezeichnet wird.
Random Walk
Lassen Sie uns unser Problem zunächst lösen, indem wir eine Random-Walk-Strategie implementieren.
# Let's run a random walk experiment several times and see the average number of steps taken: code block 3
# code block 4
Belohnungsfunktion
Um unsere Strategie intelligenter zu machen, müssen wir verstehen, welche Züge "besser" sind als andere.
#code block 5
Q-Learning
Erstellen Sie eine Q-Tabelle oder ein mehrdimensionales Array. Da unser Spielfeld die Dimensionen width x height hat, können wir die Q-Tabelle durch ein numpy-Array mit der Form width x height x len(actions) darstellen:
# code block 6
Geben Sie die Q-Tabelle an die plot-Funktion weiter, um die Tabelle auf dem Brett zu visualisieren:
m.plot(Q)
Essenz von Q-Learning: Bellman-Gleichung und Lernalgorithmus
Schreiben Sie einen Pseudo-Code für unseren Lernalgorithmus:
- Initialisiere die Q-Tabelle Q mit gleichen Werten für alle Zustände und Aktionen
- Setze die Lernrate $\alpha\leftarrow 1$
- Wiederhole die Simulation viele Male
1. Starte an einer zufälligen Position
1. Wiederhole
1. Wähle eine Aktion $a$ im Zustand $s$
2. Führe die Aktion aus, indem du zu einem neuen Zustand $s'$ wechselst
3. Wenn wir eine Spielende-Bedingung erreichen oder die Gesamtbelohnung zu klein ist - beende die Simulation
4. Berechne die Belohnung $r$ im neuen Zustand 5. Aktualisiere die Q-Funktion gemäß der Bellman-Gleichung: $Q(s,a)\leftarrow (1-\alpha)Q(s,a)+\alpha(r+\gamma\max_{a'}Q(s',a'))$ 6. $s\leftarrow s'$ 7. Aktualisiere die Gesamtbelohnung und reduziere $\alpha$.
Ausnutzen vs. Erkunden
Der beste Ansatz ist, ein Gleichgewicht zwischen Erkundung und Ausnutzung zu finden. Während wir mehr über unsere Umgebung lernen, sind wir eher geneigt, den optimalen Weg zu folgen, jedoch sollten wir gelegentlich den unerforschten Weg wählen.
Python-Implementierung
Nun sind wir bereit, den Lernalgorithmus zu implementieren. Zuvor benötigen wir auch eine Funktion, die beliebige Zahlen in der Q-Tabelle in einen Wahrscheinlichkeitsvektor für die entsprechenden Aktionen umwandelt:
# code block 7
Wir fügen dem ursprünglichen Vektor eine kleine Menge eps hinzu, um eine Division durch 0 im Anfangsfall zu vermeiden, wenn alle Komponenten des Vektors identisch sind.
Der eigentliche Lernalgorithmus, den wir für 5000 Experimente ausführen werden, auch Epochen genannt:
from IPython.display import clear_output
lpath = []
# code block 8
Nach der Ausführung dieses Algorithmus sollte die Q-Tabelle mit Werten aktualisiert werden, die die Attraktivität verschiedener Aktionen in jedem Schritt definieren. Visualisieren Sie die Tabelle hier:
m.plot(Q)
Überprüfung der Richtlinie
Da die Q-Tabelle die "Attraktivität" jeder Aktion in jedem Zustand auflistet, ist es ziemlich einfach, sie zu verwenden, um die effiziente Navigation in unserer Welt zu definieren. Im einfachsten Fall können wir einfach die Aktion auswählen, die dem höchsten Wert in der Q-Tabelle entspricht:
# code block 9
Wenn Sie den obigen Code mehrmals ausprobieren, werden Sie möglicherweise feststellen, dass er manchmal einfach "hängen bleibt" und Sie die STOP-Taste im Notebook drücken müssen, um ihn zu unterbrechen.
> Aufgabe 1: Ändern Sie die walk-Funktion, um die maximale Pfadlänge auf eine bestimmte Anzahl von Schritten (z. B. 100) zu begrenzen, und beobachten Sie, wie der obige Code diesen Wert von Zeit zu Zeit zurückgibt.
> Aufgabe 2: Ändern Sie die walk-Funktion so, dass sie nicht zu Orten zurückkehrt, an denen sie zuvor bereits gewesen ist. Dies wird verhindern, dass walk in Schleifen gerät, jedoch kann der Agent trotzdem an einem Ort "gefangen" werden, von dem er nicht entkommen kann.
# code block 10
plt.plot(lpath)
Übung
Eine realistischere Welt von Peter und der Wolf
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in Reinforcement Learning und Q-Learning
> Sketchnote von Tomomi Imura
Reinforcement Learning umfasst drei wichtige Konzepte: den Agenten, einige Zustände und eine Menge von Aktionen pro Zustand. Indem der Agent in einem bestimmten Zustand eine Aktion ausführt, erhält er eine Belohnung. Stellen Sie sich erneut das Computerspiel Super Mario vor. Sie sind Mario, befinden sich in einem Level und stehen am Rand einer Klippe. Über Ihnen schwebt eine Münze. Sie, als Mario, in einem Level, an einer bestimmten Position ... das ist Ihr Zustand. Wenn Sie einen Schritt nach rechts machen (eine Aktion), fallen Sie über die Klippe, was Ihnen eine niedrige Punktzahl einbringt. Drücken Sie jedoch die Sprungtaste, können Sie eine Münze einsammeln und bleiben am Leben. Das ist ein positives Ergebnis und sollte mit einer positiven Punktzahl belohnt werden.
Mit Reinforcement Learning und einem Simulator (dem Spiel) können Sie lernen, wie Sie das Spiel spielen, um die Belohnung zu maximieren, also am Leben zu bleiben und so viele Punkte wie möglich zu sammeln.
> 🎥 Klicken Sie auf das Bild oben, um Dmitry über Reinforcement Learning sprechen zu hören.
Quiz vor der Lektion
Voraussetzungen und Einrichtung
In dieser Lektion werden wir mit etwas Python-Code experimentieren. Sie sollten in der Lage sein, den Jupyter-Notebook-Code aus dieser Lektion entweder auf Ihrem Computer oder in der Cloud auszuführen.
Sie können das Notebook zur Lektion öffnen und die Lektion Schritt für Schritt durchgehen.
> Hinweis: Wenn Sie diesen Code aus der Cloud öffnen, müssen Sie auch die Datei rlboard.py abrufen, die im Notebook-Code verwendet wird. Fügen Sie sie in dasselbe Verzeichnis wie das Notebook ein.
Einführung
In dieser Lektion erkunden wir die Welt von Peter und der Wolf, inspiriert von einem musikalischen Märchen des russischen Komponisten Sergei Prokofjew. Wir verwenden Reinforcement Learning, um Peter seine Umgebung erkunden zu lassen, leckere Äpfel zu sammeln und dem Wolf auszuweichen.
Reinforcement Learning (RL) ist eine Lerntechnik, die es uns ermöglicht, das optimale Verhalten eines Agenten in einer bestimmten Umgebung durch viele Experimente zu erlernen. Ein Agent in dieser Umgebung sollte ein Ziel haben, das durch eine Belohnungsfunktion definiert ist.
Die Umgebung
Der Einfachheit halber nehmen wir an, dass Peters Welt ein quadratisches Spielfeld der Größe Breite x Höhe ist, wie dieses:

Jede Zelle auf diesem Spielfeld kann entweder sein:
- Boden, auf dem Peter und andere Wesen laufen können.
- Wasser, auf dem man offensichtlich nicht laufen kann.
- ein Baum oder Gras, ein Ort, an dem man sich ausruhen kann.
- ein Apfel, den Peter gerne finden würde, um sich zu ernähren.
- ein Wolf, der gefährlich ist und gemieden werden sollte.
Es gibt ein separates Python-Modul, rlboard.py, das den Code für die Arbeit mit dieser Umgebung enthält. Da dieser Code nicht entscheidend für das Verständnis unserer Konzepte ist, importieren wir das Modul und verwenden es, um das Beispielbrett zu erstellen (Codeblock 1):
from rlboard import *
width, height = 8,8
m = Board(width,height)
m.randomize(seed=13)
m.plot()
Dieser Code sollte ein Bild der Umgebung ausgeben, das dem oben gezeigten ähnelt.
Aktionen und Strategie
In unserem Beispiel besteht Peters Ziel darin, einen Apfel zu finden, während er dem Wolf und anderen Hindernissen ausweicht. Dazu kann er sich im Grunde umherbewegen, bis er einen Apfel findet.
An jeder Position kann er zwischen den folgenden Aktionen wählen: nach oben, nach unten, nach links und nach rechts.
Wir definieren diese Aktionen als ein Wörterbuch und ordnen sie Paaren von entsprechenden Koordinatenänderungen zu. Zum Beispiel würde die Bewegung nach rechts (R) einem Paar (1,0) entsprechen. (Codeblock 2):
actions = { "U" : (0,-1), "D" : (0,1), "L" : (-1,0), "R" : (1,0) }
action_idx = { a : i for i,a in enumerate(actions.keys()) }
Zusammengefasst sind die Strategie und das Ziel dieses Szenarios wie folgt:
-
Die Strategie unseres Agenten (Peter) wird durch eine sogenannte Policy definiert. Eine Policy ist eine Funktion, die die Aktion in einem bestimmten Zustand zurückgibt. In unserem Fall wird der Zustand des Problems durch das Spielfeld einschließlich der aktuellen Position des Spielers dargestellt.
-
Das Ziel des Reinforcement Learning ist es, schließlich eine gute Policy zu erlernen, die es uns ermöglicht, das Problem effizient zu lösen. Als Ausgangspunkt betrachten wir jedoch die einfachste Policy, die als Random Walk bezeichnet wird.
Random Walk
Lassen Sie uns zunächst unser Problem lösen, indem wir eine Random-Walk-Strategie implementieren. Beim Random Walk wählen wir zufällig die nächste Aktion aus den erlaubten Aktionen, bis wir den Apfel erreichen (Codeblock 3).
-
Implementieren Sie den Random Walk mit dem folgenden Code:
```python def random_policy(m): return random.choice(list(actions))
def walk(m,policy,start_position=None): n = 0 # number of steps # set initial position if start_position: m.human = start_position else: m.random_start() while True: if m.at() == Board.Cell.apple: return n # success! if m.at() in [Board.Cell.wolf, Board.Cell.water]: return -1 # eaten by wolf or drowned while True: a = actions[policy(m)] new_pos = m.move_pos(m.human,a) if m.is_valid(new_pos) and m.at(new_pos)!=Board.Cell.water: m.move(a) # do the actual move break n+=1
walk(m,random_policy) ```
Der Aufruf von
walksollte die Länge des entsprechenden Pfads zurückgeben, die von einem Lauf zum anderen variieren kann. -
Führen Sie das Walk-Experiment mehrmals durch (z. B. 100 Mal) und geben Sie die resultierenden Statistiken aus (Codeblock 4):
```python def print_statistics(policy): s,w,n = 0,0,0 for _ in range(100): z = walk(m,policy) if z<0: w+=1 else: s += z n += 1 print(f"Average path length = {s/n}, eaten by wolf: {w} times")
print_statistics(random_policy) ```
Beachten Sie, dass die durchschnittliche Länge eines Pfads etwa 30-40 Schritte beträgt, was ziemlich viel ist, wenn man bedenkt, dass die durchschnittliche Entfernung zum nächsten Apfel etwa 5-6 Schritte beträgt.
Sie können auch sehen, wie sich Peter während des Random Walks bewegt:

Belohnungsfunktion
Um unsere Policy intelligenter zu machen, müssen wir verstehen, welche Züge "besser" sind als andere. Dazu müssen wir unser Ziel definieren.
Das Ziel kann in Form einer Belohnungsfunktion definiert werden, die für jeden Zustand einen Punktwert zurückgibt. Je höher die Zahl, desto besser die Belohnung. (Codeblock 5)
move_reward = -0.1
goal_reward = 10
end_reward = -10
def reward(m,pos=None):
pos = pos or m.human
if not m.is_valid(pos):
return end_reward
x = m.at(pos)
if x==Board.Cell.water or x == Board.Cell.wolf:
return end_reward
if x==Board.Cell.apple:
return goal_reward
return move_reward
Eine interessante Eigenschaft von Belohnungsfunktionen ist, dass in den meisten Fällen eine wesentliche Belohnung erst am Ende des Spiels gegeben wird. Das bedeutet, dass unser Algorithmus irgendwie "gute" Schritte, die zu einer positiven Belohnung am Ende führen, speichern und deren Bedeutung erhöhen sollte. Ebenso sollten alle Züge, die zu schlechten Ergebnissen führen, entmutigt werden.
Q-Learning
Ein Algorithmus, den wir hier besprechen werden, heißt Q-Learning. In diesem Algorithmus wird die Policy durch eine Funktion (oder eine Datenstruktur) definiert, die als Q-Tabelle bezeichnet wird. Sie zeichnet die "Güte" jeder Aktion in einem bestimmten Zustand auf.
Die Q-Tabelle wird so genannt, weil es oft praktisch ist, sie als Tabelle oder mehrdimensionales Array darzustellen. Da unser Spielfeld die Dimensionen Breite x Höhe hat, können wir die Q-Tabelle mit einem numpy-Array der Form Breite x Höhe x len(actions) darstellen: (Codeblock 6)
Q = np.ones((width,height,len(actions)),dtype=np.float)*1.0/len(actions)
Beachten Sie, dass wir alle Werte der Q-Tabelle mit einem gleichen Wert initialisieren, in unserem Fall 0,25. Dies entspricht der "Random-Walk"-Policy, da alle Züge in jedem Zustand gleich gut sind. Wir können die Q-Tabelle an die plot-Funktion übergeben, um die Tabelle auf dem Spielfeld zu visualisieren: m.plot(Q).

In der Mitte jeder Zelle befindet sich ein "Pfeil", der die bevorzugte Bewegungsrichtung anzeigt. Da alle Richtungen gleich sind, wird ein Punkt angezeigt.
Nun müssen wir die Simulation ausführen, unsere Umgebung erkunden und eine bessere Verteilung der Q-Tabelle-Werte erlernen, die es uns ermöglicht, den Weg zum Apfel viel schneller zu finden.
Essenz des Q-Learning: Bellman-Gleichung
Sobald wir uns bewegen, hat jede Aktion eine entsprechende Belohnung, d. h. wir könnten theoretisch die nächste Aktion basierend auf der höchsten unmittelbaren Belohnung auswählen. In den meisten Zuständen wird der Zug jedoch nicht unser Ziel, den Apfel zu erreichen, erfüllen, und daher können wir nicht sofort entscheiden, welche Richtung besser ist.
> Denken Sie daran, dass nicht das unmittelbare Ergebnis zählt, sondern das Endergebnis, das wir am Ende der Simulation erhalten.
Um diese verzögerte Belohnung zu berücksichtigen, müssen wir die Prinzipien der dynamischen Programmierung verwenden, die es uns ermöglichen, unser Problem rekursiv zu betrachten.
Angenommen, wir befinden uns jetzt im Zustand s und möchten zum nächsten Zustand s' wechseln. Indem wir dies tun, erhalten wir die unmittelbare Belohnung r(s,a), die durch die Belohnungsfunktion definiert ist, plus eine zukünftige Belohnung. Wenn wir annehmen, dass unsere Q-Tabelle die "Attraktivität" jeder Aktion korrekt widerspiegelt, dann wählen wir im Zustand s' eine Aktion a, die dem maximalen Wert von Q(s',a') entspricht. Somit wird die bestmögliche zukünftige Belohnung, die wir im Zustand s erhalten könnten, durch max
Überprüfung der Richtlinie
Da die Q-Tabelle die "Attraktivität" jeder Aktion in jedem Zustand auflistet, ist es recht einfach, sie zu nutzen, um eine effiziente Navigation in unserer Welt zu definieren. Im einfachsten Fall können wir die Aktion auswählen, die dem höchsten Wert in der Q-Tabelle entspricht: (Codeblock 9)
def qpolicy_strict(m):
x,y = m.human
v = probs(Q[x,y])
a = list(actions)[np.argmax(v)]
return a
walk(m,qpolicy_strict)
> Wenn Sie den obigen Code mehrmals ausprobieren, werden Sie möglicherweise feststellen, dass er manchmal "hängt" und Sie die STOP-Taste im Notebook drücken müssen, um ihn zu unterbrechen. Dies passiert, weil es Situationen geben kann, in denen zwei Zustände sich gegenseitig in Bezug auf den optimalen Q-Wert "zeigen", wodurch der Agent zwischen diesen Zuständen endlos hin- und herwechselt.
🚀Herausforderung
> Aufgabe 1: Ändern Sie die Funktion walk, um die maximale Pfadlänge auf eine bestimmte Anzahl von Schritten (z. B. 100) zu begrenzen, und beobachten Sie, wie der obige Code diesen Wert von Zeit zu Zeit zurückgibt.
> Aufgabe 2: Ändern Sie die Funktion walk so, dass sie nicht an Orte zurückkehrt, an denen sie zuvor bereits war. Dies verhindert, dass walk in einer Schleife hängen bleibt. Allerdings kann der Agent dennoch in einer Position "gefangen" sein, aus der er nicht entkommen kann.
Navigation
Eine bessere Navigationsstrategie wäre die, die wir während des Trainings verwendet haben, die Ausnutzung und Erkundung kombiniert. In dieser Strategie wählen wir jede Aktion mit einer bestimmten Wahrscheinlichkeit aus, die proportional zu den Werten in der Q-Tabelle ist. Diese Strategie kann dazu führen, dass der Agent zu einer Position zurückkehrt, die er bereits erkundet hat. Wie Sie jedoch aus dem untenstehenden Code sehen können, führt sie zu einem sehr kurzen durchschnittlichen Pfad zur gewünschten Position (denken Sie daran, dass print_statistics die Simulation 100 Mal ausführt): (Codeblock 10)
def qpolicy(m):
x,y = m.human
v = probs(Q[x,y])
a = random.choices(list(actions),weights=v)[0]
return a
print_statistics(qpolicy)
Nach Ausführung dieses Codes sollten Sie eine deutlich kürzere durchschnittliche Pfadlänge als zuvor erhalten, im Bereich von 3-6.
Untersuchung des Lernprozesses
Wie bereits erwähnt, ist der Lernprozess ein Gleichgewicht zwischen der Erkundung und der Nutzung des gewonnenen Wissens über die Struktur des Problemraums. Wir haben gesehen, dass die Ergebnisse des Lernens (die Fähigkeit, einem Agenten zu helfen, einen kurzen Weg zum Ziel zu finden) sich verbessert haben. Es ist jedoch auch interessant zu beobachten, wie sich die durchschnittliche Pfadlänge während des Lernprozesses verhält:
Die Erkenntnisse lassen sich wie folgt zusammenfassen:
-
Durchschnittliche Pfadlänge nimmt zu. Was wir hier sehen, ist, dass die durchschnittliche Pfadlänge zunächst zunimmt. Dies liegt wahrscheinlich daran, dass wir, wenn wir nichts über die Umgebung wissen, dazu neigen, in schlechten Zuständen, wie Wasser oder bei einem Wolf, gefangen zu werden. Wenn wir mehr lernen und dieses Wissen nutzen, können wir die Umgebung länger erkunden, wissen aber immer noch nicht genau, wo sich die Äpfel befinden.
-
Pfadlänge nimmt ab, je mehr wir lernen. Sobald wir genug gelernt haben, wird es für den Agenten einfacher, das Ziel zu erreichen, und die Pfadlänge beginnt abzunehmen. Wir sind jedoch weiterhin offen für Erkundungen, sodass wir oft vom besten Weg abweichen und neue Optionen erkunden, was den Pfad länger als optimal macht.
-
Länge nimmt abrupt zu. Was wir auf diesem Diagramm ebenfalls beobachten, ist, dass die Länge an einem Punkt abrupt zunimmt. Dies zeigt die stochastische Natur des Prozesses und dass wir die Q-Tabellen-Koeffizienten durch Überschreiben mit neuen Werten "verderben" können. Dies sollte idealerweise minimiert werden, indem die Lernrate verringert wird (zum Beispiel passen wir gegen Ende des Trainings die Q-Tabellen-Werte nur noch geringfügig an).
Insgesamt ist es wichtig zu bedenken, dass der Erfolg und die Qualität des Lernprozesses stark von Parametern wie Lernrate, Abnahme der Lernrate und Diskontierungsfaktor abhängen. Diese werden oft als Hyperparameter bezeichnet, um sie von Parametern zu unterscheiden, die wir während des Trainings optimieren (zum Beispiel Q-Tabellen-Koeffizienten). Der Prozess, die besten Werte für die Hyperparameter zu finden, wird als Hyperparameter-Optimierung bezeichnet und verdient ein eigenes Thema.
Quiz nach der Vorlesung
Aufgabe
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Peter und der Wolf: Realistische Umgebung
In unserer Situation konnte Peter sich fast ohne Müdigkeit oder Hunger bewegen. In einer realistischeren Welt muss er sich von Zeit zu Zeit hinsetzen und ausruhen sowie sich ernähren. Lassen Sie uns unsere Welt realistischer gestalten, indem wir die folgenden Regeln umsetzen:
- Beim Bewegen von einem Ort zum anderen verliert Peter Energie und sammelt Müdigkeit.
- Peter kann mehr Energie gewinnen, indem er Äpfel isst.
- Peter kann Müdigkeit loswerden, indem er sich unter einem Baum oder auf dem Gras ausruht (d.h. indem er ein Feld mit einem Baum oder Gras betritt - grünes Feld).
- Peter muss den Wolf finden und töten.
- Um den Wolf zu töten, muss Peter bestimmte Energie- und Müdigkeitslevel haben, andernfalls verliert er den Kampf.
import matplotlib.pyplot as plt
import numpy as np
import random
import math
from rlboard import *
width, height = 8,8
m = Board(width,height)
m.randomize(seed=13)
m.plot()
actions = { "U" : (0,-1), "D" : (0,1), "L" : (-1,0), "R" : (1,0) }
action_idx = { a : i for i,a in enumerate(actions.keys()) }
Definition des Zustands
In unseren neuen Spielregeln müssen wir bei jedem Spielzustand Energie und Erschöpfung im Blick behalten. Daher erstellen wir ein Objekt state, das alle notwendigen Informationen über den aktuellen Problemzustand enthält, einschließlich des Zustands des Spielfelds, der aktuellen Energie- und Erschöpfungswerte und der Frage, ob wir den Wolf im Endzustand besiegen können:
class state:
def __init__(self,board,energy=10,fatigue=0,init=True):
self.board = board
self.energy = energy
self.fatigue = fatigue
self.dead = False
if init:
self.board.random_start()
self.update()
def at(self):
return self.board.at()
def update(self):
if self.at() == Board.Cell.water:
self.dead = True
return
if self.at() == Board.Cell.tree:
self.fatigue = 0
if self.at() == Board.Cell.apple:
self.energy = 10
def move(self,a):
self.board.move(a)
self.energy -= 1
self.fatigue += 1
self.update()
def is_winning(self):
return self.energy > self.fatigue
Lass uns versuchen, das Problem mit einem Random Walk zu lösen und sehen, ob wir Erfolg haben:
def random_policy(state):
return random.choice(list(actions))
def walk(board,policy):
n = 0 # number of steps
s = state(board)
while True:
if s.at() == Board.Cell.wolf:
if s.is_winning():
return n # success!
else:
return -n # failure!
if s.at() == Board.Cell.water:
return 0 # died
a = actions[policy(m)]
s.move(a)
n+=1
walk(m,random_policy)
def print_statistics(policy):
s,w,n = 0,0,0
for _ in range(100):
z = walk(m,policy)
if z<0:
w+=1
elif z==0:
n+=1
else:
s+=1
print(f"Killed by wolf = {w}, won: {s} times, drown: {n} times")
print_statistics(random_policy)
Belohnungsfunktion
Einführung
Die Belohnungsfunktion ist ein entscheidender Bestandteil des Verstärkungslernens. Sie dient als Leitfaden für den Agenten, um zu verstehen, welche Aktionen wünschenswert sind und welche vermieden werden sollten.
Aufbau einer Belohnungsfunktion
Eine gut gestaltete Belohnungsfunktion sollte: - Klar definierte Ziele haben. - Den Agenten dazu motivieren, langfristige Belohnungen zu maximieren. - Negative Belohnungen für unerwünschtes Verhalten enthalten.
Beispiele
Hier sind einige Beispiele für Belohnungsfunktionen: 1. Navigation: Belohne den Agenten für das Erreichen eines Ziels und bestrafe ihn für Kollisionen. 2. Spielstrategie: Belohne den Agenten für das Gewinnen eines Spiels und bestrafe ihn für Regelverstöße. 3. Ressourcenmanagement: Belohne den Agenten für effiziente Ressourcennutzung und bestrafe ihn für Verschwendung.
Häufige Fehler
- Übermäßige Bestrafung: Zu viele negative Belohnungen können den Agenten entmutigen.
- Unklare Ziele: Wenn die Belohnungsfunktion nicht klar definiert ist, kann der Agent inkonsistente Ergebnisse liefern.
- Kurzfristige Belohnungen: Wenn die Belohnungsfunktion nur kurzfristige Gewinne priorisiert, kann der Agent langfristige Ziele ignorieren.
Fazit
Die Gestaltung einer effektiven Belohnungsfunktion erfordert sorgfältige Planung und Tests. Sie ist entscheidend für den Erfolg eines Verstärkungslernungsmodells.
def reward(s):
r = s.energy-s.fatigue
if s.at()==Board.Cell.wolf:
return 100 if s.is_winning() else -100
if s.at()==Board.Cell.water:
return -100
return r
Q-Learning-Algorithmus
Der eigentliche Lernalgorithmus bleibt weitgehend unverändert, wir verwenden lediglich state anstelle der reinen Brettposition.
Q = np.ones((width,height,len(actions)),dtype=np.float)*1.0/len(actions)
def probs(v,eps=1e-4):
v = v-v.min()+eps
v = v/v.sum()
return v
from IPython.display import clear_output
lpath = []
for epoch in range(10000):
clear_output(wait=True)
print(f"Epoch = {epoch}",end='')
# Pick initial point
s = state(m)
# Start travelling
n=0
cum_reward = 0
while True:
x,y = s.board.human
v = probs(Q[x,y])
while True:
a = random.choices(list(actions),weights=v)[0]
dpos = actions[a]
if s.board.is_valid(s.board.move_pos(s.board.human,dpos)):
break
s.move(dpos)
r = reward(s)
if abs(r)==100: # end of game
print(f" {n} steps",end='\r')
lpath.append(n)
break
alpha = np.exp(-n / 3000)
gamma = 0.5
ai = action_idx[a]
Q[x,y,ai] = (1 - alpha) * Q[x,y,ai] + alpha * (r + gamma * Q[x+dpos[0], y+dpos[1]].max())
n+=1
m.plot(Q)
Ergebnisse
Schauen wir mal, ob wir erfolgreich waren, Peter darauf vorzubereiten, gegen den Wolf zu kämpfen!
def qpolicy(m):
x,y = m.human
v = probs(Q[x,y])
a = random.choices(list(actions),weights=v)[0]
return a
print_statistics(qpolicy)
Wir sehen jetzt viel weniger Fälle von Ertrinken, aber Peter ist immer noch nicht immer in der Lage, den Wolf zu töten. Versuchen Sie zu experimentieren und sehen Sie, ob Sie dieses Ergebnis durch das Spielen mit Hyperparametern verbessern können.
plt.plot(lpath)
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Peter und der Wolf: Einführung in Reinforcement Learning
In diesem Tutorial lernen wir, wie man Reinforcement Learning auf ein Problem der Wegfindung anwendet. Das Szenario ist inspiriert von Peter und der Wolf, einem musikalischen Märchen des russischen Komponisten Sergei Prokofiev. Es ist die Geschichte des jungen Pioniers Peter, der mutig sein Haus verlässt, um auf der Waldlichtung den Wolf zu jagen. Wir werden maschinelle Lernalgorithmen trainieren, die Peter dabei helfen, die Umgebung zu erkunden und eine optimale Navigationskarte zu erstellen.
Zuerst importieren wir eine Reihe nützlicher Bibliotheken:
import matplotlib.pyplot as plt
import numpy as np
import random
import math
Überblick über Reinforcement Learning
Reinforcement Learning (RL) ist eine Lerntechnik, die es uns ermöglicht, das optimale Verhalten eines Agenten in einer bestimmten Umgebung durch das Durchführen vieler Experimente zu erlernen. Ein Agent in dieser Umgebung sollte ein Ziel haben, das durch eine Belohnungsfunktion definiert ist.
Die Umgebung
Zur Vereinfachung nehmen wir an, dass Peters Welt ein quadratisches Spielfeld der Größe width x height ist. Jede Zelle auf diesem Spielfeld kann entweder sein:
* Boden, auf dem Peter und andere Kreaturen laufen können
* Wasser, auf dem man offensichtlich nicht laufen kann
* ein Baum oder Gras – ein Ort, an dem man sich ausruhen kann
* ein Apfel, der etwas darstellt, das Peter gerne finden würde, um sich zu ernähren
* ein Wolf, der gefährlich ist und vermieden werden sollte
Um mit der Umgebung zu arbeiten, definieren wir eine Klasse namens Board. Um dieses Notebook nicht zu überladen, haben wir den gesamten Code, der mit dem Spielfeld arbeitet, in ein separates Modul namens rlboard ausgelagert, das wir nun importieren. Sie können einen Blick in dieses Modul werfen, um mehr Details über die interne Implementierung zu erfahren.
from rlboard import *
Lassen Sie uns nun ein zufälliges Brett erstellen und sehen, wie es aussieht:
width, height = 8,8
m = Board(width,height)
m.randomize(seed=13)
m.plot()
Aktionen und Richtlinien
In unserem Beispiel besteht Peters Ziel darin, einen Apfel zu finden, während er dem Wolf und anderen Hindernissen ausweicht. Um dies zu erreichen, kann er im Grunde herumlaufen, bis er einen Apfel findet. An jeder Position kann er daher eine der folgenden Aktionen wählen: nach oben, nach unten, nach links und nach rechts. Wir werden diese Aktionen als ein Wörterbuch definieren und sie mit Paaren von entsprechenden Koordinatenänderungen verknüpfen. Zum Beispiel würde die Bewegung nach rechts (R) einem Paar (1,0) entsprechen.
actions = { "U" : (0,-1), "D" : (0,1), "L" : (-1,0), "R" : (1,0) }
action_idx = { a : i for i,a in enumerate(actions.keys()) }
Die Strategie unseres Agenten (Peter) wird durch eine sogenannte Policy definiert. Betrachten wir die einfachste Policy, die als Zufallsbewegung bezeichnet wird.
Zufallsbewegung
Lassen Sie uns zunächst unser Problem lösen, indem wir eine Strategie der Zufallsbewegung implementieren.
def random_policy(m):
return random.choice(list(actions))
def walk(m,policy,start_position=None):
n = 0 # number of steps
# set initial position
if start_position:
m.human = start_position
else:
m.random_start()
while True:
if m.at() == Board.Cell.apple:
return n # success!
if m.at() in [Board.Cell.wolf, Board.Cell.water]:
return -1 # eaten by wolf or drowned
while True:
a = actions[policy(m)]
new_pos = m.move_pos(m.human,a)
if m.is_valid(new_pos) and m.at(new_pos)!=Board.Cell.water:
m.move(a) # do the actual move
break
n+=1
walk(m,random_policy)
Lassen Sie uns das Random-Walk-Experiment mehrmals durchführen und die durchschnittliche Anzahl der Schritte betrachten:
def print_statistics(policy):
s,w,n = 0,0,0
for _ in range(100):
z = walk(m,policy)
if z<0:
w+=1
else:
s += z
n += 1
print(f"Average path length = {s/n}, eaten by wolf: {w} times")
print_statistics(random_policy)
Belohnungsfunktion
Um unsere Strategie intelligenter zu machen, müssen wir verstehen, welche Züge "besser" sind als andere.
move_reward = -0.1
goal_reward = 10
end_reward = -10
def reward(m,pos=None):
pos = pos or m.human
if not m.is_valid(pos):
return end_reward
x = m.at(pos)
if x==Board.Cell.water or x == Board.Cell.wolf:
return end_reward
if x==Board.Cell.apple:
return goal_reward
return move_reward
Q-Learning
Erstellen Sie eine Q-Tabelle oder ein mehrdimensionales Array. Da unser Spielfeld die Dimensionen width x height hat, können wir die Q-Tabelle durch ein numpy-Array mit der Form width x height x len(actions) darstellen:
Q = np.ones((width,height,len(actions)),dtype=np.float)*1.0/len(actions)
Übergeben Sie die Q-Tabelle an die Plot-Funktion, um die Tabelle auf dem Brett zu visualisieren:
m.plot(Q)
Essenz des Q-Learning: Bellman-Gleichung und Lernalgorithmus
Schreiben Sie einen Pseudocode für unseren Lernalgorithmus:
- Initialisiere die Q-Tabelle Q mit gleichen Werten für alle Zustände und Aktionen
- Setze die Lernrate $\alpha\leftarrow 1$
- Wiederhole die Simulation viele Male
1. Starte an einer zufälligen Position
1. Wiederhole
1. Wähle eine Aktion $a$ im Zustand $s$
2. Führe die Aktion aus, indem du zu einem neuen Zustand $s'$ wechselst
3. Wenn wir eine Spielende-Bedingung erreichen oder die Gesamtbelohnung zu klein ist - beende die Simulation
4. Berechne die Belohnung $r$ im neuen Zustand 5. Aktualisiere die Q-Funktion gemäß der Bellman-Gleichung: $Q(s,a)\leftarrow (1-\alpha)Q(s,a)+\alpha(r+\gamma\max_{a'}Q(s',a'))$ 6. $s\leftarrow s'$ 7. Aktualisiere die Gesamtbelohnung und verringere $\alpha$.
Ausnutzen vs. Erkunden
Der beste Ansatz ist, ein Gleichgewicht zwischen Erkundung und Ausnutzung zu finden. Während wir mehr über unsere Umgebung lernen, werden wir eher dazu neigen, den optimalen Weg zu folgen, jedoch gelegentlich auch den unerforschten Pfad wählen.
Python-Implementierung
Nun sind wir bereit, den Lernalgorithmus zu implementieren. Zuvor benötigen wir jedoch eine Funktion, die beliebige Zahlen in der Q-Tabelle in einen Wahrscheinlichkeitsvektor für die entsprechenden Aktionen umwandelt:
def probs(v,eps=1e-4):
v = v-v.min()+eps
v = v/v.sum()
return v
Wir fügen dem ursprünglichen Vektor eine kleine Menge eps hinzu, um eine Division durch 0 im Anfangsfall zu vermeiden, wenn alle Komponenten des Vektors identisch sind.
Der eigentliche Lernalgorithmus, den wir für 5000 Experimente ausführen werden, auch Epochen genannt:
from IPython.display import clear_output
lpath = []
for epoch in range(10000):
clear_output(wait=True)
print(f"Epoch = {epoch}",end='')
# Pick initial point
m.random_start()
# Start travelling
n=0
cum_reward = 0
while True:
x,y = m.human
v = probs(Q[x,y])
a = random.choices(list(actions),weights=v)[0]
dpos = actions[a]
m.move(dpos,check_correctness=False) # we allow player to move outside the board, which terminates episode
r = reward(m)
cum_reward += r
if r==end_reward or cum_reward < -1000:
print(f" {n} steps",end='\r')
lpath.append(n)
break
alpha = np.exp(-n / 3000)
gamma = 0.5
ai = action_idx[a]
Q[x,y,ai] = (1 - alpha) * Q[x,y,ai] + alpha * (r + gamma * Q[x+dpos[0], y+dpos[1]].max())
n+=1
Nach der Ausführung dieses Algorithmus sollte die Q-Tabelle mit Werten aktualisiert werden, die die Attraktivität verschiedener Aktionen in jedem Schritt definieren. Visualisieren Sie die Tabelle hier:
m.plot(Q)
Überprüfung der Richtlinie
Da die Q-Tabelle die "Attraktivität" jeder Aktion in jedem Zustand auflistet, ist es ziemlich einfach, sie zu verwenden, um die effiziente Navigation in unserer Welt zu definieren. Im einfachsten Fall können wir einfach die Aktion auswählen, die dem höchsten Wert in der Q-Tabelle entspricht:
def qpolicy_strict(m):
x,y = m.human
v = probs(Q[x,y])
a = list(actions)[np.argmax(v)]
return a
walk(m,qpolicy_strict)
Wenn Sie den obigen Code mehrmals ausprobieren, werden Sie feststellen, dass er manchmal einfach "hängt" und Sie die STOP-Taste im Notebook drücken müssen, um ihn zu unterbrechen.
> Aufgabe 1: Ändern Sie die walk-Funktion so, dass die maximale Pfadlänge auf eine bestimmte Anzahl von Schritten (z. B. 100) begrenzt wird, und beobachten Sie, wie der obige Code diesen Wert von Zeit zu Zeit zurückgibt.
> Aufgabe 2: Ändern Sie die walk-Funktion so, dass sie nicht an Orte zurückkehrt, an denen sie zuvor bereits gewesen ist. Dies wird verhindern, dass walk in einer Schleife hängen bleibt. Allerdings kann es dennoch passieren, dass der Agent an einem Ort "gefangen" wird, von dem er nicht mehr entkommen kann.
def qpolicy(m):
x,y = m.human
v = probs(Q[x,y])
a = random.choices(list(actions),weights=v)[0]
return a
print_statistics(qpolicy)
plt.plot(lpath)
Was wir hier sehen, ist, dass die durchschnittliche Pfadlänge zunächst zugenommen hat. Dies liegt wahrscheinlich daran, dass wir, wenn wir nichts über die Umgebung wissen, dazu neigen, in schlechten Zuständen, Wasser oder bei einem Wolf, gefangen zu werden. Sobald wir mehr lernen und dieses Wissen nutzen, können wir die Umgebung länger erkunden, aber wir wissen immer noch nicht genau, wo sich die Äpfel befinden.
Sobald wir genug gelernt haben, wird es für den Agenten einfacher, das Ziel zu erreichen, und die Pfadlänge beginnt zu sinken. Allerdings sind wir weiterhin offen für Erkundungen, sodass wir oft vom besten Weg abweichen und neue Optionen ausprobieren, was den Pfad länger als optimal macht.
Was wir auf diesem Diagramm ebenfalls beobachten, ist, dass die Länge an einem bestimmten Punkt plötzlich zugenommen hat. Dies deutet auf die stochastische Natur des Prozesses hin und darauf, dass wir die Q-Tabellen-Koeffizienten zu einem bestimmten Zeitpunkt „verderben“ können, indem wir sie mit neuen Werten überschreiben. Dies sollte idealerweise minimiert werden, indem die Lernrate verringert wird (d. h. gegen Ende des Trainings passen wir die Q-Tabellen-Werte nur noch geringfügig an).
Insgesamt ist es wichtig, sich daran zu erinnern, dass der Erfolg und die Qualität des Lernprozesses erheblich von Parametern wie Lernrate, Lernratenabnahme und Diskontfaktor abhängen. Diese werden oft als Hyperparameter bezeichnet, um sie von Parametern zu unterscheiden, die wir während des Trainings optimieren (z. B. Q-Tabellen-Koeffizienten). Der Prozess, die besten Werte für Hyperparameter zu finden, wird als Hyperparameter-Optimierung bezeichnet und verdient ein eigenes Thema.
Übung
Eine realistischere Welt von Peter und der Wolf
In unserer Situation konnte sich Peter fast ohne Ermüdung oder Hunger bewegen. In einer realistischeren Welt muss er sich von Zeit zu Zeit hinsetzen und ausruhen sowie sich selbst versorgen. Machen wir unsere Welt realistischer, indem wir die folgenden Regeln umsetzen:
- Wenn Peter sich von einem Ort zum anderen bewegt, verliert er Energie und sammelt Erschöpfung an.
- Peter kann mehr Energie gewinnen, indem er Äpfel isst.
- Peter kann Erschöpfung loswerden, indem er sich unter einem Baum oder auf dem Gras ausruht (d.h. indem er auf ein Spielfeld mit einem Baum oder Gras - grünes Feld - geht).
- Peter muss den Wolf finden und töten.
- Um den Wolf zu töten, muss Peter bestimmte Energie- und Erschöpfungswerte haben, sonst verliert er den Kampf.
Modifizieren Sie die oben genannte Belohnungsfunktion entsprechend den Spielregeln, führen Sie den Reinforcement-Learning-Algorithmus aus, um die beste Strategie zum Gewinnen des Spiels zu erlernen, und vergleichen Sie die Ergebnisse eines zufälligen Spaziergangs mit Ihrem Algorithmus in Bezug auf die Anzahl der gewonnenen und verlorenen Spiele.
> Hinweis: Sie müssen möglicherweise die Hyperparameter anpassen, damit es funktioniert, insbesondere die Anzahl der Epochen. Da der Erfolg des Spiels (Kampf gegen den Wolf) ein seltenes Ereignis ist, können Sie mit einer deutlich längeren Trainingszeit rechnen.
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
dies ist ein temporärer Platzhalter
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Train Mountain Car
OpenAI Gym wurde so konzipiert, dass alle Umgebungen dieselbe API bereitstellen – d.h. dieselben Methoden reset, step und render sowie dieselben Abstraktionen von Action Space und Observation Space. Daher sollte es möglich sein, dieselben Reinforcement-Learning-Algorithmen mit minimalen Codeänderungen an verschiedene Umgebungen anzupassen.
Eine Mountain-Car-Umgebung
Die Mountain-Car-Umgebung enthält ein Auto, das in einem Tal feststeckt:
Das Ziel ist es, aus dem Tal herauszukommen und die Fahne zu erreichen, indem man bei jedem Schritt eine der folgenden Aktionen ausführt:
| Wert | Bedeutung |
|---|---|
| 0 | Nach links beschleunigen |
| 1 | Nicht beschleunigen |
| 2 | Nach rechts beschleunigen |
Der Hauptkniff bei diesem Problem ist jedoch, dass der Motor des Autos nicht stark genug ist, um den Berg in einem einzigen Anlauf zu erklimmen. Daher besteht die einzige Möglichkeit, erfolgreich zu sein, darin, hin- und herzufahren, um Schwung aufzubauen.
Der Observation Space besteht aus nur zwei Werten:
| Nr. | Beobachtung | Min | Max |
|---|---|---|---|
| 0 | Position des Autos | -1.2 | 0.6 |
| 1 | Geschwindigkeit des Autos | -0.07 | 0.07 |
Das Belohnungssystem für das Mountain Car ist ziemlich knifflig:
- Eine Belohnung von 0 wird vergeben, wenn der Agent die Fahne (Position = 0.5) auf dem Berggipfel erreicht.
- Eine Belohnung von -1 wird vergeben, wenn die Position des Agenten kleiner als 0.5 ist.
Die Episode endet, wenn die Position des Autos größer als 0.5 ist oder die Episodenlänge 200 überschreitet.
Anweisungen
Passen Sie unseren Reinforcement-Learning-Algorithmus an, um das Mountain-Car-Problem zu lösen. Beginnen Sie mit dem bestehenden Code in notebook.ipynb, ersetzen Sie die Umgebung, ändern Sie die Funktionen zur Diskretisierung des Zustands und versuchen Sie, den bestehenden Algorithmus mit minimalen Codeänderungen zu trainieren. Optimieren Sie das Ergebnis, indem Sie die Hyperparameter anpassen.
> Hinweis: Es wird wahrscheinlich notwendig sein, die Hyperparameter anzupassen, damit der Algorithmus konvergiert.
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Der Q-Learning-Algorithmus wurde erfolgreich aus dem CartPole-Beispiel übernommen, mit minimalen Codeänderungen, und ist in der Lage, das Problem des Erreichens der Fahne in weniger als 200 Schritten zu lösen. | Ein neuer Q-Learning-Algorithmus wurde aus dem Internet übernommen, aber gut dokumentiert; oder ein bestehender Algorithmus wurde übernommen, erreicht jedoch nicht die gewünschten Ergebnisse. | Der Student war nicht in der Lage, erfolgreich einen Algorithmus zu übernehmen, hat jedoch wesentliche Schritte zur Lösung unternommen (z. B. Implementierung der Zustandsdiskretisierung, Q-Table-Datenstruktur usw.). |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
CartPole Skating
> Problem: Wenn Peter dem Wolf entkommen möchte, muss er sich schneller bewegen können als dieser. Wir werden sehen, wie Peter das Skaten lernen kann, insbesondere das Halten des Gleichgewichts, mithilfe von Q-Learning.
Zuerst installieren wir das Gym und importieren die benötigten Bibliotheken:
#code block 1
Erstelle eine Cartpole-Umgebung
#code block 2
Um zu sehen, wie die Umgebung funktioniert, lassen Sie uns eine kurze Simulation für 100 Schritte durchführen.
#code block 3
Während der Simulation müssen wir Beobachtungen erhalten, um zu entscheiden, wie wir handeln sollen. Tatsächlich gibt uns die step-Funktion die aktuellen Beobachtungen, die Belohnungsfunktion und das done-Flag zurück, das anzeigt, ob es sinnvoll ist, die Simulation fortzusetzen oder nicht:
#code block 4
Wir können den Mindest- und Höchstwert dieser Zahlen erhalten:
#code block 5
#code block 6
Lassen Sie uns auch eine andere Diskretisierungsmethode mit Bins erkunden:
#code block 7
Lassen Sie uns nun eine kurze Simulation durchführen und diese diskreten Umgebungswerte beobachten.
#code block 8
Q-Tabellenstruktur
#code block 9
#code block 10
#code block 11
plt.plot(rewards)
Aus diesem Diagramm lässt sich nichts erkennen, da aufgrund der Natur des stochastischen Trainingsprozesses die Länge der Trainingseinheiten stark variiert. Um dieses Diagramm besser zu verstehen, können wir den gleitenden Durchschnitt über eine Reihe von Experimenten berechnen, sagen wir 100. Dies kann bequem mit np.convolve durchgeführt werden:
#code block 12
Variieren von Hyperparametern und Beobachten der Ergebnisse in Aktion
Nun wäre es interessant, tatsächlich zu sehen, wie sich das trainierte Modell verhält. Lassen Sie uns die Simulation durchführen, wobei wir dieselbe Aktionsauswahlstrategie wie während des Trainings verwenden: Sampling entsprechend der Wahrscheinlichkeitsverteilung in der Q-Tabelle:
# code block 13
Speichern des Ergebnisses als animiertes GIF
Wenn du deine Freunde beeindrucken möchtest, kannst du ihnen das animierte GIF-Bild der Balancierstange schicken. Dafür können wir env.render aufrufen, um ein Bildframe zu erzeugen, und diese anschließend mit der PIL-Bibliothek als animiertes GIF speichern:
from PIL import Image
obs = env.reset()
done = False
i=0
ims = []
while not done:
s = discretize(obs)
img=env.render(mode='rgb_array')
ims.append(Image.fromarray(img))
v = probs(np.array([Qbest.get((s,a),0) for a in actions]))
a = random.choices(actions,weights=v)[0]
obs,_,done,_ = env.step(a)
i+=1
env.close()
ims[0].save('images/cartpole-balance.gif',save_all=True,append_images=ims[1::2],loop=0,duration=5)
print(i)
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Voraussetzungen
In dieser Lektion verwenden wir eine Bibliothek namens OpenAI Gym, um verschiedene Umgebungen zu simulieren. Du kannst den Code dieser Lektion lokal ausführen (z. B. in Visual Studio Code), wobei die Simulation in einem neuen Fenster geöffnet wird. Wenn du den Code online ausführst, musst du möglicherweise einige Anpassungen vornehmen, wie hier beschrieben.
OpenAI Gym
In der vorherigen Lektion wurden die Spielregeln und der Zustand durch die Board-Klasse definiert, die wir selbst erstellt haben. Hier verwenden wir eine spezielle Simulationsumgebung, die die Physik hinter der balancierenden Stange simuliert. Eine der beliebtesten Simulationsumgebungen für das Training von Reinforcement-Learning-Algorithmen ist das Gym, das von OpenAI gepflegt wird. Mit diesem Gym können wir verschiedene Umgebungen erstellen, von einer CartPole-Simulation bis hin zu Atari-Spielen.
> Hinweis: Weitere Umgebungen von OpenAI Gym findest du hier.
Zuerst installieren wir das Gym und importieren die benötigten Bibliotheken (Codeblock 1):
import sys
!{sys.executable} -m pip install gym
import gym
import matplotlib.pyplot as plt
import numpy as np
import random
Übung - Initialisiere eine CartPole-Umgebung
Um mit dem CartPole-Balancierproblem zu arbeiten, müssen wir die entsprechende Umgebung initialisieren. Jede Umgebung ist mit einem:
-
Beobachtungsraum verbunden, der die Struktur der Informationen definiert, die wir von der Umgebung erhalten. Beim CartPole-Problem erhalten wir die Position der Stange, die Geschwindigkeit und einige andere Werte.
-
Aktionsraum, der mögliche Aktionen definiert. In unserem Fall ist der Aktionsraum diskret und besteht aus zwei Aktionen - links und rechts. (Codeblock 2)
-
Um zu initialisieren, gib den folgenden Code ein:
python env = gym.make("CartPole-v1") print(env.action_space) print(env.observation_space) print(env.action_space.sample())
Um zu sehen, wie die Umgebung funktioniert, führen wir eine kurze Simulation für 100 Schritte durch. Bei jedem Schritt geben wir eine der Aktionen vor - in dieser Simulation wählen wir zufällig eine Aktion aus dem action_space.
-
Führe den folgenden Code aus und sieh dir an, was passiert.
✅ Denke daran, dass es bevorzugt wird, diesen Code in einer lokalen Python-Installation auszuführen! (Codeblock 3)
```python env.reset()
for i in range(100): env.render() env.step(env.action_space.sample()) env.close() ```
Du solltest etwas Ähnliches wie dieses Bild sehen:

-
Während der Simulation müssen wir Beobachtungen erhalten, um zu entscheiden, wie wir handeln sollen. Tatsächlich gibt die
step-Funktion aktuelle Beobachtungen, eine Belohnungsfunktion und eindone-Flag zurück, das anzeigt, ob es sinnvoll ist, die Simulation fortzusetzen oder nicht: (Codeblock 4)```python env.reset()
done = False while not done: env.render() obs, rew, done, info = env.step(env.action_space.sample()) print(f"{obs} -> {rew}") env.close() ```
Du wirst etwas Ähnliches wie dies in der Notebook-Ausgabe sehen:
text [ 0.03403272 -0.24301182 0.02669811 0.2895829 ] -> 1.0 [ 0.02917248 -0.04828055 0.03248977 0.00543839] -> 1.0 [ 0.02820687 0.14636075 0.03259854 -0.27681916] -> 1.0 [ 0.03113408 0.34100283 0.02706215 -0.55904489] -> 1.0 [ 0.03795414 0.53573468 0.01588125 -0.84308041] -> 1.0 ... [ 0.17299878 0.15868546 -0.20754175 -0.55975453] -> 1.0 [ 0.17617249 0.35602306 -0.21873684 -0.90998894] -> 1.0Der Beobachtungsvektor, der bei jedem Schritt der Simulation zurückgegeben wird, enthält die folgenden Werte: - Position des Wagens - Geschwindigkeit des Wagens - Winkel der Stange - Rotationsrate der Stange
-
Ermittle den minimalen und maximalen Wert dieser Zahlen: (Codeblock 5)
python print(env.observation_space.low) print(env.observation_space.high)Du wirst auch feststellen, dass der Belohnungswert bei jedem Simulationsschritt immer 1 ist. Das liegt daran, dass unser Ziel darin besteht, so lange wie möglich zu überleben, d. h. die Stange so lange wie möglich in einer einigermaßen vertikalen Position zu halten.
✅ Tatsächlich gilt die CartPole-Simulation als gelöst, wenn wir es schaffen, eine durchschnittliche Belohnung von 195 über 100 aufeinanderfolgende Versuche zu erreichen.
Zustandsdiskretisierung
Beim Q-Learning müssen wir eine Q-Tabelle erstellen, die definiert, was in jedem Zustand zu tun ist. Um dies tun zu können, muss der Zustand diskret sein, genauer gesagt, er sollte eine endliche Anzahl diskreter Werte enthalten. Daher müssen wir unsere Beobachtungen irgendwie diskretisieren, indem wir sie auf eine endliche Menge von Zuständen abbilden.
Es gibt einige Möglichkeiten, dies zu tun:
- In Bins aufteilen. Wenn wir das Intervall eines bestimmten Wertes kennen, können wir dieses Intervall in eine Anzahl von Bins aufteilen und dann den Wert durch die Bin-Nummer ersetzen, zu der er gehört. Dies kann mit der numpy-Methode
digitizedurchgeführt werden. In diesem Fall kennen wir die Zustandsgröße genau, da sie von der Anzahl der Bins abhängt, die wir für die Digitalisierung auswählen.
✅ Wir können lineare Interpolation verwenden, um Werte auf ein endliches Intervall (z. B. von -20 bis 20) zu bringen, und dann Zahlen durch Runden in ganze Zahlen umwandeln. Dies gibt uns etwas weniger Kontrolle über die Größe des Zustands, insbesondere wenn wir die genauen Bereiche der Eingabewerte nicht kennen. Zum Beispiel haben in unserem Fall 2 von 4 Werten keine oberen/unteren Grenzen, was zu einer unendlichen Anzahl von Zuständen führen kann.
In unserem Beispiel verwenden wir den zweiten Ansatz. Wie du später feststellen wirst, nehmen diese Werte trotz undefinierter oberer/unterer Grenzen selten Werte außerhalb bestimmter endlicher Intervalle an, sodass Zustände mit extremen Werten sehr selten sein werden.
-
Hier ist die Funktion, die die Beobachtung aus unserem Modell nimmt und ein Tupel aus 4 ganzzahligen Werten erzeugt: (Codeblock 6)
python def discretize(x): return tuple((x/np.array([0.25, 0.25, 0.01, 0.1])).astype(np.int)) -
Lass uns auch eine andere Diskretisierungsmethode mit Bins erkunden: (Codeblock 7)
```python def create_bins(i,num): return np.arange(num+1)*(i[1]-i[0])/num+i[0]
print("Sample bins for interval (-5,5) with 10 bins\n",create_bins((-5,5),10))
ints = [(-5,5),(-2,2),(-0.5,0.5),(-2,2)] # intervals of values for each parameter nbins = [20,20,10,10] # number of bins for each parameter bins = [create_bins(ints[i],nbins[i]) for i in range(4)]
def discretize_bins(x): return tuple(np.digitize(x[i],bins[i]) for i in range(4)) ```
-
Lass uns nun eine kurze Simulation durchführen und diese diskreten Umgebungswerte beobachten. Probiere gerne sowohl
discretizeals auchdiscretize_binsaus und sieh, ob es einen Unterschied gibt.✅
discretize_binsgibt die Bin-Nummer zurück, die bei 0 beginnt. Für Eingabewerte um 0 gibt es daher die Zahl aus der Mitte des Intervalls (10) zurück. Beidiscretizehaben wir uns nicht um den Bereich der Ausgabewerte gekümmert, sodass sie negativ sein können, und 0 entspricht 0. (Codeblock 8)```python env.reset()
done = False while not done: #env.render() obs, rew, done, info = env.step(env.action_space.sample()) #print(discretize_bins(obs)) print(discretize(obs)) env.close() ```
✅ Kommentiere die Zeile, die mit
env.renderbeginnt, aus, wenn du sehen möchtest, wie die Umgebung ausgeführt wird. Andernfalls kannst du sie im Hintergrund ausführen, was schneller ist. Wir werden diese "unsichtbare" Ausführung während unseres Q-Learning-Prozesses verwenden.
Die Struktur der Q-Tabelle
In unserer vorherigen Lektion war der Zustand ein einfaches Zahlenpaar von 0 bis 8, und daher war es praktisch, die Q-Tabelle durch einen numpy-Tensor mit einer Form von 8x8x2 darzustellen. Wenn wir die Bins-Diskretisierung verwenden, ist die Größe unseres Zustandsvektors ebenfalls bekannt, sodass wir denselben Ansatz verwenden und den Zustand durch ein Array der Form 20x20x10x10x2 darstellen können (hier ist 2 die Dimension des Aktionsraums, und die ersten Dimensionen entsprechen der Anzahl der Bins, die wir für jeden der Parameter im Beobachtungsraum ausgewählt haben).
Manchmal sind jedoch die genauen Dimensionen des Beobachtungsraums nicht bekannt. Im Fall der discretize-Funktion können wir uns nie sicher sein, dass unser Zustand innerhalb bestimmter Grenzen bleibt, da einige der ursprünglichen Werte nicht begrenzt sind. Daher verwenden wir einen etwas anderen Ansatz und stellen die Q-Tabelle durch ein Wörterbuch dar.
-
Verwende das Paar (state, action) als Schlüssel des Wörterbuchs, und der Wert würde dem Eintrag der Q-Tabelle entsprechen. (Codeblock 9)
```python Q = {} actions = (0,1)
def qvalues(state): return [Q.get((state,a),0) for a in actions] ```
Hier definieren wir auch eine Funktion
qvalues(), die eine Liste von Q-Tabellenwerten für einen gegebenen Zustand zurückgibt, die allen möglichen Aktionen entspricht. Wenn der Eintrag nicht in der Q-Tabelle vorhanden ist, geben wir standardmäßig 0 zurück.
Lass uns mit Q-Learning beginnen
Jetzt sind wir bereit, Peter das Balancieren beizubringen!
-
Zuerst setzen wir einige Hyperparameter: (Codeblock 10)
```python
hyperparameters
alpha = 0.3 gamma = 0.9 epsilon = 0.90 ```
Hier ist
alphadie Lernrate, die definiert, in welchem Ausmaß wir die aktuellen Werte der Q-Tabelle bei jedem Schritt anpassen sollten. In der vorherigen Lektion haben wir mit 1 begonnen und dannalphawährend des Trainings auf niedrigere Werte reduziert. In diesem Beispiel halten wir es der Einfachheit halber konstant, und du kannst später mit der Anpassung deralpha-Werte experimentieren.gammaist der Abzinsungsfaktor, der zeigt, in welchem Ausmaß wir zukünftige Belohnungen gegenüber aktuellen Belohnungen priorisieren sollten.epsilonist der Explorations-/Exploiterungsfaktor, der bestimmt, ob wir Exploration der Exploitation vorziehen sollten oder umgekehrt. In unserem Algorithmus wählen wir inepsilonProzent der Fälle die nächste Aktion entsprechend den Q-Tabellenwerten aus, und in den verbleibenden Fällen führen wir eine zufällige Aktion aus. Dies ermöglicht es uns, Bereiche des Suchraums zu erkunden, die wir noch nie zuvor gesehen haben.✅ In Bezug auf das Balancieren - das Auswählen einer zufälligen Aktion (Exploration) würde wie ein zufälliger Stoß in die falsche Richtung wirken, und die Stange müsste lernen, wie sie das Gleichgewicht aus diesen "Fehlern" wiederherstellt.
Den Algorithmus verbessern
Wir können auch zwei Verbesserungen an unserem Algorithmus aus der vorherigen Lektion vornehmen:
-
Durchschnittliche kumulative Belohnung berechnen, über eine Anzahl von Simulationen. Wir drucken den Fortschritt alle 5000 Iterationen aus und mitteln unsere kumulative Belohnung über diesen Zeitraum. Das bedeutet, dass wir, wenn wir mehr als 195 Punkte erreichen, das Problem als gelöst betrachten können, und zwar mit einer noch höheren Qualität als erforderlich.
-
Maximales durchschnittliches kumulatives Ergebnis berechnen,
Qmax, und wir speichern die Q-Tabelle, die diesem Ergebnis entspricht. Wenn du das Training ausführst, wirst du feststellen, dass manchmal das durchschnittliche kumulative Ergebnis zu sinken beginnt, und wir möchten die Werte der Q-Tabelle beibehalten, die dem besten während des Trainings beobachteten Modell entsprechen.
-
Sammle alle kumulativen Belohnungen bei jeder Simulation im
rewards-Vektor für eine spätere Darstellung. (Codeblock 11)```python def probs(v,eps=1e-4): v = v-v.min()+eps v = v/v.sum() return v
Qmax = 0 cum_rewards = [] rewards = [] for epoch in range(100000): obs = env.reset() done = False cum_reward=0 # == do the simulation == while not done: s = discretize(obs) if random.random()<epsilon: # exploitation - chose the action according to Q-Table probabilities v = probs(np.array(qvalues(s))) a = random.choices(actions,weights=v)[0] else: # exploration - randomly chose the action a = np.random.randint(env.action_space.n)
obs, rew, done, info = env.step(a) cum_reward+=rew ns = discretize(obs) Q[(s,a)] = (1 - alpha) * Q.get((s,a),0) + alpha * (rew + gamma * max(qvalues(ns))) cum_rewards.append(cum_reward) rewards.append(cum_reward) # == Periodically print results and calculate average reward == if epoch%5000==0: print(f"{epoch}: {np.average(cum_rewards)}, alpha={alpha}, epsilon={epsilon}") if np.average(cum_rewards) > Qmax: Qmax = np.average(cum_rewards) Qbest = Q cum_rewards=[]```
Was du aus diesen Ergebnissen feststellen kannst:
-
Nahe an unserem Ziel. Wir sind dem Ziel, 195 kumulative Belohnungen über 100+ aufeinanderfolgende Simulationen zu erreichen, sehr nahe oder haben es möglicherweise sogar erreicht! Selbst wenn wir kleinere Zahlen erhalten, wissen wir es nicht genau, da wir über 5000 Läufe mitteln, und nur 100 Läufe sind im formalen Kriterium erforderlich.
-
Belohnung beginnt zu sinken. Manchmal beginnt die Belohnung zu sinken, was bedeutet, dass wir bereits gelernte Werte in der Q-Tabelle durch solche ersetzen können, die die Situation verschlechtern.
Diese Beobachtung wird deutlicher, wenn wir den Trainingsfortschritt grafisch darstellen.
Trainingsfortschritt darstellen
Während des Trainings haben wir den kumulativen Belohnungswert bei jeder Iteration im rewards-Vektor gesammelt. So sieht es aus, wenn wir es gegen die Iterationsnummer plotten:
plt.plot(rewards)

Aus diesem Diagramm lässt sich nichts ableiten, da aufgrund der stochastischen Natur des Trainingsprozesses die Länge der Trainingseinheiten stark variiert. Um dieses Diagramm sinnvoller zu machen, können wir den gleitenden Durchschnitt über eine Reihe von Experimenten berechnen, sagen wir 100. Dies kann bequem mit np.convolve durchgeführt werden: (Codeblock 12)
def running_average(x,window):
return np.convolve(x,np.ones(window)/window,mode='valid')
plt.plot(running_average(rewards,100))

Hyperparameter variieren
Um das Lernen stabiler zu machen, macht es Sinn, einige unserer Hyperparameter während des Trainings anzupassen. Insbesondere:
-
Für die Lernrate,
alpha, können wir mit Werten nahe 1 beginnen und dann den Parameter schrittweise verringern. Mit der Zeit erhalten wir gute Wahrscheinlichkeitswerte in der Q-Tabelle, und daher sollten wir sie nur leicht anpassen und nicht vollständig mit neuen Werten überschreiben. -
Epsilon erhöhen. Wir könnten
epsilonlangsam erhöhen, um weniger zu explorieren und mehr zu exploiten. Es macht wahrscheinlich Sinn, mit einem niedrigeren Wert vonepsilonzu beginnen und ihn auf fast 1 zu steigern. > Aufgabe 1: Experimentiere mit den Hyperparametern und überprüfe, ob du eine höhere kumulative Belohnung erzielen kannst. Erreichst du mehr als 195? > Aufgabe 2: Um das Problem formal zu lösen, musst du einen durchschnittlichen Reward von 195 über 100 aufeinanderfolgende Durchläufe erreichen. Messe dies während des Trainings und stelle sicher, dass du das Problem formal gelöst hast!
Das Ergebnis in Aktion sehen
Es wäre interessant zu sehen, wie sich das trainierte Modell tatsächlich verhält. Lass uns die Simulation ausführen und dieselbe Aktionsauswahlstrategie wie während des Trainings anwenden, indem wir entsprechend der Wahrscheinlichkeitsverteilung in der Q-Tabelle sampeln: (Codeblock 13)
obs = env.reset()
done = False
while not done:
s = discretize(obs)
env.render()
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
obs,_,done,_ = env.step(a)
env.close()
Du solltest etwas Ähnliches sehen wie hier:

🚀Herausforderung
> Aufgabe 3: Hier haben wir die finale Version der Q-Tabelle verwendet, die möglicherweise nicht die beste ist. Denke daran, dass wir die am besten performende Q-Tabelle in der Variable Qbest gespeichert haben! Probiere dasselbe Beispiel mit der am besten performenden Q-Tabelle aus, indem du Qbest in Q kopierst, und schau, ob du einen Unterschied bemerkst.
> Aufgabe 4: Hier haben wir nicht bei jedem Schritt die beste Aktion ausgewählt, sondern stattdessen entsprechend der Wahrscheinlichkeitsverteilung gesampelt. Wäre es sinnvoller, immer die beste Aktion mit dem höchsten Q-Tabelle-Wert auszuwählen? Das kann mit der Funktion np.argmax umgesetzt werden, um die Aktionsnummer mit dem höchsten Q-Tabelle-Wert zu ermitteln. Implementiere diese Strategie und überprüfe, ob sie das Balancieren verbessert.
Quiz nach der Vorlesung
Aufgabe
Fazit
Wir haben nun gelernt, wie man Agenten trainiert, um gute Ergebnisse zu erzielen, indem man ihnen lediglich eine Reward-Funktion bereitstellt, die den gewünschten Zustand des Spiels definiert, und ihnen die Möglichkeit gibt, den Suchraum intelligent zu erkunden. Wir haben den Q-Learning-Algorithmus erfolgreich in Fällen mit diskreten und kontinuierlichen Umgebungen angewendet, jedoch mit diskreten Aktionen.
Es ist auch wichtig, Situationen zu untersuchen, in denen der Aktionsraum ebenfalls kontinuierlich ist und der Beobachtungsraum viel komplexer wird, wie beispielsweise ein Bild vom Bildschirm eines Atari-Spiels. In solchen Problemen müssen oft leistungsstärkere Machine-Learning-Techniken wie neuronale Netze eingesetzt werden, um gute Ergebnisse zu erzielen. Diese fortgeschritteneren Themen sind Gegenstand unseres kommenden, weiterführenden KI-Kurses.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
CartPole Skating
> Problem: Wenn Peter dem Wolf entkommen möchte, muss er sich schneller bewegen können als dieser. Wir werden sehen, wie Peter das Skaten lernen kann, insbesondere das Halten des Gleichgewichts, mithilfe von Q-Learning.
Zuerst installieren wir das Gym und importieren die benötigten Bibliotheken:
import sys
!pip install gym
import gym
import matplotlib.pyplot as plt
import numpy as np
import random
Erstelle eine Cartpole-Umgebung
env = gym.make("CartPole-v1")
print(env.action_space)
print(env.observation_space)
print(env.action_space.sample())
Um zu sehen, wie die Umgebung funktioniert, lassen Sie uns eine kurze Simulation für 100 Schritte durchführen.
env.reset()
for i in range(100):
env.render()
env.step(env.action_space.sample())
env.close()
Während der Simulation müssen wir Beobachtungen erhalten, um zu entscheiden, wie wir handeln sollen. Tatsächlich gibt uns die step-Funktion die aktuellen Beobachtungen, die Belohnungsfunktion und das done-Flag zurück, das anzeigt, ob es sinnvoll ist, die Simulation fortzusetzen oder nicht:
env.reset()
done = False
while not done:
env.render()
obs, rew, done, info = env.step(env.action_space.sample())
print(f"{obs} -> {rew}")
env.close()
Wir können den Mindest- und Höchstwert dieser Zahlen erhalten:
print(env.observation_space.low)
print(env.observation_space.high)
def discretize(x):
return tuple((x/np.array([0.25, 0.25, 0.01, 0.1])).astype(np.int))
Lassen Sie uns auch eine andere Diskretisierungsmethode mit Bins erkunden:
def create_bins(i,num):
return np.arange(num+1)*(i[1]-i[0])/num+i[0]
print("Sample bins for interval (-5,5) with 10 bins\n",create_bins((-5,5),10))
ints = [(-5,5),(-2,2),(-0.5,0.5),(-2,2)] # intervals of values for each parameter
nbins = [20,20,10,10] # number of bins for each parameter
bins = [create_bins(ints[i],nbins[i]) for i in range(4)]
def discretize_bins(x):
return tuple(np.digitize(x[i],bins[i]) for i in range(4))
Lassen Sie uns nun eine kurze Simulation durchführen und diese diskreten Umgebungswerte beobachten.
env.reset()
done = False
while not done:
#env.render()
obs, rew, done, info = env.step(env.action_space.sample())
#print(discretize_bins(obs))
print(discretize(obs))
env.close()
Q-Tabellenstruktur
Q = {}
actions = (0,1)
def qvalues(state):
return [Q.get((state,a),0) for a in actions]
# hyperparameters
alpha = 0.3
gamma = 0.9
epsilon = 0.90
def probs(v,eps=1e-4):
v = v-v.min()+eps
v = v/v.sum()
return v
Qmax = 0
cum_rewards = []
rewards = []
for epoch in range(100000):
obs = env.reset()
done = False
cum_reward=0
# == do the simulation ==
while not done:
s = discretize(obs)
if random.random()<epsilon:
# exploitation - chose the action according to Q-Table probabilities
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
else:
# exploration - randomly chose the action
a = np.random.randint(env.action_space.n)
obs, rew, done, info = env.step(a)
cum_reward+=rew
ns = discretize(obs)
Q[(s,a)] = (1 - alpha) * Q.get((s,a),0) + alpha * (rew + gamma * max(qvalues(ns)))
cum_rewards.append(cum_reward)
rewards.append(cum_reward)
# == Periodically print results and calculate average reward ==
if epoch%5000==0:
print(f"{epoch}: {np.average(cum_rewards)}, alpha={alpha}, epsilon={epsilon}")
if np.average(cum_rewards) > Qmax:
Qmax = np.average(cum_rewards)
Qbest = Q
cum_rewards=[]
plt.plot(rewards)
Aus diesem Diagramm lässt sich nichts erkennen, da die Länge der Trainingssitzungen aufgrund der stochastischen Trainingsprozesse stark variiert. Um dieses Diagramm besser zu verstehen, können wir den gleitenden Durchschnitt über eine Reihe von Experimenten berechnen, sagen wir 100. Dies kann bequem mit np.convolve durchgeführt werden:
def running_average(x,window):
return np.convolve(x,np.ones(window)/window,mode='valid')
plt.plot(running_average(rewards,100))
Variieren von Hyperparametern und Beobachten der Ergebnisse in Aktion
Jetzt wäre es interessant, tatsächlich zu sehen, wie sich das trainierte Modell verhält. Lassen Sie uns die Simulation ausführen, wobei wir dieselbe Aktionsauswahlstrategie wie während des Trainings verwenden: Sampling entsprechend der Wahrscheinlichkeitsverteilung in der Q-Tabelle:
obs = env.reset()
done = False
while not done:
s = discretize(obs)
env.render()
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
obs,_,done,_ = env.step(a)
env.close()
Speichern des Ergebnisses als animiertes GIF
Wenn du deine Freunde beeindrucken möchtest, kannst du ihnen das animierte GIF-Bild der Balancierstange schicken. Dafür können wir env.render aufrufen, um ein Bildframe zu erzeugen, und diese anschließend mit der PIL-Bibliothek als animiertes GIF speichern:
from PIL import Image
obs = env.reset()
done = False
i=0
ims = []
while not done:
s = discretize(obs)
img=env.render(mode='rgb_array')
ims.append(Image.fromarray(img))
v = probs(np.array([Qbest.get((s,a),0) for a in actions]))
a = random.choices(actions,weights=v)[0]
obs,_,done,_ = env.step(a)
i+=1
env.close()
ims[0].save('images/cartpole-balance.gif',save_all=True,append_images=ims[1::2],loop=0,duration=5)
print(i)
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
dies ist ein temporärer Platzhalter
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in das Reinforcement Learning
Reinforcement Learning, RL, wird als eines der grundlegenden Paradigmen des maschinellen Lernens angesehen, neben dem überwachten und unüberwachten Lernen. RL dreht sich um Entscheidungen: die richtigen Entscheidungen treffen oder zumindest aus ihnen lernen.
Stellen Sie sich vor, Sie haben eine simulierte Umgebung wie den Aktienmarkt. Was passiert, wenn Sie eine bestimmte Regulierung einführen? Hat dies eine positive oder negative Wirkung? Wenn etwas Negatives passiert, müssen Sie diese negative Verstärkung nutzen, daraus lernen und den Kurs ändern. Wenn es ein positives Ergebnis ist, müssen Sie darauf aufbauen und die positive Verstärkung nutzen.

> Peter und seine Freunde müssen dem hungrigen Wolf entkommen! Bild von Jen Looper
Regionales Thema: Peter und der Wolf (Russland)
Peter und der Wolf ist ein musikalisches Märchen, geschrieben von dem russischen Komponisten Sergei Prokofjew. Es ist die Geschichte des jungen Pioniers Peter, der mutig sein Haus verlässt, um auf der Waldlichtung den Wolf zu jagen. In diesem Abschnitt werden wir maschinelle Lernalgorithmen trainieren, die Peter helfen:
- Die Umgebung erkunden und eine optimale Navigationskarte erstellen.
- Lernen, wie man ein Skateboard benutzt und darauf balanciert, um sich schneller fortzubewegen.
> 🎥 Klicken Sie auf das Bild oben, um Peter und der Wolf von Prokofjew zu hören.
Reinforcement Learning
In den vorherigen Abschnitten haben Sie zwei Beispiele für maschinelle Lernprobleme gesehen:
- Überwacht, bei dem wir Datensätze haben, die mögliche Lösungen für das Problem vorschlagen, das wir lösen möchten. Klassifikation und Regression sind Aufgaben des überwachten Lernens.
- Unüberwacht, bei dem wir keine gelabelten Trainingsdaten haben. Das Hauptbeispiel für unüberwachtes Lernen ist Clustering.
In diesem Abschnitt führen wir Sie in eine neue Art von Lernproblem ein, das keine gelabelten Trainingsdaten erfordert. Es gibt mehrere Arten solcher Probleme:
- Semi-überwachtes Lernen, bei dem wir viele ungelabelte Daten haben, die verwendet werden können, um das Modell vorzutrainieren.
- Reinforcement Learning, bei dem ein Agent lernt, sich zu verhalten, indem er Experimente in einer simulierten Umgebung durchführt.
Beispiel - Computerspiel
Angenommen, Sie möchten einem Computer beibringen, ein Spiel zu spielen, wie Schach oder Super Mario. Damit der Computer ein Spiel spielen kann, muss er vorhersagen, welchen Zug er in jedem Spielzustand machen soll. Obwohl dies wie ein Klassifikationsproblem erscheinen mag, ist es keines – denn wir haben keinen Datensatz mit Zuständen und entsprechenden Aktionen. Während wir einige Daten wie bestehende Schachpartien oder Aufzeichnungen von Spielern, die Super Mario spielen, haben könnten, ist es wahrscheinlich, dass diese Daten nicht ausreichend viele mögliche Zustände abdecken.
Anstatt nach bestehenden Spieldaten zu suchen, basiert Reinforcement Learning (RL) auf der Idee, dass der Computer das Spiel viele Male spielt und das Ergebnis beobachtet. Um Reinforcement Learning anzuwenden, benötigen wir daher zwei Dinge:
-
Eine Umgebung und einen Simulator, die es uns ermöglichen, ein Spiel viele Male zu spielen. Dieser Simulator würde alle Spielregeln sowie mögliche Zustände und Aktionen definieren.
-
Eine Belohnungsfunktion, die uns sagt, wie gut wir bei jedem Zug oder Spiel abgeschnitten haben.
Der Hauptunterschied zwischen anderen Arten des maschinellen Lernens und RL besteht darin, dass wir bei RL normalerweise nicht wissen, ob wir gewinnen oder verlieren, bis wir das Spiel beendet haben. Daher können wir nicht sagen, ob ein bestimmter Zug allein gut oder schlecht ist – wir erhalten die Belohnung erst am Ende des Spiels. Unser Ziel ist es, Algorithmen zu entwickeln, die es uns ermöglichen, ein Modell unter unsicheren Bedingungen zu trainieren. Wir werden einen RL-Algorithmus namens Q-Learning kennenlernen.
Lektionen
Credits
"Einführung in Reinforcement Learning" wurde mit ♥️ geschrieben von Dmitry Soshnikov
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Eine ML-Schnitzeljagd
Anweisungen
In dieser Lektion hast du viele reale Anwendungsfälle kennengelernt, die mit klassischem maschinellem Lernen gelöst wurden. Obwohl der Einsatz von Deep Learning, neuen Techniken und Tools in der KI sowie der Nutzung von neuronalen Netzwerken dazu beigetragen hat, die Entwicklung von Werkzeugen in diesen Bereichen zu beschleunigen, hat klassisches maschinelles Lernen mit den in diesem Lehrplan behandelten Techniken weiterhin großen Wert.
In dieser Aufgabe stell dir vor, dass du an einem Hackathon teilnimmst. Nutze das, was du im Lehrplan gelernt hast, um eine Lösung mit klassischem maschinellem Lernen vorzuschlagen, die ein Problem in einem der in dieser Lektion besprochenen Bereiche löst. Erstelle eine Präsentation, in der du erklärst, wie du deine Idee umsetzen wirst. Bonuspunkte gibt es, wenn du Beispieldaten sammeln und ein ML-Modell erstellen kannst, um dein Konzept zu unterstützen!
Bewertungskriterien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Eine PowerPoint-Präsentation wird vorgestellt - Bonus für ein Modell | Eine nicht innovative, grundlegende Präsentation wird vorgestellt | Die Arbeit ist unvollständig |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Nachwort: Maschinelles Lernen in der realen Welt
> Sketchnote von Tomomi Imura
In diesem Lehrplan haben Sie viele Möglichkeiten kennengelernt, Daten für das Training vorzubereiten und maschinelle Lernmodelle zu erstellen. Sie haben eine Reihe klassischer Modelle für Regression, Clustering, Klassifikation, Verarbeitung natürlicher Sprache und Zeitreihen erstellt. Herzlichen Glückwunsch! Nun fragen Sie sich vielleicht, wofür das alles gut ist... Welche Anwendungen gibt es für diese Modelle in der realen Welt?
Obwohl in der Industrie viel Interesse an KI besteht, die oft auf Deep Learning basiert, gibt es immer noch wertvolle Anwendungen für klassische maschinelle Lernmodelle. Vielleicht nutzen Sie einige dieser Anwendungen bereits heute! In dieser Lektion werden Sie erkunden, wie acht verschiedene Branchen und Fachgebiete diese Modelle nutzen, um ihre Anwendungen leistungsfähiger, zuverlässiger, intelligenter und wertvoller für die Nutzer zu machen.
Quiz vor der Vorlesung
💰 Finanzen
Der Finanzsektor bietet viele Möglichkeiten für maschinelles Lernen. Viele Probleme in diesem Bereich lassen sich modellieren und mit ML lösen.
Erkennung von Kreditkartenbetrug
Wir haben früher im Kurs k-means Clustering kennengelernt, aber wie kann es verwendet werden, um Probleme im Zusammenhang mit Kreditkartenbetrug zu lösen?
K-means Clustering ist nützlich bei einer Technik zur Erkennung von Kreditkartenbetrug, die als Ausreißererkennung bezeichnet wird. Ausreißer oder Abweichungen in Beobachtungen über einen Datensatz können uns zeigen, ob eine Kreditkarte normal verwendet wird oder ob etwas Ungewöhnliches vor sich geht. Wie im unten verlinkten Artikel gezeigt, können Sie Kreditkartendaten mit einem k-means Clustering-Algorithmus sortieren und jede Transaktion einem Cluster zuordnen, basierend darauf, wie sehr sie als Ausreißer erscheint. Anschließend können Sie die riskantesten Cluster auf betrügerische oder legitime Transaktionen bewerten. Referenz
Vermögensverwaltung
In der Vermögensverwaltung verwaltet eine Einzelperson oder Firma Investitionen im Namen ihrer Kunden. Ihre Aufgabe ist es, langfristig Vermögen zu erhalten und zu vermehren, daher ist es entscheidend, Investitionen auszuwählen, die gut abschneiden.
Eine Möglichkeit, die Leistung einer bestimmten Investition zu bewerten, ist die statistische Regression. Lineare Regression ist ein wertvolles Werkzeug, um zu verstehen, wie ein Fonds im Vergleich zu einer Benchmark abschneidet. Wir können auch ableiten, ob die Ergebnisse der Regression statistisch signifikant sind oder wie stark sie die Investitionen eines Kunden beeinflussen würden. Sie könnten Ihre Analyse sogar mit multipler Regression erweitern, bei der zusätzliche Risikofaktoren berücksichtigt werden können. Ein Beispiel dafür, wie dies für einen bestimmten Fonds funktionieren würde, finden Sie im unten verlinkten Artikel zur Bewertung der Fondsleistung mithilfe von Regression. Referenz
🎓 Bildung
Der Bildungssektor ist ebenfalls ein sehr interessanter Bereich, in dem ML angewendet werden kann. Es gibt interessante Probleme zu lösen, wie das Erkennen von Betrug bei Tests oder Aufsätzen oder das Verwalten von Vorurteilen, ob absichtlich oder nicht, im Korrekturprozess.
Vorhersage des Schülerverhaltens
Coursera, ein Anbieter von Online-Kursen, hat einen großartigen Tech-Blog, in dem viele technische Entscheidungen diskutiert werden. In dieser Fallstudie haben sie eine Regressionslinie geplottet, um eine mögliche Korrelation zwischen einer niedrigen NPS-Bewertung (Net Promoter Score) und Kursbindung oder -abbruch zu untersuchen. Referenz
Vorurteile mindern
Grammarly, ein Schreibassistent, der Rechtschreib- und Grammatikfehler überprüft, verwendet ausgeklügelte Systeme zur Verarbeitung natürlicher Sprache in seinen Produkten. Sie haben in ihrem Tech-Blog eine interessante Fallstudie veröffentlicht, wie sie mit Geschlechtervorurteilen im maschinellen Lernen umgegangen sind, was Sie in unserer Einführungslektion zur Fairness gelernt haben. Referenz
👜 Einzelhandel
Der Einzelhandelssektor kann definitiv von der Nutzung von ML profitieren, sei es durch die Schaffung einer besseren Kundenreise oder die optimale Lagerhaltung.
Personalisierung der Kundenreise
Bei Wayfair, einem Unternehmen, das Haushaltswaren wie Möbel verkauft, ist es entscheidend, den Kunden zu helfen, die richtigen Produkte für ihren Geschmack und ihre Bedürfnisse zu finden. In diesem Artikel beschreiben Ingenieure des Unternehmens, wie sie ML und NLP nutzen, um "die richtigen Ergebnisse für Kunden zu präsentieren". Insbesondere wurde ihre Query Intent Engine entwickelt, um Entitätsextraktion, Klassifikatortraining, Asset- und Meinungsextraktion sowie Sentiment-Tagging bei Kundenbewertungen zu nutzen. Dies ist ein klassischer Anwendungsfall dafür, wie NLP im Online-Einzelhandel funktioniert. Referenz
Lagerverwaltung
Innovative, agile Unternehmen wie StitchFix, ein Box-Service, der Kleidung an Verbraucher versendet, verlassen sich stark auf ML für Empfehlungen und Lagerverwaltung. Ihre Styling-Teams arbeiten tatsächlich mit ihren Merchandising-Teams zusammen: "Einer unserer Datenwissenschaftler hat mit einem genetischen Algorithmus experimentiert und ihn auf Kleidung angewendet, um vorherzusagen, welches Kleidungsstück erfolgreich sein könnte, das heute noch nicht existiert. Wir haben das dem Merchandising-Team vorgestellt, und jetzt können sie das als Werkzeug nutzen." Referenz
🏥 Gesundheitswesen
Der Gesundheitssektor kann ML nutzen, um Forschungsaufgaben und logistische Probleme wie die Wiederaufnahme von Patienten oder die Eindämmung von Krankheiten zu optimieren.
Verwaltung klinischer Studien
Toxizität in klinischen Studien ist ein großes Anliegen für Arzneimittelhersteller. Wie viel Toxizität ist tolerierbar? In dieser Studie führte die Analyse verschiedener klinischer Studienmethoden zur Entwicklung eines neuen Ansatzes zur Vorhersage der Wahrscheinlichkeit von Ergebnissen klinischer Studien. Insbesondere konnten sie Random Forest verwenden, um einen Klassifikator zu erstellen, der zwischen Gruppen von Medikamenten unterscheidet. Referenz
Krankenhaus-Wiederaufnahme-Management
Krankenhauspflege ist teuer, insbesondere wenn Patienten wieder aufgenommen werden müssen. In diesem Artikel wird ein Unternehmen diskutiert, das ML verwendet, um das Potenzial für Wiederaufnahmen mithilfe von Clustering-Algorithmen vorherzusagen. Diese Cluster helfen Analysten, "Gruppen von Wiederaufnahmen zu entdecken, die möglicherweise eine gemeinsame Ursache teilen". Referenz
Krankheitsmanagement
Die jüngste Pandemie hat deutlich gemacht, wie maschinelles Lernen dazu beitragen kann, die Ausbreitung von Krankheiten zu stoppen. In diesem Artikel erkennen Sie die Verwendung von ARIMA, logistischen Kurven, linearer Regression und SARIMA. "Diese Arbeit ist ein Versuch, die Ausbreitungsrate dieses Virus zu berechnen und somit die Todesfälle, Genesungen und bestätigten Fälle vorherzusagen, damit wir uns besser vorbereiten und überleben können." Referenz
🌲 Ökologie und grüne Technologie
Die Natur und Ökologie bestehen aus vielen empfindlichen Systemen, bei denen das Zusammenspiel zwischen Tieren und Natur im Fokus steht. Es ist wichtig, diese Systeme genau zu messen und angemessen zu handeln, wenn etwas passiert, wie ein Waldbrand oder ein Rückgang der Tierpopulation.
Waldmanagement
Sie haben in früheren Lektionen Reinforcement Learning kennengelernt. Es kann sehr nützlich sein, wenn versucht wird, Muster in der Natur vorherzusagen. Insbesondere kann es verwendet werden, um ökologische Probleme wie Waldbrände und die Ausbreitung invasiver Arten zu verfolgen. In Kanada hat eine Gruppe von Forschern Reinforcement Learning verwendet, um Modelle für die Dynamik von Waldbränden aus Satellitenbildern zu erstellen. Mithilfe eines innovativen "räumlich ausbreitenden Prozesses (SSP)" stellten sie sich einen Waldbrand als "den Agenten an jeder Zelle in der Landschaft" vor. "Die Menge an Aktionen, die das Feuer von einem Standort zu einem beliebigen Zeitpunkt ausführen kann, umfasst die Ausbreitung nach Norden, Süden, Osten oder Westen oder keine Ausbreitung."
Dieser Ansatz kehrt das übliche RL-Setup um, da die Dynamik des entsprechenden Markov Decision Process (MDP) eine bekannte Funktion für die unmittelbare Ausbreitung von Waldbränden ist. Lesen Sie mehr über die klassischen Algorithmen, die von dieser Gruppe verwendet wurden, unter dem unten stehenden Link. Referenz
Bewegungserkennung von Tieren
Während Deep Learning eine Revolution in der visuellen Verfolgung von Tierbewegungen ausgelöst hat (Sie können Ihren eigenen Eisbären-Tracker hier erstellen), hat klassisches ML immer noch einen Platz in dieser Aufgabe.
Sensoren zur Verfolgung von Bewegungen von Nutztieren und IoT nutzen diese Art der visuellen Verarbeitung, aber grundlegende ML-Techniken sind nützlich, um Daten vorzuverarbeiten. Zum Beispiel wurden in diesem Artikel die Haltungen von Schafen überwacht und analysiert, indem verschiedene Klassifikator-Algorithmen verwendet wurden. Sie könnten die ROC-Kurve auf Seite 335 erkennen. Referenz
⚡️ Energiemanagement
In unseren Lektionen über Zeitreihenprognosen haben wir das Konzept intelligenter Parkuhren eingeführt, um Einnahmen für eine Stadt basierend auf dem Verständnis von Angebot und Nachfrage zu generieren. Dieser Artikel diskutiert ausführlich, wie Clustering, Regression und Zeitreihenprognosen kombiniert wurden, um den zukünftigen Energieverbrauch in Irland vorherzusagen, basierend auf intelligenten Zählern. Referenz
💼 Versicherungen
Der Versicherungssektor ist ein weiterer Bereich, der ML nutzt, um tragfähige finanzielle und versicherungsmathematische Modelle zu erstellen und zu optimieren.
Volatilitätsmanagement
MetLife, ein Anbieter von Lebensversicherungen, ist offen darüber, wie sie Volatilität in ihren Finanzmodellen analysieren und mindern. In diesem Artikel werden Sie binäre und ordinale Klassifikationsvisualisierungen bemerken. Sie werden auch Prognosevisualisierungen entdecken. Referenz
🎨 Kunst, Kultur und Literatur
In den Künsten, beispielsweise im Journalismus, gibt es viele interessante Probleme. Die Erkennung von Fake News ist ein großes Problem, da nachgewiesen wurde, dass sie die Meinung der Menschen beeinflussen und sogar Demokratien stürzen können. Museen können ebenfalls von der Nutzung von ML profitieren, sei es bei der Suche nach Verbindungen zwischen Artefakten oder der Ressourcenplanung.
Erkennung von Fake News
Die Erkennung von Fake News ist heute ein Katz-und-Maus-Spiel in den Medien. In diesem Artikel schlagen Forscher vor, dass ein System, das mehrere der ML-Techniken kombiniert, die wir studiert haben, getestet und das beste Modell eingesetzt werden kann: "Dieses System basiert auf der Verarbeitung natürlicher Sprache, um Merkmale aus den Daten zu extrahieren, und diese Merkmale werden dann für das Training von maschinellen Lernklassifikatoren wie Naive Bayes, Support Vector Machine (SVM), Random Forest (RF), Stochastic Gradient Descent (SGD) und Logistic Regression (LR) verwendet." Referenz
Dieser Artikel zeigt, wie die Kombination verschiedener ML-Bereiche interessante Ergebnisse liefern kann, die helfen können, die Verbreitung von Fake News zu stoppen und echten Schaden zu verhindern; in diesem Fall war der Anstoß die Verbreitung von Gerüchten über COVID-Behandlungen, die zu Gewalt durch Menschenmengen führten.
Museum ML
Museen stehen am Beginn einer KI-Revolution, bei der das Katalogisieren und Digitalisieren von Sammlungen sowie das Finden von Verbindungen zwischen Artefakten einfacher wird, da die Technologie voranschreitet. Projekte wie In Codice Ratio helfen, die Geheimnisse unzugänglicher Sammlungen wie der Vatikanischen Archive zu entschlüsseln. Aber auch der geschäftliche Aspekt von Museen profitiert von ML-Modellen.
Zum Beispiel hat das Art Institute of Chicago Modelle entwickelt, um vorherzusagen, woran Besucher interessiert sind und wann sie Ausstellungen besuchen werden. Das Ziel ist es, jedes Mal, wenn der Nutzer das Museum besucht, individuelle und optimierte Besuchererlebnisse zu schaffen. "Im Geschäftsjahr 2017 sagte das Modell die Besucherzahlen und Einnahmen mit einer Genauigkeit von 1 Prozent voraus, sagt Andrew Simnick, Senior Vice President am Art Institute." Referenz
🏷 Marketing
Kundensegmentierung
Die effektivsten Marketingstrategien zielen auf Kunden auf unterschiedliche Weise ab, basierend auf verschiedenen Gruppierungen. In diesem Artikel werden die Einsatzmöglichkeiten von Clustering-Algorithmen diskutiert, um differenziertes Marketing zu unterstützen. Differenziertes Marketing hilft Unternehmen, die Markenbekanntheit zu verbessern, mehr Kunden zu erreichen und mehr Geld zu verdienen. Referenz
🚀 Herausforderung
Identifizieren Sie einen weiteren Sektor, der von einigen der Techniken profitiert, die Sie in diesem Lehrplan gelernt haben, und entdecken Sie, wie er ML nutzt.
Quiz nach der Vorlesung
Wiederholung & Selbststudium
Das Data-Science-Team von Wayfair hat mehrere interessante Videos darüber, wie sie ML in ihrem Unternehmen einsetzen. Es lohnt sich, einen Blick darauf zu werfen!
Aufgabe
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Erkunden Sie das Responsible AI (RAI) Dashboard
Anweisungen
In dieser Lektion haben Sie das RAI-Dashboard kennengelernt, eine Suite von Komponenten, die auf "Open-Source"-Tools basiert, um Datenwissenschaftlern bei der Fehleranalyse, Datenexploration, Fairnessbewertung, Modellinterpretierbarkeit, Gegenfakt-/Was-wäre-wenn-Bewertungen und Kausalanalysen von KI-Systemen zu helfen. Für diese Aufgabe erkunden Sie einige der Beispiel-Notebooks des RAI-Dashboards und berichten Ihre Ergebnisse in einem Aufsatz oder einer Präsentation.
Bewertungsrichtlinien
| Kriterien | Vorbildlich | Angemessen | Verbesserungswürdig |
|---|---|---|---|
| Ein Aufsatz oder eine PowerPoint-Präsentation wird vorgelegt, die die Komponenten des RAI-Dashboards, das ausgeführte Notebook und die daraus gezogenen Schlussfolgerungen diskutiert. | Ein Aufsatz wird vorgelegt, jedoch ohne Schlussfolgerungen. | Es wird kein Aufsatz vorgelegt. |
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Postskriptum: Modell-Debugging im maschinellen Lernen mit Komponenten des Responsible AI Dashboards
Quiz vor der Vorlesung
Einführung
Maschinelles Lernen beeinflusst unser tägliches Leben. KI findet ihren Weg in einige der wichtigsten Systeme, die uns als Individuen und unsere Gesellschaft betreffen, wie Gesundheitswesen, Finanzen, Bildung und Beschäftigung. Beispielsweise sind Systeme und Modelle an alltäglichen Entscheidungsprozessen beteiligt, wie Diagnosen im Gesundheitswesen oder der Betrugserkennung. Folglich werden die Fortschritte in der KI und ihre beschleunigte Einführung von sich entwickelnden gesellschaftlichen Erwartungen und wachsender Regulierung begleitet. Immer wieder sehen wir Bereiche, in denen KI-Systeme Erwartungen nicht erfüllen, neue Herausforderungen aufzeigen und Regierungen beginnen, KI-Lösungen zu regulieren. Daher ist es wichtig, diese Modelle zu analysieren, um faire, zuverlässige, inklusive, transparente und verantwortungsvolle Ergebnisse für alle zu gewährleisten.
In diesem Lehrplan werden wir uns praktische Werkzeuge ansehen, die verwendet werden können, um zu beurteilen, ob ein Modell Probleme im Bereich der verantwortungsvollen KI aufweist. Traditionelle Debugging-Techniken im maschinellen Lernen basieren oft auf quantitativen Berechnungen wie aggregierter Genauigkeit oder durchschnittlichem Fehlerverlust. Stellen Sie sich vor, was passieren kann, wenn die Daten, die Sie zur Erstellung dieser Modelle verwenden, bestimmte demografische Gruppen wie Rasse, Geschlecht, politische Ansichten oder Religion nicht enthalten oder diese unverhältnismäßig stark repräsentieren. Was ist, wenn die Ausgabe des Modells so interpretiert wird, dass sie eine bestimmte demografische Gruppe bevorzugt? Dies kann zu einer Über- oder Unterrepräsentation dieser sensiblen Merkmale führen, was zu Problemen in Bezug auf Fairness, Inklusivität oder Zuverlässigkeit des Modells führt. Ein weiterer Faktor ist, dass maschinelle Lernmodelle oft als Blackboxen betrachtet werden, was es schwierig macht, die treibenden Faktoren hinter den Vorhersagen eines Modells zu verstehen und zu erklären. All dies sind Herausforderungen, denen sich Datenwissenschaftler und KI-Entwickler stellen müssen, wenn sie nicht über geeignete Werkzeuge verfügen, um die Fairness oder Vertrauenswürdigkeit eines Modells zu debuggen und zu bewerten.
In dieser Lektion lernen Sie, wie Sie Ihre Modelle debuggen können, indem Sie:
- Fehleranalyse: Identifizieren, in welchen Bereichen Ihrer Datenverteilung das Modell hohe Fehlerraten aufweist.
- Modellübersicht: Vergleichende Analysen über verschiedene Datenkohorten durchführen, um Diskrepanzen in den Leistungsmetriken Ihres Modells zu entdecken.
- Datenanalyse: Untersuchen, wo es eine Über- oder Unterrepräsentation Ihrer Daten geben könnte, die Ihr Modell dazu verleiten kann, eine Daten-Demografie gegenüber einer anderen zu bevorzugen.
- Feature-Wichtigkeit: Verstehen, welche Merkmale die Vorhersagen Ihres Modells auf globaler oder lokaler Ebene beeinflussen.
Voraussetzungen
Als Voraussetzung lesen Sie bitte die Übersicht Responsible AI tools for developers.
> 
Fehleranalyse
Traditionelle Leistungsmetriken von Modellen zur Messung der Genauigkeit basieren meist auf Berechnungen von korrekten vs. falschen Vorhersagen. Zum Beispiel kann ein Modell, das zu 89 % genau ist und einen Fehlerverlust von 0,001 aufweist, als leistungsstark angesehen werden. Fehler sind jedoch oft nicht gleichmäßig in Ihrem zugrunde liegenden Datensatz verteilt. Sie könnten eine Modellgenauigkeit von 89 % erzielen, aber feststellen, dass es in bestimmten Bereichen Ihrer Daten Regionen gibt, in denen das Modell zu 42 % fehlerhaft ist. Die Konsequenzen dieser Fehlermuster bei bestimmten Datengruppen können zu Problemen in Bezug auf Fairness oder Zuverlässigkeit führen. Es ist entscheidend, die Bereiche zu verstehen, in denen das Modell gut oder schlecht abschneidet. Die Datenregionen, in denen Ihr Modell viele Ungenauigkeiten aufweist, könnten sich als wichtige demografische Daten herausstellen.

Die Fehleranalyse-Komponente des RAI Dashboards zeigt, wie Modellfehler über verschiedene Kohorten hinweg mit einer Baumvisualisierung verteilt sind. Dies ist nützlich, um Merkmale oder Bereiche zu identifizieren, in denen Ihre Daten eine hohe Fehlerrate aufweisen. Indem Sie sehen, woher die meisten Ungenauigkeiten des Modells stammen, können Sie beginnen, die Ursache zu untersuchen. Sie können auch Datenkohorten erstellen, um Analysen durchzuführen. Diese Datenkohorten helfen im Debugging-Prozess, um festzustellen, warum die Modellleistung in einer Kohorte gut, in einer anderen jedoch fehlerhaft ist.

Die visuellen Indikatoren in der Baumkarte helfen, Problemstellen schneller zu lokalisieren. Zum Beispiel zeigt ein dunklerer Rotton eines Baumknotens eine höhere Fehlerrate an.
Eine weitere Visualisierungsfunktion ist die Heatmap, mit der Benutzer die Fehlerrate anhand eines oder zweier Merkmale untersuchen können, um einen Beitrag zu den Modellfehlern im gesamten Datensatz oder in Kohorten zu finden.

Verwenden Sie die Fehleranalyse, wenn Sie:
- Ein tiefes Verständnis dafür gewinnen möchten, wie Modellfehler über einen Datensatz und mehrere Eingabe- und Merkmalsdimensionen verteilt sind.
- Die aggregierten Leistungsmetriken aufschlüsseln möchten, um fehlerhafte Kohorten automatisch zu entdecken und gezielte Maßnahmen zur Behebung zu ergreifen.
Modellübersicht
Die Bewertung der Leistung eines maschinellen Lernmodells erfordert ein ganzheitliches Verständnis seines Verhaltens. Dies kann erreicht werden, indem mehr als eine Metrik wie Fehlerrate, Genauigkeit, Recall, Präzision oder MAE (Mean Absolute Error) überprüft wird, um Diskrepanzen zwischen den Leistungsmetriken zu finden. Eine Leistungsmetrik mag großartig aussehen, aber Ungenauigkeiten können in einer anderen Metrik aufgedeckt werden. Darüber hinaus hilft der Vergleich der Metriken über den gesamten Datensatz oder Kohorten hinweg, Licht darauf zu werfen, wo das Modell gut oder schlecht abschneidet. Dies ist besonders wichtig, um die Leistung des Modells bei sensiblen vs. unsensiblen Merkmalen (z. B. ethnische Zugehörigkeit, Geschlecht oder Alter von Patienten) zu sehen, um potenzielle Unfairness des Modells aufzudecken. Zum Beispiel kann die Entdeckung, dass das Modell in einer Kohorte mit sensiblen Merkmalen fehlerhafter ist, potenzielle Unfairness aufzeigen.
Die Modellübersicht-Komponente des RAI Dashboards hilft nicht nur bei der Analyse der Leistungsmetriken der Datenrepräsentation in einer Kohorte, sondern gibt Benutzern auch die Möglichkeit, das Verhalten des Modells über verschiedene Kohorten hinweg zu vergleichen.

Die funktionsbasierte Analysefunktion der Komponente ermöglicht es Benutzern, Datensubgruppen innerhalb eines bestimmten Merkmals einzugrenzen, um Anomalien auf granularer Ebene zu identifizieren. Beispielsweise verfügt das Dashboard über eine eingebaute Intelligenz, um Kohorten für ein vom Benutzer ausgewähltes Merkmal automatisch zu generieren (z. B. "time_in_hospital < 3" oder "time_in_hospital >= 7"). Dies ermöglicht es einem Benutzer, ein bestimmtes Merkmal aus einer größeren Datengruppe zu isolieren, um zu sehen, ob es ein Schlüsselfaktor für die fehlerhaften Ergebnisse des Modells ist.

Die Modellübersicht-Komponente unterstützt zwei Klassen von Diskrepanzmetriken:
Diskrepanz in der Modellleistung: Diese Metriken berechnen die Diskrepanz (Differenz) in den Werten der ausgewählten Leistungsmetrik über Untergruppen von Daten. Hier einige Beispiele:
- Diskrepanz in der Genauigkeitsrate
- Diskrepanz in der Fehlerrate
- Diskrepanz in der Präzision
- Diskrepanz im Recall
- Diskrepanz im mittleren absoluten Fehler (MAE)
Diskrepanz in der Auswahlrate: Diese Metrik enthält die Differenz in der Auswahlrate (günstige Vorhersage) zwischen Untergruppen. Ein Beispiel hierfür ist die Diskrepanz in den Kreditgenehmigungsraten. Die Auswahlrate bezeichnet den Anteil der Datenpunkte in jeder Klasse, die als 1 klassifiziert werden (bei binärer Klassifikation) oder die Verteilung der Vorhersagewerte (bei Regression).
Datenanalyse
> "Wenn man Daten lange genug foltert, gestehen sie alles" - Ronald Coase
Diese Aussage klingt extrem, aber es stimmt, dass Daten manipuliert werden können, um jede Schlussfolgerung zu unterstützen. Eine solche Manipulation kann manchmal unbeabsichtigt geschehen. Als Menschen haben wir alle Vorurteile, und es ist oft schwierig, bewusst zu erkennen, wann man Vorurteile in Daten einführt. Fairness in KI und maschinellem Lernen zu gewährleisten, bleibt eine komplexe Herausforderung.
Daten sind ein großer blinder Fleck für traditionelle Modellleistungsmetriken. Sie können hohe Genauigkeitswerte haben, aber das spiegelt nicht immer die zugrunde liegenden Datenverzerrungen wider, die in Ihrem Datensatz vorhanden sein könnten. Zum Beispiel, wenn ein Datensatz von Mitarbeitern 27 % Frauen in Führungspositionen und 73 % Männer auf derselben Ebene enthält, könnte ein auf diesen Daten trainiertes Stellenanzeigen-KI-Modell hauptsächlich ein männliches Publikum für Führungspositionen ansprechen. Dieses Ungleichgewicht in den Daten hat die Vorhersage des Modells verzerrt, sodass eine Geschlechterpräferenz entsteht. Dies zeigt ein Fairness-Problem, bei dem ein Geschlechterbias im KI-Modell vorliegt.
Die Datenanalyse-Komponente des RAI Dashboards hilft, Bereiche zu identifizieren, in denen es eine Über- oder Unterrepräsentation im Datensatz gibt. Sie hilft Benutzern, die Ursache von Fehlern und Fairness-Problemen zu diagnostizieren, die durch Datenungleichgewichte oder mangelnde Repräsentation einer bestimmten Datengruppe entstehen. Dies gibt Benutzern die Möglichkeit, Datensätze basierend auf vorhergesagten und tatsächlichen Ergebnissen, Fehlergruppen und spezifischen Merkmalen zu visualisieren. Manchmal kann die Entdeckung einer unterrepräsentierten Datengruppe auch aufzeigen, dass das Modell nicht gut lernt, was zu hohen Ungenauigkeiten führt. Ein Modell mit Datenbias ist nicht nur ein Fairness-Problem, sondern zeigt auch, dass das Modell nicht inklusiv oder zuverlässig ist.

Verwenden Sie die Datenanalyse, wenn Sie:
- Statistiken Ihres Datensatzes erkunden möchten, indem Sie verschiedene Filter auswählen, um Ihre Daten in verschiedene Dimensionen (auch Kohorten genannt) aufzuteilen.
- Die Verteilung Ihres Datensatzes über verschiedene Kohorten und Merkmalsgruppen hinweg verstehen möchten.
- Feststellen möchten, ob Ihre Erkenntnisse zu Fairness, Fehleranalyse und Kausalität (abgeleitet aus anderen Dashboard-Komponenten) auf der Verteilung Ihres Datensatzes basieren.
- Entscheiden möchten, in welchen Bereichen Sie mehr Daten sammeln sollten, um Fehler zu mindern, die durch Repräsentationsprobleme, Label-Rauschen, Merkmalsrauschen, Label-Bias und ähnliche Faktoren entstehen.
Modellinterpretierbarkeit
Maschinelle Lernmodelle werden oft als Blackboxen betrachtet. Es kann schwierig sein zu verstehen, welche Schlüsseldatenmerkmale die Vorhersagen eines Modells antreiben. Es ist wichtig, Transparenz darüber zu schaffen, warum ein Modell eine bestimmte Vorhersage trifft. Zum Beispiel, wenn ein KI-System vorhersagt, dass ein Diabetespatient ein Risiko hat, innerhalb von weniger als 30 Tagen wieder ins Krankenhaus eingeliefert zu werden, sollte es unterstützende Daten liefern können, die zu seiner Vorhersage geführt haben. Solche unterstützenden Datenindikatoren schaffen Transparenz, um Kliniken oder Krankenhäusern zu helfen, fundierte Entscheidungen zu treffen. Darüber hinaus ermöglicht die Fähigkeit, zu erklären, warum ein Modell eine Vorhersage für einen einzelnen Patienten getroffen hat, die Einhaltung von Gesundheitsvorschriften. Wenn Sie maschinelle Lernmodelle in Bereichen einsetzen, die das Leben von Menschen betreffen, ist es entscheidend, das Verhalten eines Modells zu verstehen und zu erklären. Modell-Erklärbarkeit und -Interpretierbarkeit hilft, Fragen in Szenarien wie diesen zu beantworten:
- Modell-Debugging: Warum hat mein Modell diesen Fehler gemacht? Wie kann ich mein Modell verbessern?
- Mensch-KI-Zusammenarbeit: Wie kann ich die Entscheidungen des Modells verstehen und ihm vertrauen?
- Gesetzliche Anforderungen: Erfüllt mein Modell die rechtlichen Vorgaben?
Die Feature-Wichtigkeit-Komponente des RAI Dashboards hilft Ihnen, Ihr Modell zu debuggen und ein umfassendes Verständnis dafür zu gewinnen, wie ein Modell Vorhersagen trifft. Sie ist auch ein nützliches Werkzeug für Fachleute im maschinellen Lernen und Entscheidungsträger, um zu erklären und nachzuweisen, welche Merkmale das Verhalten eines Modells beeinflussen, um gesetzliche Anforderungen zu erfüllen. Benutzer können sowohl globale als auch lokale Erklärungen untersuchen, um zu validieren, welche Merkmale die Vorhersagen eines Modells antreiben. Globale Erklärungen listen die wichtigsten Merkmale auf, die die Gesamtvorhersage eines Modells beeinflusst haben. Lokale Erklärungen zeigen, welche Merkmale zu einer Vorhersage des Modells für einen einzelnen Fall geführt haben. Die Möglichkeit, lokale Erklärungen zu bewerten, ist auch hilfreich beim Debugging oder bei der Prüfung eines bestimmten Falls, um besser zu verstehen und zu interpretieren, warum ein Modell eine korrekte oder fehlerhafte Vorhersage getroffen hat.

- Globale Erklärungen: Zum Beispiel, welche Merkmale beeinflussen das Gesamtverhalten eines Modells zur Vorhersage von Krankenhauswiedereinweisungen bei Diabetes?
- Lokale Erklärungen: Zum Beispiel, warum wurde ein Diabetespatient über 60 Jahre mit vorherigen Krankenhausaufenthalten vorhergesagt, innerhalb von 30 Tagen wieder oder nicht wieder ins Krankenhaus eingeliefert zu werden?
Im Debugging-Prozess, bei dem die Leistung eines Modells über verschiedene Kohorten untersucht wird, zeigt die Feature-Wichtigkeit, wie stark ein Merkmal die Kohorten beeinflusst. Sie hilft, Anomalien aufzudecken, wenn man den Einfluss eines Merkmals auf die fehlerhaften Vorhersagen eines Modells vergleicht. Die Feature-Wichtigkeit-Komponente kann zeigen, welche Werte in einem Merkmal die Ergebnisse des Modells positiv oder negativ beeinflusst haben. Wenn ein Modell beispielsweise eine fehlerhafte Vorhersage gemacht hat, gibt die Komponente Ihnen die Möglichkeit, ins Detail zu gehen und herauszufinden, welche Merkmale oder Merkmalswerte die Vorhersage beeinflusst haben. Dieses Detailniveau hilft nicht nur beim Debugging, sondern bietet auch Transparenz und Verantwortlichkeit in Prüfungssituationen. Schließlich kann die Komponente helfen, Fairness-Probleme zu identifizieren. Wenn beispielsweise ein sensibles Merkmal wie ethnische Zugehörigkeit oder Geschlecht einen hohen Einfluss auf die Vorhersage eines Modells hat, könnte dies ein Hinweis auf Rassen- oder Geschlechterbias im Modell sein.

Verwenden Sie Interpretierbarkeit, wenn Sie:
- Bestimmen möchten, wie vertrauenswürdig die Vorhersagen Ihres KI-Systems sind, indem Sie verstehen, welche Merkmale für die Vorhersagen am wichtigsten sind.
- Den Debugging-Prozess Ihres Modells angehen möchten, indem Sie es zuerst verstehen und feststellen, ob das Modell gesunde Merkmale oder lediglich falsche Korrelationen verwendet.
- Potenzielle Quellen von Unfairness aufdecken möchten, indem Sie verstehen, ob das Modell Vorhersagen auf sensiblen Merkmalen oder auf Merkmalen, die stark mit ihnen korreliert sind, basiert.
- Das Vertrauen der Benutzer in die Entscheidungen Ihres Modells aufbauen möchten, indem Sie lokale Erklärungen generieren, um deren Ergebnisse zu veranschaulichen.
- Eine gesetzliche Prüfung eines KI-Systems abschließen möchten, um Modelle zu validieren und die Auswirkungen von Modellentscheidungen auf Menschen zu überwachen.
Fazit
Alle Komponenten des RAI Dashboards sind praktische Werkzeuge, die Ihnen helfen, maschinelle Lernmodelle zu entwickeln, die weniger schädlich und vertrauenswürdiger für die Gesellschaft sind. Sie tragen dazu bei, Bedrohungen der Menschenrechte zu verhindern, wie die Diskriminierung oder den Ausschluss bestimmter Gruppen von Lebenschancen, sowie das Risiko physischer oder psychischer Schäden. Sie helfen auch, Vertrauen in die Entscheidungen Ihres Modells aufzubauen, indem sie lokale Erklärungen generieren, um deren Ergebnisse zu veranschaulichen. Einige der potenziellen Schäden können wie folgt klassifiziert werden:
- Zuweisung: Wenn beispielsweise ein Geschlecht oder eine ethnische Zugehörigkeit gegenüber einer anderen bevorzugt wird.
- Qualität des Dienstes: Wenn Sie die Daten für ein spezifisches Szenario trainieren, die Realität jedoch viel komplexer ist, führt dies zu einem schlecht funktionierenden Dienst.
- Stereotypisierung: Die Zuordnung einer bestimmten Gruppe zu vorgegebenen Eigenschaften.
- Herabwürdigung: Eine unfaire Kritik oder Etikettierung von etwas oder jemandem.
- Über- oder Unterrepräsentation. Die Idee dahinter ist, dass eine bestimmte Gruppe in einem bestimmten Berufsfeld nicht vertreten ist, und jede Dienstleistung oder Funktion, die dies weiter fördert, trägt zu Schaden bei.
Azure RAI-Dashboard
Das Azure RAI-Dashboard basiert auf Open-Source-Tools, die von führenden akademischen Institutionen und Organisationen, einschließlich Microsoft, entwickelt wurden. Diese Tools sind für Datenwissenschaftler und KI-Entwickler von entscheidender Bedeutung, um das Verhalten von Modellen besser zu verstehen, unerwünschte Probleme in KI-Modellen zu erkennen und zu beheben.
-
Erfahren Sie, wie Sie die verschiedenen Komponenten nutzen können, indem Sie die Dokumentation zum RAI-Dashboard lesen.
-
Schauen Sie sich einige Beispiel-Notebooks des RAI-Dashboards an, um verantwortungsvollere KI-Szenarien in Azure Machine Learning zu debuggen.
🚀 Herausforderung
Um statistische oder datenbezogene Verzerrungen von Anfang an zu vermeiden, sollten wir:
- eine Vielfalt an Hintergründen und Perspektiven unter den Personen haben, die an den Systemen arbeiten
- in Datensätze investieren, die die Vielfalt unserer Gesellschaft widerspiegeln
- bessere Methoden entwickeln, um Verzerrungen zu erkennen und zu korrigieren, wenn sie auftreten
Denken Sie über reale Szenarien nach, in denen Unfairness beim Erstellen und Verwenden von Modellen offensichtlich ist. Was sollten wir noch berücksichtigen?
Quiz nach der Vorlesung
Rückblick & Selbststudium
In dieser Lektion haben Sie einige praktische Werkzeuge kennengelernt, um verantwortungsvolle KI in maschinelles Lernen zu integrieren.
Sehen Sie sich diesen Workshop an, um tiefer in die Themen einzutauchen:
- Responsible AI Dashboard: Eine zentrale Anlaufstelle für die Operationalisierung von RAI in der Praxis von Besmira Nushi und Mehrnoosh Sameki
> 🎥 Klicken Sie auf das Bild oben, um das Video anzusehen: Responsible AI Dashboard: Eine zentrale Anlaufstelle für die Operationalisierung von RAI in der Praxis von Besmira Nushi und Mehrnoosh Sameki
Nutzen Sie die folgenden Materialien, um mehr über verantwortungsvolle KI zu erfahren und vertrauenswürdigere Modelle zu entwickeln:
-
Microsofts RAI-Dashboard-Tools zur Fehlerbehebung bei ML-Modellen: Ressourcen für Responsible AI-Tools
-
Erkunden Sie das Responsible AI Toolkit: Github
-
Microsofts RAI-Ressourcenzentrum: Responsible AI Resources – Microsoft AI
-
Microsofts FATE-Forschungsgruppe: FATE: Fairness, Accountability, Transparency, and Ethics in AI - Microsoft Research
Aufgabe
Erkunden Sie das RAI-Dashboard
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Nachwort: Anwendungen klassischer maschineller Lernverfahren in der realen Welt
In diesem Abschnitt des Lehrplans werden Sie mit einigen realen Anwendungen des klassischen maschinellen Lernens vertraut gemacht. Wir haben das Internet durchforstet, um Whitepapers und Artikel über Anwendungen zu finden, die diese Strategien genutzt haben, und dabei neuralen Netzwerken, Deep Learning und KI so weit wie möglich vermieden. Erfahren Sie, wie maschinelles Lernen in Geschäftssystemen, ökologischen Anwendungen, Finanzen, Kunst und Kultur und mehr eingesetzt wird.

> Foto von <a href="https://unsplash.com/@childeye?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Alexis Fauvet</a> auf <a href="https://unsplash.com/s/photos/artificial-intelligence?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
Lektion
- Anwendungen des maschinellen Lernens in der realen Welt
- Modell-Debugging im maschinellen Lernen mit Komponenten des Responsible AI Dashboards
Credits
"Anwendungen des maschinellen Lernens in der realen Welt" wurde von einem Team geschrieben, darunter Jen Looper und Ornella Altunyan.
"Modell-Debugging im maschinellen Lernen mit Komponenten des Responsible AI Dashboards" wurde von Ruth Yakubu verfasst.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
AGENTS.md
Projektübersicht
Dies ist Maschinelles Lernen für Anfänger, ein umfassender 12-wöchiger Lehrplan mit 26 Lektionen, der klassische Konzepte des maschinellen Lernens mit Python (hauptsächlich mit Scikit-learn) und R behandelt. Das Repository ist als selbstgesteuertes Lernressource mit praktischen Projekten, Quizfragen und Aufgaben konzipiert. Jede Lektion untersucht ML-Konzepte anhand von realen Daten aus verschiedenen Kulturen und Regionen weltweit.
Wichtige Bestandteile: - Bildungsinhalte: 26 Lektionen zu Einführung in ML, Regression, Klassifikation, Clustering, NLP, Zeitreihen und Verstärkungslernen - Quiz-Anwendung: Quiz-App auf Basis von Vue.js mit Vor- und Nach-Lektionsbewertungen - Mehrsprachige Unterstützung: Automatische Übersetzungen in über 40 Sprachen via GitHub Actions - Duale Sprachunterstützung: Lektionen verfügbar in Python (Jupyter-Notebooks) und R (R Markdown-Dateien) - Projektbasiertes Lernen: Jedes Thema enthält praktische Projekte und Aufgaben
Repository-Struktur
ML-For-Beginners/
├── 1-Introduction/ # ML basics, history, fairness, techniques
├── 2-Regression/ # Regression models with Python/R
├── 3-Web-App/ # Flask web app for ML model deployment
├── 4-Classification/ # Classification algorithms
├── 5-Clustering/ # Clustering techniques
├── 6-NLP/ # Natural Language Processing
├── 7-TimeSeries/ # Time series forecasting
├── 8-Reinforcement/ # Reinforcement learning
├── 9-Real-World/ # Real-world ML applications
├── quiz-app/ # Vue.js quiz application
├── translations/ # Auto-generated translations
└── sketchnotes/ # Visual learning aids
Jeder Lektionen-Ordner enthält typischerweise:
- README.md - Hauptinhalt der Lektion
- notebook.ipynb - Python Jupyter-Notebook
- solution/ - Lösungscode (Python- und R-Versionen)
- assignment.md - Übungsaufgaben
- images/ - Visuelle Ressourcen
Setup-Befehle
Für Python-Lektionen
Die meisten Lektionen verwenden Jupyter-Notebooks. Installieren Sie die erforderlichen Abhängigkeiten:
# Install Python 3.8+ if not already installed
python --version
# Install Jupyter
pip install jupyter
# Install common ML libraries
pip install scikit-learn pandas numpy matplotlib seaborn
# For specific lessons, check lesson-specific requirements
# Example: Web App lesson
pip install flask
Für R-Lektionen
R-Lektionen befinden sich in den solution/R/-Ordnern als .rmd- oder .ipynb-Dateien:
# Install R and required packages
# In R console:
install.packages(c("tidyverse", "tidymodels", "caret"))
Für die Quiz-Anwendung
Die Quiz-App ist eine Vue.js-Anwendung im Verzeichnis quiz-app/:
cd quiz-app
npm install
Für die Dokumentationsseite
Um die Dokumentation lokal auszuführen:
# Install Docsify
npm install -g docsify-cli
# Serve from repository root
docsify serve
# Access at http://localhost:3000
Entwicklungsworkflow
Arbeiten mit Lektionen-Notebooks
- Navigieren Sie zum Lektionen-Verzeichnis (z. B.
2-Regression/1-Tools/) - Öffnen Sie das Jupyter-Notebook:
bash jupyter notebook notebook.ipynb - Arbeiten Sie die Lektioneninhalte und Übungen durch
- Überprüfen Sie die Lösungen im
solution/-Ordner bei Bedarf
Python-Entwicklung
- Lektionen verwenden Standard-Bibliotheken für Datenwissenschaft in Python
- Jupyter-Notebooks für interaktives Lernen
- Lösungscode ist in jedem Lektionen-Ordner im
solution/-Ordner verfügbar
R-Entwicklung
- R-Lektionen sind im
.rmd-Format (R Markdown) - Lösungen befinden sich in den
solution/R/-Unterverzeichnissen - Verwenden Sie RStudio oder Jupyter mit R-Kernel, um R-Notebooks auszuführen
Entwicklung der Quiz-Anwendung
cd quiz-app
# Start development server
npm run serve
# Access at http://localhost:8080
# Build for production
npm run build
# Lint and fix files
npm run lint
Testanweisungen
Testen der Quiz-Anwendung
cd quiz-app
# Lint code
npm run lint
# Build to verify no errors
npm run build
Hinweis: Dies ist hauptsächlich ein Bildungs-Repository. Es gibt keine automatisierten Tests für die Lektioneninhalte. Die Validierung erfolgt durch: - Abschluss der Lektionenübungen - Erfolgreiches Ausführen der Notebook-Zellen - Überprüfung der Ausgabe mit den erwarteten Ergebnissen in den Lösungen
Richtlinien für Code-Stil
Python-Code
- Befolgen Sie die PEP 8-Stilrichtlinien
- Verwenden Sie klare, beschreibende Variablennamen
- Fügen Sie Kommentare für komplexe Operationen hinzu
- Jupyter-Notebooks sollten Markdown-Zellen enthalten, die Konzepte erklären
JavaScript/Vue.js (Quiz-App)
- Befolgt die Vue.js-Stilrichtlinien
- ESLint-Konfiguration in
quiz-app/package.json - Führen Sie
npm run lintaus, um Probleme zu überprüfen und automatisch zu beheben
Dokumentation
- Markdown-Dateien sollten klar und gut strukturiert sein
- Codebeispiele in umschlossenen Codeblöcken einfügen
- Relative Links für interne Verweise verwenden
- Bestehende Formatierungskonventionen befolgen
Build und Deployment
Deployment der Quiz-Anwendung
Die Quiz-App kann auf Azure Static Web Apps bereitgestellt werden:
-
Voraussetzungen: - Azure-Konto - GitHub-Repository (bereits geforkt)
-
Bereitstellung auf Azure: - Erstellen Sie eine Azure Static Web App-Ressource - Verbinden Sie das GitHub-Repository - Legen Sie den App-Standort fest:
/quiz-app- Legen Sie den Ausgabeort fest:dist- Azure erstellt automatisch einen GitHub Actions-Workflow -
GitHub Actions-Workflow: - Workflow-Datei wird unter
.github/workflows/azure-static-web-apps-*.ymlerstellt - Automatischer Build und Deployment bei Push auf den Hauptbranch
Dokumentation als PDF
Generieren Sie ein PDF aus der Dokumentation:
npm install
npm run convert
Übersetzungsworkflow
Wichtig: Übersetzungen werden automatisiert über GitHub Actions mit Co-op Translator durchgeführt.
- Übersetzungen werden automatisch generiert, wenn Änderungen in den
main-Branch gepusht werden - NICHT manuell Inhalte übersetzen - das System übernimmt dies
- Workflow definiert in
.github/workflows/co-op-translator.yml - Verwendet Azure AI/OpenAI-Dienste für Übersetzungen
- Unterstützt über 40 Sprachen
Richtlinien für Beiträge
Für Inhaltsbeiträge
- Forken Sie das Repository und erstellen Sie einen Feature-Branch
- Ändern Sie die Lektioneninhalte, wenn Sie Lektionen hinzufügen/aktualisieren
- Ändern Sie keine übersetzten Dateien - diese werden automatisch generiert
- Testen Sie Ihren Code - stellen Sie sicher, dass alle Notebook-Zellen erfolgreich ausgeführt werden
- Überprüfen Sie Links und Bilder, ob sie korrekt funktionieren
- Reichen Sie eine Pull-Anfrage ein mit einer klaren Beschreibung
Richtlinien für Pull-Anfragen
- Titel-Format:
[Abschnitt] Kurze Beschreibung der Änderungen - Beispiel:
[Regression] Tippfehler in Lektion 5 korrigiert - Beispiel:
[Quiz-App] Abhängigkeiten aktualisiert - Vor dem Einreichen:
- Stellen Sie sicher, dass alle Notebook-Zellen fehlerfrei ausgeführt werden
- Führen Sie
npm run lintaus, wenn Sie die Quiz-App ändern - Überprüfen Sie die Markdown-Formatierung
- Testen Sie alle neuen Codebeispiele
- PR muss enthalten:
- Beschreibung der Änderungen
- Grund für die Änderungen
- Screenshots bei UI-Änderungen
- Verhaltenskodex: Befolgen Sie den Microsoft Open Source Code of Conduct
- CLA: Sie müssen die Contributor License Agreement unterzeichnen
Lektionenstruktur
Jede Lektion folgt einem konsistenten Muster:
- Quiz vor der Vorlesung - Testen Sie das Basiswissen
- Lektioneninhalt - Schriftliche Anweisungen und Erklärungen
- Code-Demonstrationen - Praktische Beispiele in Notebooks
- Wissensüberprüfungen - Überprüfen Sie das Verständnis während der Lektion
- Herausforderung - Wenden Sie Konzepte eigenständig an
- Aufgabe - Erweiterte Übung
- Quiz nach der Vorlesung - Bewerten Sie die Lernergebnisse
Referenz für häufige Befehle
# Python/Jupyter
jupyter notebook # Start Jupyter server
jupyter notebook notebook.ipynb # Open specific notebook
pip install -r requirements.txt # Install dependencies (where available)
# Quiz App
cd quiz-app
npm install # Install dependencies
npm run serve # Development server
npm run build # Production build
npm run lint # Lint and fix
# Documentation
docsify serve # Serve documentation locally
npm run convert # Generate PDF
# Git workflow
git checkout -b feature/my-change # Create feature branch
git add . # Stage changes
git commit -m "Description" # Commit changes
git push origin feature/my-change # Push to remote
Zusätzliche Ressourcen
- Microsoft Learn Collection: ML für Anfänger-Module
- Quiz-App: Online-Quiz
- Diskussionsforum: GitHub Discussions
- Videoanleitungen: YouTube-Playlist
Schlüsseltechnologien
- Python: Hauptsprache für ML-Lektionen (Scikit-learn, Pandas, NumPy, Matplotlib)
- R: Alternative Implementierung mit tidyverse, tidymodels, caret
- Jupyter: Interaktive Notebooks für Python-Lektionen
- R Markdown: Dokumente für R-Lektionen
- Vue.js 3: Framework für die Quiz-Anwendung
- Flask: Webanwendungs-Framework für ML-Modellbereitstellung
- Docsify: Generator für Dokumentationsseiten
- GitHub Actions: CI/CD und automatisierte Übersetzungen
Sicherheitsüberlegungen
- Keine Geheimnisse im Code: Niemals API-Schlüssel oder Zugangsdaten einfügen
- Abhängigkeiten: Halten Sie npm- und pip-Pakete aktuell
- Benutzereingaben: Flask-Web-App-Beispiele enthalten grundlegende Eingabevalidierung
- Sensible Daten: Beispieldatensätze sind öffentlich und nicht sensibel
Fehlerbehebung
Jupyter-Notebooks
- Kernel-Probleme: Starten Sie den Kernel neu, wenn Zellen hängen: Kernel → Neustart
- Importfehler: Stellen Sie sicher, dass alle erforderlichen Pakete mit pip installiert sind
- Pfadprobleme: Führen Sie Notebooks aus ihrem enthaltenen Verzeichnis aus
Quiz-Anwendung
- npm install schlägt fehl: Löschen Sie den npm-Cache:
npm cache clean --force - Portkonflikte: Ändern Sie den Port mit:
npm run serve -- --port 8081 - Build-Fehler: Löschen Sie
node_modulesund installieren Sie neu:rm -rf node_modules && npm install
R-Lektionen
- Paket nicht gefunden: Installieren Sie es mit:
install.packages("package-name") - RMarkdown-Rendering: Stellen Sie sicher, dass das rmarkdown-Paket installiert ist
- Kernel-Probleme: Möglicherweise müssen Sie IRkernel für Jupyter installieren
Projektspezifische Hinweise
- Dies ist hauptsächlich ein Lernlehrplan, kein Produktionscode
- Der Fokus liegt auf dem Verständnis von ML-Konzepten durch praktische Übungen
- Codebeispiele priorisieren Klarheit vor Optimierung
- Die meisten Lektionen sind eigenständig und können unabhängig abgeschlossen werden
- Lösungen sind verfügbar, aber Lernende sollten zuerst die Übungen versuchen
- Das Repository verwendet Docsify für die Web-Dokumentation ohne Build-Schritt
- Sketchnotes bieten visuelle Zusammenfassungen von Konzepten
- Mehrsprachige Unterstützung macht Inhalte weltweit zugänglich
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Microsoft Open Source Verhaltenskodex
Dieses Projekt hat den Microsoft Open Source Verhaltenskodex übernommen.
Ressourcen:
- Microsoft Open Source Verhaltenskodex
- Microsoft Verhaltenskodex FAQ
- Kontaktieren Sie opencode@microsoft.com bei Fragen oder Anliegen
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Mitwirken
Dieses Projekt begrüßt Beiträge und Vorschläge. Die meisten Beiträge erfordern, dass Sie einer Contributor License Agreement (CLA) zustimmen, die erklärt, dass Sie das Recht haben und tatsächlich gewähren, uns die Rechte zur Nutzung Ihres Beitrags zu übertragen. Einzelheiten finden Sie unter https://cla.microsoft.com.
> Wichtig: Wenn Sie Texte in diesem Repository übersetzen, stellen Sie bitte sicher, dass Sie keine maschinelle Übersetzung verwenden. Wir werden die Übersetzungen durch die Community überprüfen, daher sollten Sie nur Übersetzungen in Sprachen anbieten, in denen Sie versiert sind.
Wenn Sie einen Pull-Request einreichen, wird ein CLA-Bot automatisch feststellen, ob Sie eine CLA bereitstellen müssen, und den PR entsprechend kennzeichnen (z. B. Label, Kommentar). Folgen Sie einfach den Anweisungen des Bots. Dies müssen Sie nur einmal für alle Repositories tun, die unsere CLA verwenden.
Dieses Projekt hat den Microsoft Open Source Code of Conduct übernommen. Weitere Informationen finden Sie in den Code of Conduct FAQ oder kontaktieren Sie opencode@microsoft.com bei zusätzlichen Fragen oder Kommentaren.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
- Einführung
- Einführung in Machine Learning
- Geschichte des Machine Learning
- ML und Fairness
-
Regression
- Werkzeuge des Fachs
- Daten
- Lineare Regression
-
Eine Web-App erstellen
-
Klassifikation
- Einführung in Klassifikation
- Klassifikatoren 1
- Klassifikatoren 2
-
Clustering
- Daten visualisieren
-
NLP
- Einführung in NLP
- NLP-Aufgaben
- Übersetzung und Sentimentanalyse
- Hotelbewertungen 1
-
Zeitreihenprognose
- Einführung in Zeitreihenprognose
- ARIMA
-
Reinforcement Learning
- Q-Learning
-
ML in der realen Welt
- Anwendungen
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Für Lehrkräfte
Möchten Sie dieses Curriculum in Ihrem Unterricht verwenden? Fühlen Sie sich frei, es zu nutzen!
Tatsächlich können Sie es direkt auf GitHub verwenden, indem Sie GitHub Classroom nutzen.
Dazu müssen Sie dieses Repository forken. Sie müssen für jede Lektion ein eigenes Repository erstellen, indem Sie jeden Ordner in ein separates Repository extrahieren. Auf diese Weise kann GitHub Classroom jede Lektion einzeln erfassen.
Diese vollständigen Anweisungen geben Ihnen eine Vorstellung davon, wie Sie Ihr Klassenzimmer einrichten können.
Nutzung des Repositories im aktuellen Zustand
Wenn Sie dieses Repository so verwenden möchten, wie es derzeit ist, ohne GitHub Classroom zu nutzen, ist das ebenfalls möglich. Sie müssten Ihren Schülern mitteilen, welche Lektion sie gemeinsam durcharbeiten sollen.
In einem Online-Format (Zoom, Teams oder andere) könnten Sie Breakout-Räume für die Quizfragen einrichten und die Schüler unterstützen, damit sie bereit sind zu lernen. Anschließend können Sie die Schüler einladen, die Quizfragen zu bearbeiten und ihre Antworten zu einem bestimmten Zeitpunkt als "Issues" einzureichen. Dasselbe könnten Sie mit Aufgaben machen, wenn Sie möchten, dass die Schüler offen und kollaborativ arbeiten.
Wenn Sie ein privateres Format bevorzugen, bitten Sie Ihre Schüler, das Curriculum Lektion für Lektion in ihre eigenen privaten GitHub-Repositories zu forken und Ihnen Zugriff zu gewähren. Dann können sie Quizfragen und Aufgaben privat bearbeiten und diese über Issues in Ihrem Klassen-Repository einreichen.
Es gibt viele Möglichkeiten, dies in einem Online-Klassenzimmer-Format umzusetzen. Lassen Sie uns wissen, was für Sie am besten funktioniert!
Bitte teilen Sie uns Ihre Meinung mit!
Wir möchten dieses Curriculum für Sie und Ihre Schüler optimal gestalten. Bitte geben Sie uns Feedback.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
import torch
torch.__version__
print("I am excited to run this")
import torch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
print(torch.__version__)
# scalar
scalar = torch.tensor(7)
scalar
scalar.ndim
scalar.item()
# vector
vector = torch.tensor([7, 7])
vector
#vector.ndim
#vector.item()
vector.shape
# Matrix
MATRIX = torch.tensor([[7, 8],[9, 10]])
MATRIX
MATRIX.ndim
MATRIX[0]
MATRIX[1]
# Tensor
TENSOR = torch.tensor([[[1, 2, 3],[3,6,9], [2,4,5]]])
TENSOR
TENSOR.shape
TENSOR.ndim
TENSOR[0]
random_tensor = torch.rand(3,4)
random_tensor
random_tensor.ndim
random_tensor.shape
random_tensor.size()
random_image_tensor = torch.rand(size=(3, 224, 224)) #color channels, height, width
random_image_tensor.ndim, random_image_tensor.shape
random_tensor_ofownsize = torch.rand(size=(5,10,10))
random_tensor_ofownsize.ndim, random_tensor_ofownsize.shape
zero = torch.zeros(size=(3, 4))
zero
zero*random_tensor
ones = torch.ones(size=(3, 4))
ones
ones.dtype
ones*zero
one_to_ten = torch.arange(start = 1, end = 11, step = 1)
one_to_ten
ten_zeros = torch.zeros_like(one_to_ten)
ten_zeros
Tensor-Datentypen
float_32_tensor = torch.tensor([3.0, 6.0,9.0], dtype = None, device = None, requires_grad = False)
float_32_tensor
float_32_tensor.dtype
float_16_tensor = float_32_tensor.type(torch.float16)
float_16_tensor.dtype
float_16_tensor*float_32_tensor
int_32_tensor = torch.tensor([3, 6, 9], dtype = torch.int32)
int_32_tensor
int_32_tensor*float_32_tensor
x = torch.arange(0,100,10)
x
x.min()
x.max()
torch.mean(x.type(torch.float32))
x.type(torch.float32).mean()
x.sum()
x.argmax()
x.argmin()
x[0]
x[9]
x = torch.arange(1, 10)
x.shape
x_reshaped = x.reshape(1,9)
x_reshaped, x_reshaped.shape
x_reshaped.view(1,9)
x_stacked = torch.stack([x, x, x, x], dim = 1)
x_stacked
x_stacked.squeeze()
x_stacked.unsqueeze(dim=1)
x_stacked.squeeze()
x_stacked.unsqueeze(dim=-2)
import torch
tensor = torch.tensor([1, 2, 3])
tensor = tensor - 10
tensor
torch.mul(tensor, 10)
torch.sub(tensor, 100)
torch.add(tensor, 100)
torch.divide(tensor, 2)
torch.matmul(tensor, tensor)
tensor@tensor
%%time
tensor@tensor
%%time
torch.matmul(tensor,tensor)
torch.rand(3,2)
torch.matmul(torch.rand(3,2), torch.rand(2,3))
import torch
x = torch.rand(2,9)
x
y=torch.randn(2,3,5)
y
x_original = torch.rand(size=(224,224,3))
x_original
x_permuted=x_original.permute(2, 0, 1)
print(x_original.shape)
print(x_permuted.shape)
x_original[0,0,0]
x_permuted[0,0,0]
x_original[0,0,0]=0.989
x_original[0,0,0]
x_permuted[0,0,0]
x=torch.arange(1,10).reshape(1,3,3)
x, x.shape
x[0]
x[0][0]
x[0][0][0]
x[0][2][2]
x[:,1,1]
x[0,0,:]
x[0,:,2]
import numpy as np
array = np.arange(1.0, 8.0)
array
tensor = torch.from_numpy(array)
tensor
array[3]=11.0
array
tensor
tensor = torch.ones(7)
tensor, tensor.dtype
numpy_tensor = tensor.numpy()
numpy_tensor, numpy_tensor.dtype
import torch
random_tensor_A = torch.rand(3,4)
random_tensor_B = torch.rand(3,4)
print(random_tensor_A)
print(random_tensor_B)
print(random_tensor_A == random_tensor_B)
RANDOM_SEED = 42
torch.manual_seed(RANDOM_SEED)
random_tensor_C = torch.rand(3,4)
torch.manual_seed(RANDOM_SEED)
random_tensor_D = torch.rand(3,4)
print(random_tensor_C)
print(random_tensor_D)
print(random_tensor_C == random_tensor_D)
!nvidia-smi
import torch
torch.cuda.is_available()
device = "cuda" if torch.cuda.is_available() else "cpu"
device
torch.cuda.device_count()
tensor = torch.tensor([1,2,3], device = "cpu")
print(tensor, tensor.device)
tensor_on_gpu = tensor.to(device)
tensor_on_gpu
tensor_on_gpu.numpy()
tensor_on_cpu = tensor_on_gpu.cpu().numpy()
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Quizfragen
Diese Quizfragen sind die Vor- und Nachbereitungsquiz für das ML-Curriculum unter https://aka.ms/ml-beginners
Projektsetup
npm install
Kompiliert und lädt für die Entwicklung neu
npm run serve
Kompiliert und minimiert für die Produktion
npm run build
Überprüft und behebt Dateien
npm run lint
Konfiguration anpassen
Siehe Konfigurationsreferenz.
Credits: Dank an die ursprüngliche Version dieser Quiz-App: https://github.com/arpan45/simple-quiz-vue
Deployment auf Azure
Hier ist eine Schritt-für-Schritt-Anleitung, um Ihnen den Einstieg zu erleichtern:
-
Forken Sie ein GitHub-Repository
Stellen Sie sicher, dass der Code Ihrer statischen Web-App in Ihrem GitHub-Repository liegt. Forken Sie dieses Repository. -
Erstellen Sie eine Azure Static Web App
- Erstellen Sie ein Azure-Konto
- Gehen Sie zum Azure-Portal
- Klicken Sie auf „Create a resource“ und suchen Sie nach „Static Web App“.
- Klicken Sie auf „Create“. -
Konfigurieren Sie die Static Web App
- Grundlagen:
- Abonnement: Wählen Sie Ihr Azure-Abonnement aus.
- Ressourcengruppe: Erstellen Sie eine neue Ressourcengruppe oder verwenden Sie eine bestehende.
- Name: Geben Sie Ihrer statischen Web-App einen Namen.
- Region: Wählen Sie die Region, die Ihren Nutzern am nächsten liegt.
-
Deployment-Details:
- Quelle: Wählen Sie „GitHub“.
- GitHub-Konto: Autorisieren Sie Azure, auf Ihr GitHub-Konto zuzugreifen.
- Organisation: Wählen Sie Ihre GitHub-Organisation aus.
- Repository: Wählen Sie das Repository, das Ihre statische Web-App enthält.
-
Branch: Wählen Sie den Branch, von dem Sie deployen möchten.
-
Build-Details:
- Build-Voreinstellungen: Wählen Sie das Framework, mit dem Ihre App erstellt wurde (z. B. React, Angular, Vue usw.).
- App-Standort: Geben Sie den Ordner an, der Ihren App-Code enthält (z. B. /, wenn er sich im Root befindet).
- API-Standort: Falls Sie eine API haben, geben Sie deren Standort an (optional).
- Output-Standort: Geben Sie den Ordner an, in dem die Build-Ausgabe generiert wird (z. B. build oder dist).
-
Überprüfen und Erstellen
Überprüfen Sie Ihre Einstellungen und klicken Sie auf „Create“. Azure wird die notwendigen Ressourcen einrichten und einen GitHub Actions-Workflow in Ihrem Repository erstellen. -
GitHub Actions Workflow
Azure erstellt automatisch eine GitHub Actions-Workflow-Datei in Ihrem Repository (.github/workflows/azure-static-web-apps-<name>.yml). Dieser Workflow übernimmt den Build- und Deployment-Prozess. -
Überwachen Sie das Deployment
Gehen Sie zum Tab „Actions“ in Ihrem GitHub-Repository.
Sie sollten einen laufenden Workflow sehen. Dieser Workflow wird Ihre statische Web-App auf Azure erstellen und deployen.
Sobald der Workflow abgeschlossen ist, ist Ihre App unter der bereitgestellten Azure-URL live.
Beispiel-Workflow-Datei
Hier ist ein Beispiel, wie die GitHub Actions-Workflow-Datei aussehen könnte:
name: Azure Static Web Apps CI/CD
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- main
jobs:
build_and_deploy_job:
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v2
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
action: "upload"
app_location: "/quiz-app" # App source code path
api_location: ""API source code path optional
output_location: "dist" #Built app content directory - optional
Zusätzliche Ressourcen
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
🌐 Mehrsprachige Unterstützung
Unterstützt durch GitHub Action (Automatisiert & immer aktuell)
<!-- CO-OP TRANSLATOR LANGUAGES TABLE START --> Arabisch | Bengalisch | Bulgarisch | Birmanisch (Myanmar) | Chinesisch (Vereinfacht) | Chinesisch (Traditionell, Hongkong) | Chinesisch (Traditionell, Macau) | Chinesisch (Traditionell, Taiwan) | Kroatisch | Tschechisch | Dänisch | Niederländisch | Estnisch | Finnisch | Französisch | Deutsch | Griechisch | Hebräisch | Hindi | Ungarisch | Indonesisch | Italienisch | Japanisch | Kannada | Khmer | Koreanisch | Litauisch | Malaiisch | Malayalam | Marathi | Nepalesisch | Nigerianisches Pidgin | Norwegisch | Persisch (Farsi) | Polnisch | Portugiesisch (Brasilien) | Portugiesisch (Portugal) | Punjabi (Gurmukhi) | Rumänisch | Russisch | Serbisch (Kyrillisch) | Slowakisch | Slowenisch | Spanisch | Swahili | Schwedisch | Tagalog (Filipino) | Tamil | Telugu | Thailändisch | Türkisch | Ukrainisch | Urdu | Vietnamesisch
> Möchten Sie lieber lokal klonen?
>
> Dieses Repository enthält über 50 Sprachübersetzungen, was die Downloadgröße erheblich erhöht. Für das Klonen ohne Übersetzungen verwenden Sie Sparse Checkout:
>
> Bash / macOS / Linux:
> bash
> git clone --filter=blob:none --sparse https://github.com/microsoft/ML-For-Beginners.git
> cd ML-For-Beginners
> git sparse-checkout set --no-cone '/*' '!translations' '!translated_images'
>
>
> CMD (Windows):
> cmd
> git clone --filter=blob:none --sparse https://github.com/microsoft/ML-For-Beginners.git
> cd ML-For-Beginners
> git sparse-checkout set --no-cone "/*" "!translations" "!translated_images"
>
>
> Damit erhalten Sie alles, was Sie brauchen, um den Kurs zu absolvieren, mit einem viel schnelleren Download.
<!-- CO-OP TRANSLATOR LANGUAGES TABLE END -->
Treten Sie unserer Community bei
Wir haben eine Discord-Lernreihe mit KI am Laufen, erfahren Sie mehr und machen Sie mit bei Learn with AI Series vom 18. bis 30. September 2025. Sie erhalten Tipps und Tricks zur Verwendung von GitHub Copilot für Data Science.

Maschinelles Lernen für Anfänger – Ein Lehrplan
> 🌍 Reisen Sie um die Welt, während wir Maschinelles Lernen durch Weltkulturen erkunden 🌍
Cloud Advocates bei Microsoft freuen sich, einen 12-wöchigen Lehrplan mit 26 Lektionen rund um Maschinelles Lernen anzubieten. In diesem Lehrplan lernen Sie, was manchmal als klassisches maschinelles Lernen bezeichnet wird, wobei hauptsächlich Scikit-learn als Bibliothek verwendet wird und tiefes Lernen vermieden wird, das in unserem AI for Beginners-Lehrplan behandelt wird. Kombinieren Sie diese Lektionen auch mit unserem 'Data Science for Beginners'-Lehrplan.
Reisen Sie mit uns um die Welt, während wir diese klassischen Techniken auf Daten aus verschiedenen Regionen der Welt anwenden. Jede Lektion enthält Vor- und Nach-Lektion Quizze, schriftliche Anleitungen zum Abschließen der Lektion, eine Lösung, eine Aufgabe und mehr. Unsere projektbasierte Pädagogik ermöglicht es Ihnen, durch praktische Anwendung zu lernen – eine bewährte Methode, um neue Fähigkeiten nachhaltig zu verankern.
✍️ Herzlicher Dank an unsere Autoren Jen Looper, Stephen Howell, Francesca Lazzeri, Tomomi Imura, Cassie Breviu, Dmitry Soshnikov, Chris Noring, Anirban Mukherjee, Ornella Altunyan, Ruth Yakubu und Amy Boyd
🎨 Ebenso Dank an unsere Illustratoren Tomomi Imura, Dasani Madipalli und Jen Looper
🙏 Besonderer Dank 🙏 an unsere Microsoft Student Ambassador Autoren, Gutachter und Inhaltsbeiträger, insbesondere Rishit Dagli, Muhammad Sakib Khan Inan, Rohan Raj, Alexandru Petrescu, Abhishek Jaiswal, Nawrin Tabassum, Ioan Samuila und Snigdha Agarwal
🤩 Extra Dank an die Microsoft Student Ambassadors Eric Wanjau, Jasleen Sondhi und Vidushi Gupta für unsere R-Lektionen!
Erste Schritte
Befolgen Sie diese Schritte:
1. Forken Sie das Repository: Klicken Sie auf die Schaltfläche „Fork“ oben rechts auf dieser Seite.
2. Klonen Sie das Repository: git clone https://github.com/microsoft/ML-For-Beginners.git
> Finden Sie alle zusätzlichen Ressourcen für diesen Kurs in unserer Microsoft Learn Sammlung
> 🔧 Brauchen Sie Hilfe? Schauen Sie in unseren Fehlerbehebungsleitfaden für Lösungen zu häufigen Problemen bei Installation, Einrichtung und Ausführung der Lektionen.
Schüler, um diesen Lehrplan zu nutzen, forken Sie das gesamte Repo in Ihr eigenes GitHub-Konto und bearbeiten Sie die Übungen eigenständig oder in einer Gruppe:
- Beginnen Sie mit einem Quiz vor der Vorlesung.
- Lesen Sie die Vorlesung und bearbeiten Sie die Aktivitäten, pausieren Sie und reflektieren Sie bei jedem Wissenscheck.
- Versuchen Sie, die Projekte zu erstellen, indem Sie die Lektionen verstehen, anstatt nur den Lösungscode auszuführen; der Code ist jedoch in den
/solution-Ordnern jeder projektorientierten Lektion verfügbar. - Machen Sie das Quiz nach der Vorlesung.
- Lösen Sie die Herausforderung.
- Bearbeiten Sie die Aufgabe.
- Nach Abschluss einer Lektionengruppe besuchen Sie das Diskussionsforum und „lernen Sie laut“, indem Sie das passende PAT-Rubrikformular ausfüllen. Ein 'PAT' ist ein Fortschrittsbewertungstool, bei dem Sie eine Rubrik ausfüllen, um Ihr Lernen zu vertiefen. Sie können auch auf andere PATs reagieren, um gemeinsam zu lernen.
> Für weiterführendes Studium empfehlen wir das Durcharbeiten dieser Microsoft Learn Module und Lernpfade.
Lehrkräfte, wir haben einige Vorschläge zur Nutzung dieses Lehrplans zusammengestellt.
Videoanleitungen
Einige der Lektionen sind als Kurzvideos verfügbar. Sie finden alle diese direkt in den Lektionen oder in der ML for Beginners Playlist auf dem Microsoft Developer YouTube-Kanal über Klick auf das Bild unten.
Das Team kennenlernen
Gif von Mohit Jaisal
> 🎥 Klicken Sie auf das Bild oben für ein Video über das Projekt und die Personen, die es erstellt haben!
Pädagogik
Wir haben beim Aufbau dieses Lehrplans zwei pädagogische Grundsätze gewählt: sicherzustellen, dass er praktisch projektbasiert ist und dass er häufige Quizze enthält. Zudem hat dieser Lehrplan ein gemeinsames Thema, das ihm Kohärenz verleiht.
Indem die Inhalte auf Projekte abgestimmt sind, wird der Prozess für die Lernenden ansprechender und das Behalten von Konzepten wird verbessert. Zudem setzt ein Quiz vor der Unterrichtseinheit die Lernabsicht, während ein zweites Quiz danach das Behalten weiter fördert. Dieser Lehrplan wurde so gestaltet, dass er flexibel und unterhaltsam ist und ganz oder teilweise absolviert werden kann. Die Projekte starten klein und werden bis zum Ende des 12-Wochen-Zyklus immer komplexer. Der Lehrplan enthält auch einen Nachtrag zu realen Anwendungen von ML, der als Zusatzleistung oder Diskussionsgrundlage genutzt werden kann.
> Finden Sie unsere Richtlinien zu Verhaltenskodex, Mitwirkung, Übersetzungen und Fehlerbehebung. Wir freuen uns auf Ihr konstruktives Feedback!
Jede Lektion beinhaltet
- optionale Sketchnote
- optionales ergänzendes Video
- Videoanleitung (nur einige Lektionen)
- Pre-Lecture Warmup-Quiz
- schriftliche Lektion
- für projektbasierte Lektionen Schritt-für-Schritt-Anleitungen zum Bau des Projekts
- Wissenschecks
- eine Herausforderung
- ergänzende Lektüre
- Aufgabe
- Post-Lecture Quiz
> Eine Anmerkung zu den Sprachen: Diese Lektionen sind hauptsächlich in Python geschrieben, aber viele sind auch in R verfügbar. Um eine R-Lektion abzuschließen, gehen Sie zum Ordner
/solutionund suchen Sie dort nach R-Lektionen. Diese enthalten eine .rmd-Erweiterung, die eine R Markdown-Datei darstellt, welche einfach als Einbettung vonCodeabschnitten(von R oder anderen Sprachen) und einemYAML-Header(der steuert, wie Ausgaben wie PDF formatiert werden) in einemMarkdown-Dokumentdefiniert werden kann. Als solche dient sie als beispielhaftes Autorensystem für Data Science, da sie es ermöglicht, Ihren Code, dessen Ausgabe und Ihre Gedanken zu kombinieren, indem Sie diese in Markdown niederschreiben. Darüber hinaus können R Markdown-Dokumente in Ausgabedateiformate wie PDF, HTML oder Word gerendert werden.
> Eine Anmerkung zu Quizzen: Alle Quizze sind im Ordner Quiz App folder enthalten, insgesamt 52 Quizze mit jeweils drei Fragen. Sie sind innerhalb der Lektionen verlinkt, aber die Quiz-App kann lokal ausgeführt werden; folgen Sie der Anleitung im Ordner quiz-app, um sie lokal zu hosten oder auf Azure zu deployen.
| Lektion Nummer | Thema | Lektion Gruppierung | Lernziele | Verknüpfte Lektion | Autor |
|---|---|---|---|---|---|
| 01 | Einführung in maschinelles Lernen | Introduction | Lernen Sie die grundlegenden Konzepte hinter dem maschinellen Lernen | Lektion | Muhammad |
| 02 | Die Geschichte des maschinellen Lernens | Introduction | Lernen Sie die Geschichte dieses Fachgebiets | Lektion | Jen und Amy |
| 03 | Fairness und maschinelles Lernen | Introduction | Welche wichtigen philosophischen Fragen zur Fairness sollten Lernende bei der Erstellung und Anwendung von ML-Modellen beachten? | Lektion | Tomomi |
| 04 | Techniken für maschinelles Lernen | Introduction | Welche Techniken verwenden ML-Forscher zum Aufbau von ML-Modellen? | Lektion | Chris und Jen |
| 05 | Einführung in Regression | Regression | Einstieg in Python und Scikit-learn für Regressionsmodelle | Python • R | Jen • Eric Wanjau |
| 06 | Nordamerikanische Kürbispreise 🎃 | Regression | Daten visualisieren und bereinigen zur Vorbereitung für ML | Python • R | Jen • Eric Wanjau |
| 07 | Nordamerikanische Kürbispreise 🎃 | Regression | Erstellen Sie lineare und polynomiale Regressionsmodelle | Python • R | Jen und Dmitry • Eric Wanjau |
| 08 | Nordamerikanische Kürbispreise 🎃 | Regression | Erstellen Sie ein logistisches Regressionsmodell | Python • R | Jen • Eric Wanjau |
| 09 | Eine Web-App 🔌 | Web App | Erstellen Sie eine Webanwendung, um Ihr trainiertes Modell zu verwenden | Python | Jen |
| 10 | Einführung in Klassifikation | Classification | Bereinigen, vorbereiten und visualisieren Sie Ihre Daten; Einführung in die Klassifikation | Python • R | Jen und Cassie • Eric Wanjau |
| 11 | Köstliche asiatische und indische Küchen 🍜 | Classification | Einführung in Klassifikatoren | Python • R | Jen und Cassie • Eric Wanjau |
| 12 | Köstliche asiatische und indische Küchen 🍜 | Classification | Weitere Klassifikatoren | Python • R | Jen und Cassie • Eric Wanjau |
| 13 | Köstliche asiatische und indische Küchen 🍜 | Classification | Erstellen Sie eine Empfehlungs-Webanwendung unter Verwendung Ihres Modells | Python | Jen |
| 14 | Einführung in Clustering | Clustering | Bereinigen, vorbereiten und visualisieren Sie Ihre Daten; Einführung in Clustering | Python • R | Jen • Eric Wanjau |
| 15 | Erkunden der nigerianischen Musikkultur 🎧 | Clustering | Erkunden Sie die K-Means-Clustering-Methode | Python • R | Jen • Eric Wanjau |
| 16 | Einführung in natürliche Sprachverarbeitung ☕️ | Natural language processing | Lernen Sie die Grundlagen der NLP, indem Sie einen einfachen Bot erstellen | Python | Stephen |
| 17 | Häufige NLP-Aufgaben ☕️ | Natural language processing | Vertiefen Sie Ihr NLP-Wissen, indem Sie häufige Aufgaben verstehen, die bei der Arbeit mit Sprachstrukturen erforderlich sind | Python | Stephen |
| 18 | Übersetzung und Sentiment-Analyse ♥️ | Natural language processing | Übersetzung und Sentiment-Analyse mit Jane Austen | Python | Stephen |
| 19 | Romantische Hotels in Europa ♥️ | Natural language processing | Sentiment-Analyse mit Hotelbewertungen 1 | Python | Stephen |
| 20 | Romantische Hotels in Europa ♥️ | Natural language processing | Sentiment-Analyse mit Hotelbewertungen 2 | Python | Stephen |
| 21 | Einführung in Zeitreihen-Vorhersagen | Time series | Einführung in Zeitreihen-Vorhersagen | Python | Francesca |
| 22 | ⚡️ Weltstromverbrauch ⚡️ - Zeitreihenvorhersage mit ARIMA | Time series | Zeitreihenvorhersage mit ARIMA | Python | Francesca |
| 23 | ⚡️ Weltstromverbrauch ⚡️ - Zeitreihenvorhersage mit SVR | Time series | Zeitreihenvorhersage mit Support Vector Regressor | Python | Anirban |
| 24 | Einführung in Reinforcement Learning | Reinforcement learning | Einführung in Reinforcement Learning mit Q-Learning | Python | Dmitry |
| 25 | Hilf Peter, den Wolf zu vermeiden! 🐺 | Reinforcement learning | Reinforcement Learning Gym | Python | Dmitry |
| Nachwort | Echte ML-Szenarien und Anwendungen | ML in the Wild | Interessante und aufschlussreiche Anwendungen klassischer ML in der Praxis | Lektion | Team |
| Nachwort | Modell-Debugging in ML mit RAI-Dashboard | ML in the Wild | Modell-Debugging in Machine Learning mit Komponenten des Responsible AI-Dashboards | Lektion | Ruth Yakubu |
> finden Sie alle zusätzlichen Ressourcen zu diesem Kurs in unserer Microsoft Learn Sammlung
Offline-Zugriff
Sie können diese Dokumentation offline mit Docsify ausführen. Forken Sie dieses Repository, installieren Sie Docsify auf Ihrem lokalen Rechner und geben Sie dann im Stammverzeichnis dieses Repositories docsify serve ein. Die Website wird auf Port 3000 auf Ihrem lokalen Rechner unter localhost:3000 bereitgestellt.
PDFs
Finden Sie eine pdf des Curriculums mit Links hier.
🎒 Andere Kurse
Unser Team bietet weitere Kurse an! Schauen Sie sich an:
<!-- CO-OP TRANSLATOR OTHER COURSES START -->
LangChain
Azure / Edge / MCP / Agents
Generative KI-Serie
Grundlegendes Lernen
Copilot-Serie
<!-- CO-OP TRANSLATOR OTHER COURSES END -->
Hilfe erhalten
Wenn Sie beim Lernen von Machine Learning oder beim Erstellen von KI-Anwendungen nicht weiterkommen oder Fragen haben, keine Sorge – Hilfe ist verfügbar.
Sie können an Diskussionen mit anderen Lernenden und Entwicklern teilnehmen, Fragen stellen und Ihre Ideen mit der Community teilen.
- Treten Sie der Community bei, um Fragen zu stellen und gemeinsam zu lernen
- Diskutieren Sie Machine Learning-Konzepte und Projektideen
- Erhalten Sie Anleitung von erfahrenen Entwicklern
Eine unterstützende Gemeinschaft ist eine großartige Möglichkeit, Ihre Fähigkeiten zu erweitern und Probleme schneller zu lösen.
Microsoft Foundry Discord Community
Wenn Sie Fehler, Probleme oder Verbesserungsvorschläge haben, können Sie auch ein Issue in diesem Repository eröffnen, um das Problem zu melden.
Für Produktfeedback oder zur Suche nach bestehenden Community-Beiträgen besuchen Sie das Entwicklerforum:
Zusätzliche Lerntipps
- Überprüfen Sie nach jeder Lektion die Notebooks für ein besseres Verständnis.
- Üben Sie, Algorithmen selbständig zu implementieren.
- Erkunden Sie reale Datensätze mit den gelernten Konzepten.
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir um Genauigkeit bemüht sind, bitte beachten Sie, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das ursprüngliche Dokument in seiner Originalsprache ist als maßgebliche Quelle zu betrachten. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Verwendung dieser Übersetzung ergeben.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Sicherheit
Microsoft nimmt die Sicherheit seiner Softwareprodukte und -dienste ernst, einschließlich aller Quellcode-Repositories, die über unsere GitHub-Organisationen verwaltet werden, zu denen Microsoft, Azure, DotNet, AspNet, Xamarin und unsere GitHub-Organisationen gehören.
Wenn Sie glauben, eine Sicherheitslücke in einem von Microsoft verwalteten Repository gefunden zu haben, die Microsofts Definition einer Sicherheitslücke entspricht, melden Sie diese bitte wie unten beschrieben.
Melden von Sicherheitsproblemen
Bitte melden Sie Sicherheitslücken nicht über öffentliche GitHub-Issues.
Stattdessen melden Sie diese bitte dem Microsoft Security Response Center (MSRC) unter https://msrc.microsoft.com/create-report.
Falls Sie es vorziehen, ohne Anmeldung einzureichen, senden Sie eine E-Mail an secure@microsoft.com. Wenn möglich, verschlüsseln Sie Ihre Nachricht mit unserem PGP-Schlüssel; Sie können ihn von der Microsoft Security Response Center PGP Key-Seite herunterladen.
Sie sollten innerhalb von 24 Stunden eine Antwort erhalten. Falls dies aus irgendeinem Grund nicht geschieht, folgen Sie bitte per E-Mail nach, um sicherzustellen, dass wir Ihre ursprüngliche Nachricht erhalten haben. Weitere Informationen finden Sie unter microsoft.com/msrc.
Bitte fügen Sie die unten aufgeführten Informationen (so weit wie möglich) bei, um uns zu helfen, die Art und den Umfang des möglichen Problems besser zu verstehen:
- Art des Problems (z. B. Buffer Overflow, SQL Injection, Cross-Site Scripting usw.)
- Vollständige Pfade der Quelldatei(en), die mit dem Problem in Zusammenhang stehen
- Der Standort des betroffenen Quellcodes (Tag/Branch/Commit oder direkte URL)
- Jegliche spezielle Konfiguration, die erforderlich ist, um das Problem zu reproduzieren
- Schritt-für-Schritt-Anleitung zur Reproduktion des Problems
- Proof-of-Concept oder Exploit-Code (falls möglich)
- Auswirkungen des Problems, einschließlich der möglichen Ausnutzung durch einen Angreifer
Diese Informationen helfen uns, Ihren Bericht schneller zu bearbeiten.
Wenn Sie im Rahmen eines Bug-Bounty-Programms berichten, können vollständigere Berichte zu einer höheren Prämie führen. Besuchen Sie unsere Seite zum Microsoft Bug Bounty Program für weitere Details zu unseren aktiven Programmen.
Bevorzugte Sprachen
Wir bevorzugen alle Kommunikation in Englisch.
Richtlinie
Microsoft folgt dem Prinzip der Koordinierten Offenlegung von Sicherheitslücken.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Attribution-ShareAlike 4.0 International
=======================================================================
Creative Commons Corporation („Creative Commons“) ist keine Anwaltskanzlei und bietet keine juristischen Dienstleistungen oder Rechtsberatung an. Die Verbreitung von Creative-Commons-Lizenzen begründet keine Anwalt-Mandanten-Beziehung oder andere Beziehung. Creative Commons stellt seine Lizenzen und zugehörigen Informationen „wie sie sind“ zur Verfügung. Creative Commons gibt keine Garantien in Bezug auf seine Lizenzen, jegliches unter deren Bedingungen lizenziertes Material oder zugehörige Informationen. Creative Commons lehnt jegliche Haftung für Schäden, die aus ihrer Nutzung entstehen, im größtmöglichen gesetzlich zulässigen Umfang ab.
Verwendung von Creative-Commons-Lizenzen
Creative-Commons-Lizenzen bieten eine standardisierte Reihe von Bedingungen, die Urheber und andere Rechteinhaber nutzen können, um originale Werke und anderes urheberrechtlich geschütztes Material sowie bestimmte andere Rechte gemäß der unten stehenden Lizenz zu teilen. Die folgenden Überlegungen dienen nur Informationszwecken, sind nicht abschließend und sind kein Bestandteil unserer Lizenzen.
Überlegungen für Lizenzgeber: Unsere Lizenzen sind für diejenigen gedacht, die berechtigt sind, der Öffentlichkeit die Nutzung von Material zu gestatten, das ansonsten durch Urheberrecht und bestimmte andere Rechte eingeschränkt ist. Unsere Lizenzen sind unwiderruflich. Lizenzgeber sollten die Bedingungen der gewählten Lizenz lesen und verstehen, bevor sie sie anwenden. Lizenzgeber sollten auch sicherstellen, dass sie alle notwendigen Rechte besitzen, bevor sie unsere Lizenzen anwenden, damit die Öffentlichkeit das Material wie erwartet wiederverwenden kann. Lizenzgeber sollten klar kennzeichnen, welches Material nicht unter die Lizenz fällt. Dazu gehören andere CC-lizenzierte Materialien oder Materialien, die unter einer Ausnahme oder Einschränkung des Urheberrechts verwendet werden. Weitere Überlegungen für Lizenzgeber:
wiki.creativecommons.org/Considerations_for_licensors
Überlegungen für die Öffentlichkeit: Durch die Nutzung einer unserer Lizenzen gewährt ein Lizenzgeber der Öffentlichkeit die Erlaubnis, das lizenzierte Material unter den angegebenen Bedingungen zu nutzen. Wenn die Erlaubnis des Lizenzgebers aus irgendeinem Grund nicht erforderlich ist – beispielsweise aufgrund einer anwendbaren Ausnahme oder Einschränkung des Urheberrechts – wird diese Nutzung nicht durch die Lizenz geregelt. Unsere Lizenzen gewähren nur Rechte unter dem Urheberrecht und bestimmten anderen Rechten, die ein Lizenzgeber berechtigt ist zu gewähren. Die Nutzung des lizenzierten Materials kann aus anderen Gründen weiterhin eingeschränkt sein, beispielsweise weil andere Urheberrechte oder andere Rechte an dem Material bestehen. Ein Lizenzgeber kann besondere Wünsche äußern, wie etwa die Kennzeichnung oder Beschreibung aller Änderungen. Obwohl dies nicht durch unsere Lizenzen vorgeschrieben ist, wird empfohlen, solche Wünsche, soweit angemessen, zu respektieren. Weitere Überlegungen für die Öffentlichkeit:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution-ShareAlike 4.0 Internationale Lizenz
Durch die Ausübung der lizenzierten Rechte (wie unten definiert) akzeptieren und stimmen Sie den Bedingungen dieser Creative Commons Attribution-ShareAlike 4.0 Internationalen Lizenz („Öffentliche Lizenz“) zu. Soweit diese Öffentliche Lizenz als Vertrag ausgelegt werden kann, werden Ihnen die lizenzierten Rechte im Gegenzug für Ihre Annahme dieser Bedingungen gewährt, und der Lizenzgeber gewährt Ihnen diese Rechte im Gegenzug für die Vorteile, die der Lizenzgeber durch die Bereitstellung des lizenzierten Materials unter diesen Bedingungen erhält.
Abschnitt 1 – Definitionen.
a. Angepasstes Material bezeichnet Material, das dem Urheberrecht und ähnlichen Rechten unterliegt und aus dem lizenzierten Material abgeleitet oder darauf basierend erstellt wurde, wobei das lizenzierte Material übersetzt, verändert, arrangiert, transformiert oder anderweitig in einer Weise modifiziert wird, die eine Genehmigung gemäß dem Urheberrecht und ähnlichen Rechten des Lizenzgebers erfordert. Für Zwecke dieser Öffentlichen Lizenz wird bei musikalischen Werken, Darbietungen oder Tonaufnahmen immer angepasstes Material erstellt, wenn das lizenzierte Material zeitlich synchronisiert mit einem bewegten Bild verwendet wird.
b. Lizenz des Bearbeiters bezeichnet die Lizenz, die Sie gemäß den Bedingungen dieser Öffentlichen Lizenz auf Ihre Urheberrechte und ähnlichen Rechte an Ihren Beiträgen zu angepasstem Material anwenden.
c. BY-SA-kompatible Lizenz bezeichnet eine Lizenz, die unter creativecommons.org/compatiblelicenses aufgeführt ist und von Creative Commons als im Wesentlichen gleichwertig mit dieser Öffentlichen Lizenz anerkannt wurde.
d. Urheberrecht und ähnliche Rechte bezeichnet das Urheberrecht und/oder ähnliche Rechte, die eng mit dem Urheberrecht verbunden sind, einschließlich, aber nicht beschränkt auf Aufführungs-, Rundfunk-, Tonaufnahme- und Sui-Generis-Datenbankrechte, unabhängig davon, wie die Rechte bezeichnet oder kategorisiert werden. Für Zwecke dieser Öffentlichen Lizenz sind die in Abschnitt 2(b)(1)-(2) genannten Rechte keine Urheberrechte und ähnlichen Rechte.
e. Wirksame technische Schutzmaßnahmen bezeichnet Maßnahmen, die ohne ordnungsgemäße Autorisierung nicht umgangen werden dürfen gemäß Gesetzen, die Verpflichtungen aus Artikel 11 des WIPO-Urheberrechtsvertrags vom 20. Dezember 1996 und/oder ähnlichen internationalen Vereinbarungen erfüllen.
f. Ausnahmen und Einschränkungen bezeichnet „Fair Use“, „Fair Dealing“ und/oder andere Ausnahmen oder Einschränkungen des Urheberrechts und ähnlicher Rechte, die für Ihre Nutzung des lizenzierten Materials gelten.
g. Lizenzbestandteile bezeichnet die Lizenzattribute, die im Namen einer Creative-Commons-Lizenz aufgeführt sind. Die Lizenzbestandteile dieser Öffentlichen Lizenz sind Namensnennung und Weitergabe unter gleichen Bedingungen.
h. Lizenziertes Material bezeichnet das künstlerische oder literarische Werk, die Datenbank oder anderes Material, auf das der Lizenzgeber diese Öffentliche Lizenz angewendet hat.
i. Lizenzierte Rechte bezeichnet die Ihnen gemäß den Bedingungen dieser Öffentlichen Lizenz gewährten Rechte, die auf alle Urheberrechte und ähnlichen Rechte beschränkt sind, die für Ihre Nutzung des lizenzierten Materials gelten und die der Lizenzgeber berechtigt ist zu lizenzieren.
j. Lizenzgeber bezeichnet die Person(en) oder Organisation(en), die Rechte gemäß dieser Öffentlichen Lizenz gewähren.
k. Teilen bezeichnet die Bereitstellung von Material für die Öffentlichkeit durch jegliche Mittel oder Prozesse, die eine Genehmigung gemäß den lizenzierten Rechten erfordern, wie Vervielfältigung, öffentliche Darstellung, öffentliche Aufführung, Verbreitung, Kommunikation oder Import sowie die Bereitstellung von Material für die Öffentlichkeit, einschließlich auf eine Weise, die es Mitgliedern der Öffentlichkeit ermöglicht, das Material von einem Ort und zu einer Zeit ihrer Wahl zu nutzen.
l. Sui-Generis-Datenbankrechte bezeichnet Rechte, die nicht aus dem Urheberrecht resultieren und sich aus der Richtlinie 96/9/EG des Europäischen Parlaments und des Rates vom 11. März 1996 über den rechtlichen Schutz von Datenbanken ergeben, sowie andere im Wesentlichen gleichwertige Rechte weltweit.
m. Sie bezeichnet die Person oder Organisation, die die lizenzierten Rechte gemäß dieser Öffentlichen Lizenz ausübt. Ihr hat eine entsprechende Bedeutung.
Abschnitt 2 – Umfang.
a. Lizenzgewährung.
1. Vorbehaltlich der Bedingungen dieser Öffentlichen Lizenz gewährt der Lizenzgeber Ihnen hiermit eine weltweite, lizenzgebührenfreie, nicht unterlizenzierbare, nicht exklusive, unwiderrufliche Lizenz zur Ausübung der lizenzierten Rechte am lizenzierten Material, um:
a. das lizenzierte Material ganz oder teilweise zu vervielfältigen und zu teilen; und
b. angepasstes Material zu erstellen, zu vervielfältigen und zu teilen.
2. Ausnahmen und Einschränkungen. Zur Klarstellung: Wenn Ausnahmen und Einschränkungen für Ihre Nutzung gelten, findet diese Öffentliche Lizenz keine Anwendung, und Sie müssen ihre Bedingungen nicht einhalten.
3. Laufzeit. Die Laufzeit dieser Öffentlichen Lizenz ist in Abschnitt 6(a) angegeben.
4. Medien und Formate; technische Änderungen erlaubt. Der Lizenzgeber autorisiert Sie, die lizenzierten Rechte in allen Medien und Formaten auszuüben, die jetzt bekannt sind oder später entwickelt werden, und technische Änderungen vorzunehmen, die dafür erforderlich sind. Der Lizenzgeber verzichtet auf und/oder stimmt zu, keine Rechte oder Befugnisse geltend zu machen, die Sie daran hindern könnten, technische Änderungen vorzunehmen, die für die Ausübung der lizenzierten Rechte erforderlich sind, einschließlich technischer Änderungen, die erforderlich sind, um wirksame technische Schutzmaßnahmen zu umgehen. Für Zwecke dieser Öffentlichen Lizenz führt das bloße Vornehmen von Änderungen, die gemäß Abschnitt 2(a)(4) autorisiert sind, niemals zur Erstellung von angepasstem Material.
5. Nachgelagerte Empfänger.
a. Angebot des Lizenzgebers – Lizenziertes Material. Jeder Empfänger des lizenzierten Materials erhält automatisch ein Angebot des Lizenzgebers zur Ausübung der lizenzierten Rechte gemäß den Bedingungen dieser Öffentlichen Lizenz.
b. Zusätzliches Angebot des Lizenzgebers – Angepasstes Material. Jeder Empfänger von angepasstem Material von Ihnen erhält automatisch ein Angebot des Lizenzgebers zur Ausübung der lizenzierten Rechte am angepassten Material gemäß den Bedingungen der Lizenz des Bearbeiters, die Sie anwenden.
c. Keine nachgelagerten Einschränkungen. Sie dürfen keine zusätzlichen oder abweichenden Bedingungen anbieten oder auferlegen oder wirksame technische Schutzmaßnahmen auf das lizenzierte Material anwenden, wenn dies die Ausübung der lizenzierten Rechte durch einen Empfänger des lizenzierten Materials einschränkt.
6. Keine Unterstützung. Nichts in dieser Öffentlichen Lizenz stellt eine Erlaubnis dar oder kann so ausgelegt werden, dass Sie oder Ihre Nutzung des lizenzierten Materials mit dem Lizenzgeber oder anderen, die gemäß Abschnitt 3(a)(1)(A)(i) als Urheber genannt werden sollen, verbunden, unterstützt oder offiziell anerkannt sind.
b. Andere Rechte.
1. Persönlichkeitsrechte, wie das Recht auf Integrität, werden nicht gemäß dieser Öffentlichen Lizenz lizenziert, ebenso wenig wie Rechte auf Öffentlichkeit, Privatsphäre und/oder andere ähnliche Persönlichkeitsrechte; jedoch verzichtet der Lizenzgeber, soweit möglich, auf und/oder stimmt zu, keine solchen Rechte geltend zu machen, die der Lizenzgeber besitzt, soweit dies erforderlich ist, um Ihnen die Ausübung der lizenzierten Rechte zu ermöglichen, jedoch nicht darüber hinaus.
2. Patent- und Markenrechte werden nicht gemäß dieser Öffentlichen Lizenz lizenziert.
3. Soweit möglich, verzichtet der Lizenzgeber auf jegliches Recht, Lizenzgebühren von Ihnen für die Ausübung der lizenzierten Rechte zu erheben, sei es direkt oder über eine Verwertungsgesellschaft gemäß einem freiwilligen oder verzichtbaren gesetzlichen oder obligatorischen Lizenzierungssystem. In allen anderen Fällen behält sich der Lizenzgeber ausdrücklich das Recht vor, solche Lizenzgebühren zu erheben.
Abschnitt 3 – Lizenzbedingungen.
Ihre Ausübung der lizenzierten Rechte unterliegt ausdrücklich den folgenden Bedingungen.
a. Namensnennung.
1. Wenn Sie das lizenzierte Material (einschließlich in modifizierter Form) teilen, müssen Sie:
a. Folgendes beibehalten, wenn es vom Lizenzgeber mit dem lizenzierten Material bereitgestellt wird:
i. Identifikation der Urheber des lizenzierten Materials und aller anderen, die als Urheber genannt werden sollen, in einer vom Lizenzgeber angemessenen Weise (einschließlich durch Pseudonym, falls angegeben);
ii. einen Urheberrechtshinweis;
iii. einen Hinweis, der auf diese Öffentliche Lizenz verweist;
iv. einen Hinweis, der auf den Haftungsausschluss verweist;
v. eine URI oder einen Hyperlink zum lizenzierten Material, soweit dies praktikabel ist;
b. angeben, ob Sie das lizenzierte Material modifiziert haben, und eine Angabe zu vorherigen Änderungen beibehalten; und
c. angeben, dass das lizenzierte Material unter dieser Öffentlichen Lizenz lizenziert ist, und den Text dieser Lizenz oder die URI oder den Hyperlink zu dieser Lizenz beifügen.
2. Sie können die Bedingungen in Abschnitt 3(a)(1) auf jede angemessene Weise erfüllen, basierend auf dem Medium, den Mitteln und dem Kontext, in dem Sie das lizenzierte Material teilen. Beispielsweise kann es angemessen sein, die Bedingungen durch Bereitstellung einer URI oder eines Hyperlinks zu einer Ressource zu erfüllen, die die erforderlichen Informationen enthält.
3. Wenn der Lizenzgeber dies verlangt, müssen Sie alle Informationen gemäß Abschnitt 3(a)(1)(A) entfernen, soweit dies praktikabel ist.
b. Weitergabe unter gleichen Bedingungen.
Zusätzlich zu den Bedingungen in Abschnitt 3(a) gelten die folgenden Bedingungen, wenn Sie angepasstes Material teilen, das Sie erstellt haben.
1. Die Lizenz des Bearbeiters, die Sie anwenden, muss eine Creative-Commons-Lizenz mit denselben Lizenzbestandteilen sein, diese Version oder später, oder eine BY-SA-kompatible Lizenz.
2. Sie müssen den Text der Lizenz des Bearbeiters, die Sie anwenden, oder die URI oder den Hyperlink zu dieser Lizenz beifügen. Sie können diese Bedingung auf jede angemessene Weise erfüllen, basierend auf dem Medium, den Mitteln und dem Kontext, in dem Sie angepasstes Material teilen.
3. Sie dürfen keine zusätzlichen oder abweichenden Bedingungen anbieten oder auferlegen oder wirksame technische Schutzmaßnahmen auf angepasstes Material anwenden, die die Ausübung der gemäß der Lizenz des Bearbeiters gewährten Rechte einschränken.
Abschnitt 4 – Sui-Generis-Datenbankrechte.
Wenn die lizenzierten Rechte Sui-Generis-Datenbankrechte umfassen, die für Ihre Nutzung des lizenzierten Materials gelten:
a. Zur Klarstellung: Abschnitt 2(a)(1) gewährt Ihnen das Recht, alle oder einen wesentlichen Teil der Inhalte der Datenbank zu extrahieren, wiederzuverwenden, zu vervielfältigen und zu teilen;
b. Wenn Sie alle oder einen wesentlichen Teil der Inhalte der Datenbank in eine Datenbank aufnehmen, in der Sie Sui-Generis-Datenbankrechte besitzen: Rechte, dann die Datenbank, in der Sie Sui Generis-Datenbankrechte haben (aber nicht deren einzelne Inhalte), ist angepasstes Material,
einschließlich für Zwecke von Abschnitt 3(b); und
c. Sie müssen die Bedingungen in Abschnitt 3(a) einhalten, wenn Sie alle oder einen wesentlichen Teil der Inhalte der Datenbank teilen.
Zur Klarstellung ergänzt dieser Abschnitt 4 Ihre Verpflichtungen aus dieser öffentlichen Lizenz und ersetzt sie nicht, wenn die lizenzierten Rechte andere Urheberrechte und ähnliche Rechte umfassen.
Abschnitt 5 – Haftungsausschluss und Begrenzung der Haftung.
a. SOFERN NICHT ANDERS VOM LIZENZGEBER SEPARAT VEREINBART, BIETET DER LIZENZGEBER DAS LIZENZIERTE MATERIAL, SOWEIT MÖGLICH, "WIE BESEHEN" UND "WIE VERFÜGBAR" AN UND MACHT KEINE ZUSICHERUNGEN ODER GARANTIEN IRGENDWELCHER ART IN BEZUG AUF DAS LIZENZIERTE MATERIAL, OB AUSDRÜCKLICH, STILLSCHWEIGEND, GESETZLICH ODER ANDERWEITIG. DIES UMFASST UNTER ANDEREM GARANTIEN BEZÜGLICH TITEL, HANDELSÜBLICHKEIT, EIGNUNG FÜR EINEN BESTIMMTEN ZWECK, NICHTVERLETZUNG, FEHLEN VON VERBORGENEN ODER ANDEREN MÄNGELN, GENAUIGKEIT ODER DAS VORHANDENSEIN ODER NICHTVORHANDENSEIN VON FEHLERN, OB BEKANNT ODER ENTDECKBAR. WO HAFTUNGSAUSSCHLÜSSE VON GARANTIEN NICHT VOLLSTÄNDIG ODER TEILWEISE ERLAUBT SIND, KANN DIESER HAFTUNGSAUSSCHLUSS FÜR SIE NICHT GELTEN.
b. SOWEIT MÖGLICH, HAFTET DER LIZENZGEBER IN KEINEM FALL IHNEN GEGENÜBER AUF GRUNDLAGE IRGENDEINER RECHTSTHEORIE (EINSCHLIESSLICH, ABER NICHT BESCHRÄNKT AUF FAHRLÄSSIGKEIT) ODER ANDERWEITIG FÜR DIREKTE, BESONDERE, INDIREKTE, ZUFÄLLIGE, FOLGESCHÄDEN, STRAFSCHÄDEN, EXEMPLARISCHE ODER ANDERE VERLUSTE, KOSTEN, AUSGABEN ODER SCHÄDEN, DIE AUS DIESER ÖFFENTLICHEN LIZENZ ODER DER NUTZUNG DES LIZENZIERTEN MATERIALS ENTSTEHEN, SELBST WENN DER LIZENZGEBER AUF DIE MÖGLICHKEIT SOLCHER VERLUSTE, KOSTEN, AUSGABEN ODER SCHÄDEN HINGEWIESEN WURDE. WO EINE HAFTUNGSBEGRENZUNG NICHT VOLLSTÄNDIG ODER TEILWEISE ERLAUBT IST, KANN DIESE BEGRENZUNG FÜR SIE NICHT GELTEN.
c. Der oben bereitgestellte Haftungsausschluss und die Haftungsbegrenzung sind so auszulegen, dass sie, soweit möglich, einem absoluten Haftungsausschluss und Verzicht auf jegliche Haftung am nächsten kommen.
Abschnitt 6 – Laufzeit und Beendigung.
a. Diese öffentliche Lizenz gilt für die Laufzeit der hier lizenzierten Urheberrechte und ähnlichen Rechte. Wenn Sie jedoch gegen diese öffentliche Lizenz verstoßen, enden Ihre Rechte aus dieser öffentlichen Lizenz automatisch.
b. Wenn Ihr Recht zur Nutzung des lizenzierten Materials gemäß Abschnitt 6(a) beendet wurde, wird es wiederhergestellt:
- automatisch ab dem Datum, an dem der Verstoß behoben wird, vorausgesetzt, er wird innerhalb von 30 Tagen nach Ihrer Entdeckung des Verstoßes behoben; oder
- durch ausdrückliche Wiederherstellung durch den Lizenzgeber.
Zur Klarstellung: Dieser Abschnitt 6(b) berührt nicht das Recht des Lizenzgebers, Rechtsmittel wegen Ihrer Verstöße gegen diese öffentliche Lizenz einzulegen.
c. Zur Klarstellung: Der Lizenzgeber kann das lizenzierte Material auch unter separaten Bedingungen anbieten oder die Verbreitung des lizenzierten Materials jederzeit einstellen; dies beendet jedoch diese öffentliche Lizenz nicht.
d. Die Abschnitte 1, 5, 6, 7 und 8 bleiben auch nach Beendigung dieser öffentlichen Lizenz bestehen.
Abschnitt 7 – Andere Bedingungen.
a. Der Lizenzgeber ist nicht an zusätzliche oder abweichende Bedingungen gebunden, die Sie mitteilen, es sei denn, sie wurden ausdrücklich vereinbart.
b. Jegliche Vereinbarungen, Absprachen oder Übereinkünfte bezüglich des lizenzierten Materials, die hier nicht angegeben sind, sind getrennt und unabhängig von den Bedingungen dieser öffentlichen Lizenz.
Abschnitt 8 – Auslegung.
a. Zur Klarstellung: Diese öffentliche Lizenz reduziert, beschränkt, beschränkt oder auferlegt keine Bedingungen für die Nutzung des lizenzierten Materials, die rechtmäßig ohne Erlaubnis gemäß dieser öffentlichen Lizenz erfolgen könnten.
b. Soweit möglich, wird jede Bestimmung dieser öffentlichen Lizenz, die als nicht durchsetzbar erachtet wird, automatisch auf das Mindestmaß reformiert, das erforderlich ist, um sie durchsetzbar zu machen. Wenn die Bestimmung nicht reformiert werden kann, wird sie von dieser öffentlichen Lizenz abgetrennt, ohne die Durchsetzbarkeit der verbleibenden Bedingungen zu beeinträchtigen.
c. Kein Begriff oder keine Bedingung dieser öffentlichen Lizenz wird aufgehoben und keine Nichteinhaltung wird akzeptiert, es sei denn, dies wurde ausdrücklich vom Lizenzgeber vereinbart.
d. Nichts in dieser öffentlichen Lizenz stellt eine Einschränkung oder einen Verzicht auf Privilegien und Immunitäten dar, die für den Lizenzgeber oder Sie gelten, einschließlich der rechtlichen Verfahren einer Gerichtsbarkeit oder Behörde.
=======================================================================
Creative Commons ist keine Partei seiner öffentlichen Lizenzen. Nichtsdestotrotz kann Creative Commons eine seiner öffentlichen Lizenzen auf Material anwenden, das es veröffentlicht, und wird in diesen Fällen als „Lizenzgeber“ betrachtet. Der Text der Creative-Commons-Öffentlichen-Lizenzen ist der Öffentlichkeit unter der CC0 Public Domain Dedication gewidmet. Abgesehen von dem begrenzten Zweck, anzugeben, dass Material unter einer Creative-Commons-Öffentlichen-Lizenz geteilt wird, oder wie anderweitig durch die Creative-Commons-Richtlinien unter creativecommons.org/policies gestattet, autorisiert Creative Commons die Verwendung der Marke „Creative Commons“ oder einer anderen Marke oder eines Logos von Creative Commons nicht ohne vorherige schriftliche Zustimmung, einschließlich, aber nicht beschränkt auf, in Verbindung mit nicht autorisierten Änderungen an einer seiner öffentlichen Lizenzen oder anderen Vereinbarungen, Absprachen oder Übereinkünften bezüglich der Nutzung des lizenzierten Materials. Zur Klarstellung: Dieser Absatz ist nicht Teil der öffentlichen Lizenzen.
Creative Commons kann unter creativecommons.org kontaktiert werden.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Alle Sketchnotes des Lehrplans können hier heruntergeladen werden.
🖨 Für den Druck in hoher Auflösung sind die TIFF-Versionen in diesem Repository verfügbar.
🎨 Erstellt von: Tomomi Imura (Twitter: @girlie_mac)
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Unterstützung
So melden Sie Probleme und erhalten Hilfe
Bevor Sie ein Problem melden, überprüfen Sie bitte unseren Leitfaden zur Fehlerbehebung für Lösungen zu häufigen Problemen bei Installation, Einrichtung und Durchführung der Lektionen.
Dieses Projekt verwendet GitHub Issues, um Fehler und Funktionsanfragen zu verfolgen. Bitte durchsuchen Sie die vorhandenen Issues, bevor Sie neue erstellen, um Duplikate zu vermeiden. Für neue Issues melden Sie Ihren Fehler oder Ihre Funktionsanfrage als neues Issue.
Für Hilfe und Fragen zur Nutzung dieses Projekts können Sie außerdem: - Den Leitfaden zur Fehlerbehebung überprüfen - Unseren Discord-Diskussionskanal #ml-for-beginners besuchen - Ein Issue erstellen
Microsoft-Support-Richtlinie
Die Unterstützung für dieses Repository beschränkt sich auf die oben aufgeführten Ressourcen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Fehlerbehebungsanleitung
Diese Anleitung hilft Ihnen, häufige Probleme beim Arbeiten mit dem Machine Learning for Beginners-Lehrplan zu lösen. Sollten Sie hier keine Lösung finden, schauen Sie in unseren Discord-Diskussionen vorbei oder eröffnen Sie ein Issue.
Inhaltsverzeichnis
- Installationsprobleme
- Probleme mit Jupyter Notebook
- Probleme mit Python-Paketen
- Probleme mit der R-Umgebung
- Probleme mit der Quiz-Anwendung
- Daten- und Dateipfadprobleme
- Häufige Fehlermeldungen
- Leistungsprobleme
- Umgebung und Konfiguration
Installationsprobleme
Python-Installation
Problem: python: command not found
Lösung:
1. Installieren Sie Python 3.8 oder höher von python.org
2. Überprüfen Sie die Installation: python --version oder python3 --version
3. Unter macOS/Linux müssen Sie möglicherweise python3 anstelle von python verwenden
Problem: Mehrere Python-Versionen verursachen Konflikte
Lösung:
# Use virtual environments to isolate projects
python -m venv ml-env
# Activate virtual environment
# On Windows:
ml-env\Scripts\activate
# On macOS/Linux:
source ml-env/bin/activate
Jupyter-Installation
Problem: jupyter: command not found
Lösung:
# Install Jupyter
pip install jupyter
# Or with pip3
pip3 install jupyter
# Verify installation
jupyter --version
Problem: Jupyter öffnet sich nicht im Browser
Lösung:
# Try specifying the browser
jupyter notebook --browser=chrome
# Or copy the URL with token from terminal and paste in browser manually
# Look for: http://localhost:8888/?token=...
R-Installation
Problem: R-Pakete lassen sich nicht installieren
Lösung:
# Ensure you have the latest R version
# Install packages with dependencies
install.packages(c("tidyverse", "tidymodels", "caret"), dependencies = TRUE)
# If compilation fails, try installing binary versions
install.packages("package-name", type = "binary")
Problem: IRkernel ist in Jupyter nicht verfügbar
Lösung:
# In R console
install.packages('IRkernel')
IRkernel::installspec(user = TRUE)
Probleme mit Jupyter Notebook
Kernel-Probleme
Problem: Kernel stürzt ab oder startet ständig neu
Lösung:
1. Kernel neu starten: Kernel → Restart
2. Ausgabe löschen und neu starten: Kernel → Restart & Clear Output
3. Überprüfen Sie Speicherprobleme (siehe Leistungsprobleme)
4. Führen Sie die Zellen einzeln aus, um problematischen Code zu identifizieren
Problem: Falscher Python-Kernel ausgewählt
Lösung:
1. Aktuellen Kernel überprüfen: Kernel → Change Kernel
2. Wählen Sie die richtige Python-Version aus
3. Falls der Kernel fehlt, erstellen Sie ihn:
python -m ipykernel install --user --name=ml-env
Problem: Kernel startet nicht
Lösung:
# Reinstall ipykernel
pip uninstall ipykernel
pip install ipykernel
# Register the kernel again
python -m ipykernel install --user
Probleme mit Notebook-Zellen
Problem: Zellen laufen, zeigen aber keine Ausgabe
Lösung:
1. Überprüfen Sie, ob die Zelle noch läuft (achten Sie auf den [*]-Indikator)
2. Kernel neu starten und alle Zellen ausführen: Kernel → Restart & Run All
3. Überprüfen Sie die Browser-Konsole auf JavaScript-Fehler (F12)
Problem: Zellen lassen sich nicht ausführen - keine Reaktion beim Klicken auf "Run"
Lösung: 1. Überprüfen Sie, ob der Jupyter-Server noch im Terminal läuft 2. Aktualisieren Sie die Browserseite 3. Schließen und öffnen Sie das Notebook erneut 4. Starten Sie den Jupyter-Server neu
Probleme mit Python-Paketen
Importfehler
Problem: ModuleNotFoundError: No module named 'sklearn'
Lösung:
pip install scikit-learn
# Common ML packages for this course
pip install scikit-learn pandas numpy matplotlib seaborn
Problem: ImportError: cannot import name 'X' from 'sklearn'
Lösung:
# Update scikit-learn to latest version
pip install --upgrade scikit-learn
# Check version
python -c "import sklearn; print(sklearn.__version__)"
Versionskonflikte
Problem: Fehler aufgrund von Paketversionsinkompatibilitäten
Lösung:
# Create a new virtual environment
python -m venv fresh-env
source fresh-env/bin/activate # or fresh-env\Scripts\activate on Windows
# Install packages fresh
pip install jupyter scikit-learn pandas numpy matplotlib seaborn
# If specific version needed
pip install scikit-learn==1.3.0
Problem: pip install schlägt mit Berechtigungsfehlern fehl
Lösung:
# Install for current user only
pip install --user package-name
# Or use virtual environment (recommended)
python -m venv venv
source venv/bin/activate
pip install package-name
Probleme beim Laden von Daten
Problem: FileNotFoundError beim Laden von CSV-Dateien
Lösung:
import os
# Check current working directory
print(os.getcwd())
# Use relative paths from notebook location
df = pd.read_csv('../../data/filename.csv')
# Or use absolute paths
df = pd.read_csv('/full/path/to/data/filename.csv')
Probleme mit der R-Umgebung
Paketinstallation
Problem: Paketinstallation schlägt mit Kompilierungsfehlern fehl
Lösung:
# Install binary version (Windows/macOS)
install.packages("package-name", type = "binary")
# Update R to latest version if packages require it
# Check R version
R.version.string
# Install system dependencies (Linux)
# For Ubuntu/Debian, in terminal:
# sudo apt-get install r-base-dev
Problem: tidyverse lässt sich nicht installieren
Lösung:
# Install dependencies first
install.packages(c("rlang", "vctrs", "pillar"))
# Then install tidyverse
install.packages("tidyverse")
# Or install components individually
install.packages(c("dplyr", "ggplot2", "tidyr", "readr"))
Probleme mit RMarkdown
Problem: RMarkdown lässt sich nicht rendern
Lösung:
# Install/update rmarkdown
install.packages("rmarkdown")
# Install pandoc if needed
install.packages("pandoc")
# For PDF output, install tinytex
install.packages("tinytex")
tinytex::install_tinytex()
Probleme mit der Quiz-Anwendung
Build und Installation
Problem: npm install schlägt fehl
Lösung:
# Clear npm cache
npm cache clean --force
# Remove node_modules and package-lock.json
rm -rf node_modules package-lock.json
# Reinstall
npm install
# If still fails, try with legacy peer deps
npm install --legacy-peer-deps
Problem: Port 8080 ist bereits belegt
Lösung:
# Use different port
npm run serve -- --port 8081
# Or find and kill process using port 8080
# On Linux/macOS:
lsof -ti:8080 | xargs kill -9
# On Windows:
netstat -ano | findstr :8080
taskkill /PID <PID> /F
Build-Fehler
Problem: npm run build schlägt fehl
Lösung:
# Check Node.js version (should be 14+)
node --version
# Update Node.js if needed
# Then clean install
rm -rf node_modules package-lock.json
npm install
npm run build
Problem: Linting-Fehler verhindern den Build
Lösung:
# Fix auto-fixable issues
npm run lint -- --fix
# Or temporarily disable linting in build
# (not recommended for production)
Daten- und Dateipfadprobleme
Pfadprobleme
Problem: Daten werden beim Ausführen von Notebooks nicht gefunden
Lösung:
1. Führen Sie Notebooks immer aus ihrem Verzeichnis aus
bash
cd /path/to/lesson/folder
jupyter notebook
- Überprüfen Sie relative Pfade im Code ```python # Correct path from notebook location df = pd.read_csv('../data/filename.csv')
# Not from your terminal location ```
- Verwenden Sie bei Bedarf absolute Pfade
python import os base_path = os.path.dirname(os.path.abspath(__file__)) data_path = os.path.join(base_path, 'data', 'filename.csv')
Fehlende Datendateien
Problem: Datensätze fehlen
Lösung:
1. Überprüfen Sie, ob die Daten im Repository enthalten sein sollten – die meisten Datensätze sind enthalten
2. Einige Lektionen erfordern das Herunterladen von Daten – überprüfen Sie die README der Lektion
3. Stellen Sie sicher, dass Sie die neuesten Änderungen gezogen haben:
bash
git pull origin main
Häufige Fehlermeldungen
Speicherfehler
Fehler: MemoryError oder Kernel stürzt beim Verarbeiten von Daten ab
Lösung:
# Load data in chunks
for chunk in pd.read_csv('large_file.csv', chunksize=10000):
process(chunk)
# Or read only needed columns
df = pd.read_csv('file.csv', usecols=['col1', 'col2'])
# Free memory when done
del large_dataframe
import gc
gc.collect()
Konvergenzwarnungen
Warnung: ConvergenceWarning: Maximum number of iterations reached
Lösung:
from sklearn.linear_model import LogisticRegression
# Increase max iterations
model = LogisticRegression(max_iter=1000)
# Or scale your features first
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
Probleme mit Diagrammen
Problem: Diagramme werden in Jupyter nicht angezeigt
Lösung:
# Enable inline plotting
%matplotlib inline
# Import pyplot
import matplotlib.pyplot as plt
# Show plot explicitly
plt.plot(data)
plt.show()
Problem: Seaborn-Diagramme sehen anders aus oder werfen Fehler
Lösung:
import warnings
warnings.filterwarnings('ignore', category=UserWarning)
# Update to compatible version
# pip install --upgrade seaborn matplotlib
Unicode-/Codierungsfehler
Problem: UnicodeDecodeError beim Lesen von Dateien
Lösung:
# Specify encoding explicitly
df = pd.read_csv('file.csv', encoding='utf-8')
# Or try different encoding
df = pd.read_csv('file.csv', encoding='latin-1')
# For errors='ignore' to skip problematic characters
df = pd.read_csv('file.csv', encoding='utf-8', errors='ignore')
Leistungsprobleme
Langsame Ausführung von Notebooks
Problem: Notebooks laufen sehr langsam
Lösung:
1. Kernel neu starten, um Speicher freizugeben: Kernel → Restart
2. Schließen Sie ungenutzte Notebooks, um Ressourcen freizugeben
3. Verwenden Sie kleinere Datensamples zum Testen:
python
# Work with subset during development
df_sample = df.sample(n=1000)
4. Profilieren Sie Ihren Code, um Engpässe zu finden:
python
%time operation() # Time single operation
%timeit operation() # Time with multiple runs
Hoher Speicherverbrauch
Problem: System läuft aufgrund von Speichermangel langsam
Lösung:
# Check memory usage
df.info(memory_usage='deep')
# Optimize data types
df['column'] = df['column'].astype('int32') # Instead of int64
# Drop unnecessary columns
df = df[['col1', 'col2']] # Keep only needed columns
# Process in batches
for batch in np.array_split(df, 10):
process(batch)
Umgebung und Konfiguration
Probleme mit virtuellen Umgebungen
Problem: Virtuelle Umgebung wird nicht aktiviert
Lösung:
# Windows
python -m venv venv
venv\Scripts\activate.bat
# macOS/Linux
python3 -m venv venv
source venv/bin/activate
# Check if activated (should show venv name in prompt)
which python # Should point to venv python
Problem: Pakete installiert, aber im Notebook nicht gefunden
Lösung:
# Ensure notebook uses the correct kernel
# Install ipykernel in your venv
pip install ipykernel
python -m ipykernel install --user --name=ml-env --display-name="Python (ml-env)"
# In Jupyter: Kernel → Change Kernel → Python (ml-env)
Git-Probleme
Problem: Kann neueste Änderungen nicht ziehen – Merge-Konflikte
Lösung:
# Stash your changes
git stash
# Pull latest
git pull origin main
# Reapply your changes
git stash pop
# If conflicts, resolve manually or:
git checkout --theirs path/to/file # Take remote version
git checkout --ours path/to/file # Keep your version
VS Code-Integration
Problem: Jupyter-Notebooks lassen sich in VS Code nicht öffnen
Lösung:
1. Installieren Sie die Python-Erweiterung in VS Code
2. Installieren Sie die Jupyter-Erweiterung in VS Code
3. Wählen Sie den richtigen Python-Interpreter aus: Ctrl+Shift+P → "Python: Select Interpreter"
4. Starten Sie VS Code neu
Zusätzliche Ressourcen
- Discord-Diskussionen: Stellen Sie Fragen und teilen Sie Lösungen im #ml-for-beginners-Kanal
- Microsoft Learn: ML for Beginners-Module
- Video-Tutorials: YouTube-Playlist
- Issue-Tracker: Fehler melden
Haben Sie immer noch Probleme?
Wenn Sie die oben genannten Lösungen ausprobiert haben und weiterhin Probleme auftreten:
- Suchen Sie nach bestehenden Issues: GitHub Issues
- Überprüfen Sie Diskussionen auf Discord: Discord-Diskussionen
- Eröffnen Sie ein neues Issue: Geben Sie Folgendes an: - Ihr Betriebssystem und dessen Version - Python-/R-Version - Fehlermeldung (vollständiger Traceback) - Schritte zur Reproduktion des Problems - Was Sie bereits ausprobiert haben
Wir helfen Ihnen gerne weiter! 🚀
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
AGENTS.md
Projektübersicht
AI for Beginners ist ein umfassender 12-wöchiger Lehrplan mit 24 Lektionen, der die Grundlagen der Künstlichen Intelligenz abdeckt. Dieses Bildungs-Repository enthält praktische Lektionen mit Jupyter Notebooks, Quizfragen und interaktiven Übungen. Der Lehrplan umfasst:
- Symbolische KI mit Wissensrepräsentation und Expertensystemen
- Neuronale Netze und Deep Learning mit TensorFlow und PyTorch
- Techniken und Architekturen der Computer Vision
- Verarbeitung natürlicher Sprache (NLP), einschließlich Transformer und BERT
- Spezialisierte Themen: Genetische Algorithmen, Verstärkendes Lernen, Multi-Agenten-Systeme
- KI-Ethik und Prinzipien verantwortungsvoller KI
Wichtige Technologien: Python 3, Jupyter Notebooks, TensorFlow, PyTorch, Keras, OpenCV, Vue.js (für die Quiz-App)
Architektur: Bildungsinhalts-Repository mit Jupyter Notebooks, organisiert nach Themenbereichen, ergänzt durch eine Vue.js-basierte Quiz-Anwendung und umfangreiche mehrsprachige Unterstützung.
Setup-Befehle
Primäre Entwicklungsumgebung (Python/Jupyter)
Der Lehrplan ist für die Ausführung mit Python und Jupyter Notebooks konzipiert. Die empfohlene Methode ist die Verwendung von Miniconda:
# Clone the repository
git clone https://github.com/microsoft/ai-for-beginners
cd ai-for-beginners
# Create and activate conda environment
conda env create --name ai4beg --file environment.yml
conda activate ai4beg
# Start Jupyter Notebook
jupyter notebook
# OR
jupyter lab
Alternative: Verwendung von devcontainer
# Open in VS Code and select "Reopen in Container" when prompted
# The devcontainer will automatically set up the environment
Einrichtung der Quiz-Anwendung
Die Quiz-App ist eine separate Vue.js-Anwendung, die sich unter etc/quiz-app/ befindet:
cd etc/quiz-app
npm install
npm run serve # Development server
npm run build # Production build
npm run lint # Lint and fix files
Entwicklungsworkflow
Arbeiten mit Jupyter Notebooks
-
Lokale Entwicklung: - Conda-Umgebung aktivieren:
conda activate ai4beg- Jupyter starten:jupyter notebookoderjupyter lab- Zu den Lektionen-Ordnern navigieren und.ipynb-Dateien öffnen - Zellen interaktiv ausführen, um den Lektionen zu folgen -
VS Code mit Python-Erweiterung: - Repository in VS Code öffnen - Python-Erweiterung installieren - VS Code erkennt und verwendet automatisch die Conda-Umgebung -
.ipynb-Dateien direkt in VS Code öffnen -
Cloud-Entwicklung: - GitHub Codespaces: Klicken Sie auf "Code" → "Codespaces" → "Codespace auf main erstellen" - Binder: Verwenden Sie das Binder-Badge in der README, um im Browser zu starten - Hinweis: Binder hat begrenzte Ressourcen und einige Einschränkungen beim Webzugriff
GPU-Unterstützung für fortgeschrittene Lektionen
Spätere Lektionen profitieren erheblich von GPU-Beschleunigung:
- Azure Data Science VM: Verwenden Sie NC-Serie VMs mit GPU-Unterstützung
- Azure Machine Learning: Nutzen Sie Notebook-Funktionen mit GPU-Computing
- Google Colab: Laden Sie Notebooks einzeln hoch (kostenlose GPU-Unterstützung verfügbar)
Entwicklung der Quiz-App
cd etc/quiz-app
npm run serve # Hot-reload development server at http://localhost:8080
Testanweisungen
Dieses Repository ist auf Lerninhalte ausgerichtet und nicht auf Softwaretests. Es gibt keine traditionelle Test-Suite.
Validierungsansätze:
- Jupyter Notebooks: Zellen nacheinander ausführen, um sicherzustellen, dass die Codebeispiele funktionieren
- Quiz-App-Tests: Manuelles Testen über den Entwicklungsserver
- Validierung der Übersetzungen: Überprüfen Sie die übersetzten Inhalte im Ordner
translations/ - Linting der Quiz-App:
npm run lintinetc/quiz-app/ausführen
Ausführung von Codebeispielen:
# Activate environment first
conda activate ai4beg
# Run Python scripts directly
python lessons/4-ComputerVision/07-ConvNets/pytorchcv.py
# Or execute notebooks
jupyter notebook lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb
Code-Stil
Python-Code-Stil
- Standard-Python-Konventionen für Bildungs-Code
- Klarer, lesbarer Code, der Lernen über Optimierung priorisiert
- Kommentare, die wichtige Konzepte erklären
- Jupyter Notebook-freundlich: Zellen sollten möglichst eigenständig sein
- Keine strengen Linting-Anforderungen für Lehrinhalte
JavaScript/Vue.js (Quiz-App)
- ESLint-Konfiguration in
etc/quiz-app/package.json npm run lintausführen, um Probleme zu überprüfen und automatisch zu beheben- Vue 2.x-Konventionen
- Komponentenbasierte Architektur
Dateiorganisation
lessons/
├── 0-course-setup/ # Setup instructions
├── 1-Intro/ # Introduction to AI
├── 2-Symbolic/ # Symbolic AI
├── 3-NeuralNetworks/ # Neural Networks basics
├── 4-ComputerVision/ # Computer Vision
├── 5-NLP/ # Natural Language Processing
├── 6-Other/ # Other AI techniques
├── 7-Ethics/ # AI Ethics
└── X-Extras/ # Additional content
etc/
├── quiz-app/ # Vue.js quiz application
└── quiz-src/ # Quiz source files
translations/ # Multi-language translations
Build und Deployment
Jupyter-Inhalte
Kein Build-Prozess erforderlich - Jupyter Notebooks werden direkt ausgeführt.
Quiz-Anwendung
cd etc/quiz-app
# Development
npm run serve
# Production build
npm run build # Outputs to etc/quiz-app/dist/
# Deploy to Azure Static Web Apps
# Azure automatically creates GitHub Actions workflow
# See etc/quiz-app/README.md for detailed deployment instructions
Dokumentationsseite
Das Repository verwendet Docsify für die Dokumentation:
- index.html dient als Einstiegspunkt
- Kein Build erforderlich - direkt über GitHub Pages bereitgestellt
- Zugriff unter: https://microsoft.github.io/AI-For-Beginners/
Richtlinien für Beiträge
Pull-Request-Prozess
- Titel-Format: Klare, beschreibende Titel, die die Änderung erklären
- CLA-Anforderung: Microsoft CLA muss unterzeichnet sein (automatische Überprüfung)
- Inhaltsrichtlinien: - Bildungsfokus und anfängerfreundlichen Ansatz beibehalten - Alle Codebeispiele in Notebooks testen - Sicherstellen, dass Notebooks durchgehend ausführbar sind - Übersetzungen aktualisieren, wenn englische Inhalte geändert werden
- Änderungen an der Quiz-App:
npm run lintvor dem Commit ausführen
Übersetzungsbeiträge
- Übersetzungen werden automatisiert über GitHub Actions mit co-op-translator durchgeführt
- Manuelle Übersetzungen werden in
translations/<language-code>/abgelegt - Quiz-Übersetzungen in
etc/quiz-app/src/assets/translations/ - Unterstützte Sprachen: Über 40 Sprachen (siehe README für vollständige Liste)
Aktive Beitragsbereiche
Siehe etc/CONTRIBUTING.md für aktuelle Bedürfnisse:
- Abschnitte zu Deep Reinforcement Learning
- Verbesserungen bei der Objekterkennung
- Beispiele für Named Entity Recognition
- Trainingsbeispiele für benutzerdefinierte Einbettungen
Umgebungskonfiguration
Erforderliche Abhängigkeiten
# Core Python packages (from requirements.txt)
tensorflow==2.17.0
torch (via conda)
torchvision (via conda)
keras==3.5.0
opencv (via conda)
scikit-learn
numpy==1.26
pandas==2.2.2
matplotlib==3.9
jupyter
Umgebungsvariablen
Keine speziellen Umgebungsvariablen für die grundlegende Nutzung erforderlich.
Für Azure-Bereitstellungen (Quiz-App):
- AZURE_STATIC_WEB_APPS_API_TOKEN (automatisch von Azure gesetzt)
Debugging und Fehlerbehebung
Häufige Probleme
Problem: Erstellung der Conda-Umgebung schlägt fehl
- Lösung: Conda zuerst aktualisieren: conda update conda -y
- Ausreichend Speicherplatz sicherstellen (50GB empfohlen)
Problem: Jupyter-Kernel nicht gefunden
- Lösung:
bash
conda activate ai4beg
python -m ipykernel install --user --name ai4beg
Problem: GPU wird in Notebooks nicht erkannt
- Lösung:
- CUDA-Installation überprüfen: nvidia-smi
- PyTorch-GPU überprüfen: python -c "import torch; print(torch.cuda.is_available())"
- TensorFlow-GPU überprüfen: python -c "import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))"
Problem: Quiz-App startet nicht
- Lösung:
bash
cd etc/quiz-app
rm -rf node_modules package-lock.json
npm install
npm run serve
Problem: Binder läuft ab oder blockiert Downloads - Lösung: Verwenden Sie GitHub Codespaces oder lokale Einrichtung für besseren Ressourcen-Zugriff
Speicherprobleme
Einige Lektionen erfordern erheblichen RAM (8GB+ empfohlen): - Verwenden Sie Cloud-VMs für ressourcenintensive Lektionen - Schließen Sie andere Anwendungen, wenn Modelle trainiert werden - Reduzieren Sie die Batch-Größen in Notebooks, wenn der Speicher knapp wird
Zusätzliche Hinweise
Für Kursleiter
- Siehe
lessons/0-course-setup/for-teachers.mdfür Lehranweisungen - Lektionen sind eigenständig und können in Reihenfolge oder einzeln unterrichtet werden
- Geschätzte Dauer: 12 Wochen mit 2 Lektionen pro Woche
Cloud-Ressourcen
- Azure for Students: Kostenlose Credits für Studierende verfügbar
- Microsoft Learn: Ergänzende Lernpfade, die im gesamten Lehrplan verlinkt sind
- Binder: Kostenlos, aber mit begrenzten Ressourcen und einigen Netzwerkeinschränkungen
Optionen zur Codeausführung
- Lokal (empfohlen): Volle Kontrolle, beste Leistung, GPU-Unterstützung
- GitHub Codespaces: Cloud-basiertes VS Code, gut für schnellen Zugriff
- Binder: Browserbasiertes Jupyter, kostenlos, aber begrenzt
- Azure ML Notebooks: Unternehmensoption mit GPU-Unterstützung
- Google Colab: Notebooks einzeln hochladen, kostenloser GPU-Tarif verfügbar
Arbeiten mit Notebooks
- Notebooks sind so konzipiert, dass sie Zelle für Zelle ausgeführt werden können, um zu lernen
- Viele Notebooks laden Datensätze beim ersten Ausführen herunter (kann Zeit in Anspruch nehmen)
- Einige Modelle erfordern GPU für angemessene Trainingszeiten
- Vorgefertigte Modelle werden verwendet, wo möglich, um den Rechenaufwand zu reduzieren
Leistungsüberlegungen
- Spätere Lektionen zur Computer Vision (CNNs, GANs) profitieren von GPU
- NLP-Transformer-Lektionen können erheblichen RAM erfordern
- Training von Grund auf ist lehrreich, aber zeitaufwendig
- Beispiele für Transfer-Learning minimieren die Trainingszeit
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Microsoft Open Source Verhaltenskodex
Dieses Projekt hat den Microsoft Open Source Verhaltenskodex übernommen.
Ressourcen:
- Microsoft Open Source Verhaltenskodex
- Microsoft Verhaltenskodex FAQ
- Kontaktieren Sie opencode@microsoft.com bei Fragen oder Bedenken
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Beiträge
Dieses Projekt begrüßt Beiträge und Vorschläge. Die meisten Beiträge erfordern, dass Sie einer Contributor License Agreement (CLA) zustimmen, die erklärt, dass Sie das Recht haben und tatsächlich gewähren, uns die Rechte zur Nutzung Ihres Beitrags zu übertragen. Weitere Details finden Sie unter https://cla.microsoft.com.
Wenn Sie eine Pull-Anfrage einreichen, wird ein CLA-Bot automatisch feststellen, ob Sie eine CLA bereitstellen müssen, und die PR entsprechend kennzeichnen (z. B. Label, Kommentar). Folgen Sie einfach den Anweisungen des Bots. Dies müssen Sie nur einmal für alle Repositories tun, die unsere CLA verwenden.
Dieses Projekt hat den Microsoft Open Source Code of Conduct übernommen. Weitere Informationen finden Sie in den Code of Conduct FAQ oder kontaktieren Sie opencode@microsoft.com bei zusätzlichen Fragen oder Kommentaren.
Gesuchte Beiträge
Wir suchen derzeit aktiv nach Beiträgen zu den folgenden Themen:
- [ ] Abschnitt über Deep Reinforcement Learning schreiben
- [ ] Abschnitt + Notebook zur Objekterkennung verbessern
- [ ] PyTorch Lightning (für diesen Abschnitt)
- [ ] Abschnitt + Beispiele zu Named Entity Recognition schreiben
- [ ] Beispiele erstellen, um eigene Embeddings für diesen Abschnitt zu trainieren
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
KI
Einführung in KI
- KI Definition
- Geschichte der KI
- Ansätze der KI
- Top-down/Symbolisch
- Bottom-up/Neural
- Evolutionär
- Synergetisch / Emergent KI
- Microsoft AI Business School
Symbolische KI
- Wissensrepräsentation
- Expertensysteme
- Ontologien
- Semantisches Web
Neuronale Netze
Computervision
- Auf MS Learn
- Einführung in CV. OpenCV
- Faltungsnetze
- CNN Architekturen
- Transferlernen
- Trainingstricks
- Autoencoder und VAEs
- Generative Adversariale Netze
- Stiltransfer
- Objekterkennung
- Segmentierung
Verarbeitung natürlicher Sprache
- Auf MS Learn
- Textrepräsentation
- Bag of Words
- TF/IDF
- Semantische Einbettungen
- Word2Vec
- GloVE
- Sprachmodellierung
- Rekurrente neuronale Netze
- LSTM
- GRU
- Generative rekurrente Netze
- Transformers und BERT
- Named Entity Recognition
- Textgenerierung und GPT
Andere Techniken
KI Ethik
Extras
- Multimodale Netzwerke
- CLIP
- DALL-E
- VQ-GAN
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir auf Genauigkeit achten, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache ist als maßgebliche Quelle zu betrachten. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Verwendung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Quizfragen
Diese Quizfragen sind die Vor- und Nachbereitungsquizfragen für den KI-Lehrplan unter https://aka.ms/ai-beginners
Hinzufügen eines übersetzten Quiz-Sets
Füge eine Quiz-Übersetzung hinzu, indem du passende Quizstrukturen in den Ordnern assets/translations erstellst. Die ursprünglichen Quizfragen befinden sich in assets/translations/en. Die Quizfragen sind nach Lektionen in mehrere Gruppen unterteilt. Achte darauf, die Nummerierung mit dem entsprechenden Quizabschnitt abzugleichen. Insgesamt gibt es 40 Quizfragen in diesem Lehrplan, beginnend mit der Nummer 0.
Nach dem Bearbeiten der Übersetzungen bearbeite die Datei index.js im Übersetzungsordner, um alle Dateien gemäß den Konventionen in en zu importieren.
Bearbeite die Datei index.js in assets/translations, um die neuen übersetzten Dateien zu importieren.
Bearbeite anschließend das Dropdown-Menü in App.vue in dieser App, um deine Sprache hinzuzufügen. Passe die lokalisierte Abkürzung an den Ordnernamen deiner Sprache an.
Schließlich bearbeite alle Quiz-Links in den übersetzten Lektionen, falls vorhanden, um diese Lokalisierung als Abfrageparameter hinzuzufügen: z. B. ?loc=fr.
Projektsetup
npm install
Kompiliert und lädt für die Entwicklung neu
npm run serve
Kompiliert und minimiert für die Produktion
npm run build
Überprüft und behebt Dateien
npm run lint
Konfiguration anpassen
Siehe Konfigurationsreferenz.
Credits: Dank an die ursprüngliche Version dieser Quiz-App: https://github.com/arpan45/simple-quiz-vue
Bereitstellung auf Azure
Hier ist eine Schritt-für-Schritt-Anleitung, um dir den Einstieg zu erleichtern:
-
Forke ein GitHub-Repository
Stelle sicher, dass sich der Code deiner statischen Web-App in deinem GitHub-Repository befindet. Forke dieses Repository. -
Erstelle eine Azure Static Web App
- Erstelle ein Azure-Konto
- Gehe zum Azure-Portal
- Klicke auf „Ressource erstellen“ und suche nach „Static Web App“.
- Klicke auf „Erstellen“. -
Konfiguriere die Static Web App
- Grundlagen:
- Abonnement: Wähle dein Azure-Abonnement aus.
- Ressourcengruppe: Erstelle eine neue Ressourcengruppe oder verwende eine bestehende.
- Name: Gib deiner statischen Web-App einen Namen.
- Region: Wähle die Region, die deinen Nutzern am nächsten liegt.
-
Bereitstellungsdetails:
- Quelle: Wähle „GitHub“.
- GitHub-Konto: Autorisiere Azure, auf dein GitHub-Konto zuzugreifen.
- Organisation: Wähle deine GitHub-Organisation aus.
- Repository: Wähle das Repository, das deine statische Web-App enthält.
-
Branch: Wähle den Branch, von dem aus du bereitstellen möchtest.
-
Build-Details:
- Build-Voreinstellungen: Wähle das Framework, mit dem deine App erstellt wurde (z. B. React, Angular, Vue usw.).
- App-Standort: Gib den Ordner an, der deinen App-Code enthält (z. B. /, wenn er sich im Root-Verzeichnis befindet).
- API-Standort: Falls du eine API hast, gib deren Standort an (optional).
- Ausgabe-Standort: Gib den Ordner an, in dem die Build-Ausgabe generiert wird (z. B. build oder dist).
-
Überprüfen und Erstellen
Überprüfe deine Einstellungen und klicke auf „Erstellen“. Azure wird die erforderlichen Ressourcen einrichten und einen GitHub Actions-Workflow in deinem Repository erstellen. -
GitHub Actions-Workflow
Azure erstellt automatisch eine GitHub Actions-Workflow-Datei in deinem Repository (.github/workflows/azure-static-web-apps-<name>.yml). Dieser Workflow übernimmt den Build- und Bereitstellungsprozess. -
Überwache die Bereitstellung
Gehe zum Tab „Actions“ in deinem GitHub-Repository.
Du solltest sehen, dass ein Workflow ausgeführt wird. Dieser Workflow wird deine statische Web-App auf Azure erstellen und bereitstellen.
Sobald der Workflow abgeschlossen ist, ist deine App unter der bereitgestellten Azure-URL live.
Beispiel für eine Workflow-Datei
Hier ist ein Beispiel, wie die GitHub Actions-Workflow-Datei aussehen könnte:
name: Azure Static Web Apps CI/CD
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- main
jobs:
build_and_deploy_job:
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v2
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
action: "upload"
app_location: "etc/quiz-app # App source code path"
api_location: ""API source code path optional
output_location: "dist" #Built app content directory - optional
Zusätzliche Ressourcen
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Unterstützung
So melden Sie Probleme und erhalten Hilfe
Dieses Projekt verwendet GitHub Issues, um Fehler und Funktionsanfragen zu verfolgen. Bitte durchsuchen Sie die vorhandenen Issues, bevor Sie neue erstellen, um Duplikate zu vermeiden. Für neue Issues melden Sie Ihren Fehler oder Ihre Funktionsanfrage als neues Issue.
Für Hilfe und Fragen zur Nutzung dieses Projekts nutzen Sie bitte die Diskussionsforen.
Microsoft-Support-Richtlinie
Die Unterstützung für dieses Projekt beschränkt sich auf die oben aufgeführten Ressourcen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Beiträge durch Übersetzung von Lektionen
Wir freuen uns über Übersetzungen der Lektionen in diesem Lehrplan!
Richtlinien
In jedem Lektionen-Ordner und Einführungsordner der Lektionen gibt es Unterordner, die die übersetzten Markdown-Dateien enthalten.
> Hinweis: Bitte übersetzen Sie keinen Code in den Codebeispieldateien; die einzigen Dinge, die übersetzt werden sollen, sind README, Aufgaben und die Quizfragen. Danke!
Übersetzte Dateien sollten folgendem Namensschema folgen:
README.[language].md
wobei [language] eine zweibuchstabige Sprachabkürzung gemäß dem ISO 639-1-Standard ist (z. B. README.es.md für Spanisch und README.nl.md für Niederländisch).
assignment.[language].md
Ähnlich wie bei den Readme-Dateien, übersetzen Sie bitte auch die Aufgaben.
Quizfragen
-
Fügen Sie Ihre Übersetzung zur Quiz-App hinzu, indem Sie hier eine Datei hinzufügen: https://github.com/microsoft/AI-For-Beginners/tree/main/etc/quiz-app/src/assets/translations, mit dem richtigen Namensschema (en.json, fr.json). Bitte lokalisieren Sie jedoch nicht die Wörter 'true' oder 'false'. Danke!
-
Fügen Sie Ihren Sprachcode zum Dropdown-Menü in der App.vue-Datei der Quiz-App hinzu.
-
Bearbeiten Sie die translations index.js Datei der Quiz-App, um Ihre Sprache hinzuzufügen.
-
Bearbeiten Sie schließlich ALLE Quiz-Links in Ihren übersetzten README.md-Dateien, damit sie direkt auf Ihr übersetztes Quiz verweisen: https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/1 wird zu https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/1?loc=id
DANKE
Wir schätzen Ihre Bemühungen wirklich sehr!
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einfacher Bildklassifikator
Dieses Notebook zeigt, wie man Bilder mit einem vortrainierten neuronalen Netzwerk klassifiziert.
Was Sie lernen werden: - Wie man ein vortrainiertes Modell lädt und verwendet - Bildvorverarbeitung - Vorhersagen für Bilder treffen - Verständnis von Vertrauenswerten
Anwendungsfall: Objekte in Bildern identifizieren (wie "Katze", "Hund", "Auto" usw.)
Schritt 1: Erforderliche Bibliotheken importieren
Lassen Sie uns die benötigten Tools importieren. Keine Sorge, wenn Sie noch nicht alles davon verstehen!
# Core libraries
import numpy as np
from PIL import Image
import requests
from io import BytesIO
# TensorFlow for deep learning
try:
import tensorflow as tf
from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input, decode_predictions
print("✅ TensorFlow loaded successfully!")
print(f" Version: {tf.__version__}")
except ImportError:
print("❌ Please install TensorFlow: pip install tensorflow")
Schritt 2: Vortrainiertes Modell laden
Wir verwenden MobileNetV2, ein neuronales Netzwerk, das bereits mit Millionen von Bildern trainiert wurde.
Das nennt man Transfer Learning – die Nutzung eines Modells, das von jemand anderem trainiert wurde!
print("📦 Loading pre-trained MobileNetV2 model...")
print(" This may take a minute on first run (downloading weights)...")
# Load the model
# include_top=True means we use the classification layer
# weights='imagenet' means it was trained on ImageNet dataset
model = MobileNetV2(weights='imagenet', include_top=True)
print("✅ Model loaded!")
print(f" The model can recognize 1000 different object categories")
Schritt 3: Hilfsfunktionen
Lassen Sie uns Funktionen erstellen, um Bilder für unser Modell zu laden und vorzubereiten.
def load_image_from_url(url):
"""
Load an image from a URL.
Args:
url: Web address of the image
Returns:
PIL Image object
"""
response = requests.get(url)
img = Image.open(BytesIO(response.content))
return img
def prepare_image(img):
"""
Prepare an image for the model.
Steps:
1. Resize to 224x224 (model's expected size)
2. Convert to array
3. Add batch dimension
4. Preprocess for MobileNetV2
Args:
img: PIL Image
Returns:
Preprocessed image array
"""
# Resize to 224x224 pixels
img = img.resize((224, 224))
# Convert to numpy array
img_array = np.array(img)
# Add batch dimension (model expects multiple images)
img_array = np.expand_dims(img_array, axis=0)
# Preprocess for MobileNetV2
img_array = preprocess_input(img_array)
return img_array
def classify_image(img):
"""
Classify an image and return top predictions.
Args:
img: PIL Image
Returns:
List of (class_name, confidence) tuples
"""
# Prepare the image
img_array = prepare_image(img)
# Make prediction
predictions = model.predict(img_array, verbose=0)
# Decode predictions to human-readable labels
# top=5 means we get the top 5 most likely classes
decoded = decode_predictions(predictions, top=5)[0]
# Convert to simpler format
results = [(label, float(confidence)) for (_, label, confidence) in decoded]
return results
print("✅ Helper functions ready!")
Schritt 4: Testen mit Beispielbildern
Lass uns einige Bilder aus dem Internet klassifizieren!
# Sample images to classify
# These are from Unsplash (free stock photos)
test_images = [
{
"url": "https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?w=400",
"description": "A cat"
},
{
"url": "https://images.unsplash.com/photo-1552053831-71594a27632d?w=400",
"description": "A dog"
},
{
"url": "https://images.unsplash.com/photo-1511919884226-fd3cad34687c?w=400",
"description": "A car"
},
]
print(f"🧪 Testing on {len(test_images)} images...")
print("=" * 70)
Klassifizieren Sie jedes Bild
for i, img_data in enumerate(test_images, 1):
print(f"\n📸 Image {i}: {img_data['description']}")
print("-" * 70)
try:
# Load image
img = load_image_from_url(img_data['url'])
# Display image
display(img.resize((200, 200))) # Show smaller version
# Classify
results = classify_image(img)
# Show predictions
print("\n🎯 Top 5 Predictions:")
for rank, (label, confidence) in enumerate(results, 1):
# Create a visual bar
bar_length = int(confidence * 50)
bar = "█" * bar_length
print(f" {rank}. {label:20s} {confidence*100:5.2f}% {bar}")
except Exception as e:
print(f"❌ Error: {e}")
print("\n" + "=" * 70)
Schritt 5: Probieren Sie Ihre eigenen Bilder aus!
Ersetzen Sie die untenstehende URL durch eine beliebige Bild-URL, die Sie klassifizieren möchten.
# Try your own image!
# Replace this URL with any image URL
custom_image_url = "https://images.unsplash.com/photo-1472491235688-bdc81a63246e?w=400" # A flower
print("🖼️ Classifying your custom image...")
print("=" * 70)
try:
# Load and show image
img = load_image_from_url(custom_image_url)
display(img.resize((300, 300)))
# Classify
results = classify_image(img)
# Show results
print("\n🎯 Top 5 Predictions:")
print("-" * 70)
for rank, (label, confidence) in enumerate(results, 1):
bar_length = int(confidence * 50)
bar = "█" * bar_length
print(f" {rank}. {label:20s} {confidence*100:5.2f}% {bar}")
# Highlight top prediction
top_label, top_confidence = results[0]
print("\n" + "=" * 70)
print(f"\n🏆 Best guess: {top_label} ({top_confidence*100:.2f}% confident)")
except Exception as e:
print(f"❌ Error: {e}")
print(" Make sure the URL points to a valid image!")
💡 Was ist gerade passiert?
- Wir haben ein vortrainiertes Modell geladen - MobileNetV2 wurde mit Millionen von Bildern trainiert.
- Wir haben Bilder vorverarbeitet - Sie wurden für das Modell passend skaliert und formatiert.
- Das Modell hat Vorhersagen getroffen - Es hat Wahrscheinlichkeiten für 1000 Objektklassen ausgegeben.
- Wir haben die Ergebnisse dekodiert - Zahlen wurden in menschenlesbare Labels umgewandelt.
Verständnis der Vertrauenswerte
- 90-100%: Sehr sicher (fast garantiert korrekt)
- 70-90%: Sicher (wahrscheinlich korrekt)
- 50-70%: Etwas sicher (könnte korrekt sein)
- Unter 50%: Nicht sehr sicher (unsicher)
Warum könnten Vorhersagen falsch sein?
- Ungewöhnlicher Winkel oder Beleuchtung - Das Modell wurde mit typischen Fotos trainiert.
- Mehrere Objekte - Das Modell erwartet ein Hauptobjekt.
- Seltene Objekte - Das Modell kennt nur 1000 Kategorien.
- Schlechte Bildqualität - Verschwommene oder verpixelte Bilder sind schwieriger zu erkennen.
🚀 Nächste Schritte
-
Probieren Sie verschiedene Bilder aus: - Finden Sie Bilder auf Unsplash - Rechtsklick → „Bildadresse kopieren“, um die URL zu erhalten
-
Experimentieren: - Was passiert mit abstrakter Kunst? - Kann es Objekte aus verschiedenen Blickwinkeln erkennen? - Wie geht es mit mehreren Objekten um?
-
Mehr erfahren: - Erkunden Sie Computer Vision Lektionen - Lernen Sie, Ihren eigenen Bildklassifikator zu trainieren - Verstehen Sie, wie CNNs (Convolutional Neural Networks) funktionieren
🎉 Herzlichen Glückwunsch!
Sie haben gerade einen Bildklassifikator mit einem hochmodernen neuronalen Netzwerk erstellt!
Diese Technik wird verwendet für: - Google Fotos (Organisieren Ihrer Bilder) - Selbstfahrende Autos (Objekterkennung) - Medizinische Diagnosen (Analyse von Röntgenbildern) - Qualitätskontrolle (Erkennung von Defekten)
Bleiben Sie neugierig und lernen Sie weiter! 🚀
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Anfängerfreundliche KI-Beispiele
Willkommen! Dieses Verzeichnis enthält einfache, eigenständige Beispiele, die Ihnen den Einstieg in KI und maschinelles Lernen erleichtern sollen. Jedes Beispiel ist anfängerfreundlich gestaltet und enthält ausführliche Kommentare sowie Schritt-für-Schritt-Erklärungen.
📚 Überblick über die Beispiele
| Beispiel | Beschreibung | Schwierigkeitsgrad | Voraussetzungen |
|---|---|---|---|
| Hello AI World | Ihr erstes KI-Programm – einfache Mustererkennung | ⭐ Anfänger | Grundkenntnisse in Python |
| Einfaches Neuronales Netzwerk | Erstellen Sie ein neuronales Netzwerk von Grund auf | ⭐⭐ Anfänger+ | Python, grundlegende Mathematik |
| Bildklassifikator | Klassifizieren Sie Bilder mit einem vortrainierten Modell | ⭐⭐ Anfänger+ | Python, numpy |
| Textstimmung | Analysieren Sie die Stimmung von Texten (positiv/negativ) | ⭐⭐ Anfänger+ | Python |
🚀 Erste Schritte
Voraussetzungen
Stellen Sie sicher, dass Python installiert ist (empfohlen wird Version 3.8 oder höher). Installieren Sie die benötigten Pakete:
# For Python scripts
pip install numpy
# For Jupyter notebooks (image classifier)
pip install jupyter numpy pillow tensorflow
Oder verwenden Sie die Conda-Umgebung aus dem Hauptcurriculum:
conda env create --name ai4beg --file ../environment.yml
conda activate ai4beg
Ausführen der Beispiele
Für Python-Skripte (.py-Dateien):
python 01-hello-ai-world.py
Für Jupyter-Notebooks (.ipynb-Dateien):
jupyter notebook 03-image-classifier.ipynb
📖 Lernpfad
Wir empfehlen, die Beispiele in der folgenden Reihenfolge zu bearbeiten:
- Beginnen Sie mit "Hello AI World" – Lernen Sie die Grundlagen der Mustererkennung
- Erstellen Sie ein einfaches neuronales Netzwerk – Verstehen Sie, wie neuronale Netzwerke funktionieren
- Probieren Sie den Bildklassifikator aus – Erleben Sie KI in Aktion mit echten Bildern
- Analysieren Sie die Textstimmung – Erkunden Sie die Verarbeitung natürlicher Sprache
💡 Tipps für Anfänger
- Lesen Sie die Kommentare im Code sorgfältig – Sie erklären, was jede Zeile macht
- Experimentieren Sie! – Ändern Sie Werte und sehen Sie, was passiert
- Machen Sie sich keine Sorgen, alles sofort zu verstehen – Lernen braucht Zeit
- Stellen Sie Fragen – Nutzen Sie das Diskussionsforum
🔗 Nächste Schritte
Nachdem Sie diese Beispiele abgeschlossen haben, erkunden Sie das vollständige Curriculum: - Einführung in KI - Neuronale Netzwerke - Computer Vision - Verarbeitung natürlicher Sprache
🤝 Mitwirken
Fanden Sie diese Beispiele hilfreich? Helfen Sie uns, sie zu verbessern: - Melden Sie Probleme oder schlagen Sie Verbesserungen vor - Fügen Sie weitere Beispiele für Anfänger hinzu - Verbessern Sie die Dokumentation und Kommentare
Denken Sie daran: Jeder Experte war einmal ein Anfänger. Viel Spaß beim Lernen! 🎓
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Für Lehrkräfte
Möchten Sie dieses Curriculum in Ihrem Unterricht verwenden? Fühlen Sie sich frei, es zu nutzen!
Tatsächlich können Sie es direkt auf GitHub verwenden, indem Sie GitHub Classroom nutzen.
Dazu müssen Sie dieses Repository forken. Sie müssen für jede Lektion ein eigenes Repository erstellen, indem Sie jeden Ordner in ein separates Repository extrahieren. Auf diese Weise kann GitHub Classroom jede Lektion einzeln erfassen.
Diese vollständigen Anweisungen geben Ihnen eine Vorstellung davon, wie Sie Ihr Klassenzimmer einrichten können.
Nutzung des Repos wie es ist
Wenn Sie dieses Repository in seiner aktuellen Form verwenden möchten, ohne GitHub Classroom zu nutzen, ist das ebenfalls möglich. Sie müssten Ihren Schülern mitteilen, welche Lektion Sie gemeinsam durcharbeiten möchten.
In einem Online-Format (Zoom, Teams oder andere) könnten Sie Breakout-Räume für die Quizfragen einrichten und die Schüler unterstützen, damit sie bereit sind zu lernen. Anschließend können Sie die Schüler einladen, die Quizfragen zu bearbeiten und ihre Antworten zu einem bestimmten Zeitpunkt als 'Issues' einzureichen. Dasselbe könnten Sie mit Aufgaben machen, wenn Sie möchten, dass die Schüler offen und kollaborativ arbeiten.
Wenn Sie ein privateres Format bevorzugen, bitten Sie Ihre Schüler, das Curriculum Lektion für Lektion in ihre eigenen privaten GitHub-Repositories zu forken und Ihnen Zugriff zu gewähren. So können sie Quizfragen und Aufgaben privat bearbeiten und diese über Issues in Ihrem Klassen-Repository einreichen.
Es gibt viele Möglichkeiten, dies in einem Online-Klassenzimmer-Format umzusetzen. Lassen Sie uns wissen, was für Sie am besten funktioniert!
Bitte teilen Sie uns Ihre Meinung mit
Wir möchten, dass dieses Curriculum für Sie und Ihre Schüler funktioniert. Bitte geben Sie uns Feedback in den Diskussionsforen!
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Wie man den Code ausführt
Dieses Curriculum enthält viele ausführbare Beispiele und Labs, die Sie ausführen möchten. Um dies zu tun, benötigen Sie die Möglichkeit, Python-Code in Jupyter Notebooks auszuführen, die als Teil dieses Curriculums bereitgestellt werden. Sie haben mehrere Optionen, um den Code auszuführen:
Lokal auf Ihrem Computer ausführen
Um den Code lokal auf Ihrem Computer auszuführen, ist eine Python-Installation erforderlich. Eine Empfehlung ist die Installation von miniconda – es ist eine eher leichtgewichtige Installation, die den conda Paketmanager für verschiedene Python-virtuelle Umgebungen unterstützt.
Nachdem Sie miniconda installiert haben, klonen Sie das Repository und erstellen eine virtuelle Umgebung, die für diesen Kurs verwendet wird:
git clone http://github.com/microsoft/ai-for-beginners
cd ai-for-beginners
conda env create --name ai4beg --file .devcontainer/environment.yml
conda activate ai4beg
Verwendung von Visual Studio Code mit Python-Erweiterung
Dieses Curriculum wird am besten verwendet, wenn es in Visual Studio Code mit der Python-Erweiterung geöffnet wird.
> Hinweis: Sobald Sie das Verzeichnis klonen und in VS Code öffnen, wird automatisch vorgeschlagen, Python-Erweiterungen zu installieren. Sie müssen auch miniconda wie oben beschrieben installieren.
> Hinweis: Wenn VS Code vorschlägt, das Repository in einem Container erneut zu öffnen, sollten Sie dies ablehnen, um die lokale Python-Installation zu verwenden.
Verwendung von Jupyter im Browser
Sie können auch eine Jupyter-Umgebung aus dem Browser auf Ihrem eigenen Computer verwenden. Sowohl klassisches Jupyter als auch JupyterHub bieten eine bequeme Entwicklungsumgebung mit Autovervollständigung, Code-Hervorhebung usw.
Um Jupyter lokal zu starten, wechseln Sie in das Verzeichnis des Kurses und führen aus:
jupyter notebook
oder
jupyterhub
Sie können dann zu einer beliebigen .ipynb-Datei navigieren, sie öffnen und mit der Arbeit beginnen.
Ausführen in einem Container
Eine Alternative zur Python-Installation wäre das Ausführen des Codes in einem Container. Da unser Repository einen speziellen .devcontainer-Ordner bereitstellt, der beschreibt, wie ein Container für dieses Repo gebaut wird, bietet VS Code die Möglichkeit, den Code in einem Container erneut zu öffnen. Dies erfordert die Installation von Docker und wäre auch komplexer, daher empfehlen wir dies eher erfahrenen Nutzern.
Ausführung in der Cloud
Wenn Sie Python nicht lokal installieren möchten und Zugriff auf Cloud-Ressourcen haben – eine gute Alternative ist es, den Code in der Cloud auszuführen. Es gibt mehrere Möglichkeiten, dies zu tun:
- Verwendung von GitHub Codespaces, einer virtuellen Umgebung, die für Sie auf GitHub erstellt wird und über eine VS Code-Browseroberfläche zugänglich ist. Wenn Sie Zugriff auf Codespaces haben, können Sie einfach auf die Code-Schaltfläche im Repo klicken, einen Codespace starten und sofort loslegen.
- Verwendung von Binder. Binder bietet kostenfreie Cloud-Computing-Ressourcen für Personen wie Sie, um Code auf GitHub auszuprobieren. Es gibt eine Schaltfläche auf der Startseite, um das Repository in Binder zu öffnen – dies sollte Sie schnell auf die Binder-Seite bringen, die einen zugrundeliegenden Container baut und nahtlos eine Jupyter-Weboberfläche für Sie startet.
> Hinweis: Zur Vermeidung von Missbrauch hat Binder den Zugriff auf einige Webressourcen blockiert. Dies kann verhindern, dass ein Teil des Codes funktioniert, der Modelle und/oder Datensätze aus dem öffentlichen Internet lädt. Sie müssen möglicherweise einige Umgehungen finden. Außerdem sind die von Binder bereitgestellten Rechenressourcen eher grundlegend, sodass das Training langsam sein wird, besonders in späteren, komplexeren Lektionen.
Ausführung in der Cloud mit GPU
Einige der späteren Lektionen in diesem Curriculum würden erheblich von GPU-Unterstützung profitieren. Das Modelltraining kann sonst sehr langsam sein. Es gibt einige Möglichkeiten, die Sie nutzen können, besonders wenn Sie über Azure for Students oder über Ihre Institution Zugang zur Cloud haben:
- Erstellen Sie eine Data Science Virtual Machine und verbinden Sie sich über Jupyter mit ihr. Sie können dann das Repo direkt auf die Maschine klonen und mit dem Lernen beginnen. NC-Serien VMs unterstützen GPU.
> Hinweis: Einige Abonnements, einschließlich Azure for Students, bieten nicht standardmäßig GPU-Unterstützung. Möglicherweise müssen Sie zusätzliche GPU-Kerne per technischem Supportantrag anfordern.
- Erstellen Sie einen Azure Machine Learning Workspace und verwenden Sie dort die Notizbuchfunktion. Dieses Video zeigt, wie man ein Repository in ein Azure ML-Notizbuch klont und es verwendet.
Sie können auch Google Colab verwenden, das über eine kostenlose GPU-Unterstützung verfügt, und Jupyter Notebooks dort hochladen, um sie einzeln auszuführen.
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir bemüht sind, eine genaue Übersetzung zu gewährleisten, sollten Sie beachten, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache gilt als verbindliche Quelle. Für wichtige Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Einstieg in dieses Curriculum
Bist du ein Student?
Beginne mit den folgenden Ressourcen:
- Student Hub Seite Auf dieser Seite findest du Ressourcen für Anfänger, Student Packs und sogar Möglichkeiten, einen kostenlosen Zertifikatsgutschein zu erhalten. Diese Seite solltest du dir unbedingt als Lesezeichen speichern und regelmäßig besuchen, da wir den Inhalt mindestens monatlich aktualisieren.
- Microsoft Student Learn Ambassadors Werde Teil einer globalen Gemeinschaft von Studentenbotschaftern – dies könnte dein Einstieg bei Microsoft sein.
Studenten, es gibt mehrere Möglichkeiten, das Curriculum zu nutzen. Zunächst kannst du einfach den Text lesen und den Code direkt auf GitHub durchsehen. Wenn du den Code in einem der Notebooks ausführen möchtest, lies unsere Anweisungen und finde weitere Tipps dazu in diesem Blogbeitrag.
> Note: Anweisungen, wie man den Code in diesem Curriculum ausführt
Selbststudium
Falls du den Kurs als Selbststudienprojekt absolvieren möchtest, empfehlen wir dir, das gesamte Repository in deinen eigenen GitHub-Account zu forken und die Übungen eigenständig oder in einer Gruppe zu bearbeiten:
- Beginne mit einem Quiz vor der Vorlesung.
- Lies den Einführungstext zur Vorlesung.
- Falls die Vorlesung zusätzliche Notebooks enthält, arbeite diese durch, indem du den Code liest und ausführst. Wenn sowohl TensorFlow- als auch PyTorch-Notebooks bereitgestellt werden, kannst du dich auf eines davon konzentrieren – wähle dein bevorzugtes Framework.
- In den Notebooks gibt es oft Herausforderungen, bei denen du den Code ein wenig anpassen musst, um zu experimentieren.
- Mache das Quiz nach der Vorlesung.
- Falls ein Labor mit dem Modul verbunden ist, bearbeite die Aufgabe.
- Besuche das Diskussionsforum, um "laut zu lernen".
> Für weiterführendes Lernen empfehlen wir, diese Microsoft Learn Module und Lernpfade zu verfolgen.
Lehrer, wir haben einige Vorschläge aufgenommen, wie dieses Curriculum genutzt werden kann.
Pädagogik
Wir haben zwei pädagogische Grundsätze gewählt, während wir dieses Curriculum erstellt haben: sicherzustellen, dass es projektbasiert und hands-on ist und dass es häufige Quizfragen enthält.
Indem wir sicherstellen, dass der Inhalt auf Projekte abgestimmt ist, wird der Lernprozess für Studenten ansprechender und das Verständnis der Konzepte wird verbessert. Außerdem setzt ein niedrigschwelliges Quiz vor einer Klasse die Absicht des Studenten, ein Thema zu lernen, während ein zweites Quiz nach der Klasse das Verständnis weiter festigt. Dieses Curriculum wurde so gestaltet, dass es flexibel und unterhaltsam ist und entweder vollständig oder teilweise absolviert werden kann. Die Projekte beginnen klein und werden bis zum Ende des 12-Wochen-Zyklus zunehmend komplexer.
> Eine Anmerkung zu den Quizfragen: Alle Quizfragen sind in dieser App enthalten, insgesamt 50 Quizfragen mit jeweils drei Fragen. Sie sind in den Lektionen verlinkt, aber die Quiz-App kann lokal ausgeführt werden; folge den Anweisungen im etc/quiz-app Ordner.
Offline-Zugriff
Du kannst diese Dokumentation offline nutzen, indem du Docsify verwendest. Forke dieses Repository, installiere Docsify auf deinem lokalen Rechner und gib dann im Root-Ordner dieses Repositories docsify serve ein. Die Website wird auf Port 3000 auf deinem localhost bereitgestellt: localhost:3000. Eine PDF-Version des Curriculums ist unter diesem Link verfügbar.
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Game Jam
Spiele sind ein Bereich, der stark von Entwicklungen in KI und ML beeinflusst wurde. In dieser Aufgabe sollst du ein kurzes Essay über ein Spiel schreiben, das dir gefällt und das von der Entwicklung der KI beeinflusst wurde. Es sollte ein Spiel sein, das alt genug ist, um von verschiedenen Arten von Computersystemen beeinflusst worden zu sein. Ein gutes Beispiel ist Schach oder Go, aber schaue dir auch Videospiele wie Pong oder Pac-Man an. Schreibe einen Aufsatz, der die Vergangenheit, Gegenwart und die KI-Zukunft des Spiels diskutiert.
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Einführung in KI

> Sketchnote von Tomomi Imura
Quiz vor der Vorlesung
Künstliche Intelligenz ist eine spannende wissenschaftliche Disziplin, die untersucht, wie wir Computer dazu bringen können, intelligentes Verhalten zu zeigen, z. B. Dinge zu tun, die Menschen gut können.
Ursprünglich wurden Computer von Charles Babbage erfunden, um Zahlen nach einem klar definierten Verfahren – einem Algorithmus – zu verarbeiten. Moderne Computer, obwohl sie wesentlich fortschrittlicher sind als das ursprüngliche Modell aus dem 19. Jahrhundert, folgen immer noch derselben Idee kontrollierter Berechnungen. Daher ist es möglich, einen Computer so zu programmieren, dass er etwas tut, wenn wir die genaue Abfolge der Schritte kennen, die wir ausführen müssen, um das Ziel zu erreichen.

> Foto von Vickie Soshnikova
> ✅ Das Alter einer Person anhand eines Fotos zu bestimmen, ist eine Aufgabe, die nicht explizit programmiert werden kann, da wir nicht wissen, wie wir die Zahl in unserem Kopf ermitteln, wenn wir es tun.
Es gibt jedoch Aufgaben, bei denen wir nicht genau wissen, wie wir sie lösen können. Überlegen Sie, wie man das Alter einer Person anhand eines Fotos bestimmt. Wir lernen es irgendwie, weil wir viele Beispiele von Menschen unterschiedlichen Alters gesehen haben, aber wir können nicht genau erklären, wie wir es tun, noch können wir den Computer so programmieren, dass er es tut. Genau solche Aufgaben interessieren die Künstliche Intelligenz (kurz KI).
✅ Überlegen Sie sich einige Aufgaben, die Sie an einen Computer auslagern könnten und die von KI profitieren würden. Denken Sie an die Bereiche Finanzen, Medizin und Kunst – wie profitieren diese Bereiche heute von KI?
Schwache KI vs. Starke KI
| Schwache KI | Starke KI |
|---|---|
| Schwache KI bezieht sich auf KI-Systeme, die für eine spezifische Aufgabe oder eine enge Aufgabenmenge entwickelt und trainiert wurden. | Starke KI, oder Allgemeine Künstliche Intelligenz (AGI), bezieht sich auf KI-Systeme mit menschlicher Intelligenz und Verständnis. |
| Diese KI-Systeme sind nicht allgemein intelligent; sie sind hervorragend darin, eine vordefinierte Aufgabe auszuführen, besitzen jedoch kein echtes Verständnis oder Bewusstsein. | Diese KI-Systeme können jede intellektuelle Aufgabe ausführen, die ein Mensch bewältigen kann, sich an verschiedene Bereiche anpassen und eine Form von Bewusstsein oder Selbstwahrnehmung besitzen. |
| Beispiele für schwache KI sind virtuelle Assistenten wie Siri oder Alexa, Empfehlungsalgorithmen von Streaming-Diensten und Chatbots, die für spezifische Kundenservice-Aufgaben entwickelt wurden. | Das Erreichen von Starker KI ist ein langfristiges Ziel der KI-Forschung und würde die Entwicklung von KI-Systemen erfordern, die in der Lage sind, zu argumentieren, zu lernen, zu verstehen und sich über eine Vielzahl von Aufgaben und Kontexten hinweg anzupassen. |
| Schwache KI ist hochspezialisiert und besitzt keine menschenähnlichen kognitiven Fähigkeiten oder allgemeine Problemlösungsfähigkeiten außerhalb ihres engen Bereichs. | Starke KI ist derzeit ein theoretisches Konzept, und kein KI-System hat dieses Niveau allgemeiner Intelligenz erreicht. |
Weitere Informationen finden Sie unter Allgemeine Künstliche Intelligenz (AGI).
Die Definition von Intelligenz und der Turing-Test
Eines der Probleme im Umgang mit dem Begriff Intelligenz ist, dass es keine klare Definition dieses Begriffs gibt. Man könnte argumentieren, dass Intelligenz mit abstraktem Denken oder Selbstbewusstsein verbunden ist, aber wir können sie nicht eindeutig definieren.

> Foto von Amber Kipp auf Unsplash
Um die Mehrdeutigkeit des Begriffs Intelligenz zu verdeutlichen, versuchen Sie, folgende Frage zu beantworten: "Ist eine Katze intelligent?". Verschiedene Menschen neigen dazu, unterschiedliche Antworten auf diese Frage zu geben, da es keinen allgemein anerkannten Test gibt, um die Behauptung zu beweisen oder zu widerlegen. Und wenn Sie denken, es gäbe einen – versuchen Sie, Ihre Katze durch einen IQ-Test zu schicken...
✅ Denken Sie eine Minute darüber nach, wie Sie Intelligenz definieren. Ist eine Krähe, die ein Labyrinth lösen kann, um an Futter zu gelangen, intelligent? Ist ein Kind intelligent?
Wenn wir über AGI sprechen, brauchen wir eine Möglichkeit, festzustellen, ob wir ein wirklich intelligentes System geschaffen haben. Alan Turing schlug eine Methode vor, die als Turing-Test bekannt ist und gleichzeitig als Definition von Intelligenz dient. Der Test vergleicht ein gegebenes System mit etwas inhärent Intelligenten – einem echten Menschen. Da jeder automatische Vergleich von einem Computerprogramm umgangen werden kann, verwenden wir einen menschlichen Befrager. Wenn ein Mensch nicht in der Lage ist, zwischen einer echten Person und einem Computersystem in einem textbasierten Dialog zu unterscheiden, wird das System als intelligent angesehen.
> Ein Chatbot namens Eugene Goostman, entwickelt in St. Petersburg, kam 2014 dem Bestehen des Turing-Tests nahe, indem er einen cleveren Persönlichkeitstrick anwandte. Er gab von Anfang an an, ein 13-jähriger ukrainischer Junge zu sein, was das fehlende Wissen und einige Unstimmigkeiten im Text erklären würde. Der Bot überzeugte 30 % der Richter, dass er ein Mensch sei, nach einem 5-minütigen Dialog – eine Metrik, von der Turing glaubte, dass sie eine Maschine bis zum Jahr 2000 erreichen könnte. Man sollte jedoch verstehen, dass dies nicht bedeutet, dass wir ein intelligentes System geschaffen haben oder dass ein Computersystem den menschlichen Befrager getäuscht hat – das System hat die Menschen nicht getäuscht, sondern die Bot-Entwickler!
✅ Wurden Sie jemals von einem Chatbot getäuscht und dachten, Sie sprechen mit einem Menschen? Wie hat er Sie überzeugt?
Verschiedene Ansätze zur KI
Wenn wir wollen, dass ein Computer sich wie ein Mensch verhält, müssen wir irgendwie unsere Denkweise im Computer modellieren. Folglich müssen wir versuchen zu verstehen, was einen Menschen intelligent macht.
> Um Intelligenz in eine Maschine programmieren zu können, müssen wir verstehen, wie unsere eigenen Entscheidungsprozesse funktionieren. Wenn Sie ein wenig Selbstreflexion betreiben, werden Sie feststellen, dass einige Prozesse unbewusst ablaufen – z. B. können wir eine Katze von einem Hund unterscheiden, ohne darüber nachzudenken – während andere Überlegungen erfordern.
Es gibt zwei mögliche Ansätze für dieses Problem:
| Top-down-Ansatz (symbolisches Denken) | Bottom-up-Ansatz (Neuronale Netze) |
|---|---|
| Ein Top-down-Ansatz modelliert die Art und Weise, wie eine Person denkt, um ein Problem zu lösen. Es beinhaltet das Extrahieren von Wissen von einem Menschen und das Darstellen in einer computerlesbaren Form. Wir müssen auch eine Möglichkeit entwickeln, Schlussfolgerungen im Computer zu modellieren. | Ein Bottom-up-Ansatz modelliert die Struktur des menschlichen Gehirns, das aus einer großen Anzahl einfacher Einheiten besteht, die als Neuronen bezeichnet werden. Jedes Neuron agiert wie ein gewichteter Durchschnitt seiner Eingaben, und wir können ein Netzwerk von Neuronen trainieren, um nützliche Probleme zu lösen, indem wir Trainingsdaten bereitstellen. |
Es gibt auch einige andere mögliche Ansätze zur Intelligenz:
-
Ein emergenter, synergetischer oder Multi-Agenten-Ansatz basiert auf der Tatsache, dass komplexes intelligentes Verhalten durch die Interaktion einer großen Anzahl einfacher Agenten entstehen kann. Laut der evolutionären Kybernetik kann Intelligenz im Prozess des Metasystem-Übergangs aus einfacheren, reaktiven Verhaltensweisen entstehen.
-
Ein evolutionärer Ansatz oder genetischer Algorithmus ist ein Optimierungsprozess, der auf den Prinzipien der Evolution basiert.
Wir werden diese Ansätze später im Kurs betrachten, aber im Moment konzentrieren wir uns auf zwei Hauptansätze: Top-down und Bottom-up.
Der Top-Down-Ansatz
Beim Top-down-Ansatz versuchen wir, unser Denken zu modellieren. Da wir unseren Gedanken folgen können, wenn wir nachdenken, können wir versuchen, diesen Prozess zu formalisieren und ihn im Computer zu programmieren. Dies wird als symbolisches Denken bezeichnet.
Menschen haben oft Regeln im Kopf, die ihre Entscheidungsprozesse leiten. Zum Beispiel kann ein Arzt bei der Diagnose eines Patienten feststellen, dass eine Person Fieber hat und daher möglicherweise eine Entzündung im Körper vorliegt. Durch die Anwendung einer großen Menge von Regeln auf ein spezifisches Problem kann ein Arzt möglicherweise die endgültige Diagnose stellen.
Dieser Ansatz stützt sich stark auf Wissensrepräsentation und Schlussfolgerungen. Wissen von einem menschlichen Experten zu extrahieren, könnte der schwierigste Teil sein, da ein Arzt in vielen Fällen nicht genau weiß, warum er oder sie zu einer bestimmten Diagnose kommt. Manchmal kommt die Lösung einfach in den Kopf, ohne explizites Nachdenken. Einige Aufgaben, wie das Bestimmen des Alters einer Person anhand eines Fotos, können überhaupt nicht auf die Manipulation von Wissen reduziert werden.
Bottom-Up-Ansatz
Alternativ können wir versuchen, die einfachsten Elemente in unserem Gehirn zu modellieren – ein Neuron. Wir können ein sogenanntes künstliches neuronales Netzwerk im Computer konstruieren und dann versuchen, es durch Beispiele zu trainieren, um Probleme zu lösen. Dieser Prozess ähnelt dem, wie ein neugeborenes Kind seine Umgebung durch Beobachtungen kennenlernt.
✅ Recherchieren Sie ein wenig, wie Babys lernen. Was sind die grundlegenden Elemente des Gehirns eines Babys?
> | Was ist mit ML? | |
> |--------------|-----------|
> | Ein Teil der Künstlichen Intelligenz, der darauf basiert, dass Computer lernen, ein Problem anhand von Daten zu lösen, wird als Maschinelles Lernen bezeichnet. Wir werden klassisches maschinelles Lernen in diesem Kurs nicht behandeln – wir verweisen Sie auf den separaten Maschinelles Lernen für Anfänger-Lehrplan. |
|
Ein kurzer Überblick über die Geschichte der KI
Künstliche Intelligenz wurde Mitte des 20. Jahrhunderts als Forschungsfeld begründet. Anfangs war symbolisches Denken der vorherrschende Ansatz, und es führte zu einer Reihe wichtiger Erfolge, wie z. B. Expertensysteme – Computerprogramme, die in der Lage waren, in begrenzten Problembereichen als Experte zu agieren. Es wurde jedoch bald klar, dass ein solcher Ansatz nicht gut skalierbar ist. Wissen von einem Experten zu extrahieren, es im Computer darzustellen und diese Wissensbasis aktuell zu halten, stellte sich als sehr komplexe Aufgabe heraus und war in vielen Fällen zu teuer, um praktikabel zu sein. Dies führte in den 1970er Jahren zum sogenannten KI-Winter.
<img alt="Kurze Geschichte der KI" src="../../../../translated_images/de/history-of-ai.7e83efa70b537f5a.webp" width="70%"/>
> Bild von Dmitry Soshnikov
Mit der Zeit wurden Rechenressourcen günstiger, und es standen mehr Daten zur Verfügung, sodass neuronale Netzwerke in vielen Bereichen, wie z. B. der Computer Vision oder dem Sprachverständnis, großartige Leistungen zeigten. In den letzten zehn Jahren wurde der Begriff Künstliche Intelligenz meist als Synonym für Neuronale Netzwerke verwendet, da die meisten Erfolge der KI, von denen wir hören, auf ihnen basieren.
Wir können beobachten, wie sich die Ansätze geändert haben, z. B. bei der Entwicklung eines Schachprogramms:
- Frühe Schachprogramme basierten auf der Suche – ein Programm versuchte explizit, mögliche Züge eines Gegners für eine bestimmte Anzahl von Zügen vorauszuschätzen und wählte einen optimalen Zug basierend auf der besten Position, die in wenigen Zügen erreicht werden kann. Dies führte zur Entwicklung des sogenannten Alpha-Beta-Suchalgorithmus.
- Suchstrategien funktionieren gut gegen Ende des Spiels, wenn der Suchraum durch eine geringe Anzahl möglicher Züge begrenzt ist. Zu Beginn des Spiels ist der Suchraum jedoch riesig, und der Algorithmus kann durch das Lernen aus bestehenden Partien zwischen menschlichen Spielern verbessert werden. Spätere Experimente verwendeten sogenanntes Fallbasiertes Schließen, bei dem das Programm nach Fällen in der Wissensbasis suchte, die der aktuellen Spielsituation sehr ähnlich sind.
- Moderne Programme, die menschliche Spieler besiegen, basieren auf neuronalen Netzwerken und Verstärkungslernen, bei dem die Programme allein durch das Spielen gegen sich selbst und das Lernen aus ihren eigenen Fehlern lernen – ähnlich wie Menschen, wenn sie Schach lernen. Ein Computerprogramm kann jedoch viel mehr Spiele in viel kürzerer Zeit spielen und somit viel schneller lernen.
✅ Recherchieren Sie ein wenig über andere Spiele, die von KI gespielt wurden.
Ähnlich können wir sehen, wie sich der Ansatz zur Erstellung von „sprechenden Programmen“ (die den Turing-Test bestehen könnten) verändert hat:
- Frühe Programme dieser Art, wie Eliza, basierten auf sehr einfachen grammatikalischen Regeln und der Umformulierung des Eingabesatzes in eine Frage.
- Moderne Assistenten wie Cortana, Siri oder Google Assistant sind alle Hybridsysteme, die neuronale Netzwerke verwenden, um Sprache in Text umzuwandeln und unsere Absicht zu erkennen, und dann einige Schlussfolgerungen oder explizite Algorithmen anwenden, um die erforderlichen Aktionen auszuführen.
- In der Zukunft können wir erwarten, dass ein vollständiges neuronales Modell den Dialog eigenständig handhabt. Die jüngsten GPT- und Turing-NLG-Familien von neuronalen Netzwerken zeigen große Erfolge in diesem Bereich.
<img alt="Die Entwicklung des Turing-Tests" src="../../../../translated_images/de/turing-test-evol.4184696701293ead.webp" width="70%"/> > Bild von Dmitry Soshnikov, Foto von Marina Abrosimova, Unsplash
Aktuelle KI-Forschung
Das enorme Wachstum der Forschung zu neuronalen Netzwerken begann etwa 2010, als große öffentliche Datensätze verfügbar wurden. Eine riesige Sammlung von Bildern namens ImageNet, die etwa 14 Millionen annotierte Bilder enthält, führte zur Entstehung der ImageNet Large Scale Visual Recognition Challenge.

> Bild von Dmitry Soshnikov
Im Jahr 2012 wurden Convolutional Neural Networks erstmals für die Bildklassifikation eingesetzt, was zu einem signifikanten Rückgang der Klassifikationsfehler führte (von fast 30 % auf 16,4 %). Im Jahr 2015 erreichte die ResNet-Architektur von Microsoft Research menschliche Genauigkeit.
Seitdem haben neuronale Netzwerke in vielen Aufgaben sehr erfolgreiche Ergebnisse gezeigt:
| Jahr | Menschliche Gleichwertigkeit erreicht |
|---|---|
| 2015 | Bildklassifikation |
| 2016 | Gesprächsbasierte Spracherkennung |
| 2018 | Automatische maschinelle Übersetzung (Chinesisch-Englisch) |
| 2020 | Bildbeschreibung |
In den letzten Jahren haben wir große Erfolge mit großen Sprachmodellen wie BERT und GPT-3 erlebt. Dies geschah vor allem, weil es eine große Menge an allgemeinen Textdaten gibt, die es uns ermöglichen, Modelle zu trainieren, um die Struktur und Bedeutung von Texten zu erfassen, sie auf allgemeinen Textsammlungen vorzutrainieren und diese Modelle dann für spezifischere Aufgaben zu spezialisieren. Wir werden später in diesem Kurs mehr über Natural Language Processing lernen.
🚀 Herausforderung
Machen Sie eine Internet-Recherche, um herauszufinden, wo Ihrer Meinung nach KI am effektivsten eingesetzt wird. Ist es in einer Karten-App, einem Sprach-zu-Text-Dienst oder einem Videospiel? Recherchieren Sie, wie das System aufgebaut wurde.
Quiz nach der Vorlesung
Rückblick & Selbststudium
Überblicken Sie die Geschichte der KI und des maschinellen Lernens, indem Sie diese Lektion durchlesen. Nehmen Sie ein Element aus der Sketchnote am Anfang dieser Lektion oder dieser hier und recherchieren Sie es genauer, um den kulturellen Kontext zu verstehen, der seine Entwicklung beeinflusst hat.
Aufgabe: Game Jam
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Implementierung eines Expertensystems für Tiere
Ein Beispiel aus dem AI for Beginners Curriculum.
In diesem Beispiel werden wir ein einfaches wissensbasiertes System implementieren, um ein Tier anhand einiger körperlicher Merkmale zu bestimmen. Das System kann durch den folgenden AND-OR-Baum dargestellt werden (dies ist ein Teil des gesamten Baums, wir können problemlos weitere Regeln hinzufügen):

Unser eigenes Expertensystem-Shell mit Rückwärtsverkettung
Lassen Sie uns versuchen, eine einfache Sprache für die Wissensrepräsentation basierend auf Produktionsregeln zu definieren. Wir verwenden Python-Klassen als Schlüsselwörter, um Regeln zu definieren. Es gibt im Wesentlichen 3 Arten von Klassen:
* Ask repräsentiert eine Frage, die dem Benutzer gestellt werden muss. Es enthält die Menge möglicher Antworten.
* If repräsentiert eine Regel und ist nur ein syntaktischer Zucker, um den Inhalt der Regel zu speichern.
* AND/OR sind Klassen, um AND/OR-Verzweigungen des Baums darzustellen. Sie speichern nur die Liste der Argumente darin. Zur Vereinfachung des Codes ist die gesamte Funktionalität in der Oberklasse Content definiert.
class Ask():
def __init__(self,choices=['y','n']):
self.choices = choices
def ask(self):
if max([len(x) for x in self.choices])>1:
for i,x in enumerate(self.choices):
print("{0}. {1}".format(i,x),flush=True)
x = int(input())
return self.choices[x]
else:
print("/".join(self.choices),flush=True)
return input()
class Content():
def __init__(self,x):
self.x=x
class If(Content):
pass
class AND(Content):
pass
class OR(Content):
pass
In unserem System würde das Arbeitsgedächtnis die Liste der Fakten als Attribut-Wert-Paare enthalten. Die Wissensbasis kann als ein großes Wörterbuch definiert werden, das Aktionen (neue Fakten, die in das Arbeitsgedächtnis eingefügt werden sollen) auf Bedingungen abbildet, die als UND-ODER-Ausdrücke dargestellt sind. Außerdem können einige Fakten Ask-ed werden.
rules = {
'default': Ask(['y','n']),
'color' : Ask(['red-brown','black and white','other']),
'pattern' : Ask(['dark stripes','dark spots']),
'mammal': If(OR(['hair','gives milk'])),
'carnivor': If(OR([AND(['sharp teeth','claws','forward-looking eyes']),'eats meat'])),
'ungulate': If(['mammal',OR(['has hooves','chews cud'])]),
'bird': If(OR(['feathers',AND(['flies','lies eggs'])])),
'animal:monkey' : If(['mammal','carnivor','color:red-brown','pattern:dark spots']),
'animal:tiger' : If(['mammal','carnivor','color:red-brown','pattern:dark stripes']),
'animal:giraffe' : If(['ungulate','long neck','long legs','pattern:dark spots']),
'animal:zebra' : If(['ungulate','pattern:dark stripes']),
'animal:ostrich' : If(['bird','long nech','color:black and white','cannot fly']),
'animal:pinguin' : If(['bird','swims','color:black and white','cannot fly']),
'animal:albatross' : If(['bird','flies well'])
}
Um die Rückwärtsinferenz durchzuführen, definieren wir die Klasse Knowledgebase. Sie wird enthalten:
* Arbeitsspeicher memory – ein Wörterbuch, das Attribute auf Werte abbildet
* Knowledgebase-rules im oben definierten Format
Zwei Hauptmethoden sind:
* get, um den Wert eines Attributs zu erhalten, wobei bei Bedarf eine Inferenz durchgeführt wird. Zum Beispiel würde get('color') den Wert eines Farb-Slots abfragen (es wird bei Bedarf gefragt und der Wert für die spätere Verwendung im Arbeitsspeicher gespeichert). Wenn wir get('color:blue') abfragen, wird nach einer Farbe gefragt und dann abhängig von der Farbe ein y/n-Wert zurückgegeben.
* eval führt die eigentliche Inferenz durch, d.h. durchläuft den AND/OR-Baum, bewertet Teilziele usw.
class KnowledgeBase():
def __init__(self,rules):
self.rules = rules
self.memory = {}
def get(self,name):
if ':' in name:
k,v = name.split(':')
vv = self.get(k)
return 'y' if v==vv else 'n'
if name in self.memory.keys():
return self.memory[name]
for fld in self.rules.keys():
if fld==name or fld.startswith(name+":"):
# print(" + proving {}".format(fld))
value = 'y' if fld==name else fld.split(':')[1]
res = self.eval(self.rules[fld],field=name)
if res!='y' and res!='n' and value=='y':
self.memory[name] = res
return res
if res=='y':
self.memory[name] = value
return value
# field is not found, using default
res = self.eval(self.rules['default'],field=name)
self.memory[name]=res
return res
def eval(self,expr,field=None):
# print(" + eval {}".format(expr))
if isinstance(expr,Ask):
print(field)
return expr.ask()
elif isinstance(expr,If):
return self.eval(expr.x)
elif isinstance(expr,AND) or isinstance(expr,list):
expr = expr.x if isinstance(expr,AND) else expr
for x in expr:
if self.eval(x)=='n':
return 'n'
return 'y'
elif isinstance(expr,OR):
for x in expr.x:
if self.eval(x)=='y':
return 'y'
return 'n'
elif isinstance(expr,str):
return self.get(expr)
else:
print("Unknown expr: {}".format(expr))
Definieren wir nun unsere Tierwissensdatenbank und führen die Beratung durch. Beachten Sie, dass Ihnen bei diesem Aufruf Fragen gestellt werden. Sie können mit y/n für Ja-Nein-Fragen antworten oder eine Zahl (0..N) für Fragen mit längeren Mehrfachauswahlantworten angeben.
kb = KnowledgeBase(rules)
kb.get('animal')
Verwendung von Experta für Vorwärts-Schlussfolgerungen
Im nächsten Beispiel werden wir versuchen, Vorwärts-Schlussfolgerungen mit einer der Bibliotheken für Wissensrepräsentation, Experta, zu implementieren. Experta ist eine Bibliothek zur Erstellung von Vorwärts-Schlusssystemen in Python, die so gestaltet ist, dass sie dem klassischen alten System CLIPS ähnelt.
Wir hätten die Vorwärtsverkettung auch selbst ohne große Probleme implementieren können, aber naive Implementierungen sind normalerweise nicht sehr effizient. Für ein effektiveres Regelmatching wird ein spezieller Algorithmus namens Rete verwendet.
import sys
!{sys.executable} -m pip install git+https://github.com/nilp0inter/experta
from experta import *
#import experta
Wir definieren unser System als eine Klasse, die von KnowledgeEngine erbt. Jede Regel wird durch eine separate Funktion mit der @Rule-Annotation definiert, die angibt, wann die Regel ausgelöst werden soll. Innerhalb der Regel können wir mit der Funktion declare neue Fakten hinzufügen, und das Hinzufügen dieser Fakten führt dazu, dass weitere Regeln durch die vorwärtsgerichtete Inferenzmaschine aufgerufen werden.
class Animals(KnowledgeEngine):
@Rule(OR(
AND(Fact('sharp teeth'),Fact('claws'),Fact('forward looking eyes')),
Fact('eats meat')))
def cornivor(self):
self.declare(Fact('carnivor'))
@Rule(OR(Fact('hair'),Fact('gives milk')))
def mammal(self):
self.declare(Fact('mammal'))
@Rule(Fact('mammal'),
OR(Fact('has hooves'),Fact('chews cud')))
def hooves(self):
self.declare('ungulate')
@Rule(OR(Fact('feathers'),AND(Fact('flies'),Fact('lays eggs'))))
def bird(self):
self.declare('bird')
@Rule(Fact('mammal'),Fact('carnivor'),
Fact(color='red-brown'),
Fact(pattern='dark spots'))
def monkey(self):
self.declare(Fact(animal='monkey'))
@Rule(Fact('mammal'),Fact('carnivor'),
Fact(color='red-brown'),
Fact(pattern='dark stripes'))
def tiger(self):
self.declare(Fact(animal='tiger'))
@Rule(Fact('ungulate'),
Fact('long neck'),
Fact('long legs'),
Fact(pattern='dark spots'))
def giraffe(self):
self.declare(Fact(animal='giraffe'))
@Rule(Fact('ungulate'),
Fact(pattern='dark stripes'))
def zebra(self):
self.declare(Fact(animal='zebra'))
@Rule(Fact('bird'),
Fact('long neck'),
Fact('cannot fly'),
Fact(color='black and white'))
def straus(self):
self.declare(Fact(animal='ostrich'))
@Rule(Fact('bird'),
Fact('swims'),
Fact('cannot fly'),
Fact(color='black and white'))
def pinguin(self):
self.declare(Fact(animal='pinguin'))
@Rule(Fact('bird'),
Fact('flies well'))
def albatros(self):
self.declare(Fact(animal='albatross'))
@Rule(Fact(animal=MATCH.a))
def print_result(self,a):
print('Animal is {}'.format(a))
def factz(self,l):
for x in l:
self.declare(x)
Sobald wir eine Wissensbasis definiert haben, füllen wir unser Arbeitsgedächtnis mit einigen Anfangsfakten und rufen dann die run()-Methode auf, um die Inferenz durchzuführen. Sie können als Ergebnis sehen, dass neue abgeleitete Fakten dem Arbeitsgedächtnis hinzugefügt werden, einschließlich der endgültigen Tatsache über das Tier (wenn wir alle anfänglichen Fakten korrekt eingerichtet haben).
ex1 = Animals()
ex1.reset()
ex1.factz([
Fact(color='red-brown'),
Fact(pattern='dark stripes'),
Fact('sharp teeth'),
Fact('claws'),
Fact('forward looking eyes'),
Fact('gives milk')])
ex1.run()
ex1.facts
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache gilt als maßgebliche Quelle. Für wichtige Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Erstellen Sie eine Ontologie
Eine Wissensbasis zu erstellen bedeutet, ein Modell zu kategorisieren, das Fakten zu einem bestimmten Thema darstellt. Wählen Sie ein Thema – wie eine Person, einen Ort oder ein Objekt – und erstellen Sie dann ein Modell zu diesem Thema. Verwenden Sie einige der in dieser Lektion beschriebenen Techniken und Strategien zur Modellerstellung. Ein Beispiel wäre das Erstellen einer Ontologie eines Wohnzimmers mit Möbeln, Lampen und so weiter. Worin unterscheidet sich das Wohnzimmer von der Küche? Dem Badezimmer? Woran erkennen Sie, dass es sich um ein Wohnzimmer und nicht um ein Esszimmer handelt? Verwenden Sie Protégé, um Ihre Ontologie zu erstellen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Ontologie der Familienbeziehungen
Dieses Beispiel ist Teil des AI for Beginners Curriculum und wurde von diesem Blogbeitrag inspiriert.
Ich finde es immer schwierig, mir die verschiedenen Beziehungen zwischen Personen in einer Familie zu merken. In diesem Beispiel werden wir eine Ontologie verwenden, die Familienbeziehungen definiert, sowie den tatsächlichen Stammbaum, und zeigen, wie wir dann automatische Schlussfolgerungen ziehen können, um alle Verwandten zu finden.
Den Stammbaum erhalten
Als Beispiel nehmen wir den Stammbaum der Romanow-Zarenfamilie. Das gebräuchlichste Format zur Beschreibung von Familienbeziehungen ist GEDCOM. Wir werden den Stammbaum der Romanow-Familie im GEDCOM-Format verwenden:
!head -15 data/tsars.ged
Um die GEDCOM-Datei zu verwenden, können wir die Bibliothek python-gedcom verwenden:
import sys
!{sys.executable} -m pip install python-gedcom
Diese Bibliothek nimmt einige der technischen Probleme beim Datei-Parsing weg, aber sie gibt uns dennoch ziemlich niedrigstufigen Zugriff auf alle Personen und Familien im Baum. Hier ist, wie wir die Datei parsen und die Liste aller Personen anzeigen können:
from gedcom.parser import Parser
from gedcom.element.individual import IndividualElement
from gedcom.element.family import FamilyElement
g = Parser()
g.parse_file('data/tsars.ged')
d = g.get_element_dictionary()
[ (k,v.get_name()) for k,v in d.items() if isinstance(v,IndividualElement)]
Hier ist, wie wir Informationen über Familien erhalten können. Beachten Sie, dass dies uns eine Liste von Kennungen gibt, und wir müssen sie in Namen umwandeln, wenn wir mehr Klarheit wünschen:
d = g.get_element_dictionary()
[ (k,[x.get_value() for x in v.get_child_elements()]) for k,v in d.items() if isinstance(v,FamilyElement)]
Familienontologie abrufen
Schauen wir uns als Nächstes die Familienontologie an, die als eine Menge von Semantic-Web-Tripeln definiert ist. Diese Ontologie beschreibt Beziehungen wie isUncleOf, isCousinOf und viele andere. All diese Beziehungen werden auf Basis der grundlegenden Prädikate isMotherOf, isFatherOf, isBrotherOf und isSisterOf definiert. Wir werden automatisches Schließen verwenden, um alle anderen Beziehungen mithilfe der Ontologie abzuleiten.
Hier ist eine Beispieldefinition der Eigenschaft isAuntOf, die als Komposition von isSisterOf und isParentOf definiert ist (Eine Tante ist die Schwester eines Elternteils).
fhkb:isAuntOf a owl:ObjectProperty ;
rdfs:domain fhkb:Woman ;
rdfs:range fhkb:Person ;
owl:propertyChainAxiom ( fhkb:isSisterOf fhkb:isParentOf ) .
!head -20 data/onto.ttl
Erstellung einer Ontologie für Schlussfolgerungen
Der Einfachheit halber erstellen wir eine Ontologiedatei, die die ursprünglichen Regeln der Familienontologie sowie Fakten über Einzelpersonen aus unserer GEDCOM-Datei enthält. Wir werden die GEDCOM-Datei durchgehen, Informationen über Familien und Einzelpersonen extrahieren und sie in Tripel umwandeln.
!cp data/onto.ttl .
gedcom_dict = g.get_element_dictionary()
individuals, marriages = {}, {}
def term2id(el):
return "i" + el.get_pointer().replace('@', '').lower()
out = open("onto.ttl","a")
for k, v in gedcom_dict.items():
if isinstance(v,IndividualElement):
children, siblings = set(), set()
idx = term2id(v)
title = v.get_name()[0] + " " + v.get_name()[1]
title = title.replace('"', '').replace('[', '').replace(']', '').replace('(', '').replace(')', '').strip()
own_families = g.get_families(v, 'FAMS')
for fam in own_families:
children |= set(term2id(i) for i in g.get_family_members(fam, "CHIL"))
parent_families = g.get_families(v, 'FAMC')
if len(parent_families):
for member in g.get_family_members(parent_families[0], "CHIL"): # NB adoptive families i.e len(parent_families)>1 are not considered (TODO?)
if member.get_pointer() == v.get_pointer():
continue
siblings.add(term2id(member))
if idx in individuals:
children |= individuals[idx].get('children', set())
siblings |= individuals[idx].get('siblings', set())
individuals[idx] = {'sex': v.get_gender().lower(), 'children': children, 'siblings': siblings, 'title': title}
elif isinstance(v,FamilyElement):
wife, husb, children = None, None, set()
children = set(term2id(i) for i in g.get_family_members(v, "CHIL"))
try:
wife = g.get_family_members(v, "WIFE")[0]
wife = term2id(wife)
if wife in individuals: individuals[wife]['children'] |= children
else: individuals[wife] = {'children': children}
except IndexError: pass
try:
husb = g.get_family_members(v, "HUSB")[0]
husb = term2id(husb)
if husb in individuals: individuals[husb]['children'] |= children
else: individuals[husb] = {'children': children}
except IndexError: pass
if wife and husb: marriages[wife + husb] = (term2id(v), wife, husb)
for idx, val in individuals.items():
added_terms = ''
if val['sex'] == 'f':
parent_predicate, sibl_predicate = "isMotherOf", "isSisterOf"
else:
parent_predicate, sibl_predicate = "isFatherOf", "isBrotherOf"
if len(val['children']):
added_terms += " ;\n fhkb:" + parent_predicate + " " + ", ".join(["fhkb:" + i for i in val['children']])
if len(val['siblings']):
added_terms += " ;\n fhkb:" + sibl_predicate + " " + ", ".join(["fhkb:" + i for i in val['siblings']])
out.write("fhkb:%s a owl:NamedIndividual, owl:Thing%s ;\n rdfs:label \"%s\" .\n" % (idx, added_terms, val['title']))
for k, v in marriages.items():
out.write("fhkb:%s a owl:NamedIndividual, owl:Thing ;\n fhkb:hasFemalePartner fhkb:%s ;\n fhkb:hasMalePartner fhkb:%s .\n" % v)
out.write("[] a owl:AllDifferent ;\n owl:distinctMembers (")
for idx in individuals.keys():
out.write(" fhkb:" + idx)
for k, v in marriages.items():
out.write(" fhkb:" + v[0])
out.write(" ) .")
out.close()
!tail onto.ttl
Durchführung von Inferenz
Nun möchten wir in der Lage sein, diese Ontologie für Inferenz und Abfragen zu nutzen. Wir werden die Bibliothek RDFLib verwenden, die es ermöglicht, RDF-Grafen in verschiedenen Formaten zu lesen, Abfragen durchzuführen usw.
Für logische Inferenz verwenden wir die Bibliothek OWL-RL, die es uns erlaubt, die Closure des RDF-Grafen zu erstellen, d. h. alle möglichen Konzepte und Relationen hinzuzufügen, die abgeleitet werden können.
!{sys.executable} -m pip install rdflib
!{sys.executable} -m pip install git+https://github.com/RDFLib/OWL-RL.git
Lass uns die Ontologie-Datei öffnen und sehen, wie viele Tripel sie enthält:
import rdflib
from owlrl import DeductiveClosure, OWLRL_Extension
g = rdflib.Graph()
g.parse("onto.ttl", format="turtle")
print("Triplets found:%d" % len(g))
Lassen Sie uns nun die Schließung erstellen und sehen, wie die Anzahl der Tripel zunimmt:
DeductiveClosure(OWLRL_Extension).expand(g)
print("Triplets after inference:%d" % len(g))
Abfragen von Verwandten
Jetzt können wir den Graphen abfragen, um verschiedene Beziehungen zwischen Personen zu sehen. Wir können die SPARQL-Sprache zusammen mit der query-Methode verwenden. In unserem Fall schauen wir uns alle Onkel in unserem Familienstammbaum an:
qres = g.query(
"""SELECT DISTINCT ?aname ?bname
WHERE {
?a fhkb:isUncleOf ?b .
?a rdfs:label ?aname .
?b rdfs:label ?bname .
}""")
for row in qres:
print("%s is uncle of %s" % row)
Experimentiere gerne mit anderen Familienbeziehungen. Zum Beispiel kannst du dir die isAncestorOf-Beziehung ansehen, die rekursiv alle Vorfahren einer bestimmten Person definiert.
Zum Schluss räumen wir auf!
!rm onto.ttl
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Konzepte-Graph mit ConceptNet
> Hinweis: Die ursprüngliche Microsoft Concept Graph API ist nicht mehr verfügbar. Dieses Notebook wurde aktualisiert, um ConceptNet als Ersatz zu verwenden, ein frei verfügbares offenes Wissensnetzwerk mit ähnlichen is-a-Beziehungen zwischen Konzepten.
ConceptNet ist ein großes semantisches Netzwerk von Konzepten mit Beziehungen wie IsA, PartOf, UsedFor und mehr. Es ist verfügbar als:
* Eine herunterladbare Datendatei
* Eine REST API (kein API-Schlüssel erforderlich)
ConceptNet-Statistiken: * Über 8 Millionen Knoten * 21+ Millionen Kanten in 83 Sprachen
Verwendung des ConceptNet Webdienstes
ConceptNet bietet eine REST-API, um ist-ein (IsA) Beziehungen zwischen Konzepten zu erkunden. Es wird kein API-Schlüssel benötigt.
Hier ist die Beispiel-URL zum Aufrufen: https://api.conceptnet.io/query?start=/c/en/microsoft&rel=/r/IsA&limit=10
import urllib
import json
def http(x):
response = urllib.request.urlopen(x)
data = response.read()
return data.decode('utf-8')
def query(x):
concept = x.lower().replace(' ', '_')
url = "https://api.conceptnet.io/query?start=/c/en/{}&rel=/r/IsA&limit=10".format(
urllib.parse.quote(concept))
try:
result = json.loads(http(url))
except Exception:
return {}
edges = result.get('edges', [])
if not edges:
return {}
total_weight = sum(edge['weight'] for edge in edges)
if total_weight == 0:
return {}
return {edge['end']['label']: edge['weight'] / total_weight for edge in edges}
query('microsoft')
Versuchen wir, die Nachrichtentitel mithilfe übergeordneter Konzepte zu kategorisieren. Um Nachrichtentitel zu erhalten, verwenden wir den Dienst NewsApi.org. Sie müssen Ihren eigenen API-Schlüssel erhalten, um den Dienst nutzen zu können – gehen Sie auf die Website und registrieren Sie sich für den kostenlosen Entwicklerplan.
newsapi_key = '<your API key here>'
def get_news(country='us'):
res = json.loads(http("https://newsapi.org/v2/top-headlines?country={0}&apiKey={1}".format(country,newsapi_key)))
return res['articles']
all_titles = [x['title'] for x in get_news('us')+get_news('gb')]
all_titles
Zunächst möchten wir in der Lage sein, Nomen aus Nachrichtentiteln zu extrahieren. Wir werden die Bibliothek TextBlob verwenden, um dies zu tun, die viele typische NLP-Aufgaben wie diese vereinfacht.
import sys
!{sys.executable} -m pip install textblob
!{sys.executable} -m textblob.download_corpora
from textblob import TextBlob
w = {}
for x in all_titles:
for n in TextBlob(x).noun_phrases:
if n in w:
w[n].append(x)
else:
w[n]=[x]
{ x:len(w[x]) for x in w.keys()}
Wir können sehen, dass Substantive uns keine großen thematischen Gruppen liefern. Lassen Sie uns Substantive durch allgemeinere Begriffe ersetzen, die aus dem Konzeptgraphen stammen. Das wird einige Zeit dauern, da wir für jede Nominalphrase einen REST-Aufruf durchführen.
w = {}
for x in all_titles:
for noun in TextBlob(x).noun_phrases:
terms = query(noun)
for term in [u for u in terms.keys() if terms[u]>0.1]:
if term in w:
w[term].append(x)
else:
w[term]=[x]
{ x:len(w[x]) for x in w.keys() if len(w[x])>3}
print('\nECONOMY:\n'+'\n'.join(w['economy']))
print('\nNATION:\n'+'\n'.join(w['nation']))
print('\nPERSON:\n'+'\n'.join(w['person']))
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir auf Genauigkeit achten, können automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten. Das Originaldokument in seiner Ursprungssprache gilt als maßgebliche Quelle. Für wichtige Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die durch die Nutzung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Wissensrepräsentation und Expertensysteme

> Sketchnote von Tomomi Imura
Die Suche nach künstlicher Intelligenz basiert auf der Suche nach Wissen, um die Welt ähnlich wie Menschen zu verstehen. Aber wie kann man das angehen?
Vorlesungsquiz
In den frühen Tagen der KI war der Top-Down-Ansatz zur Erstellung intelligenter Systeme (im vorherigen Kapitel besprochen) beliebt. Die Idee war, Wissen von Menschen in eine maschinenlesbare Form zu extrahieren und es dann automatisch zur Problemlösung zu verwenden. Dieser Ansatz basierte auf zwei großen Ideen:
- Wissensrepräsentation
- Schlussfolgerung
Wissensrepräsentation
Eines der wichtigen Konzepte in der symbolischen KI ist Wissen. Es ist wichtig, Wissen von Information oder Daten abzugrenzen. Zum Beispiel kann man sagen, dass Bücher Wissen enthalten, weil man Bücher studieren und Experte werden kann. Aber was Bücher tatsächlich enthalten, nennt man Daten, und durch das Lesen von Büchern und die Integration dieser Daten in unser Weltmodell wandeln wir diese Daten in Wissen um.
> ✅ Wissen ist etwas, das in unserem Kopf enthalten ist und unser Verständnis der Welt repräsentiert. Es wird durch einen aktiven Lernprozess gewonnen, der erhaltene Informationsstücke in unser aktives Weltmodell integriert.
Meistens definieren wir Wissen nicht strikt, sondern ordnen es anderen verwandten Konzepten mithilfe der DIKW-Pyramide zu. Sie beinhaltet folgende Begriffe:
- Daten sind etwas, das in physischen Medien dargestellt wird, wie geschriebener Text oder gesprochene Worte. Daten existieren unabhängig von Menschen und können zwischen Menschen weitergegeben werden.
- Information ist, wie wir Daten in unserem Kopf interpretieren. Zum Beispiel haben wir beim Hören des Wortes Computer eine Vorstellung davon, was es ist.
- Wissen ist Information, die in unser Weltmodell integriert wird. Wenn wir beispielsweise lernen, was ein Computer ist, haben wir Vorstellungen darüber, wie er funktioniert, wie viel er kostet und wofür er verwendet werden kann. Dieses Netz von miteinander verbundenen Konzepten bildet unser Wissen.
- Weisheit ist eine weitere Ebene unseres Weltverständnisses und repräsentiert Metawissen, z.B. eine Vorstellung darüber, wie und wann Wissen angewendet werden sollte.
<img src="../../../../translated_images/de/DIKW_Pyramid.94126f7d2bd8db5b.webp" width="30%"/>
Bild von Wikipedia, Von Longlivetheux - Eigenes Werk, CC BY-SA 4.0
Somit besteht das Problem der Wissensrepräsentation darin, eine effektive Methode zu finden, Wissen innerhalb eines Computers in Form von Daten so darzustellen, dass es automatisch nutzbar ist. Dies kann als Spektrum gesehen werden:

> Bild von Dmitry Soshnikov
- Links sind sehr einfache Arten von Wissensrepräsentationen, die von Computern effektiv genutzt werden können. Die einfachste ist die algorithmische, bei der Wissen durch ein Computerprogramm dargestellt wird. Dies ist jedoch nicht die beste Form der Wissensrepräsentation, weil sie nicht flexibel ist. Wissen in unserem Kopf ist oft nicht-algorithmisch.
- Rechts sind Repräsentationen wie natürliche Texte. Sie sind am mächtigsten, können aber nicht für automatische Schlussfolgerungen verwendet werden.
> ✅ Denken Sie einen Moment darüber nach, wie Sie Wissen in Ihrem Kopf repräsentieren und in Notizen umwandeln. Gibt es ein bestimmtes Format, das für Sie gut funktioniert, um das Behalten zu unterstützen?
Klassifikation von Computer-Wissensrepräsentationen
Wir können verschiedene Computer-Wissensrepräsentationsmethoden in folgende Kategorien einordnen:
- Netzwerkrepräsentationen basieren auf der Tatsache, dass wir ein Netzwerk miteinander verbundener Konzepte in unserem Kopf haben. Wir können versuchen, dieselben Netzwerke als Graphen in einem Computer nachzubilden – ein sogenanntes semantisches Netzwerk.
- Objekt-Attribut-Wert-Tripel oder Attribut-Wert-Paare. Da ein Graph im Computer als Liste von Knoten und Kanten dargestellt werden kann, können wir ein semantisches Netzwerk durch eine Liste von Tripeln repräsentieren, die Objekte, Attribute und Werte enthalten. Zum Beispiel erstellen wir folgende Tripel über Programmiersprachen:
| Objekt | Attribut | Wert |
|---|---|---|
| Python | ist | Untyped-Language |
| Python | erfunden von | Guido van Rossum |
| Python | Blocksyntax | Einrückung |
| Untyped-Language | hat nicht | Typdefinitionen |
> ✅ Überlegen Sie, wie Tripel verwendet werden können, um andere Wissensarten darzustellen.
- Hierarchische Repräsentationen betonen die Tatsache, dass wir oft eine Hierarchie von Objekten in unserem Kopf anlegen. Zum Beispiel wissen wir, dass eine Kanarienvogel ein Vogel ist, und alle Vögel Flügel haben. Wir haben auch eine Vorstellung davon, welche Farbe ein Kanarienvogel gewöhnlich hat und wie schnell er fliegt.
- Frame-Repräsentation basiert darauf, jedes Objekt oder jede Objektklasse als Frame darzustellen, der Slots enthält. Slots haben mögliche Standardwerte, Wertbeschränkungen oder gespeicherte Prozeduren, die aufgerufen werden können, um den Wert eines Slots zu erhalten. Alle Frames bilden eine Hierarchie ähnlich der Objekt-Hierarchie in objektorientierten Programmiersprachen.
- Szenarien sind eine spezielle Art von Frames, die komplexe Situationen darstellen, die sich im Zeitverlauf entfalten können.
Python
| Slot | Wert | Standardwert | Intervall |
|---|---|---|---|
| Name | Python | ||
| Ist-ein | Untyped-Language | ||
| VariablenSchreibweise | CamelCase | ||
| Programmlänge | 5-5000 Zeilen | ||
| Blocksyntax | Einrückung |
-
Prozedurale Repräsentationen basieren darauf, Wissen durch eine Liste von auszuführenden Aktionen darzustellen, wenn eine bestimmte Bedingung eintritt. - Produktionsregeln sind Wenn-Dann-Anweisungen, die uns erlauben Schlussfolgerungen zu ziehen. Zum Beispiel kann ein Arzt eine Regel haben, die besagt, dass WENN ein Patient hohes Fieber ODER einen hohen C-reaktiven Proteinspiegel im Bluttest hat, DANN hat er eine Entzündung. Wenn eine der Bedingungen erfüllt wird, können wir eine Schlussfolgerung über die Entzündung ziehen und diese dann im weiteren Schlussfolgern verwenden. - Algorithmen können als eine weitere Form prozeduraler Repräsentation betrachtet werden, obwohl sie in wissensbasierten Systemen fast nie direkt verwendet werden.
-
Logik wurde ursprünglich von Aristoteles als Möglichkeit vorgeschlagen, universelles menschliches Wissen darzustellen. - Prädikatenlogik als mathematische Theorie ist zu reichhaltig, um berechenbar zu sein, daher wird normalerweise ein Teil davon verwendet, z.B. Horn-Klauseln, wie sie in Prolog verwendet werden. - Beschreibende Logik ist eine Familie von logischen Systemen, die verwendet werden, um über Hierarchien von Objekten in verteilten Wissensrepräsentationen wie dem Semantic Web zu repräsentieren und zu schlussfolgern.
Expertensysteme
Einer der frühen Erfolge der symbolischen KI waren sogenannte Expertensysteme – Computersysteme, die entwickelt wurden, um als Experte in einem begrenzten Problembereich zu wirken. Sie basierten auf einer Wissensbasis, die von einem oder mehreren menschlichen Experten extrahiert wurde, und enthielten eine Inferenzmaschine, die darauf basierend Schlussfolgerungen zog.
![]() |
![]() |
|---|---|
| Vereinfachte Struktur des menschlichen neuronalen Systems | Architektur eines wissensbasierten Systems |
Expertensysteme sind ähnlich wie das menschliche Schlusssystem aufgebaut, das Kurzzeitgedächtnis und Langzeitgedächtnis enthält. Ebenso unterscheiden wir in wissensbasierten Systemen folgende Komponenten:
- Problemspeicher: enthält Wissen über das gerade zu lösende Problem, z.B. die Temperatur oder den Blutdruck eines Patienten, ob er eine Entzündung hat oder nicht. Dieses Wissen wird auch als statisches Wissen bezeichnet, weil es einen Schnappschuss dessen darstellt, was wir aktuell über das Problem wissen – den sogenannten Problemzustand.
- Wissensbasis: repräsentiert langfristiges Wissen über ein Problemgebiet. Es wird manuell von menschlichen Experten extrahiert und ändert sich nicht von Konsultation zu Konsultation. Da es erlaubt, von einem Problemzustand zum anderen zu navigieren, wird es auch als dynamisches Wissen bezeichnet.
- Inferenzmaschine: steuert den gesamten Prozess der Suche im Problemzustandsraum und stellt bei Bedarf Fragen an den Benutzer. Sie ist auch verantwortlich dafür, die richtigen Regeln auszuwählen, die auf jeden Zustand angewendet werden.
Als Beispiel betrachten wir folgendes Expertensystem zur Bestimmung eines Tieres anhand seiner physischen Eigenschaften:

> Bild von Dmitry Soshnikov
Dieses Diagramm wird als AND-OR-Baum bezeichnet und ist eine grafische Darstellung eines Satzes von Produktionsregeln. Das Zeichnen eines Baums ist zu Beginn der Wissensextraktion vom Experten nützlich. Um das Wissen im Computer darzustellen, ist es praktischer, Regeln zu verwenden:
IF the animal eats meat
OR (animal has sharp teeth
AND animal has claws
AND animal has forward-looking eyes
)
THEN the animal is a carnivore
Man kann erkennen, dass jede Bedingung auf der linken Seite der Regel und die Aktion im Wesentlichen Objekt-Attribut-Wert-(OAV-)Tripel sind. Das Arbeitsgedächtnis enthält den Satz von OAV-Tripeln, die dem aktuell zu lösenden Problem entsprechen. Eine Regelmaschine sucht nach Regeln, deren Bedingung erfüllt ist, und wendet diese an, indem sie ein weiteres Tripel zum Arbeitsgedächtnis hinzufügt.
> ✅ Erstellen Sie Ihren eigenen AND-OR-Baum zu einem Thema, das Ihnen gefällt!
Vorwärts- vs. Rückwärtsschlussfolgerung
Der oben beschriebene Prozess wird Vorwärtsschlussfolgerung genannt. Er beginnt mit einigen Anfangsdaten über das Problem, die im Arbeitsgedächtnis vorhanden sind, und führt dann die folgende Schlussfolgerungsschleife aus:
- Wenn das Zielfeld im Arbeitsgedächtnis vorhanden ist – stoppe und gib das Ergebnis aus
- Suche alle Regeln, deren Bedingung derzeit erfüllt ist – erhalte eine Konfliktmenge von Regeln
- Führe die Konfliktauflösung durch – wähle eine Regel aus, die in diesem Schritt ausgeführt wird. Es kann verschiedene Strategien der Konfliktauflösung geben:
- Wähle die erste anwendbare Regel in der Wissensbasis
- Wähle eine zufällige Regel
- Wähle eine spezifischere Regel, d.h. diejenige, die die meisten Bedingungen auf der linken Seite (LHS) erfüllt - Wende die ausgewählte Regel an und füge ein neues Wissenselement in den Problemzustand ein
- Wiederhole ab Schritt 1.
In manchen Fällen möchten wir jedoch mit leerem Wissen über das Problem starten und Fragen stellen, die uns zur Schlussfolgerung führen. Zum Beispiel führen wir bei einer medizinischen Diagnose normalerweise nicht alle Analysen im Voraus durch, bevor wir mit der Diagnose beginnen. Stattdessen möchten wir Analysen durchführen, wenn eine Entscheidung getroffen werden muss.
Dieser Prozess kann mit Rückwärtsschlussfolgerung modelliert werden. Er wird vom Ziel angetrieben – dem Attributwert, den wir finden wollen:
- Wähle alle Regeln aus, die uns den Wert des Ziels geben können (d.h. mit dem Ziel auf der rechten Seite (RHS)) – eine Konfliktmenge
- Wenn es keine Regeln für dieses Attribut gibt oder eine Regel besagt, dass wir den Wert vom Benutzer erfragen sollen – frage danach, sonst:
- Verwende eine Konfliktauflösungsstrategie, um eine Regel auszuwählen, die wir als Hypothese verwenden – wir versuchen, sie zu beweisen
- Wiederhole rekursiv den Prozess für alle Attribute auf der linken Seite (LHS) der Regel, um sie als Ziele zu beweisen
- Wenn der Prozess an irgendeiner Stelle fehlschlägt – verwende eine andere Regel bei Schritt 3.
> ✅ In welchen Situationen ist Vorwärtsschlussfolgerung besser geeignet? Wie sieht es mit Rückwärtsschlussfolgerung aus?
Implementierung von Expertensystemen
Expertensysteme können mit verschiedenen Werkzeugen implementiert werden:
- Direkte Programmierung in einer höheren Programmiersprache. Das ist keine gute Idee, da der Hauptvorteil eines wissensbasierten Systems darin liegt, dass Wissen von der Schlussfolgerung getrennt ist und potenziell ein Experte des Fachgebiets Regeln schreiben können sollte, ohne die Details des Inferenzprozesses verstehen zu müssen.
- Verwendung einer Expertensystem-Shell, d.h. eines Systems, das speziell dafür ausgelegt ist, mit Wissen unter Verwendung einer Wissensrepräsentationssprache befüllt zu werden.
✍️ Übung: Tierische Schlussfolgerung
Siehe Animals.ipynb für ein Beispiel zur Implementierung eines Forward- und Backward-Inferenz-Expertensystems.
> Hinweis: Dieses Beispiel ist recht einfach und vermittelt nur die Idee, wie ein Expertensystem aussieht. Erst wenn Sie ein solches System mit einer bestimmten Anzahl an Regeln (etwa 200+) erstellen, werden Sie ein gewisses intelligentes Verhalten bemerken. Irgendwann werden Regeln zu komplex, um sie alle im Kopf zu behalten, und Sie fragen sich vielleicht, warum ein System bestimmte Entscheidungen trifft. Doch die wichtige Eigenschaft von wissensbasierten Systemen ist, dass Sie jederzeit erklären können, wie eine Entscheidung zustande kam.
Ontologien und das Semantic Web
Ende des 20. Jahrhunderts gab es die Initiative, Wissensrepräsentation zu verwenden, um Internet-Ressourcen zu annotieren, sodass es möglich wäre, Ressourcen zu finden, die sehr spezifischen Anfragen entsprechen. Diese Bewegung wurde Semantic Web genannt und basierte auf mehreren Konzepten:
- Eine spezielle Wissensrepräsentation basierend auf beschreibender Logik (Description Logic, DL). Sie ähnelt der Frame-Wissensrepräsentation, weil sie eine Hierarchie von Objekten mit Eigenschaften aufbaut, hat aber formale logische Semantik und Inferenz. Es gibt eine ganze Familie von DLs, die einen Ausgleich zwischen Ausdrucksstärke und der algorithmischen Komplexität der Inferenz bilden.
- Verteilte Wissensrepräsentation, bei der alle Konzepte durch eine globale URI kennzeichnet sind, was es ermöglicht, Wissenshierarchien zu erschaffen, die sich über das Internet erstrecken.
- Eine Familie von XML-basierten Sprachen zur Wissensbeschreibung: RDF (Resource Description Framework), RDFS (RDF Schema), OWL (Ontology Web Language).
Ein Kernkonzept im Semantic Web ist das Konzept der Ontologie. Es bezieht sich auf eine explizite Spezifikation eines Problemfeldes mithilfe einer formalen Wissensrepräsentation. Die einfachste Ontologie kann nur eine Hierarchie von Objekten im Problemfeld sein, aber komplexere Ontologien schließen Regeln ein, die für Schlussfolgerungen verwendet werden können.
Im Semantic Web basieren alle Repräsentationen auf Tripeln. Jedes Objekt und jede Relation wird eindeutig durch eine URI identifiziert. Zum Beispiel, wenn wir die Tatsache angeben wollen, dass dieser AI Curriculum von Dmitry Soshnikov am 1. Januar 2022 entwickelt wurde – hier sind die Tripel, die wir verwenden können:
<img src="../../../../translated_images/de/triplet.4b9b332587593298.webp" width="30%"/>
http://github.com/microsoft/ai-for-beginners http://www.example.com/terms/creation-date “Jan 1, 2022”
http://github.com/microsoft/ai-for-beginners http://purl.org/dc/elements/1.1/creator http://soshnikov.com
> ✅ Hier sind http://www.example.com/terms/creation-date und http://purl.org/dc/elements/1.1/creator einige bekannte und universell akzeptierte URIs, um die Konzepte Ersteller und Erstellungsdatum auszudrücken.
In einem komplexeren Fall, wenn wir eine Liste von Erstellern definieren wollen, können wir einige Datenstrukturen verwenden, die in RDF definiert sind.
<img src="../../../../translated_images/de/triplet-complex.32094972c7b4441b.webp" width="40%"/>
> Obige Diagramme von Dmitry Soshnikov
Der Fortschritt beim Aufbau des Semantic Web wurde durch den Erfolg von Suchmaschinen und Verfahren der natürlichen Sprachverarbeitung, die strukturierte Daten aus Text extrahieren können, etwas verlangsamt. Dennoch gibt es in einigen Bereichen weiterhin erhebliche Anstrengungen, Ontologien und Wissensbasen zu pflegen. Einige bemerkenswerte Projekte:
- WikiData ist eine Sammlung maschinenlesbarer Wissensbasen, die mit Wikipedia verbunden sind. Die meisten Daten werden aus Wikipedia InfoBoxes gewonnen, strukturierten Inhaltsfragmenten innerhalb von Wikipedia-Seiten. Sie können Wikidata in SPARQL, einer speziellen Abfragesprache für das Semantic Web, abfragen. Hier ist eine Beispielabfrage, die die beliebtesten Augenfarben bei Menschen anzeigt:
#defaultView:BubbleChart
SELECT ?eyeColorLabel (COUNT(?human) AS ?count)
WHERE
{
?human wdt:P31 wd:Q5. # human instance-of homo sapiens
?human wdt:P1340 ?eyeColor. # human eye-color ?eyeColor
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?eyeColorLabel
- DBpedia ist ein weiteres ähnliches Projekt wie WikiData.
> ✅ Wenn Sie mit dem Erstellen eigener Ontologien experimentieren oder bestehende öffnen möchten, gibt es einen großartigen visuellen Ontologie-Editor namens Protégé. Laden Sie ihn herunter oder nutzen Sie ihn online.
<img src="../../../../translated_images/de/protege.274177ceeac13b38.webp" width="70%"/>
Web-Protégé-Editor geöffnet mit der Romanov-Familienontologie. Screenshot von Dmitry Soshnikov
✍️ Übung: Eine Familienontologie
Siehe FamilyOntology.ipynb für ein Beispiel zur Verwendung von Semantic Web-Techniken, um über familiäre Beziehungen zu schlussfolgern. Wir nehmen einen Familienstammbaum, dargestellt im üblichen GEDCOM-Format, und eine Ontologie familiärer Beziehungen und bauen daraus einen Graphen aller familiären Beziehungen für eine gegebene Menge von Individuen.
Microsoft Concept Graph
In den meisten Fällen werden Ontologien sorgfältig von Hand erstellt. Es ist jedoch auch möglich, Ontologien aus unstrukturierten Daten, zum Beispiel aus natürlichen Sprachtexten, zu extrahieren.
Ein solcher Versuch wurde von Microsoft Research unternommen und führte zum Microsoft Concept Graph.
Es handelt sich um eine große Sammlung von Entitäten, die mit der ist-ein-Vererbungsbeziehung gruppiert sind. Es erlaubt Fragen zu beantworten wie "Was ist Microsoft?" – mit der Antwort in etwa: "ein Unternehmen mit Wahrscheinlichkeit 0,87 und eine Marke mit Wahrscheinlichkeit 0,75."
Der Graph ist entweder als REST-API verfügbar oder als große herunterladbare Textdatei, die alle Entitätenpaare auflistet.
✍️ Übung: Ein Konzeptgraph
Probieren Sie das Notebook MSConceptGraph.ipynb aus, um zu sehen, wie wir den Microsoft Concept Graph nutzen können, um Nachrichtenartikel in verschiedene Kategorien zu gruppieren.
Fazit
Heutzutage wird KI oft als Synonym für Machine Learning oder Neuronale Netze betrachtet. Ein menschliches Wesen zeigt jedoch auch explizites Schlussfolgern, was derzeit von neuronalen Netzen nicht behandelt wird. In realen Projekten wird explizites Schlussfolgern weiterhin eingesetzt, um Aufgaben zu erfüllen, die Erklärungen erfordern oder die Fähigkeit, das Verhalten des Systems kontrolliert zu modifizieren.
🚀 Herausforderung
Im Family Ontology-Notebook zu dieser Lektion gibt es die Möglichkeit, mit anderen familiären Beziehungen zu experimentieren. Versuchen Sie, neue Verbindungen zwischen Personen im Familienstammbaum zu entdecken.
Quiz nach der Vorlesung
Wiederholung & Selbststudium
Recherchieren Sie im Internet, um Bereiche zu entdecken, in denen Menschen versucht haben, Wissen zu quantifizieren und zu kodifizieren. Schauen Sie sich Blooms Taxonomie an und gehen Sie zurück in die Geschichte, um zu lernen, wie Menschen versucht haben, ihre Welt zu verstehen. Erkunden Sie die Arbeit von Linnaeus zur Erstellung einer Taxonomie von Organismen und beobachten Sie, wie Dmitri Mendelejew eine Methode zur Beschreibung und Gruppierung chemischer Elemente schuf. Welche anderen interessanten Beispiele können Sie finden?
Aufgabe: Erstellen Sie eine Ontologie
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, bitten wir zu beachten, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache gilt als maßgebliche Quelle. Für wichtige Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die durch die Nutzung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Mehrklassenklassifikation mit Perzeptron
Laboraufgabe aus dem AI for Beginners Curriculum.
import matplotlib.pyplot as plt
import numpy as np
import pickle
import os
Du kannst den folgenden Perzeptron-Trainingscode aus der Vorlesung verwenden:
def train(positive_examples, negative_examples, num_iterations = 100):
num_dims = positive_examples.shape[1]
weights = np.zeros((num_dims,1)) # initialize weights
pos_count = positive_examples.shape[0]
neg_count = negative_examples.shape[0]
report_frequency = 10
for i in range(num_iterations):
pos = random.choice(positive_examples)
neg = random.choice(negative_examples)
z = np.dot(pos, weights)
if z < 0:
weights = weights + pos.reshape(weights.shape)
z = np.dot(neg, weights)
if z >= 0:
weights = weights - neg.reshape(weights.shape)
if i % report_frequency == 0:
pos_out = np.dot(positive_examples, weights)
neg_out = np.dot(negative_examples, weights)
pos_correct = (pos_out >= 0).sum() / float(pos_count)
neg_correct = (neg_out < 0).sum() / float(neg_count)
print("Iteration={}, pos correct={}, neg correct={}".format(i,pos_correct,neg_correct))
return weights
def accuracy(weights, test_x, test_labels):
res = np.dot(np.c_[test_x,np.ones(len(test_x))],weights)
return (res.reshape(test_labels.shape)*test_labels>=0).sum()/float(len(test_labels))
accuracy(wts, test_x, test_labels)
Lesen des Datensatzes
Dieser Code lädt den Datensatz aus dem Repository im Internet herunter. Sie können den Datensatz auch manuell aus dem Verzeichnis /data des AI Curriculum-Repositories kopieren.
!rm *.pkl
https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/data/mnist.pkl.gz!gzip -d mnist.pkl.gz
with open('mnist.pkl', 'rb') as mnist_pickle:
MNIST = pickle.load(mnist_pickle)
print(MNIST['Train']['Features'][0][130:180])
print(MNIST['Train']['Labels'][0])
features = MNIST['Train']['Features'].astype(np.float32) / 256.0
labels = MNIST['Train']['Labels']
fig = plt.figure(figsize=(10,5))
for i in range(10):
ax = fig.add_subplot(1,10,i+1)
plt.imshow(features[i].reshape(28,28))
plt.show()
Code zum Erstellen eines one-vs-other-Datensatzes für die Zwei-Ziffern-Klassifikation. Sie müssen diesen Code ändern, um einen one-vs-all-Datensatz zu erstellen.
def set_mnist_pos_neg(positive_label, negative_label):
positive_indices = [i for i, j in enumerate(MNIST['Train']['Labels'])
if j == positive_label]
negative_indices = [i for i, j in enumerate(MNIST['Train']['Labels'])
if j == negative_label]
positive_images = MNIST['Train']['Features'][positive_indices]
negative_images = MNIST['Train']['Features'][negative_indices]
return positive_images, negative_images
Jetzt müssen Sie:
1. 10 one-vs-all Datensätze für alle Ziffern erstellen
1. 10 Perzeptrons trainieren
1. Die Funktion classify definieren, um die Ziffernklassifikation durchzuführen
1. Die Genauigkeit der Klassifikation messen und die Konfusionsmatrix ausgeben
1. [Optional] Eine verbesserte Funktion classify erstellen, die die Klassifikation mithilfe einer einzigen Matrixmultiplikation durchführt.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Mehrklassenklassifikation mit Perzeptron
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
Verwenden Sie den Code, den wir in dieser Lektion für die binäre Klassifikation von handgeschriebenen MNIST-Ziffern entwickelt haben, um einen Mehrklassenklassifikator zu erstellen, der jede Ziffer erkennen kann. Berechnen Sie die Klassifikationsgenauigkeit für den Trainings- und Testdatensatz und geben Sie die Konfusionsmatrix aus.
Hinweise
- Erstellen Sie für jede Ziffer einen Datensatz für einen binären Klassifikator, der "diese Ziffer vs. alle anderen Ziffern" unterscheidet.
- Trainieren Sie 10 verschiedene Perzeptrons für die binäre Klassifikation (jeweils eines für jede Ziffer).
- Definieren Sie eine Funktion, die eine Eingabeziffer klassifiziert.
> Tipp: Wenn wir die Gewichte aller 10 Perzeptrons in einer Matrix kombinieren, sollten wir in der Lage sein, alle 10 Perzeptrons durch eine einzige Matrixmultiplikation auf die Eingabeziffern anzuwenden. Die wahrscheinlichste Ziffer kann dann einfach durch die Anwendung der argmax-Operation auf die Ausgabe gefunden werden.
Start-Notebook
Beginnen Sie das Labor, indem Sie PerceptronMultiClass.ipynb öffnen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Perzeptron
> Dieses Notebook ist Teil des AI for Beginners Curricula. Besuchen Sie das Repository für das vollständige Lernmaterial.
Wie wir besprochen haben, ermöglicht der Perzeptron das Lösen von binären Klassifikationsproblemen, d. h. die Klassifizierung von Eingabebeispielen in zwei Klassen – wir können sie positiv und negativ nennen.
Zuerst importieren wir einige benötigte Bibliotheken.
import pylab
from matplotlib import gridspec
from sklearn.datasets import make_classification
import numpy as np
from ipywidgets import interact, interactive, fixed
import ipywidgets as widgets
import pickle
import os
import gzip
# pick the seed for reproducability - change it to explore the effects of random variations
np.random.seed(1)
import random
Spielproblem
Fangen wir mit einem einfachen Problem an, bei dem wir zwei Eingabemerkmale haben. Zum Beispiel möchten wir in der Medizin Tumore in gutartig und bösartig klassifizieren, abhängig von ihrer Größe und ihrem Alter.
Wir werden ein zufälliges Klassifikations-Dataset mit der Funktion make_classification aus der SciKit Learn-Bibliothek erstellen:
n = 50
X, Y = make_classification(n_samples = n, n_features=2,
n_redundant=0, n_informative=2, flip_y=0)
Y = Y*2-1 # convert initial 0/1 values into -1/1
X = X.astype(np.float32); Y = Y.astype(np.int32) # features - float, label - int
# Split the dataset into training and test
train_x, test_x = np.split(X, [ n*8//10])
train_labels, test_labels = np.split(Y, [n*8//10])
print("Features:\n",train_x[0:4])
print("Labels:\n",train_labels[0:4])
Lassen Sie uns auch den Datensatz plotten:
def plot_dataset(suptitle, features, labels):
# prepare the plot
fig, ax = pylab.subplots(1, 1)
#pylab.subplots_adjust(bottom=0.2, wspace=0.4)
fig.suptitle(suptitle, fontsize = 16)
ax.set_xlabel('$x_i[0]$ -- (feature 1)')
ax.set_ylabel('$x_i[1]$ -- (feature 2)')
colors = ['r' if l>0 else 'b' for l in labels]
ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)
fig.show()
plot_dataset('Training data', train_x, train_labels)
Perzeptron
Da ein Perzeptron ein binärer Klassifikator ist, wird für jeden Eingabevektor $x$ die Ausgabe unseres Perzeptrons entweder +1 oder -1 sein, abhängig von der Klasse. Die Ausgabe wird mit der Formel berechnet:
$$y(\mathbf{x}) = f(\mathbf{w}^{\mathrm{T}}\mathbf{x})$$
wobei $\mathbf{w}$ ein Gewichtungsvektor ist und $f$ eine Stufenaktivierungsfunktion ist: $$ f(x) = \begin{cases} +1 & x \geq 0 \ -1 & x < 0 \end{cases} \ $$
Ein generisches lineares Modell sollte jedoch auch einen Bias enthalten, d.h. idealerweise sollten wir $y$ als $y=f(\mathbf{w}^{\mathrm{T}}\mathbf{x}+\mathbf{b})$ berechnen. Um unser Modell zu vereinfachen, können wir diesen Bias-Term eliminieren, indem wir unseren Eingabefeatures eine weitere Dimension hinzufügen, die immer gleich 1 ist:
pos_examples = np.array([ [t[0], t[1], 1] for i,t in enumerate(train_x)
if train_labels[i]>0])
neg_examples = np.array([ [t[0], t[1], 1] for i,t in enumerate(train_x)
if train_labels[i]<0])
print(pos_examples[0:3])
Trainingsalgorithmus
Um den Perzeptron zu trainieren, müssen wir Gewichte $\mathbf{w}$ finden, die den Fehler minimieren. Der Fehler wird mithilfe des Perzeptron-Kriteriums definiert:
$$E(\mathbf{w}) = -\sum_{n \in \mathcal{M}}\mathbf{w}^{\mathrm{T}}\mathbf{x}{n}t{n}$$
- $t_{n} \in {-1, +1}$ für negative bzw. positive Trainingsbeispiele
- $\mathcal{M}$ - eine Menge falsch klassifizierter Beispiele
Wir verwenden den Prozess des Gradientenabstiegs. Beginnend mit zufälligen Anfangsgewichten $\mathbf{w}^{(0)}$, passen wir die Gewichte in jedem Schritt des Trainings mithilfe des Gradienten von $E$ an:
$$\mathbf{w}^{\tau + 1}=\mathbf{w}^{\tau} - \eta \nabla E(\mathbf{w}) = \mathbf{w}^{\tau} + \eta\sum_{n \in \mathcal{M}}\mathbf{x}{n} t{n}$$
wobei $\eta$ die Lernrate ist und $\tau\in\mathbb{N}$ die Anzahl der Iterationen.
Definieren wir diesen Algorithmus in Python:
def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):
num_dims = positive_examples.shape[1]
# Initialize weights.
# We initialize with 0 for simplicity, but random initialization is also a good idea
weights = np.zeros((num_dims,1))
pos_count = positive_examples.shape[0]
neg_count = negative_examples.shape[0]
report_frequency = 10
for i in range(num_iterations):
# Pick one positive and one negative example
pos = random.choice(positive_examples)
neg = random.choice(negative_examples)
z = np.dot(pos, weights)
if z < 0: # positive example was classified as negative
weights = weights + learning_rate * pos.reshape(weights.shape)
z = np.dot(neg, weights)
if z >= 0: # negative example was classified as positive
weights = weights - learning_rate * neg.reshape(weights.shape)
# Periodically, print out the current accuracy on all examples
if i % report_frequency == 0:
pos_out = np.dot(positive_examples, weights)
neg_out = np.dot(negative_examples, weights)
pos_correct = (pos_out >= 0).sum() / float(pos_count)
neg_correct = (neg_out < 0).sum() / float(neg_count)
print("Iteration={}, pos correct={}, neg correct={}".format(i,pos_correct,neg_correct))
return weights
Hinweis zur Lernrate: Der Parameter learning_rate (Standardwert 0.01) steuert, wie stark wir die Gewichte bei jedem Trainingsschritt anpassen. Dies implementiert die Aktualisierungsformel des Gradientenabstiegs:
$$\mathbf{w}^{\tau + 1}=\mathbf{w}^{\tau} + \eta \mathbf{x}{n} t{n}$$
- Eine größere Lernrate (z. B.
1.0) lässt das Perzeptron schneller lernen, kann jedoch die optimale Lösung überschreiten - Eine kleinere Lernrate (z. B.
0.001) lernt langsamer, kann aber präziser konvergieren - Sie können experimentieren, indem Sie folgendes aufrufen:
train(pos_examples, neg_examples, learning_rate=0.1)
Lassen Sie uns nun das Training auf unserem Datensatz durchführen:
wts = train(pos_examples,neg_examples)
print(wts.transpose())
Wie Sie sehen können, liegt die anfängliche Genauigkeit bei etwa 50 %, steigt jedoch schnell auf höhere Werte nahe 90 %.
Lassen Sie uns visualisieren, wie die Klassen getrennt werden. Unsere Klassifikationsfunktion sieht aus wie $\mathbf{w}^Tx$, und sie ist für eine Klasse größer als 0 und für die andere kleiner als 0. Daher wird die Trennlinie der Klassen durch $\mathbf{w}^Tx = 0$ definiert. Da wir nur zwei Dimensionen $x_0$ und $x_1$ haben, lautet die Gleichung für die Linie $w_0x_0+w_1x_1+w_2 = 0$ (denken Sie daran, dass wir explizit eine zusätzliche Dimension $x_2=1$ definiert haben). Lassen Sie uns diese Linie zeichnen:
def plot_boundary(positive_examples, negative_examples, weights):
if np.isclose(weights[1], 0):
if np.isclose(weights[0], 0):
x = y = np.array([-6, 6], dtype = 'float32')
else:
y = np.array([-6, 6], dtype='float32')
x = -(weights[1] * y + weights[2])/weights[0]
else:
x = np.array([-6, 6], dtype='float32')
y = -(weights[0] * x + weights[2])/weights[1]
pylab.xlim(-6, 6)
pylab.ylim(-6, 6)
pylab.plot(positive_examples[:,0], positive_examples[:,1], 'bo')
pylab.plot(negative_examples[:,0], negative_examples[:,1], 'ro')
pylab.plot(x, y, 'g', linewidth=2.0)
pylab.show()
plot_boundary(pos_examples,neg_examples,wts)
Experimentieren mit Lernraten
Lassen Sie uns nun untersuchen, wie sich verschiedene Lernraten auf den Trainingsprozess auswirken. Die Lernrate steuert die Schrittgröße im Gradientenabstieg – ein entscheidender Hyperparameter, der sowohl die Konvergenzgeschwindigkeit als auch die Stabilität beeinflusst.
# Compare different learning rates
learning_rates = [0.001, 0.01, 0.1, 1.0]
fig, axes = pylab.subplots(2, 2, figsize=(12, 10))
fig.suptitle('Effect of Different Learning Rates', fontsize=16)
for idx, lr in enumerate(learning_rates):
ax = axes[idx // 2, idx % 2]
# Train with this learning rate
weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)
# Plot decision boundary
if np.isclose(weights_lr[1], 0):
if np.isclose(weights_lr[0], 0):
x = y = np.array([-6, 6], dtype='float32')
else:
y = np.array([-6, 6], dtype='float32')
x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]
else:
x = np.array([-6, 6], dtype='float32')
y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]
ax.set_xlim(-6, 6)
ax.set_ylim(-6, 6)
ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)
ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)
ax.plot(x, y, 'g-', linewidth=2)
ax.set_title(f'Learning Rate = {lr}')
ax.set_xlabel('Feature 1')
ax.set_ylabel('Feature 2')
ax.legend()
ax.grid(True, alpha=0.3)
pylab.tight_layout()
pylab.show()
Interaktives Experiment zur Lernrate
Verwenden Sie den Schieberegler unten, um interaktiv mit verschiedenen Lernraten zu experimentieren und zu sehen, wie sie die Entscheidungsgrenze beeinflussen:
def train_and_plot_with_lr(learning_rate=0.01):
"""Train perceptron with specified learning rate and plot results"""
weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)
fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))
# Plot 1: Decision boundary
if np.isclose(weights_lr[1], 0):
if np.isclose(weights_lr[0], 0):
x = y = np.array([-6, 6], dtype='float32')
else:
y = np.array([-6, 6], dtype='float32')
x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]
else:
x = np.array([-6, 6], dtype='float32')
y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]
ax1.set_xlim(-6, 6)
ax1.set_ylim(-6, 6)
ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)
ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)
ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')
ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)
ax1.set_xlabel('Feature 1')
ax1.set_ylabel('Feature 2')
ax1.legend()
ax1.grid(True, alpha=0.3)
# Plot 2: Weight values
ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)
ax2.set_title('Final Weight Values', fontsize=14)
ax2.set_ylabel('Weight Value')
ax2.grid(True, alpha=0.3, axis='y')
ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)
pylab.tight_layout()
pylab.show()
print(f"Final weights: {weights_lr.flatten()}")
# Create interactive widget
interact(train_and_plot_with_lr,
learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001,
description='Learning Rate:', continuous_update=False))
Bewertung auf dem Testdatensatz
Zu Beginn haben wir einige Daten für den Testdatensatz beiseitegelegt. Schauen wir uns an, wie genau unser Klassifikator auf diesem Testdatensatz ist. Um dies zu tun, erweitern wir den Testdatensatz ebenfalls um eine zusätzliche Dimension, multiplizieren mit der Gewichtsmatrix und stellen sicher, dass der erhaltene Wert dasselbe Vorzeichen wie das Label hat (+1 oder -1). Anschließend summieren wir alle booleschen Werte und teilen durch die Länge der Testprobe, um die Genauigkeit zu erhalten:
def accuracy(weights, test_x, test_labels):
res = np.dot(np.c_[test_x,np.ones(len(test_x))],weights)
return (res.reshape(test_labels.shape)*test_labels>=0).sum()/float(len(test_labels))
accuracy(wts, test_x, test_labels)
Beobachtung des Trainingsprozesses
Wir haben zuvor gesehen, wie die Genauigkeit während des Trainings abnimmt. Es wäre interessant zu sehen, wie sich die Trennlinie während des Trainings verhält. Der folgende Code visualisiert alles in einem Diagramm, und Sie sollten in der Lage sein, den Schieberegler zu bewegen, um durch den Trainingsprozess zu "reisen".
def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):
num_dims = positive_examples.shape[1]
weights = np.zeros((num_dims,1)) # initialize weights
pos_count = positive_examples.shape[0]
neg_count = negative_examples.shape[0]
report_frequency = 15;
snapshots = []
for i in range(num_iterations):
pos = random.choice(positive_examples)
neg = random.choice(negative_examples)
z = np.dot(pos, weights)
if z < 0:
weights = weights + learning_rate * pos.reshape(weights.shape)
z = np.dot(neg, weights)
if z >= 0:
weights = weights - learning_rate * neg.reshape(weights.shape)
if i % report_frequency == 0:
pos_out = np.dot(positive_examples, weights)
neg_out = np.dot(negative_examples, weights)
pos_correct = (pos_out >= 0).sum() / float(pos_count)
neg_correct = (neg_out < 0).sum() / float(neg_count)
snapshots.append([np.copy(weights).flatten(), (pos_correct+neg_correct)/2.0])
return np.array(snapshots, dtype=object)
snapshots = train_graph(pos_examples,neg_examples)
def plotit(pos_examples,neg_examples,snapshots,step):
fig = pylab.figure(figsize=(10,4))
fig.add_subplot(1, 2, 1)
plot_boundary(pos_examples, neg_examples, snapshots[step][0])
fig.add_subplot(1, 2, 2)
pylab.plot(np.arange(len(snapshots[:,1])), snapshots[:,1])
pylab.ylabel('Accuracy')
pylab.xlabel('Iteration')
pylab.plot(step, snapshots[step,1], "bo")
pylab.show()
def pl1(step): plotit(pos_examples,neg_examples,snapshots,step)
interact(pl1, step=widgets.IntSlider(value=0, min=0, max=len(snapshots)-1))
Einschränkungen des Perzeptrons
Wie oben gezeigt, ist das Perzeptron ein linearer Klassifikator. Es kann zwei Klassen gut unterscheiden, wenn sie linear trennbar sind, d. h. durch eine gerade Linie getrennt werden können. Andernfalls wird der Trainingsprozess des Perzeptrons nicht konvergieren.
Ein offensichtliches Beispiel für ein Problem, das ein Perzeptron nicht lösen kann, ist das sogenannte XOR-Problem. Wir möchten, dass unser Perzeptron die XOR-Logikfunktion lernt, die folgende Wahrheitstabelle hat:
| 0 | 1 | |
|---|---|---|
| 0 | 0 | 1 |
| 1 | 1 | 0 |
Versuchen wir es! Wir werden manuell alle positiven und negativen Trainingsbeispiele einfügen und dann unsere oben definierte Trainingsfunktion aufrufen:
pos_examples_xor = np.array([[1,0,1],[0,1,1]])
neg_examples_xor = np.array([[1,1,1],[0,0,1]])
snapshots_xor = train_graph(pos_examples_xor,neg_examples_xor,1000)
def pl2(step): plotit(pos_examples_xor,neg_examples_xor,snapshots_xor,step)
interact(pl2, step=widgets.IntSlider(value=0, min=0, max=len(snapshots)-1))
Wie aus dem obigen Diagramm ersichtlich, überschreitet die Genauigkeit niemals 75 %, da es unmöglich ist, eine gerade Linie so zu ziehen, dass alle möglichen Beispiele korrekt erfasst werden.
Das XOR-Problem ist ein klassisches Beispiel für die Grenzen des Perzeptrons und wurde 1969 von Marvin Minsky und Seymour Papert in ihrem Buch Perceptrons aufgezeigt. Diese Beobachtung bremste die Forschung im Bereich der neuronalen Netze fast ein Jahrzehnt lang, obwohl – wie wir im nächsten Abschnitt unseres Kurses sehen werden – mehrschichtige Perzeptrons solche Probleme problemlos lösen können.
Komplexes Beispiel – MNIST
Auch wenn ein Perzeptron das XOR-Problem nicht lösen kann, ist es in der Lage, viele komplexere Probleme zu bewältigen, wie zum Beispiel die Erkennung handgeschriebener Zeichen.
Ein Datensatz, der häufig beim Erlernen von maschinellem Lernen verwendet wird, heißt MNIST. Er wurde vom Modified National Institute of Standards and Technology erstellt und enthält einen Trainingsdatensatz mit 60.000 handgeschriebenen Ziffern, die von etwa 250 Studenten und Mitarbeitern des Instituts gesammelt wurden. Es gibt auch einen Testdatensatz mit 10.000 Ziffern, die von anderen Personen stammen.
Alle Ziffern werden durch Graustufenbilder mit einer Größe von 28x28 Pixeln dargestellt.
> Der MNIST-Datensatz ist als Trainingswettbewerb auf Kaggle verfügbar, einer Plattform, die Wettbewerbe und Contests im Bereich maschinelles Lernen veranstaltet. Sobald Sie gelernt haben, wie man MNIST-Ziffern klassifiziert, können Sie Ihre Lösung bei Kaggle einreichen, um zu sehen, wie sie im Vergleich zu anderen Teilnehmern bewertet wird.
Wir beginnen mit dem Laden des MNIST-Datensatzes:
# If you are not running this notebook from a cloned repository, you may need to grab the binary dataset file first
# !wget https://github.com/microsoft/AI-For-Beginners/raw/main/data/mnist.pkl.gz?raw=true
# In this case correct the link to the dataset below as well.
with gzip.open('../../../data/mnist.pkl.gz', 'rb') as mnist_pickle:
MNIST = pickle.load(mnist_pickle, encoding='latin1')
Lassen Sie uns nun den Datensatz plotten:
print(MNIST['Train']['Features'][0][130:180])
print(MNIST['Train']['Labels'][0])
features = MNIST['Train']['Features'].astype(np.float32) / 256.0
labels = MNIST['Train']['Labels']
fig = pylab.figure(figsize=(10,5))
for i in range(10):
ax = fig.add_subplot(1,10,i+1)
pylab.imshow(features[i].reshape(28,28))
pylab.show()
Da der Perzeptron ein binärer Klassifikator ist, werden wir unser Problem darauf beschränken, nur zwei Ziffern zu erkennen. Die folgende Funktion wird positive und negative Beispielarrays mit zwei gegebenen Ziffern füllen (und wird auch Beispiele dieser Ziffern zur Verdeutlichung anzeigen).
def set_mnist_pos_neg(positive_label, negative_label):
positive_indices = [i for i, j in enumerate(MNIST['Train']['Labels'])
if j == positive_label]
negative_indices = [i for i, j in enumerate(MNIST['Train']['Labels'])
if j == negative_label]
positive_images = MNIST['Train']['Features'][positive_indices]
negative_images = MNIST['Train']['Features'][negative_indices]
fig = pylab.figure()
ax = fig.add_subplot(1, 2, 1)
pylab.imshow(positive_images[0].reshape(28,28), cmap='gray', interpolation='nearest')
ax.set_xticks([])
ax.set_yticks([])
ax = fig.add_subplot(1, 2, 2)
pylab.imshow(negative_images[0].reshape(28,28), cmap='gray', interpolation='nearest')
ax.set_xticks([])
ax.set_yticks([])
pylab.show()
return positive_images, negative_images
Wir werden damit beginnen, zwischen 0 und 1 zu klassifizieren:
pos1,neg1 = set_mnist_pos_neg(1,0)
def plotit2(snapshots_mn,step):
fig = pylab.figure(figsize=(10,4))
ax = fig.add_subplot(1, 2, 1)
pylab.imshow(snapshots_mn[step][0].reshape(28, 28), interpolation='nearest')
ax.set_xticks([])
ax.set_yticks([])
pylab.colorbar()
ax = fig.add_subplot(1, 2, 2)
ax.set_ylim([0,1])
pylab.plot(np.arange(len(snapshots_mn[:,1])), snapshots_mn[:,1])
pylab.plot(step, snapshots_mn[step,1], "bo")
pylab.show()
def pl3(step): plotit2(snapshots_mn,step)
def pl4(step): plotit2(snapshots_mn2,step)
snapshots_mn = train_graph(pos1,neg1,1000)
interact(pl3, step=widgets.IntSlider(value=0, min=0, max=len(snapshots_mn) - 1))
Bitte beachten Sie, wie die Genauigkeit sehr schnell auf fast 100 % ansteigt.
Bitte bewegen Sie den Schieberegler zu einer Position gegen Ende des Trainings und beobachten Sie die Gewichtsmatrix, die links dargestellt wird. Diese Matrix hilft Ihnen zu verstehen, wie der Perzeptron tatsächlich funktioniert. Sie können die hohen Gewichtswerte in der Mitte des Feldes sehen, die den Pixeln entsprechen, die typischerweise für die Ziffer 1 vorhanden sind, und niedrige negative Werte an den Seiten, wo Teile der Ziffer 0 sind. Wenn die dem Perzeptron präsentierte Ziffer tatsächlich eine 1 ist, wird der mittlere Teil mit hohen Werten multipliziert, was ein positives Ergebnis erzeugt. Im Gegensatz dazu, wenn der Perzeptron eine 0 erkennt, werden die entsprechenden Pixel mit negativen Zahlen multipliziert.
> Sie könnten bemerken, dass, wenn wir unserem Perzeptron eine Ziffer 1 geben, die leicht horizontal verschoben ist, sodass ihre Pixel den Platz einnehmen, wo sich vertikale Teile der Ziffer 0 befinden, wir ein falsches Ergebnis erhalten könnten. Da die Natur unseres MNIST-Datensatzes so ist, dass alle Ziffern zentriert und korrekt positioniert sind, verlässt sich der Perzeptron darauf, um zwischen den Ziffern zu unterscheiden.
Probieren wir nun verschiedene Ziffern aus:
pos2,neg2 = set_mnist_pos_neg(2,5)
snapshots_mn2 = train_graph(pos2,neg2,1000)
interact(pl4, step=widgets.IntSlider(value=0, min=0, max=len(snapshots_mn2) - 1))
Diskussion
Aus irgendeinem Grund sind 2 und 5 nicht so leicht voneinander zu trennen. Obwohl wir eine relativ hohe Genauigkeit (über 85%) erreichen, können wir deutlich sehen, wie der Perzeptron an einem bestimmten Punkt aufhört zu lernen.
Um zu verstehen, warum das passiert, können wir versuchen, Hauptkomponentenanalyse (PCA) zu verwenden. Dies ist eine Methode des maschinellen Lernens, die dazu dient, die Dimensionalität des Eingabedatensatzes zu reduzieren, um die bestmögliche Trennbarkeit zwischen den Klassen zu erreichen.
In unserem Fall hat ein Eingabebild 784 Pixel (Eingabemerkmale), und wir möchten PCA verwenden, um die Anzahl der Parameter auf nur 2 zu reduzieren, damit wir sie in einem Diagramm darstellen können. Diese zwei Parameter wären eine lineare Kombination der ursprünglichen Merkmale, und wir können diesen Vorgang als eine "Rotation" unseres ursprünglichen 784-dimensionalen Raums betrachten, wobei wir dessen Projektion in unseren 2D-Raum beobachten, bis wir die beste Ansicht erhalten, die die Klassen trennt.
from sklearn.decomposition import PCA
def pca_analysis(positive_label, negative_label):
positive_images, negative_images = set_mnist_pos_neg(positive_label, negative_label)
M = np.append(positive_images, negative_images, 0)
mypca = PCA(n_components=2)
mypca.fit(M)
pos_points = mypca.transform(positive_images[:200])
neg_points = mypca.transform(negative_images[:200])
pylab.plot(pos_points[:,0], pos_points[:,1], 'bo')
pylab.plot(neg_points[:,0], neg_points[:,1], 'ro')
pca_analysis(1,0)
pca_analysis(2,5)
Wie Sie sehen können, können 0 und 1 klar durch eine gerade Linie getrennt werden. Dies zeigt, dass im ursprünglichen 784-dimensionalen Raum die Punkte, die den Ziffern entsprechen, ebenfalls linear trennbar sind. Im Fall von 2 und 5 können wir jedoch keine geeignete Projektion finden, die die Ziffern klar trennt, und daher gibt es einige Fälle von falscher Klassifikation.
> Später in diesem Kurs werden wir lernen, wie man nicht-lineare Klassifikatoren mit neuronalen Netzwerken erstellt und wie man mit dem Problem umgeht, dass Ziffern nicht richtig ausgerichtet sind. Sehr bald werden wir eine Genauigkeit von über 99 % bei der MNIST-Ziffernklassifikation erreichen, während wir sie in 10 verschiedene Klassen einteilen.
Fazit
- Wir haben die einfachste Architektur eines neuronalen Netzwerks kennengelernt – den Ein-Schicht-Perzeptron.
- Wir haben den Perzeptron "von Hand" implementiert, mit einem einfachen Trainingsverfahren basierend auf Gradientenabstieg.
- Trotz seiner Einfachheit kann der Ein-Schicht-Perzeptron recht komplexe Probleme der handschriftlichen Ziffernerkennung lösen.
- Der Ein-Schicht-Perzeptron ist ein linearer Klassifikator und bietet daher die gleiche Klassifikationsleistung wie die logistische Regression.
- Im Merkmalsraum kann der Perzeptron zwei Klassen von Eingabedaten durch eine Hyperebene trennen.
Credits
Dieses Notebook ist Teil des AI for Beginners Curricula und wurde von Dmitry Soshnikov erstellt. Es ist inspiriert vom Neural Network Workshop bei Microsoft Research Cambridge. Ein Teil des Codes und der illustrativen Materialien stammt aus Präsentationen von Katja Hoffmann, Matthew Johnson und Ryoto Tomioka, sowie aus dem NeuroWorkshop-Repository.
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Einführung in Neuronale Netzwerke: Perzeptron
Quiz vor der Vorlesung
Einer der ersten Versuche, etwas Ähnliches wie ein modernes neuronales Netzwerk zu implementieren, wurde 1957 von Frank Rosenblatt vom Cornell Aeronautical Laboratory unternommen. Es handelte sich um eine Hardware-Implementierung namens "Mark-1", die darauf ausgelegt war, primitive geometrische Figuren wie Dreiecke, Quadrate und Kreise zu erkennen.
| <img src='../../../../../translated_images/de/Rosenblatt-wikipedia.294821b285ac796d.webp' alt='Frank Rosenblatt'/> | <img src='../../../../../translated_images/de/Mark_I_perceptron_wikipedia.1f84eaa2d4b76ec9.webp' alt='Das Mark 1 Perzeptron' /> |
> Bilder von Wikipedia
Ein Eingabebild wurde durch ein 20x20-Fotodiodenarray dargestellt, sodass das neuronale Netzwerk 400 Eingaben und einen binären Ausgang hatte. Ein einfaches Netzwerk enthielt einen Neuron, auch Schwellenwert-Logikeinheit genannt. Die Gewichte des neuronalen Netzwerks fungierten wie Potentiometer, die während der Trainingsphase manuell eingestellt werden mussten.
> ✅ Ein Potentiometer ist ein Gerät, das es dem Benutzer ermöglicht, den Widerstand eines Stromkreises anzupassen.
> Die New York Times schrieb damals über das Perzeptron: der Embryo eines elektronischen Computers, von dem [die Marine] erwartet, dass er laufen, sprechen, sehen, schreiben, sich selbst reproduzieren und sich seiner Existenz bewusst sein wird.
Perzeptron-Modell
Angenommen, wir haben N Merkmale in unserem Modell, in diesem Fall wäre der Eingabevektor ein Vektor der Größe N. Ein Perzeptron ist ein Modell zur binären Klassifikation, d.h. es kann zwischen zwei Klassen von Eingabedaten unterscheiden. Wir nehmen an, dass für jeden Eingabevektor x die Ausgabe unseres Perzeptrons entweder +1 oder -1 ist, je nach Klasse. Die Ausgabe wird mit der Formel berechnet:
y(x) = f(w<sup>T</sup>x)
wobei f eine Stufenaktivierungsfunktion ist.
<!-- img src="http://www.sciweavers.org/tex2img.php?eq=f%28x%29%20%3D%20%5Cbegin%7Bcases%7D%0A%20%20%20%20%20%20%20%20%20%2B1%20%26%20x%20%5Cgeq%200%20%5C%5C%0A%20%20%20%20%20%20%20%20%20-1%20%26%20x%20%3C%200%0A%20%20%20%20%20%20%20%5Cend%7Bcases%7D%20%5C%5C%0A&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0" align="center" border="0" alt="f(x) = \begin{cases} +1 & x \geq 0 \ -1 & x < 0 \end{cases} \" width="154" height="50" / --> <img src="../../../../../translated_images/de/activation-func.b4924007c7ce7764.webp"/>
Training des Perzeptrons
Um ein Perzeptron zu trainieren, müssen wir einen Gewichtsvektor w finden, der die meisten Werte korrekt klassifiziert, d.h. den kleinsten Fehler ergibt. Dieser Fehler E wird durch das Perzeptron-Kriterium wie folgt definiert:
E(w) = -∑w<sup>T</sup>x<sub>i</sub>t<sub>i</sub>
wobei:
- die Summe über die Trainingsdatenpunkte i genommen wird, die zu einer falschen Klassifikation führen
- x<sub>i</sub> die Eingabedaten sind und t<sub>i</sub> entweder -1 oder +1 für negative bzw. positive Beispiele ist.
Dieses Kriterium wird als Funktion der Gewichte w betrachtet, und wir müssen es minimieren. Oft wird eine Methode namens Gradientenabstieg verwendet, bei der wir mit einigen Anfangsgewichten w<sup>(0)</sup> beginnen und die Gewichte bei jedem Schritt gemäß der Formel aktualisieren:
w<sup>(t+1)</sup> = w<sup>(t)</sup> - η∇E(w)
Hier ist η die sogenannte Lernrate, und ∇E(w) bezeichnet den Gradienten von E. Nachdem wir den Gradienten berechnet haben, erhalten wir:
w<sup>(t+1)</sup> = w<sup>(t)</sup> + ∑ηx<sub>i</sub>t<sub>i</sub>
Der Algorithmus in Python sieht wie folgt aus:
def train(positive_examples, negative_examples, num_iterations = 100, eta = 1):
weights = [0,0,0] # Initialize weights (almost randomly :)
for i in range(num_iterations):
pos = random.choice(positive_examples)
neg = random.choice(negative_examples)
z = np.dot(pos, weights) # compute perceptron output
if z < 0: # positive example classified as negative
weights = weights + eta*weights.shape
z = np.dot(neg, weights)
if z >= 0: # negative example classified as positive
weights = weights - eta*weights.shape
return weights
Fazit
In dieser Lektion haben Sie etwas über das Perzeptron gelernt, ein Modell zur binären Klassifikation, und wie man es durch die Verwendung eines Gewichtsvektors trainiert.
🚀 Herausforderung
Wenn Sie versuchen möchten, Ihr eigenes Perzeptron zu erstellen, probieren Sie dieses Lab auf Microsoft Learn aus, das den Azure ML Designer verwendet.
Quiz nach der Vorlesung
Rückblick & Selbststudium
Um zu sehen, wie wir das Perzeptron verwenden können, um ein Spielzeugproblem sowie reale Probleme zu lösen, und um weiter zu lernen, gehen Sie zum Perceptron-Notebook.
Hier ist ein interessanter Artikel über Perzeptrons.
Aufgabe
In dieser Lektion haben wir ein Perzeptron für eine binäre Klassifikationsaufgabe implementiert und es verwendet, um zwischen zwei handgeschriebenen Ziffern zu klassifizieren. In diesem Lab sollen Sie das Problem der Ziffernklassifikation vollständig lösen, d.h. bestimmen, welche Ziffer am wahrscheinlichsten zu einem gegebenen Bild gehört.
MNIST-Ziffernklassifikation mit unserem eigenen Framework
Laboraufgabe aus dem AI for Beginners Curriculum.
Das Dataset einlesen
Dieser Code lädt das Dataset aus dem Repository im Internet herunter. Alternativ kannst du das Dataset manuell aus dem Verzeichnis /data des AI Curriculum-Repos kopieren.
!rm *.pkl
!wget https://raw.githubusercontent.com/microsoft/AI-For-Beginners/main/data/mnist.pkl.gz
!gzip -d mnist.pkl.gz
import pickle
with open('mnist.pkl','rb') as f:
MNIST = pickle.load(f)
labels = MNIST['Train']['Labels']
data = MNIST['Train']['Features']
Lass uns sehen, welche Form die Daten haben, die wir haben:
data.shape
Aufteilen der Daten
Wir verwenden Scikit Learn, um die Daten in Trainings- und Testdatensätze aufzuteilen:
from sklearn.model_selection import train_test_split
features_train, features_test, labels_train, labels_test = train_test_split(data,labels,test_size=0.2)
print(f"Train samples: {len(features_train)}, test samples: {len(features_test)}")
Anweisungen
- Nehmen Sie den Framework-Code aus der Lektion und fügen Sie ihn in dieses Notebook ein oder (noch besser) in ein separates Python-Modul.
- Definieren und trainieren Sie einen einlagigen Perzeptron, und beobachten Sie dabei die Trainings- und Validierungsgenauigkeit während des Trainings.
- Versuchen Sie zu verstehen, ob Overfitting aufgetreten ist, und passen Sie die Layer-Parameter an, um die Genauigkeit zu verbessern.
- Wiederholen Sie die vorherigen Schritte für zwei- und dreilagige Perzeptrons. Experimentieren Sie dabei mit verschiedenen Aktivierungsfunktionen zwischen den Schichten.
- Versuchen Sie, die folgenden Fragen zu beantworten:
- Beeinflusst die Aktivierungsfunktion zwischen den Schichten die Leistung des Netzwerks?
- Benötigen wir ein zwei- oder dreilagiges Netzwerk für diese Aufgabe?
- Sind während des Trainings des Netzwerks Probleme aufgetreten? Besonders, wenn die Anzahl der Schichten zugenommen hat.
- Wie verhalten sich die Gewichte des Netzwerks während des Trainings? Sie können den maximalen absoluten Wert der Gewichte im Vergleich zur Epoche plotten, um die Beziehung zu verstehen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
MNIST-Klassifikation mit unserem eigenen Framework
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
Lösen Sie das MNIST-Problem der handschriftlichen Ziffernklassifikation mithilfe eines 1-, 2- und 3-schichtigen Perzeptrons. Verwenden Sie das neuronale Netzwerk-Framework, das wir in der Lektion entwickelt haben.
Start-Notebook
Beginnen Sie das Labor, indem Sie MyFW_MNIST.ipynb öffnen.
Fragen
Versuchen Sie, als Ergebnis dieses Labors die folgenden Fragen zu beantworten:
- Beeinflusst die Aktivierungsfunktion zwischen den Schichten die Netzwerkleistung?
- Benötigen wir für diese Aufgabe ein 2- oder 3-schichtiges Netzwerk?
- Sind während des Trainings des Netzwerks Probleme aufgetreten? Besonders, wenn die Anzahl der Schichten zunahm.
- Wie verhalten sich die Gewichte des Netzwerks während des Trainings? Sie können den maximalen absoluten Wert der Gewichte im Vergleich zur Epoche plotten, um die Beziehung zu verstehen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Mehrschichtige Perzeptrons
Entwicklung unseres eigenen neuronalen Frameworks
> Dieses Notebook ist Teil des AI for Beginners Curricula. Besuchen Sie das Repository, um das vollständige Lernmaterial zu erhalten.
In diesem Notebook werden wir schrittweise unser eigenes neuronales Framework entwickeln, das sowohl Aufgaben der Mehrklassenklassifikation als auch Regression mit mehrschichtigen Perzeptrons lösen kann.
Zuerst importieren wir einige benötigte Bibliotheken.
%matplotlib nbagg
import matplotlib.pyplot as plt
from matplotlib import gridspec
from sklearn.datasets import make_classification
import numpy as np
# pick the seed for reproducibility - change it to explore the effects of random variations
np.random.seed(0)
import random
Beispieldatensatz
Wie zuvor beginnen wir mit einem einfachen Beispieldatensatz mit zwei Parametern.
n = 100
X, Y = make_classification(n_samples = n, n_features=2,
n_redundant=0, n_informative=2, flip_y=0.2)
X = X.astype(np.float32)
Y = Y.astype(np.int32)
# Split into train and test dataset
train_x, test_x = np.split(X, [n*8//10])
train_labels, test_labels = np.split(Y, [n*8//10])
def plot_dataset(suptitle, features, labels):
# prepare the plot
fig, ax = plt.subplots(1, 1)
#pylab.subplots_adjust(bottom=0.2, wspace=0.4)
fig.suptitle(suptitle, fontsize = 16)
ax.set_xlabel('$x_i[0]$ -- (feature 1)')
ax.set_ylabel('$x_i[1]$ -- (feature 2)')
colors = ['r' if l else 'b' for l in labels]
ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)
fig.show()
plot_dataset('Scatterplot of the training data', train_x, train_labels)
plt.show()
print(train_x[:5])
print(train_labels[:5])
Maschinelles Lernproblem
Angenommen, wir haben einen Eingabedatensatz $\langle X,Y\rangle$, wobei $X$ eine Menge von Merkmalen ist und $Y$ die entsprechenden Labels. Für ein Regressionsproblem gilt $y_i\in\mathbb{R}$, und für die Klassifikation wird es durch eine Klassennummer dargestellt $y_i\in{0,\dots,n}$.
Jedes maschinelle Lernmodell kann durch eine Funktion $f_\theta(x)$ dargestellt werden, wobei $\theta$ eine Menge von Parametern ist. Unser Ziel ist es, solche Parameter $\theta$ zu finden, dass unser Modell den Datensatz bestmöglich abbildet. Das Kriterium wird durch die Verlustfunktion $\mathcal{L}$ definiert, und wir müssen den optimalen Wert finden:
$$ \theta = \mathrm{argmin}\theta \mathcal{L}(f\theta(X),Y) $$
Die Verlustfunktion hängt von dem zu lösenden Problem ab.
Verlustfunktionen für Regression
Für Regression verwenden wir häufig absoluten Fehler $\mathcal{L}{abs}(\theta) = \sum{i=1}^n |y_i - f_{\theta}(x_i)|$, oder mittlere quadratische Fehler: $\mathcal{L}{sq}(\theta) = \sum{i=1}^n (y_i - f_{\theta}(x_i))^2$
# helper function for plotting various loss functions
def plot_loss_functions(suptitle, functions, ylabels, xlabel):
fig, ax = plt.subplots(1,len(functions), figsize=(9, 3))
plt.subplots_adjust(bottom=0.2, wspace=0.4)
fig.suptitle(suptitle)
for i, fun in enumerate(functions):
ax[i].set_xlabel(xlabel)
if len(ylabels) > i:
ax[i].set_ylabel(ylabels[i])
ax[i].plot(x, fun)
plt.show()
x = np.linspace(-2, 2, 101)
plot_loss_functions(
suptitle = 'Common loss functions for regression',
functions = [np.abs(x), np.power(x, 2)],
ylabels = ['$\mathcal{L}_{abs}}$ (absolute loss)',
'$\mathcal{L}_{sq}$ (squared loss)'],
xlabel = '$y - f(x_i)$')
Verlustfunktionen für Klassifikation
Betrachten wir zunächst die binäre Klassifikation. In diesem Fall haben wir zwei Klassen, nummeriert mit 0 und 1. Die Ausgabe des Netzwerks $f_\theta(x_i)\in [0,1]$ definiert im Wesentlichen die Wahrscheinlichkeit, die Klasse 1 zu wählen.
0-1 Verlust
Der 0-1 Verlust entspricht der Berechnung der Genauigkeit des Modells – wir zählen die Anzahl der korrekten Klassifikationen:
$$\mathcal{L}{0-1} = \sum{i=1}^n l_i \quad l_i = \begin{cases} 0 & (f(x_i)<0.5 \land y_i=0) \lor (f(x_i)<0.5 \land y_i=1) \ 1 & \mathrm{ sonst} \end{cases} \ $$
Allerdings zeigt die Genauigkeit allein nicht, wie weit wir von der richtigen Klassifikation entfernt sind. Es könnte sein, dass wir die richtige Klasse nur knapp verfehlt haben, was in gewisser Weise "besser" ist (im Sinne davon, dass wir die Gewichte weniger stark anpassen müssen) als eine deutliche Fehleinschätzung. Daher wird häufiger der logistische Verlust verwendet, der dies berücksichtigt.
Logistischer Verlust
$$\mathcal{L}{log} = \sum{i=1}^n -y\log(f_{\theta}(x_i)) - (1-y)\log(1-f_\theta(x_i))$$
x = np.linspace(0,1,100)
def zero_one(d):
if d < 0.5:
return 0
return 1
zero_one_v = np.vectorize(zero_one)
def logistic_loss(fx):
# assumes y == 1
return -np.log(fx)
plot_loss_functions(suptitle = 'Common loss functions for classification (class=1)',
functions = [zero_one_v(x), logistic_loss(x)],
ylabels = ['$\mathcal{L}_{0-1}}$ (0-1 loss)',
'$\mathcal{L}_{log}$ (logistic loss)'],
xlabel = '$p$')
Um den logistischen Verlust zu verstehen, betrachten wir zwei Fälle des erwarteten Outputs: * Wenn wir erwarten, dass der Output 1 ist ($y=1$), dann ist der Verlust $-log f_\theta(x_i)$. Der Verlust ist 0, wenn das Netzwerk 1 mit einer Wahrscheinlichkeit von 1 vorhersagt, und wird größer, wenn die Wahrscheinlichkeit für 1 kleiner wird. * Wenn wir erwarten, dass der Output 0 ist ($y=0$), ist der Verlust $-log(1-f_\theta(x_i))$. Hier ist $1-f_\theta(x_i)$ die vom Netzwerk vorhergesagte Wahrscheinlichkeit für 0, und die Bedeutung des log-Verlusts ist dieselbe wie im vorherigen Fall beschrieben.
Architektur des neuronalen Netzwerks
Wir haben einen Datensatz für ein binäres Klassifikationsproblem erstellt. Allerdings betrachten wir ihn von Anfang an als ein Multi-Klassen-Klassifikationsproblem, damit wir unseren Code später problemlos auf Multi-Klassen-Klassifikation umstellen können. In diesem Fall hat unser Perzeptron mit einer Schicht die folgende Architektur:
Zwei Ausgaben des Netzwerks entsprechen zwei Klassen, und die Klasse mit dem höchsten Wert unter den beiden Ausgaben entspricht der richtigen Lösung.
Das Modell wird definiert als $$ f_\theta(x) = W\times x + b $$ wobei $$\theta = \langle W,b\rangle$$ die Parameter sind.
Wir werden diese lineare Schicht als eine Python-Klasse definieren, die eine forward-Funktion enthält, die die Berechnung durchführt. Sie erhält den Eingabewert $x$ und erzeugt die Ausgabe der Schicht. Die Parameter W und b werden innerhalb der Schichtklasse gespeichert und bei der Erstellung mit zufälligen Werten bzw. Nullen initialisiert.
class Linear:
def __init__(self,nin,nout):
self.W = np.random.normal(0, 1.0/np.sqrt(nin), (nout, nin))
self.b = np.zeros((1,nout))
def forward(self, x):
return np.dot(x, self.W.T) + self.b
net = Linear(2,2)
net.forward(train_x[0:5])
In vielen Fällen ist es effizienter, nicht mit einem einzelnen Eingabewert zu arbeiten, sondern mit einem Vektor von Eingabewerten. Da wir Numpy-Operationen verwenden, können wir unserem Netzwerk einen Vektor von Eingabewerten übergeben, und es wird uns den entsprechenden Vektor von Ausgabewerten liefern.
Softmax: Ausgaben in Wahrscheinlichkeiten umwandeln
Wie Sie sehen können, sind unsere Ausgaben keine Wahrscheinlichkeiten – sie können beliebige Werte annehmen. Um sie in Wahrscheinlichkeiten umzuwandeln, müssen wir die Werte über alle Klassen hinweg normalisieren. Dies geschieht mithilfe der Softmax-Funktion: $$\sigma(\mathbf{z}c) = \frac{e^{z_c}}{\sum{j} e^{z_j}}, \quad\mathrm{für}\quad c\in 1 .. |C|$$
<img src="https://raw.githubusercontent.com/shwars/NeuroWorkshop/master/images/NeuroArch-softmax.PNG" width="50%">
> Die Ausgabe des Netzwerks $\sigma(\mathbf{z})$ kann als Wahrscheinlichkeitsverteilung über die Menge der Klassen $C$ interpretiert werden: $q = \sigma(\mathbf{z}_c) = \hat{p}(c | x)$
Wir werden die Softmax-Schicht auf die gleiche Weise definieren, als eine Klasse mit der forward-Funktion:
class Softmax:
def forward(self,z):
zmax = z.max(axis=1,keepdims=True)
expz = np.exp(z-zmax)
Z = expz.sum(axis=1,keepdims=True)
return expz / Z
softmax = Softmax()
softmax.forward(net.forward(train_x[0:10]))
Man kann sehen, dass wir jetzt Wahrscheinlichkeiten als Ausgaben erhalten, d.h. die Summe jedes Ausgabeverktors beträgt genau 1.
Falls wir mehr als 2 Klassen haben, wird Softmax die Wahrscheinlichkeiten über alle Klassen normalisieren. Hier ist ein Diagramm der Netzwerkarchitektur, die die MNIST-Ziffernklassifikation durchführt:
Kreuzentropie-Verlust
Eine Verlustfunktion in der Klassifikation ist typischerweise eine logistische Funktion, die allgemein als Kreuzentropie-Verlust bezeichnet wird. Der Kreuzentropie-Verlust ist eine Funktion, die die Ähnlichkeit zwischen zwei beliebigen Wahrscheinlichkeitsverteilungen berechnen kann. Eine ausführlichere Diskussion dazu finden Sie auf Wikipedia.
In unserem Fall ist die erste Verteilung die probabilistische Ausgabe unseres Netzwerks, und die zweite ist die sogenannte One-Hot-Verteilung, die angibt, dass eine gegebene Klasse $c$ die entsprechende Wahrscheinlichkeit 1 hat (alle anderen sind 0). In einem solchen Fall kann der Kreuzentropie-Verlust als $-\log p_c$ berechnet werden, wobei $c$ die erwartete Klasse ist und $p_c$ die entsprechende Wahrscheinlichkeit dieser Klasse ist, die von unserem neuronalen Netzwerk ausgegeben wird.
> Wenn das Netzwerk für die erwartete Klasse die Wahrscheinlichkeit 1 zurückgibt, wäre der Kreuzentropie-Verlust 0. Je näher die Wahrscheinlichkeit der tatsächlichen Klasse bei 0 liegt, desto höher ist der Kreuzentropie-Verlust (und er kann bis ins Unendliche steigen!).
def plot_cross_ent():
p = np.linspace(0.01, 0.99, 101) # estimated probability p(y|x)
cross_ent_v = np.vectorize(cross_ent)
f3, ax = plt.subplots(1,1, figsize=(8, 3))
l1, = plt.plot(p, cross_ent_v(p, 1), 'r--')
l2, = plt.plot(p, cross_ent_v(p, 0), 'r-')
plt.legend([l1, l2], ['$y = 1$', '$y = 0$'], loc = 'upper center', ncol = 2)
plt.xlabel('$\hat{p}(y|x)$', size=18)
plt.ylabel('$\mathcal{L}_{CE}$', size=18)
plt.show()
def cross_ent(prediction, ground_truth):
t = 1 if ground_truth > 0.5 else 0
return -t * np.log(prediction) - (1 - t) * np.log(1 - prediction)
plot_cross_ent()
Der Kreuzentropieverlust wird erneut als separate Schicht definiert, aber die forward-Funktion wird zwei Eingabewerte haben: die Ausgabe der vorherigen Schichten des Netzwerks p und die erwartete Klasse y:
class CrossEntropyLoss:
def forward(self,p,y):
self.p = p
self.y = y
p_of_y = p[np.arange(len(y)), y]
log_prob = np.log(p_of_y)
return -log_prob.mean() # average over all input samples
cross_ent_loss = CrossEntropyLoss()
p = softmax.forward(net.forward(train_x[0:10]))
cross_ent_loss.forward(p,train_labels[0:10])
> WICHTIG: Die Verlustfunktion gibt eine Zahl zurück, die zeigt, wie gut (oder schlecht) unser Netzwerk arbeitet. Sie sollte uns eine Zahl für den gesamten Datensatz oder für einen Teil des Datensatzes (Minibatch) liefern. Daher müssen wir nach der Berechnung des Kreuzentropie-Verlusts für jede einzelne Komponente des Eingabevektors alle Komponenten zusammen mitteln (oder addieren) – was durch den Aufruf von .mean() geschieht.
Rechengraph
Bis zu diesem Punkt haben wir verschiedene Klassen für unterschiedliche Schichten des Netzwerks definiert. Die Zusammensetzung dieser Schichten kann als Rechengraph dargestellt werden. Nun können wir den Verlust für einen gegebenen Trainingsdatensatz (oder einen Teil davon) wie folgt berechnen:
z = net.forward(train_x[0:10])
p = softmax.forward(z)
loss = cross_ent_loss.forward(p,train_labels[0:10])
print(loss)
Problem der Verlustminimierung und Netzwerktraining
Sobald wir unser Netzwerk als $f_\theta$ definiert haben und die Verlustfunktion $\mathcal{L}(Y,f_\theta(X))$ gegeben ist, können wir $\mathcal{L}$ als Funktion von $\theta$ unter unserem festen Trainingsdatensatz betrachten: $\mathcal{L}(\theta) = \mathcal{L}(Y,f_\theta(X))$
In diesem Fall wäre das Training des Netzwerks ein Minimierungsproblem von $\mathcal{L$ unter dem Argument $\theta$: $$ \theta = \mathrm{argmin}{\theta} \mathcal{L}(Y,f\theta(X)) $$
Es gibt eine bekannte Methode zur Optimierung von Funktionen, die als Gradientenabstieg bezeichnet wird. Die Idee ist, dass wir eine Ableitung (im mehrdimensionalen Fall als Gradient bezeichnet) der Verlustfunktion in Bezug auf die Parameter berechnen können und die Parameter so variieren, dass der Fehler abnimmt.
Der Gradientenabstieg funktioniert wie folgt: * Initialisiere die Parameter mit zufälligen Werten $w^{(0)}$, $b^{(0)}$ * Wiederhole den folgenden Schritt viele Male:
$$\begin{align} W^{(i+1)}&=W^{(i)}-\eta\frac{\partial\mathcal{L}}{\partial W}\ b^{(i+1)}&=b^{(i)}-\eta\frac{\partial\mathcal{L}}{\partial b} \end{align} $$
Während des Trainings sollten die Optimierungsschritte unter Berücksichtigung des gesamten Datensatzes berechnet werden (denk daran, dass der Verlust als Summe/Durchschnitt über alle Trainingsbeispiele berechnet wird). In der Praxis verwenden wir jedoch kleine Teile des Datensatzes, die als Minibatches bezeichnet werden, und berechnen die Gradienten basierend auf einem Teil der Daten. Da der Teil jedes Mal zufällig ausgewählt wird, wird diese Methode als stochastischer Gradientenabstieg (SGD) bezeichnet.
Rückwärtspropagation
<img src="images/ComputeGraph.png" width="300px" align="left"/>
$$\def\L{\mathcal{L}}\def\zz#1#2{\frac{\partial#1}{\partial#2}} \begin{align} \zz{\L}{W} =& \zz{\L}{p}\zz{p}{z}\zz{z}{W}\cr \zz{\L}{b} =& \zz{\L}{p}\zz{p}{z}\zz{z}{b} \end{align} $$
Um $\partial\mathcal{L}/\partial W$ zu berechnen, können wir die Kettenregel für die Ableitung einer zusammengesetzten Funktion verwenden, wie in den obigen Formeln gezeigt. Dies entspricht der folgenden Idee:
- Angenommen, bei einem gegebenen Input erhalten wir den Verlust $\Delta\mathcal{L}$
- Um ihn zu minimieren, müssten wir die Softmax-Ausgabe $p$ um den Wert $\Delta p = (\partial\mathcal{L}/\partial p)\Delta\mathcal{L}$ anpassen
- Dies entspricht einer Änderung des Knotens $z$ um $\Delta z = (\partial\mathcal{p}/\partial z)\Delta p$
- Um diesen Fehler zu minimieren, müssen wir die Parameter entsprechend anpassen: $\Delta W = (\partial\mathcal{z}/\partial W)\Delta z$ (und dasselbe gilt für $b$)
Dieser Prozess beginnt, den Verlustfehler vom Ausgang des Netzwerks zurück zu seinen Parametern zu verteilen. Daher wird der Prozess als Backpropagation bezeichnet.
Ein Durchlauf des Netzwerktrainings besteht aus zwei Teilen: * Forward Pass, bei dem wir den Wert der Verlustfunktion für einen gegebenen Input-Mini-Batch berechnen * Backward Pass, bei dem wir versuchen, diesen Fehler zu minimieren, indem wir ihn durch den Berechnungsgraphen zurück zu den Modellparametern verteilen.
Implementierung der Rückwärtspropagation
- Fügen wir jeder unserer Knoten eine
backward-Funktion hinzu, die die Ableitung berechnet und den Fehler während des Rückwärtsdurchlaufs weiterleitet. - Außerdem müssen wir die Aktualisierung der Parameter gemäß dem oben beschriebenen Verfahren implementieren.
Wir müssen die Ableitungen für jede Schicht manuell berechnen, zum Beispiel für die lineare Schicht $z = x\times W+b$: $$\begin{align} \frac{\partial z}{\partial W} &= x \ \frac{\partial z}{\partial b} &= 1 \ \end{align}$$
Wenn wir den Fehler $\Delta z$ am Ausgang der Schicht kompensieren müssen, müssen wir die Gewichte entsprechend aktualisieren: $$\begin{align} \Delta x &= \Delta z \times W \ \Delta W &= \frac{\partial z}{\partial W} \Delta z = \Delta z \times x \ \Delta b &= \frac{\partial z}{\partial b} \Delta z = \Delta z \ \end{align}$$
WICHTIG: Die Berechnungen werden nicht für jede Trainingsprobe einzeln durchgeführt, sondern für ein ganzes Minibatch. Die erforderlichen Parameteraktualisierungen $\Delta W$ und $\Delta b$ werden über das gesamte Minibatch berechnet, und die entsprechenden Vektoren haben die Dimensionen: $x\in\mathbb{R}^{\mathrm{minibatch}\, \times\, \mathrm{nclass}}$
class Linear:
def __init__(self,nin,nout):
self.W = np.random.normal(0, 1.0/np.sqrt(nin), (nout, nin))
self.b = np.zeros((1,nout))
self.dW = np.zeros_like(self.W)
self.db = np.zeros_like(self.b)
def forward(self, x):
self.x=x
return np.dot(x, self.W.T) + self.b
def backward(self, dz):
dx = np.dot(dz, self.W)
dW = np.dot(dz.T, self.x)
db = dz.sum(axis=0)
self.dW = dW
self.db = db
return dx
def update(self,lr):
self.W -= lr*self.dW
self.b -= lr*self.db
Auf die gleiche Weise können wir die Funktion backward für die restlichen Schichten definieren:
class Softmax:
def forward(self,z):
self.z = z
zmax = z.max(axis=1,keepdims=True)
expz = np.exp(z-zmax)
Z = expz.sum(axis=1,keepdims=True)
return expz / Z
def backward(self,dp):
p = self.forward(self.z)
pdp = p * dp
return pdp - p * pdp.sum(axis=1, keepdims=True)
class CrossEntropyLoss:
def forward(self,p,y):
self.p = p
self.y = y
p_of_y = p[np.arange(len(y)), y]
log_prob = np.log(p_of_y)
return -log_prob.mean()
def backward(self,loss):
dlog_softmax = np.zeros_like(self.p)
dlog_softmax[np.arange(len(self.y)), self.y] -= 1.0/len(self.y)
return dlog_softmax / self.p
Modell trainieren
Nun sind wir bereit, die Trainingsschleife zu schreiben, die unser Dataset durchläuft und die Optimierung Schritt für Schritt durchführt. Ein vollständiger Durchlauf durch das Dataset wird oft als Epoche bezeichnet:
lin = Linear(2,2)
softmax = Softmax()
cross_ent_loss = CrossEntropyLoss()
learning_rate = 0.1
pred = np.argmax(lin.forward(train_x),axis=1)
acc = (pred==train_labels).mean()
print("Initial accuracy: ",acc)
batch_size=4
for i in range(0,len(train_x),batch_size):
xb = train_x[i:i+batch_size]
yb = train_labels[i:i+batch_size]
# forward pass
z = lin.forward(xb)
p = softmax.forward(z)
loss = cross_ent_loss.forward(p,yb)
# backward pass
dp = cross_ent_loss.backward(loss)
dz = softmax.backward(dp)
dx = lin.backward(dz)
lin.update(learning_rate)
pred = np.argmax(lin.forward(train_x),axis=1)
acc = (pred==train_labels).mean()
print("Final accuracy: ",acc)
Es ist schön zu sehen, wie wir die Genauigkeit des Modells in nur einer Epoche von etwa 50 % auf rund 80 % steigern können.
Netzwerk-Klasse
Da ein neuronales Netzwerk in vielen Fällen einfach eine Zusammensetzung von Schichten ist, können wir eine Klasse erstellen, die es uns ermöglicht, Schichten zusammenzufügen und Vorwärts- sowie Rückwärtsdurchläufe durchzuführen, ohne diese Logik explizit programmieren zu müssen. Wir werden die Liste der Schichten innerhalb der Net-Klasse speichern und die Funktion add() verwenden, um neue Schichten hinzuzufügen:
class Net:
def __init__(self):
self.layers = []
def add(self,l):
self.layers.append(l)
def forward(self,x):
for l in self.layers:
x = l.forward(x)
return x
def backward(self,z):
for l in self.layers[::-1]:
z = l.backward(z)
return z
def update(self,lr):
for l in self.layers:
if 'update' in l.__dir__():
l.update(lr)
Mit dieser Net-Klasse wird unsere Modelldefinition und das Training übersichtlicher:
net = Net()
net.add(Linear(2,2))
net.add(Softmax())
loss = CrossEntropyLoss()
def get_loss_acc(x,y,loss=CrossEntropyLoss()):
p = net.forward(x)
l = loss.forward(p,y)
pred = np.argmax(p,axis=1)
acc = (pred==y).mean()
return l,acc
print("Initial loss={}, accuracy={}: ".format(*get_loss_acc(train_x,train_labels)))
def train_epoch(net, train_x, train_labels, loss=CrossEntropyLoss(), batch_size=4, lr=0.1):
for i in range(0,len(train_x),batch_size):
xb = train_x[i:i+batch_size]
yb = train_labels[i:i+batch_size]
p = net.forward(xb)
l = loss.forward(p,yb)
dp = loss.backward(l)
dx = net.backward(dp)
net.update(lr)
train_epoch(net,train_x,train_labels)
print("Final loss={}, accuracy={}: ".format(*get_loss_acc(train_x,train_labels)))
print("Test loss={}, accuracy={}: ".format(*get_loss_acc(test_x,test_labels)))
Darstellung des Trainingsprozesses
Es wäre schön, visuell zu sehen, wie das Netzwerk trainiert wird! Dafür werden wir eine train_and_plot-Funktion definieren. Um den Zustand des Netzwerks zu visualisieren, verwenden wir eine Level-Karte, d.h. wir stellen verschiedene Werte des Netzwerkausgangs mit unterschiedlichen Farben dar.
> Mach dir keine Sorgen, wenn du einige der unten stehenden Plotting-Codes nicht verstehst – es ist wichtiger, die zugrunde liegenden Konzepte des neuronalen Netzwerks zu verstehen.
def train_and_plot(n_epoch, net, loss=CrossEntropyLoss(), batch_size=4, lr=0.1):
fig, ax = plt.subplots(2, 1)
ax[0].set_xlim(0, n_epoch + 1)
ax[0].set_ylim(0,1)
train_acc = np.empty((n_epoch, 3))
train_acc[:] = np.NAN
valid_acc = np.empty((n_epoch, 3))
valid_acc[:] = np.NAN
for epoch in range(1, n_epoch + 1):
train_epoch(net,train_x,train_labels,loss,batch_size,lr)
tloss, taccuracy = get_loss_acc(train_x,train_labels,loss)
train_acc[epoch-1, :] = [epoch, tloss, taccuracy]
vloss, vaccuracy = get_loss_acc(test_x,test_labels,loss)
valid_acc[epoch-1, :] = [epoch, vloss, vaccuracy]
ax[0].set_ylim(0, max(max(train_acc[:, 2]), max(valid_acc[:, 2])) * 1.1)
plot_training_progress(train_acc[:, 0], (train_acc[:, 2],
valid_acc[:, 2]), fig, ax[0])
plot_decision_boundary(net, fig, ax[1])
fig.canvas.draw()
fig.canvas.flush_events()
return train_acc, valid_acc
import matplotlib.cm as cm
def plot_decision_boundary(net, fig, ax):
draw_colorbar = True
# remove previous plot
while ax.collections:
ax.collections.pop()
draw_colorbar = False
# generate countour grid
x_min, x_max = train_x[:, 0].min() - 1, train_x[:, 0].max() + 1
y_min, y_max = train_x[:, 1].min() - 1, train_x[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))
grid_points = np.c_[xx.ravel().astype('float32'), yy.ravel().astype('float32')]
n_classes = max(train_labels)+1
while train_x.shape[1] > grid_points.shape[1]:
# pad dimensions (plot only the first two)
grid_points = np.c_[grid_points,
np.empty(len(xx.ravel())).astype('float32')]
grid_points[:, -1].fill(train_x[:, grid_points.shape[1]-1].mean())
# evaluate predictions
prediction = np.array(net.forward(grid_points))
# for two classes: prediction difference
if (n_classes == 2):
Z = np.array([0.5+(p[0]-p[1])/2.0 for p in prediction]).reshape(xx.shape)
else:
Z = np.array([p.argsort()[-1]/float(n_classes-1) for p in prediction]).reshape(xx.shape)
# draw contour
levels = np.linspace(0, 1, 40)
cs = ax.contourf(xx, yy, Z, alpha=0.4, levels = levels)
if draw_colorbar:
fig.colorbar(cs, ax=ax, ticks = [0, 0.5, 1])
c_map = [cm.jet(x) for x in np.linspace(0.0, 1.0, n_classes) ]
colors = [c_map[l] for l in train_labels]
ax.scatter(train_x[:, 0], train_x[:, 1], marker='o', c=colors, s=60, alpha = 0.5)
def plot_training_progress(x, y_data, fig, ax):
styles = ['k--', 'g-']
# remove previous plot
while ax.lines:
ax.lines.pop()
# draw updated lines
for i in range(len(y_data)):
ax.plot(x, y_data[i], styles[i])
ax.legend(ax.lines, ['training accuracy', 'validation accuracy'],
loc='upper center', ncol = 2)
%matplotlib nbagg
net = Net()
net.add(Linear(2,2))
net.add(Softmax())
res = train_and_plot(30,net,lr=0.005)
Nachdem Sie die obige Zelle ausgeführt haben, sollten Sie interaktiv sehen können, wie sich die Grenze zwischen den Klassen während des Trainings verändert. Beachten Sie, dass wir eine sehr kleine Lernrate gewählt haben, damit wir beobachten können, wie der Prozess abläuft.
Mehrschichtige Modelle
Das oben gezeigte Netzwerk wurde aus mehreren Schichten aufgebaut, aber wir hatten immer noch nur eine Linear-Schicht, die die eigentliche Klassifikation durchführt. Was passiert, wenn wir beschließen, mehrere solcher Schichten hinzuzufügen?
Überraschenderweise wird unser Code funktionieren! Ein sehr wichtiger Punkt, den man beachten sollte, ist jedoch, dass wir zwischen den linearen Schichten eine nicht-lineare Aktivierungsfunktion wie tanh benötigen. Ohne eine solche Nicht-Linearität hätten mehrere lineare Schichten die gleiche Ausdruckskraft wie nur eine Schicht – denn die Zusammensetzung linearer Funktionen ist ebenfalls linear!
class Tanh:
def forward(self,x):
y = np.tanh(x)
self.y = y
return y
def backward(self,dy):
return (1.0-self.y**2)*dy
Das Hinzufügen mehrerer Schichten macht Sinn, da ein mehrschichtiges Modell im Gegensatz zu einem Netzwerk mit nur einer Schicht in der Lage ist, Mengen zu klassifizieren, die nicht linear trennbar sind. Das heißt, ein Modell mit mehreren Schichten wird leistungsfähiger sein.
> Es kann gezeigt werden, dass ein Modell mit zwei Schichten und einer ausreichenden Anzahl von Neuronen jede konvexe Menge von Datenpunkten klassifizieren kann, und ein Netzwerk mit drei Schichten kann praktisch jede Menge klassifizieren.
Mathematisch wird ein mehrschichtiges Perzeptron durch eine komplexere Funktion $f_\theta$ dargestellt, die in mehreren Schritten berechnet werden kann: * $z_1 = W_1\times x+b_1$ * $z_2 = W_2\times\alpha(z_1)+b_2$ * $f = \sigma(z_2)$
Hier ist $\alpha$ eine nichtlineare Aktivierungsfunktion, $\sigma$ eine Softmax-Funktion, und $\theta=\langle W_1,b_1,W_2,b_2\rangle$ sind die Parameter.
Der Gradientenabstiegsalgorithmus bleibt derselbe, aber es wird schwieriger, die Gradienten zu berechnen. Mithilfe der Kettenregel der Differentiation können wir die Ableitungen wie folgt berechnen:
$$\begin{align} \frac{\partial\mathcal{L}}{\partial W_2} &= \color{red}{\frac{\partial\mathcal{L}}{\partial\sigma}\frac{\partial\sigma}{\partial z_2}}\color{black}{\frac{\partial z_2}{\partial W_2}} \ \frac{\partial\mathcal{L}}{\partial W_1} &= \color{red}{\frac{\partial\mathcal{L}}{\partial\sigma}\frac{\partial\sigma}{\partial z_2}}\color{black}{\frac{\partial z_2}{\partial\alpha}\frac{\partial\alpha}{\partial z_1}\frac{\partial z_1}{\partial W_1}} \end{align} $$
Beachte, dass der Anfang all dieser Ausdrücke immer noch derselbe ist, und daher können wir die Rückpropagation über eine lineare Schicht hinaus fortsetzen, um weitere Gewichte entlang des Berechnungsgraphen anzupassen.
Lass uns nun mit einem Netzwerk mit zwei Schichten experimentieren:
net = Net()
net.add(Linear(2,10))
net.add(Tanh())
net.add(Linear(10,2))
net.add(Softmax())
loss = CrossEntropyLoss()
res = train_and_plot(30,net,lr=0.01)
Warum nicht immer ein mehrschichtiges Modell verwenden?
Wir haben gesehen, dass ein mehrschichtiges Modell mächtiger und ausdrucksstärker ist als ein einschichtiges Modell. Du fragst dich vielleicht, warum wir nicht immer ein Modell mit vielen Schichten verwenden. Die Antwort auf diese Frage lautet Overfitting.
Wir werden uns mit diesem Begriff später noch ausführlicher beschäftigen, aber die Idee dahinter ist folgende: Je mächtiger ein Modell ist, desto besser kann es Trainingsdaten approximieren, und desto mehr Daten benötigt es, um für neue, zuvor unbekannte Daten richtig zu generalisieren.
Ein lineares Modell: * Es ist wahrscheinlich, dass wir eine hohe Trainingsverlust haben – das sogenannte Underfitting, wenn das Modell nicht genug Kapazität hat, um alle Daten korrekt zu trennen. * Validierungsverlust und Trainingsverlust sind mehr oder weniger gleich. Das Modell wird wahrscheinlich gut auf Testdaten generalisieren.
Komplexes mehrschichtiges Modell * Niedriger Trainingsverlust – das Modell kann die Trainingsdaten gut approximieren, da es über genügend Ausdruckskraft verfügt. * Der Validierungsverlust kann viel höher sein als der Trainingsverlust und während des Trainings sogar steigen – das liegt daran, dass das Modell die Trainingspunkte "auswendig lernt" und dabei das "große Ganze" aus den Augen verliert.

> Auf diesem Bild steht x für Trainingsdaten, o für Validierungsdaten. Links – lineares Modell (einschichtig), es approximiert die Natur der Daten ziemlich gut. Rechts – überangepasstes Modell, das Modell approximiert die Trainingsdaten perfekt, macht aber bei anderen Daten keinen Sinn mehr (der Validierungsfehler ist sehr hoch).
Erkenntnisse
- Einfache Modelle (weniger Schichten, weniger Neuronen) mit einer geringen Anzahl von Parametern ("geringe Kapazität") neigen weniger dazu, zu überanpassen.
- Komplexere Modelle (mehr Schichten, mehr Neuronen pro Schicht, hohe Kapazität) neigen dazu, zu überanpassen. Es ist wichtig, den Validierungsfehler zu überwachen, um sicherzustellen, dass er mit weiterem Training nicht ansteigt.
- Komplexere Modelle benötigen mehr Daten für das Training.
- Das Problem der Überanpassung kann gelöst werden, indem entweder:
- das Modell vereinfacht wird,
- die Menge der Trainingsdaten erhöht wird.
- Bias-Variance-Trade-off ist ein Begriff, der zeigt, dass ein Kompromiss gefunden werden muss:
- zwischen der Leistungsfähigkeit des Modells und der Menge der Daten,
- zwischen Überanpassung und Unteranpassung.
- Es gibt kein allgemeingültiges Rezept dafür, wie viele Schichten oder Parameter benötigt werden – der beste Ansatz ist, zu experimentieren.
Credits
Dieses Notebook ist Teil des AI for Beginners Curricula und wurde von Dmitry Soshnikov erstellt. Es ist inspiriert von dem Neural Network Workshop bei Microsoft Research Cambridge. Einige Codebeispiele und Illustrationsmaterialien stammen aus Präsentationen von Katja Hoffmann, Matthew Johnson und Ryoto Tomioka, sowie aus dem NeuroWorkshop-Repository.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in Neuronale Netze. Mehrschichtige Perzeptrons
Im vorherigen Abschnitt hast du das einfachste Modell eines neuronalen Netzes kennengelernt – ein einlagiges Perzeptron, ein lineares Modell zur Klassifikation von zwei Klassen.
In diesem Abschnitt erweitern wir dieses Modell zu einem flexibleren Framework, das uns ermöglicht:
- neben der Zwei-Klassen-Klassifikation auch Mehrklassen-Klassifikation durchzuführen
- neben Klassifikationsproblemen auch Regressionsprobleme zu lösen
- Klassen zu trennen, die nicht linear separierbar sind
Außerdem entwickeln wir unser eigenes modulares Framework in Python, mit dem wir verschiedene Architekturen neuronaler Netze erstellen können.
Quiz vor der Vorlesung
Formalisierung des maschinellen Lernens
Beginnen wir mit der Formalisierung des maschinellen Lernproblems. Angenommen, wir haben einen Trainingsdatensatz X mit Labels Y, und wir müssen ein Modell f erstellen, das möglichst genaue Vorhersagen trifft. Die Qualität der Vorhersagen wird durch die Verlustfunktion ℒ gemessen. Die folgenden Verlustfunktionen werden häufig verwendet:
- Für Regressionsprobleme, bei denen wir eine Zahl vorhersagen müssen, können wir den absoluten Fehler ∑<sub>i</sub>|f(x<sup>(i)</sup>)-y<sup>(i)</sup>| oder den quadratischen Fehler ∑<sub>i</sub>(f(x<sup>(i)</sup>)-y<sup>(i)</sup>)<sup>2</sup> verwenden.
- Für Klassifikationsprobleme verwenden wir den 0-1-Verlust (der im Wesentlichen der Genauigkeit des Modells entspricht) oder den logistischen Verlust.
Für ein einlagiges Perzeptron wurde die Funktion f als lineare Funktion definiert: f(x)=wx+b (hierbei ist w die Gewichtsmatrix, x der Vektor der Eingabefeatures und b der Bias-Vektor). Für verschiedene Architekturen neuronaler Netze kann diese Funktion eine komplexere Form annehmen.
> Im Fall der Klassifikation ist es oft wünschenswert, Wahrscheinlichkeiten der entsprechenden Klassen als Ausgabe des Netzes zu erhalten. Um beliebige Zahlen in Wahrscheinlichkeiten umzuwandeln (z. B. um die Ausgabe zu normalisieren), verwenden wir oft die Softmax-Funktion σ, und die Funktion f wird zu f(x)=σ(wx+b).
In der obigen Definition von f werden w und b als Parameter θ=⟨w,b⟩ bezeichnet. Angesichts des Datensatzes ⟨X,Y⟩ können wir den Gesamterror für den gesamten Datensatz als Funktion der Parameter θ berechnen.
> ✅ Das Ziel des Trainings eines neuronalen Netzes ist es, den Fehler durch Variation der Parameter θ zu minimieren.
Optimierung durch Gradientenabstieg
Es gibt eine bekannte Methode zur Optimierung von Funktionen, die als Gradientenabstieg bezeichnet wird. Die Idee ist, dass wir eine Ableitung (im mehrdimensionalen Fall als Gradient bezeichnet) der Verlustfunktion in Bezug auf die Parameter berechnen und die Parameter so variieren können, dass der Fehler abnimmt. Dies kann wie folgt formalisiert werden:
- Initialisiere die Parameter mit zufälligen Werten w<sup>(0)</sup>, b<sup>(0)</sup>
- Wiederhole die folgenden Schritte viele Male:
- w<sup>(i+1)</sup> = w<sup>(i)</sup>-η∂ℒ/∂w
- b<sup>(i+1)</sup> = b<sup>(i)</sup>-η∂ℒ/∂b
Während des Trainings sollten die Optimierungsschritte unter Berücksichtigung des gesamten Datensatzes berechnet werden (denk daran, dass der Verlust als Summe über alle Trainingsbeispiele berechnet wird). In der Praxis nehmen wir jedoch kleine Teile des Datensatzes, sogenannte Minibatches, und berechnen die Gradienten basierend auf einem Teil der Daten. Da der Teil jedes Mal zufällig ausgewählt wird, wird diese Methode als stochastischer Gradientenabstieg (SGD) bezeichnet.
Mehrschichtige Perzeptrons und Backpropagation
Ein einlagiges Netzwerk, wie wir oben gesehen haben, ist in der Lage, linear separierbare Klassen zu klassifizieren. Um ein komplexeres Modell zu erstellen, können wir mehrere Schichten des Netzwerks kombinieren. Mathematisch bedeutet dies, dass die Funktion f eine komplexere Form annimmt und in mehreren Schritten berechnet wird: * z<sub>1</sub>=w<sub>1</sub>x+b<sub>1</sub> * z<sub>2</sub>=w<sub>2</sub>α(z<sub>1</sub>)+b<sub>2</sub> * f = σ(z<sub>2</sub>)
Hierbei ist α eine nichtlineare Aktivierungsfunktion, σ eine Softmax-Funktion, und die Parameter sind θ=<w<sub>1</sub>,b<sub>1</sub>,w<sub>2</sub>,b<sub>2</sub>>.
Der Algorithmus des Gradientenabstiegs bleibt derselbe, aber die Berechnung der Gradienten wird schwieriger. Mithilfe der Kettenregel der Differentiation können wir die Ableitungen wie folgt berechnen:
- ∂ℒ/∂w<sub>2</sub> = (∂ℒ/∂σ)(∂σ/∂z<sub>2</sub>)(∂z<sub>2</sub>/∂w<sub>2</sub>)
- ∂ℒ/∂w<sub>1</sub> = (∂ℒ/∂σ)(∂σ/∂z<sub>2</sub>)(∂z<sub>2</sub>/∂α)(∂α/∂z<sub>1</sub>)(∂z<sub>1</sub>/∂w<sub>1</sub>)
> ✅ Die Kettenregel der Differentiation wird verwendet, um die Ableitungen der Verlustfunktion in Bezug auf die Parameter zu berechnen.
Beachte, dass der linke Teil all dieser Ausdrücke derselbe ist, und daher können wir die Ableitungen effektiv berechnen, indem wir von der Verlustfunktion ausgehend "rückwärts" durch den Berechnungsgraphen gehen. Daher wird die Methode zum Trainieren eines mehrschichtigen Perzeptrons als Backpropagation oder 'Backprop' bezeichnet.
<img alt="Berechnungsgraph" src="../../../../../translated_images/de/ComputeGraphGrad.4626252c0de03507.webp"/>
> TODO: Bildquelle angeben
> ✅ Wir werden Backpropagation in unserem Notebook-Beispiel noch viel detaillierter behandeln.
Fazit
In dieser Lektion haben wir unsere eigene Bibliothek für neuronale Netze erstellt und sie für eine einfache zweidimensionale Klassifikationsaufgabe verwendet.
🚀 Herausforderung
Im begleitenden Notebook wirst du dein eigenes Framework zur Erstellung und zum Training mehrschichtiger Perzeptrons implementieren. Du wirst im Detail sehen, wie moderne neuronale Netze funktionieren.
Gehe zum OwnFramework Notebook und arbeite es durch.
Quiz nach der Vorlesung
Rückblick & Selbststudium
Backpropagation ist ein gängiger Algorithmus in KI und ML, der es wert ist, im Detail untersucht zu werden.
Aufgabe
In diesem Labor wirst du das Framework, das du in dieser Lektion erstellt hast, verwenden, um die Klassifikation handgeschriebener Ziffern aus dem MNIST-Datensatz zu lösen.
Einfachste Einführung in neuronale Netzwerke mit Keras
> Dieses Notebook ist Teil des AI for Beginners Curricula. Besuchen Sie das Repository für das vollständige Lernmaterial.
Neuronale Frameworks
Es gibt mehrere Frameworks zum Trainieren von neuronalen Netzwerken. Wenn Sie jedoch schnell starten möchten und nicht zu sehr ins Detail gehen wollen, wie die Dinge intern funktionieren, sollten Sie Keras in Betracht ziehen. Dieses kurze Tutorial hilft Ihnen beim Einstieg, und wenn Sie tiefer verstehen möchten, wie die Dinge funktionieren, werfen Sie einen Blick in das Notebook Introduction to Tensorflow and Keras.
Vorbereitung
Keras ist ein Teil des Tensorflow 2.x-Frameworks. Lassen Sie uns sicherstellen, dass wir Version 2.x.x von Tensorflow installiert haben:
pip install tensorflow
oder
conda install tensorflow
import tensorflow as tf
from tensorflow import keras
import numpy as np
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt
print(f'Tensorflow version = {tf.__version__}')
print(f'Keras version = {keras.__version__}')
Grundkonzepte: Tensor
Ein Tensor ist ein mehrdimensionales Array. Es ist sehr praktisch, Tensoren zu verwenden, um verschiedene Arten von Daten darzustellen: * 400x400 - Schwarz-Weiß-Bild * 400x400x3 - Farbbild * 16x400x400x3 - Minibatch von 16 Farbbildern * 25x400x400x3 - eine Sekunde eines Videos mit 25 Bildern pro Sekunde * 8x25x400x400x3 - Minibatch von 8 einsekündigen Videos
Tensoren bieten uns eine bequeme Möglichkeit, Eingabe-/Ausgabedaten darzustellen, ebenso wie Gewichte innerhalb des neuronalen Netzwerks.
Beispielproblem
Betrachten wir ein Problem der binären Klassifikation. Ein gutes Beispiel für ein solches Problem wäre die Klassifikation eines Tumors als bösartig oder gutartig basierend auf seiner Größe und seinem Alter. Beginnen wir damit, einige Beispieldaten zu generieren:
np.random.seed(0) # pick the seed for reproducibility - change it to explore the effects of random variations
n = 100
X, Y = make_classification(n_samples = n, n_features=2,
n_redundant=0, n_informative=2, flip_y=0.05,class_sep=1.5)
X = X.astype(np.float32)
Y = Y.astype(np.int32)
split = [ 70*n//100 ]
train_x, test_x = np.split(X, split)
train_labels, test_labels = np.split(Y, split)
def plot_dataset(features, labels, W=None, b=None):
# prepare the plot
fig, ax = plt.subplots(1, 1)
ax.set_xlabel('$x_i[0]$ -- (feature 1)')
ax.set_ylabel('$x_i[1]$ -- (feature 2)')
colors = ['r' if l else 'b' for l in labels]
ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)
if W is not None:
min_x = min(features[:,0])
max_x = max(features[:,1])
min_y = min(features[:,1])*(1-.1)
max_y = max(features[:,1])*(1+.1)
cx = np.array([min_x,max_x],dtype=np.float32)
cy = (0.5-W[0]*cx-b)/W[1]
ax.plot(cx,cy,'g')
ax.set_ylim(min_y,max_y)
fig.show()
plot_dataset(train_x, train_labels)
Normalisierung von Daten
Vor dem Training ist es üblich, unsere Eingabefeatures auf den Standardbereich von [0,1] (oder [-1,1]) zu bringen. Die genauen Gründe dafür werden wir später im Kurs besprechen, aber kurz gesagt liegt der Grund darin: Wir möchten vermeiden, dass Werte, die durch unser Netzwerk fließen, zu groß oder zu klein werden, und normalerweise stimmen wir darin überein, alle Werte in einem kleinen Bereich nahe 0 zu halten. Daher initialisieren wir die Gewichte mit kleinen Zufallszahlen und halten die Signale im gleichen Bereich.
Beim Normalisieren von Daten müssen wir den Minimalwert subtrahieren und durch die Spannweite teilen. Wir berechnen den Minimalwert und die Spannweite anhand der Trainingsdaten und normalisieren dann den Test-/Validierungsdatensatz mit denselben Minimal- und Spannweitenwerten aus dem Trainingssatz. Der Grund dafür ist, dass wir im echten Leben nur den Trainingssatz kennen und nicht alle neuen eingehenden Werte, die das Netzwerk vorhersagen soll. Gelegentlich kann es vorkommen, dass ein neuer Wert außerhalb des [0,1]-Bereichs liegt, aber das ist nicht entscheidend.
train_x_norm = (train_x-np.min(train_x,axis=0)) / (np.max(train_x,axis=0)-np.min(train_x,axis=0))
test_x_norm = (test_x-np.min(train_x,axis=0)) / (np.max(train_x,axis=0)-np.min(train_x,axis=0))
Training eines Ein-Schicht-Netzwerks (Perzeptron)
In vielen Fällen besteht ein neuronales Netzwerk aus einer Abfolge von Schichten. Es kann in Keras mit dem Sequential-Modell auf folgende Weise definiert werden:
model = keras.models.Sequential()
model.add(keras.Input(shape=(2,)))
model.add(keras.layers.Dense(1))
model.add(keras.layers.Activation(keras.activations.sigmoid))
model.summary()
Hier erstellen wir zunächst das Modell und fügen dann Schichten hinzu:
* Die erste Input-Schicht (die streng genommen keine Schicht ist) enthält die Spezifikation der Eingabegröße des Netzwerks.
* Die Dense-Schicht ist der eigentliche Perzeptron, der trainierbare Gewichte enthält.
* Schließlich gibt es eine Schicht mit der sigmoid Activation-Funktion, um das Ergebnis des Netzwerks in den Bereich von 0-1 zu bringen (um es zu einer Wahrscheinlichkeit zu machen).
Die Eingabegröße sowie die Aktivierungsfunktion können der Kürze halber auch direkt in der Dense-Schicht angegeben werden:
model = keras.models.Sequential()
model.add(keras.layers.Dense(1,input_shape=(2,),activation='sigmoid'))
model.summary()
Bevor wir das Modell trainieren, müssen wir es kompilieren, was im Wesentlichen bedeutet, dass wir Folgendes festlegen:
* Loss-Funktion, die definiert, wie der Verlust berechnet wird. Da wir ein Zwei-Klassen-Klassifikationsproblem haben, verwenden wir binary cross-entropy loss.
* Optimizer, der verwendet werden soll. Die einfachste Option wäre sgd für stochastic gradient descent, oder man kann fortschrittlichere Optimierer wie adam verwenden.
* Metriken, die wir verwenden möchten, um den Erfolg unseres Trainings zu messen. Da es sich um eine Klassifikationsaufgabe handelt, wäre eine gute Metrik Accuracy (oder kurz acc).
Wir können Loss, Metriken und Optimizer entweder als Strings angeben oder indem wir Objekte aus dem Keras-Framework bereitstellen. In unserem Beispiel müssen wir den Parameter learning_rate festlegen, um die Lernrate unseres Modells zu optimieren. Daher geben wir den vollständigen Namen des Keras SGD-Optimierers an.
model.compile(optimizer=keras.optimizers.SGD(learning_rate=0.2),loss='binary_crossentropy',metrics=['acc'])
Nach dem Kompilieren des Modells können wir das eigentliche Training durch Aufrufen der fit-Methode durchführen. Die wichtigsten Parameter sind:
x und y geben die Trainingsdaten an, wobei x die Merkmale und y die Labels repräsentiert
Wenn wir möchten, dass bei jeder Epoche eine Validierung durchgeführt wird, können wir den Parameter validation_data angeben, der ein Tupel aus Merkmalen und Labels sein sollte
epochs gibt die Anzahl der Epochen an
Wenn das Training in Minibatches erfolgen soll, können wir den Parameter batch_size angeben. Alternativ können die Daten auch manuell vorab in Batches aufgeteilt werden, bevor sie an x/y/validation_data übergeben werden. In diesem Fall ist batch_size nicht erforderlich
model.fit(x=train_x_norm,y=train_labels,validation_data=(test_x_norm,test_labels),epochs=10,batch_size=1)
Du kannst mit verschiedenen Trainingsparametern experimentieren, um zu sehen, wie sie das Training beeinflussen:
* Wenn batch_size zu groß eingestellt wird (oder gar nicht angegeben wird), kann dies zu einem weniger stabilen Training führen, da bei niedrigdimensionalen Daten kleinere Batch-Größen eine präzisere Richtung des Gradienten für jeden spezifischen Fall liefern.
* Ein zu hoher learning_rate kann zu Overfitting oder weniger stabilen Ergebnissen führen, während eine zu niedrige Lernrate bedeutet, dass mehr Epochen benötigt werden, um das gewünschte Ergebnis zu erreichen.
> Beachte, dass du die fit-Funktion mehrmals hintereinander aufrufen kannst, um das Netzwerk weiter zu trainieren. Wenn du das Training von Grund auf neu starten möchtest, musst du die Zelle mit der Modelldefinition erneut ausführen.
Um sicherzustellen, dass unser Training funktioniert hat, lass uns die Linie plotten, die die beiden Klassen trennt. Die Trennlinie wird durch die Gleichung $W\times x + b = 0.5$ definiert.
plot_dataset(train_x,train_labels,model.layers[0].weights[0],model.layers[0].weights[1])
Darstellung der Trainingsdiagramme
Die fit-Funktion gibt ein history-Objekt zurück, das verwendet werden kann, um den Verlust und die Metriken in jeder Epoche zu beobachten. Im folgenden Beispiel starten wir das Training mit einer kleinen Lernrate neu und beobachten, wie sich der Verlust und die Genauigkeit verhalten.
> Hinweis: Wir verwenden eine leicht abweichende Syntax, um das Sequential-Modell zu definieren. Anstatt die Schichten einzeln mit add hinzuzufügen, können wir die Liste der Schichten direkt bei der Erstellung des Modells angeben – dies ist eine etwas kürzere Syntax, die Sie möglicherweise bevorzugen.
model = keras.models.Sequential([
keras.layers.Dense(1,input_shape=(2,),activation='sigmoid')])
model.compile(optimizer=keras.optimizers.SGD(learning_rate=0.05),loss='binary_crossentropy',metrics=['acc'])
hist = model.fit(x=train_x_norm,y=train_labels,validation_data=(test_x_norm,test_labels),epochs=10,batch_size=1)
plt.plot(hist.history['acc'])
plt.plot(hist.history['val_acc'])
Mehrklassenklassifikation
Wenn Sie ein Problem der Mehrklassenklassifikation lösen müssen, hat Ihr Netzwerk mehr als einen Output – entsprechend der Anzahl der Klassen $C$. Jeder Output enthält die Wahrscheinlichkeit für eine bestimmte Klasse.
> Beachten Sie, dass Sie auch ein Netzwerk mit zwei Outputs verwenden können, um binäre Klassifikation auf die gleiche Weise durchzuführen. Genau das werden wir jetzt demonstrieren.
Wenn Sie erwarten, dass ein Netzwerk eine Menge von Wahrscheinlichkeiten $p_1,\dots, p_C$ ausgibt, müssen alle zusammen 1 ergeben. Um dies sicherzustellen, verwenden wir softmax als finale Aktivierungsfunktion in der letzten Schicht. Softmax nimmt einen Vektor als Eingabe und sorgt dafür, dass alle Komponenten dieses Vektors in Wahrscheinlichkeiten umgewandelt werden.
Da der Output des Netzwerks ein $C$-dimensionaler Vektor ist, müssen die Labels die gleiche Form haben. Dies kann durch One-Hot-Encoding erreicht werden, bei dem die Nummer einer Klasse $i$ in einen Vektor aus Nullen umgewandelt wird, mit einer 1 an der $i$-ten Position.
Um den Wahrscheinlichkeitsoutput des neuronalen Netzwerks mit dem erwarteten One-Hot-codierten Label zu vergleichen, verwenden wir die Cross-Entropy-Verlustfunktion. Sie nimmt zwei Wahrscheinlichkeitsverteilungen und gibt einen Wert aus, der angibt, wie unterschiedlich sie sind.
Zusammengefasst, was wir für die Mehrklassenklassifikation mit $C$ Klassen benötigen:
* Das Netzwerk sollte $C$ Neuronen in der letzten Schicht haben
* Die letzte Aktivierungsfunktion sollte Softmax sein
* Der Verlust sollte Cross-Entropy-Verlust sein
* Labels sollten in One-Hot-Encoding umgewandelt werden (dies kann mit numpy oder den Keras-Utils to_categorical erfolgen)
model = keras.models.Sequential([
keras.layers.Dense(5,input_shape=(2,),activation='relu'),
keras.layers.Dense(2,activation='softmax')
])
model.compile(keras.optimizers.Adam(0.01),'categorical_crossentropy',['acc'])
# Two ways to convert to one-hot encoding
train_labels_onehot = keras.utils.to_categorical(train_labels)
test_labels_onehot = np.eye(2)[test_labels]
hist = model.fit(x=train_x_norm,y=train_labels_onehot,
validation_data=[test_x_norm,test_labels_onehot],batch_size=1,epochs=10)
Sparse Kategorische Kreuzentropie
Oft werden Labels in der Mehrklassenklassifikation durch Klassennummern dargestellt. Keras unterstützt auch eine andere Art von Verlustfunktion namens sparse kategorische Kreuzentropie, die erwartet, dass Klassennummern als ganze Zahlen und nicht als One-Hot-Vektoren vorliegen. Mit dieser Art von Verlustfunktion können wir unseren Trainingscode vereinfachen:
model.compile(keras.optimizers.Adam(0.01),'sparse_categorical_crossentropy',['acc'])
model.fit(x=train_x_norm,y=train_labels,validation_data=[test_x_norm,test_labels],batch_size=1,epochs=10)
Multi-Label-Klassifikation
Manchmal gibt es Fälle, in denen unsere Objekte gleichzeitig zu zwei Klassen gehören können. Als Beispiel nehmen wir an, wir möchten einen Klassifikator für Katzen und Hunde auf Bildern entwickeln, aber wir möchten auch Fälle zulassen, in denen sowohl Katzen als auch Hunde vorhanden sind.
Bei der Multi-Label-Klassifikation haben wir anstelle eines One-Hot-encodierten Vektors einen Vektor, der an den Positionen, die den relevanten Klassen des Eingabe-Samples entsprechen, eine 1 enthält. Daher sollte die Ausgabe des Netzwerks keine normalisierten Wahrscheinlichkeiten für alle Klassen haben, sondern vielmehr für jede Klasse einzeln – was der Verwendung der Sigmoid-Aktivierungsfunktion entspricht. Die Cross-Entropy-Loss-Funktion kann weiterhin als Verlustfunktion verwendet werden.
> Hinweis: Dies ist sehr ähnlich wie die Verwendung verschiedener neuronaler Netzwerke, um eine binäre Klassifikation für jede einzelne Klasse durchzuführen – nur der Anfangsteil des Netzwerks (bis zur finalen Klassifikationsschicht) wird für alle Klassen gemeinsam genutzt.
Zusammenfassung der Verlustfunktionen für Klassifikation
Wir haben gesehen, dass binäre, mehrklassige und mehrlabelige Klassifikation sich durch die Art der Verlustfunktion und die Aktivierungsfunktion in der letzten Schicht des Netzwerks unterscheiden. Es kann anfangs etwas verwirrend sein, aber hier sind ein paar Regeln, die man sich merken sollte: * Wenn das Netzwerk einen einzigen Output hat (binäre Klassifikation), verwenden wir die Aktivierungsfunktion sigmoid, für mehrklassige Klassifikation - softmax. * Wenn die Ausgabeklasse als One-Hot-Encoding dargestellt wird, ist die Verlustfunktion cross entropy loss (kategorische Kreuzentropie). Wenn die Ausgabe die Klassennummer enthält - sparse categorical cross-entropy. Für binäre Klassifikation - verwenden Sie binary cross-entropy (gleichbedeutend mit log loss). * Mehrlabelige Klassifikation bedeutet, dass ein Objekt gleichzeitig zu mehreren Klassen gehören kann. In diesem Fall müssen die Labels mit One-Hot-Encoding kodiert werden und die Aktivierungsfunktion sigmoid verwendet werden, sodass die Wahrscheinlichkeit jeder Klasse zwischen 0 und 1 liegt.
| Klassifikation | Label-Format | Aktivierungsfunktion | Verlust |
|---|---|---|---|
| Binär | Wahrscheinlichkeit der 1. Klasse | sigmoid | binary crossentropy |
| Binär | One-Hot-Encoding (2 Outputs) | softmax | categorical crossentropy |
| Mehrklassig | One-Hot-Encoding | softmax | categorical crossentropy |
| Mehrklassig | Klassennummer | softmax | sparse categorical crossentropy |
| Mehrlabelig | One-Hot-Encoding | sigmoid | categorical crossentropy |
Aufgabe:
Verwenden Sie Keras, um einen Klassifikator für handgeschriebene MNIST-Ziffern zu trainieren:
Beachten Sie, dass Keras einige Standard-Datensätze enthält, darunter MNIST. Um MNIST mit Keras zu verwenden, benötigen Sie nur ein paar Zeilen Code (weitere Informationen hier).
Probieren Sie verschiedene Netzwerk-Konfigurationen aus, mit unterschiedlicher Anzahl von Schichten/Neuronen und Aktivierungsfunktionen.
Welche Genauigkeit konnten Sie maximal erreichen?
Erkenntnisse
- Keras wird Anfängern sehr empfohlen, da es ermöglicht, Netzwerke aus Schichten ganz einfach zu erstellen und sie dann mit nur wenigen Codezeilen zu trainieren.
- Wenn eine nicht standardmäßige Architektur benötigt wird, muss man sich etwas tiefer mit Tensorflow beschäftigen. Alternativ kann man jemanden bitten, benutzerdefinierte Logik als Keras-Schicht zu implementieren und diese dann in Keras-Modellen zu verwenden.
- Es ist auch eine gute Idee, sich PyTorch anzusehen und die Ansätze zu vergleichen.
Ein gutes Beispiel-Notebook vom Ersteller von Keras über Keras und Tensorflow 2.0 findet sich hier.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in Tensorflow und Keras
> Dieses Notebook ist Teil des AI for Beginners Curricula. Besuchen Sie das Repository für das vollständige Lernmaterial.
Neuronale Frameworks
Wir haben gelernt, dass man zum Trainieren von neuronalen Netzwerken Folgendes benötigt: * Schnelle Matrixmultiplikation (Tensormultiplikation) * Gradientenberechnung, um die Gradientenabstiegsoptimierung durchzuführen
Was neuronale Netzwerk-Frameworks ermöglichen: * Arbeiten mit Tensoren auf beliebiger verfügbarer Hardware, sei es CPU, GPU oder sogar TPU * Automatische Berechnung von Gradienten (sie sind für alle eingebauten Tensorfunktionen explizit programmiert)
Optional:
* Konstruktor für neuronale Netzwerke / höherstufige API (Netzwerk als Abfolge von Schichten beschreiben)
* Einfache Trainingsfunktionen (fit, wie in Scikit Learn)
* Eine Reihe von Optimierungsalgorithmen zusätzlich zum Gradientenabstieg
* Datenverarbeitungsabstraktionen (die idealerweise auch auf der GPU funktionieren)
Beliebteste Frameworks
- Tensorflow 1.x - erstes weit verbreitetes Framework (Google). Ermöglichte die Definition eines statischen Berechnungsgraphen, dessen Übertragung auf die GPU und die explizite Auswertung
- PyTorch - ein Framework von Facebook, das immer beliebter wird
- Keras - eine höherstufige API auf Basis von Tensorflow/PyTorch, die die Nutzung von neuronalen Netzwerken vereinheitlicht und vereinfacht (Francois Chollet)
- Tensorflow 2.x + Keras - neue Version von Tensorflow mit integrierter Keras-Funktionalität, die dynamische Berechnungsgraphen unterstützt und Tensoroperationen ermöglicht, die sehr ähnlich zu numpy (und PyTorch) sind
Wir werden Tensorflow 2.x und Keras betrachten. Stellen Sie sicher, dass Sie Version 2.x.x von Tensorflow installiert haben:
pip install tensorflow
oder
conda install tensorflow
import tensorflow as tf
import numpy as np
print(tf.__version__)
Grundkonzepte: Tensor
Ein Tensor ist ein mehrdimensionales Array. Es ist sehr praktisch, Tensoren zu verwenden, um verschiedene Arten von Daten darzustellen: * 400x400 - Schwarz-Weiß-Bild * 400x400x3 - Farbbild * 16x400x400x3 - Minibatch von 16 Farbbildern * 25x400x400x3 - Eine Sekunde eines Videos mit 25 Bildern pro Sekunde * 8x25x400x400x3 - Minibatch von 8 einsekündigen Videos
Einfache Tensors
Sie können ganz einfach einfache Tensors aus Listen von np-Arrays erstellen oder zufällige generieren:
a = tf.constant([[1,2],[3,4]])
print(a)
a = tf.random.normal(shape=(10,3))
print(a)
Sie können arithmetische Operationen auf Tensoren anwenden, die elementweise wie in numpy ausgeführt werden. Tensoren werden bei Bedarf automatisch auf die erforderliche Dimension erweitert. Um ein numpy-Array aus einem Tensor zu extrahieren, verwenden Sie .numpy():
print(a-a[0])
print(tf.exp(a)[0].numpy())
Variablen
Variablen sind nützlich, um Tensorwerte darzustellen, die mithilfe von assign und assign_add geändert werden können. Sie werden häufig verwendet, um die Gewichte eines neuronalen Netzwerks darzustellen.
Hier ist ein einfaches Beispiel, wie man die Summe aller Zeilen des Tensors a berechnen kann:
s = tf.Variable(tf.zeros_like(a[0]))
for i in a:
s.assign_add(i)
print(s)
tf.reduce_sum(a,axis=0)
Gradienten berechnen
Für das Backpropagation-Verfahren müssen Gradienten berechnet werden. Dies geschieht mit dem tf.GradientTape()-Idiom:
* Füge einen with tf.GradientTape-Block um unsere Berechnungen hinzu
* Markiere die Tensoren, für die wir Gradienten berechnen möchten, indem du tape.watch aufrufst (alle Variablen werden automatisch überwacht)
* Berechne, was benötigt wird (erstelle den Berechnungsgraphen)
* Erhalte die Gradienten mit tape.gradient
a = tf.random.normal(shape=(2, 2))
b = tf.random.normal(shape=(2, 2))
with tf.GradientTape() as tape:
tape.watch(a) # Start recording the history of operations applied to `a`
c = tf.sqrt(tf.square(a) + tf.square(b)) # Do some math using `a`
# What's the gradient of `c` with respect to `a`?
dc_da = tape.gradient(c, a)
print(dc_da)
Beispiel 1: Lineare Regression
Jetzt wissen wir genug, um das klassische Problem der linearen Regression zu lösen. Lassen Sie uns ein kleines synthetisches Datenset erstellen:
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification, make_regression
from sklearn.model_selection import train_test_split
import random
np.random.seed(13) # pick the seed for reproducability - change it to explore the effects of random variations
train_x = np.linspace(0, 3, 120)
train_labels = 2 * train_x + 0.9 + np.random.randn(*train_x.shape) * 0.5
plt.scatter(train_x,train_labels)
Lineare Regression wird durch eine gerade Linie $f_{W,b}(x) = Wx+b$ definiert, wobei $W, b$ Modellparameter sind, die wir bestimmen müssen. Ein Fehler auf unserem Datensatz ${x_i,y_i}{i=1}^N$ (auch als Verlustfunktion bezeichnet) kann als mittlere quadratische Abweichung definiert werden: $$ \mathcal{L}(W,b) = {1\over N}\sum{i=1}^N (f_{W,b}(x_i)-y_i)^2 $$
Lassen Sie uns unser Modell und die Verlustfunktion definieren:
input_dim = 1
output_dim = 1
learning_rate = 0.1
# This is our weight matrix
w = tf.Variable([[100.0]])
# This is our bias vector
b = tf.Variable(tf.zeros(shape=(output_dim,)))
def f(x):
return tf.matmul(x,w) + b
def compute_loss(labels, predictions):
return tf.reduce_mean(tf.square(labels - predictions))
Wir werden das Modell mit einer Reihe von Minibatches trainieren. Wir verwenden Gradientenabstieg, um die Modellparameter mit den folgenden Formeln anzupassen: $$ \begin{array}{l} W^{(n+1)}=W^{(n)}-\eta\frac{\partial\mathcal{L}}{\partial W} \ b^{(n+1)}=b^{(n)}-\eta\frac{\partial\mathcal{L}}{\partial b} \ \end{array} $$
def train_on_batch(x, y):
with tf.GradientTape() as tape:
predictions = f(x)
loss = compute_loss(y, predictions)
# Note that `tape.gradient` works with a list as well (w, b).
dloss_dw, dloss_db = tape.gradient(loss, [w, b])
w.assign_sub(learning_rate * dloss_dw)
b.assign_sub(learning_rate * dloss_db)
return loss
Lass uns mit dem Training beginnen. Wir werden mehrere Durchläufe durch den Datensatz machen (sogenannte Epochen), ihn in Minibatches aufteilen und die oben definierte Funktion aufrufen:
# Shuffle the data.
indices = np.random.permutation(len(train_x))
features = tf.constant(train_x[indices],dtype=tf.float32)
labels = tf.constant(train_labels[indices],dtype=tf.float32)
batch_size = 4
for epoch in range(10):
for i in range(0,len(features),batch_size):
loss = train_on_batch(tf.reshape(features[i:i+batch_size],(-1,1)),tf.reshape(labels[i:i+batch_size],(-1,1)))
print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))
Wir haben nun optimierte Parameter $W$ und $b$ erhalten. Beachten Sie, dass ihre Werte den ursprünglichen Werten ähneln, die bei der Erstellung des Datensatzes verwendet wurden ($W=2, b=1$).
w,b
plt.scatter(train_x,train_labels)
x = np.array([min(train_x),max(train_x)])
y = w.numpy()[0,0]*x+b.numpy()[0]
plt.plot(x,y,color='red')
Berechnungsgraph und GPU-Berechnungen
Immer wenn wir Tensor-Ausdrücke berechnen, erstellt Tensorflow einen Berechnungsgraphen, der auf dem verfügbaren Rechengerät, z. B. CPU oder GPU, ausgeführt werden kann. Da wir in unserem Code beliebige Python-Funktionen verwendet haben, können diese nicht Teil des Berechnungsgraphen sein. Daher müssen wir beim Ausführen unseres Codes auf der GPU die Daten zwischen CPU und GPU hin- und herübertragen und die benutzerdefinierte Funktion auf der CPU berechnen.
Tensorflow ermöglicht es uns, unsere Python-Funktion mit dem @tf.function-Dekorator zu markieren, wodurch diese Funktion Teil desselben Berechnungsgraphen wird. Dieser Dekorator kann auf Funktionen angewendet werden, die standardmäßige Tensorflow-Tensoroperationen verwenden.
@tf.function
def train_on_batch(x, y):
with tf.GradientTape() as tape:
predictions = f(x)
loss = compute_loss(y, predictions)
# Note that `tape.gradient` works with a list as well (w, b).
dloss_dw, dloss_db = tape.gradient(loss, [w, b])
w.assign_sub(learning_rate * dloss_dw)
b.assign_sub(learning_rate * dloss_db)
return loss
Der Code hat sich nicht geändert, aber wenn du diesen Code auf einer GPU und mit einem größeren Datensatz ausgeführt hättest, hättest du den Geschwindigkeitsunterschied bemerkt.
Dataset-API
TensorFlow enthält eine praktische API, um mit Daten zu arbeiten. Lass uns versuchen, sie zu nutzen. Wir werden auch unser Modell von Grund auf neu trainieren.
w.assign([[10.0]])
b.assign([0.0])
# Create a tf.data.Dataset object for easy batched iteration
dataset = tf.data.Dataset.from_tensor_slices((train_x.astype(np.float32), train_labels.astype(np.float32)))
dataset = dataset.shuffle(buffer_size=1024).batch(256)
for epoch in range(10):
for step, (x, y) in enumerate(dataset):
loss = train_on_batch(tf.reshape(x,(-1,1)), tf.reshape(y,(-1,1)))
print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))
Beispiel 2: Klassifikation
Nun betrachten wir ein Problem der binären Klassifikation. Ein gutes Beispiel für ein solches Problem wäre die Klassifikation eines Tumors als bösartig oder gutartig basierend auf seiner Größe und seinem Alter.
Das Kernmodell ähnelt der Regression, aber wir müssen eine andere Verlustfunktion verwenden. Beginnen wir mit der Generierung von Beispieldaten:
np.random.seed(0) # pick the seed for reproducibility - change it to explore the effects of random variations
n = 100
X, Y = make_classification(n_samples = n, n_features=2,
n_redundant=0, n_informative=2, flip_y=0.05,class_sep=1.5)
X = X.astype(np.float32)
Y = Y.astype(np.int32)
split = [ 70*n//100, (15+70)*n//100 ]
train_x, valid_x, test_x = np.split(X, split)
train_labels, valid_labels, test_labels = np.split(Y, split)
def plot_dataset(features, labels, W=None, b=None):
# prepare the plot
fig, ax = plt.subplots(1, 1)
ax.set_xlabel('$x_i[0]$ -- (feature 1)')
ax.set_ylabel('$x_i[1]$ -- (feature 2)')
colors = ['r' if l else 'b' for l in labels]
ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)
if W is not None:
min_x = min(features[:,0])
max_x = max(features[:,1])
min_y = min(features[:,1])*(1-.1)
max_y = max(features[:,1])*(1+.1)
cx = np.array([min_x,max_x],dtype=np.float32)
cy = (0.5-W[0]*cx-b)/W[1]
ax.plot(cx,cy,'g')
ax.set_ylim(min_y,max_y)
fig.show()
plot_dataset(train_x, train_labels)
Normalisierung von Daten
Vor dem Training ist es üblich, unsere Eingabefeatures auf den Standardbereich von [0,1] (oder [-1,1]) zu bringen. Die genauen Gründe dafür werden wir später im Kurs besprechen, aber kurz gesagt liegt der Grund darin: Wir möchten vermeiden, dass die Werte, die durch unser Netzwerk fließen, zu groß oder zu klein werden. Normalerweise einigen wir uns darauf, alle Werte in einem kleinen Bereich nahe 0 zu halten. Daher initialisieren wir die Gewichte mit kleinen Zufallszahlen und halten die Signale im gleichen Bereich.
Beim Normalisieren von Daten müssen wir den Minimalwert abziehen und durch die Spannweite teilen. Wir berechnen den Minimalwert und die Spannweite anhand der Trainingsdaten und normalisieren dann den Test-/Validierungsdatensatz mit denselben Minimal- und Spannweitenwerten aus dem Trainingssatz. Der Grund dafür ist, dass wir in der Praxis nur den Trainingssatz kennen und nicht alle neuen eingehenden Werte, die das Netzwerk vorhersagen soll. Gelegentlich kann es vorkommen, dass ein neuer Wert außerhalb des [0,1]-Bereichs liegt, aber das ist nicht entscheidend.
train_x_norm = (train_x-np.min(train_x)) / (np.max(train_x)-np.min(train_x))
valid_x_norm = (valid_x-np.min(train_x)) / (np.max(train_x)-np.min(train_x))
test_x_norm = (test_x-np.min(train_x)) / (np.max(train_x)-np.min(train_x))
Training eines Ein-Schicht-Perzeptrons
Lassen Sie uns die Gradientenberechnungs-Mechanismen von Tensorflow nutzen, um ein Ein-Schicht-Perzeptron zu trainieren.
Unser neuronales Netzwerk wird 2 Eingaben und 1 Ausgabe haben. Die Gewichtsmatrix $W$ wird die Größe $2\times1$ haben, und der Bias-Vektor $b$ -- $1$.
Das Kernmodell wird dasselbe sein wie im vorherigen Beispiel, aber die Verlustfunktion wird ein logistischer Verlust sein. Um den logistischen Verlust anzuwenden, müssen wir den Wert der Wahrscheinlichkeit als Ausgabe unseres Netzwerks erhalten, d.h. wir müssen die Ausgabe $z$ in den Bereich [0,1] bringen, indem wir die sigmoid-Aktivierungsfunktion verwenden: $p=\sigma(z)$.
Wenn wir die Wahrscheinlichkeit $p_i$ für den i-ten Eingabewert erhalten, der der tatsächlichen Klasse $y_i\in{0,1}$ entspricht, berechnen wir den Verlust als $\mathcal{L_i}=-(y_i\log p_i + (1-y_i)\log(1-p_i))$.
In Tensorflow können beide Schritte (Anwenden von Sigmoid und dann logistischer Verlust) mit einem einzigen Aufruf der Funktion sigmoid_cross_entropy_with_logits durchgeführt werden. Da wir unser Netzwerk in Minibatches trainieren, müssen wir den Verlust über alle Elemente eines Minibatches mit reduce_mean mitteln:
W = tf.Variable(tf.random.normal(shape=(2,1)),dtype=tf.float32)
b = tf.Variable(tf.zeros(shape=(1,),dtype=tf.float32))
learning_rate = 0.1
@tf.function
def train_on_batch(x, y):
with tf.GradientTape() as tape:
z = tf.matmul(x, W) + b
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y,logits=z))
dloss_dw, dloss_db = tape.gradient(loss, [W, b])
W.assign_sub(learning_rate * dloss_dw)
b.assign_sub(learning_rate * dloss_db)
return loss
Wir werden Minibatches mit 16 Elementen verwenden und ein paar Epochen des Trainings durchführen:
# Create a tf.data.Dataset object for easy batched iteration
dataset = tf.data.Dataset.from_tensor_slices((train_x_norm.astype(np.float32), train_labels.astype(np.float32)))
dataset = dataset.shuffle(128).batch(2)
for epoch in range(10):
for step, (x, y) in enumerate(dataset):
loss = train_on_batch(x, tf.expand_dims(y,1))
print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))
Um sicherzustellen, dass unser Training funktioniert hat, lassen Sie uns die Linie plotten, die zwei Klassen trennt. Die Trennlinie wird durch die Gleichung $W\times x + b = 0.5$ definiert.
plot_dataset(train_x,train_labels,W.numpy(),b.numpy())
Lassen Sie uns sehen, wie sich unser Modell auf den Validierungsdaten verhält.
pred = tf.matmul(test_x,W)+b
fig,ax = plt.subplots(1,2)
ax[0].scatter(test_x[:,0],test_x[:,1],c=pred[:,0]>0.5)
ax[1].scatter(test_x[:,0],test_x[:,1],c=valid_labels)
Um die Genauigkeit der Validierungsdaten zu berechnen, können wir den Booleschen Typ in Float umwandeln und den Mittelwert berechnen:
tf.reduce_mean(tf.cast(((pred[0]>0.5)==test_labels),tf.float32))
Lassen Sie uns erklären, was hier passiert:
* pred sind die vom Netzwerk vorhergesagten Werte. Es handelt sich dabei nicht direkt um Wahrscheinlichkeiten, da wir keine Aktivierungsfunktion verwendet haben. Werte größer als 0,5 entsprechen Klasse 1, und kleinere Werte - Klasse 0.
* pred[0]>0.5 erstellt einen booleschen Tensor mit Ergebnissen, wobei True Klasse 1 entspricht und False - Klasse 0.
* Wir vergleichen diesen Tensor mit den erwarteten Labels valid_labels und erhalten einen booleschen Vektor der korrekten Vorhersagen, wobei True einer korrekten Vorhersage entspricht und False einer falschen.
* Wir konvertieren diesen Tensor mit tf.cast in Gleitkommazahlen.
* Anschließend berechnen wir den Mittelwert mit tf.reduce_mean - das ist genau die gewünschte Genauigkeit.
Verwendung von TensorFlow/Keras-Optimierern
TensorFlow ist eng mit Keras integriert, das viele nützliche Funktionen enthält. Zum Beispiel können wir verschiedene Optimierungsalgorithmen verwenden. Lassen Sie uns das tun und dabei auch die erzielte Genauigkeit während des Trainings ausgeben.
optimizer = tf.keras.optimizers.Adam(0.01)
W = tf.Variable(tf.random.normal(shape=(2,1)))
b = tf.Variable(tf.zeros(shape=(1,),dtype=tf.float32))
@tf.function
def train_on_batch(x, y):
vars = [W, b]
with tf.GradientTape() as tape:
z = tf.sigmoid(tf.matmul(x, W) + b)
loss = tf.reduce_mean(tf.keras.losses.binary_crossentropy(z,y))
correct_prediction = tf.equal(tf.round(y), tf.round(z))
acc = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
grads = tape.gradient(loss, vars)
optimizer.apply_gradients(zip(grads,vars))
return loss,acc
for epoch in range(20):
for step, (x, y) in enumerate(dataset):
loss,acc = train_on_batch(tf.reshape(x,(-1,2)), tf.reshape(y,(-1,1)))
print('Epoch %d: last batch loss = %.4f, acc = %.4f' % (epoch, float(loss),acc))
Aufgabe 1: Zeichne die Graphen der Verlustfunktion und Genauigkeit auf Trainings- und Validierungsdaten während des Trainings.
Aufgabe 2: Versuche, das MNIST-Klassifikationsproblem mit diesem Code zu lösen. Hinweis: Verwende softmax_crossentropy_with_logits oder sparse_softmax_cross_entropy_with_logits als Verlustfunktion. Im ersten Fall musst du die erwarteten Ausgabewerte in One-Hot-Encoding bereitstellen, und im zweiten Fall - als Ganzzahlen der Klassen.
Keras
Deep Learning für Menschen
- Keras ist eine Bibliothek, die ursprünglich von Francois Chollet entwickelt wurde, um auf Tensorflow, CNTK und Theano aufzubauen und alle niedrigeren Frameworks zu vereinheitlichen. Sie können Keras weiterhin als separate Bibliothek installieren, aber es wird nicht empfohlen.
- Keras ist jetzt Teil der Tensorflow-Bibliothek.
- Sie können neuronale Netzwerke einfach aus Schichten konstruieren.
- Enthält die Funktion
fit, um das gesamte Training durchzuführen, sowie viele Funktionen, um mit typischen Daten (Bilder, Text usw.) zu arbeiten. - Viele Beispiele.
- Funktionale API vs. Sequenzielle API.
Keras bietet höhere Abstraktionen für neuronale Netzwerke, sodass wir mit Schichten, Modellen und Optimierern arbeiten können und nicht mit Tensors und Gradienten.
Klassisches Buch über Deep Learning vom Erfinder von Keras: Deep Learning mit Python
Funktionale API
Bei der Verwendung der funktionalen API definieren wir den Input des Netzwerks als keras.Input und berechnen dann den Output, indem wir ihn durch eine Reihe von Berechnungen leiten. Schließlich definieren wir das Modell als ein Objekt, das den Input in den Output transformiert.
Sobald wir das Modell-Objekt erhalten haben, müssen wir:
* Es kompilieren, indem wir die Verlustfunktion und den Optimierer angeben, den wir mit unserem Modell verwenden möchten.
* Es trainieren, indem wir die Funktion fit mit den Trainingsdaten (und möglicherweise Validierungsdaten) aufrufen.
inputs = tf.keras.Input(shape=(2,))
z = tf.keras.layers.Dense(1,kernel_initializer='glorot_uniform',activation='sigmoid')(inputs)
model = tf.keras.models.Model(inputs,z)
model.compile(tf.keras.optimizers.Adam(0.1),'binary_crossentropy',['accuracy'])
model.summary()
h = model.fit(train_x_norm,train_labels,batch_size=8,epochs=15)
plt.plot(h.history['accuracy'])
Sequenzielle API
Alternativ können wir ein Modell als eine Abfolge von Schichten betrachten und diese Schichten einfach hinzufügen, indem wir sie dem model-Objekt hinzufügen:
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(5,activation='sigmoid',input_shape=(2,)))
model.add(tf.keras.layers.Dense(1,activation='sigmoid'))
model.compile(tf.keras.optimizers.Adam(0.1),'binary_crossentropy',['accuracy'])
model.summary()
model.fit(train_x_norm,train_labels,validation_data=(test_x_norm,test_labels),batch_size=8,epochs=15)
Klassifikationsverlustfunktionen
Es ist wichtig, die Verlustfunktion und die Aktivierungsfunktion in der letzten Schicht des Netzwerks korrekt anzugeben. Die Hauptregeln sind folgende: * Wenn das Netzwerk eine Ausgabe hat (binäre Klassifikation), verwenden wir die Sigmoid-Aktivierungsfunktion, für Mehrklassenklassifikation - Softmax. * Wenn die Ausgabeklasse als One-Hot-Encoding dargestellt wird, ist die Verlustfunktion Cross-Entropy-Loss (kategoriale Kreuzentropie). Wenn die Ausgabe die Klassennummer enthält - Sparse Categorical Cross-Entropy. Für binäre Klassifikation - verwenden Sie Binary Cross-Entropy (gleichbedeutend mit Log Loss). * Multilabel-Klassifikation bedeutet, dass ein Objekt mehreren Klassen gleichzeitig angehören kann. In diesem Fall müssen wir die Labels mit One-Hot-Encoding kodieren und Sigmoid als Aktivierungsfunktion verwenden, sodass die Wahrscheinlichkeit jeder Klasse zwischen 0 und 1 liegt.
| Klassifikation | Labelformat | Aktivierungsfunktion | Verlust |
|---|---|---|---|
| Binär | Wahrscheinlichkeit der 1. Klasse | sigmoid | binary crossentropy |
| Binär | One-Hot-Encoding (2 Ausgaben) | softmax | categorical crossentropy |
| Mehrklassen | One-Hot-Encoding | softmax | categorical crossentropy |
| Mehrklassen | Klassennummer | softmax | sparse categorical crossentropy |
| Multilabel | One-Hot-Encoding | sigmoid | categorical crossentropy |
> Binäre Klassifikation kann auch als Sonderfall der Mehrklassenklassifikation mit zwei Ausgaben behandelt werden. In diesem Fall müssen wir Softmax verwenden.
Aufgabe 3:
Verwenden Sie Keras, um einen MNIST-Klassifikator zu trainieren:
Beachten Sie, dass Keras einige Standard-Datensätze enthält, einschließlich MNIST. Um MNIST aus Keras zu verwenden, benötigen Sie nur ein paar Zeilen Code (weitere Informationen hier).
Probieren Sie verschiedene Netzwerk-Konfigurationen aus, mit unterschiedlicher Anzahl von Schichten/Neuronen und Aktivierungsfunktionen.
Welche Genauigkeit konnten Sie maximal erreichen?
Wichtige Erkenntnisse
- Tensorflow ermöglicht es, auf niedrigem Niveau mit Tensors zu arbeiten, was maximale Flexibilität bietet.
- Es gibt praktische Werkzeuge, um mit Daten (
td.Data) und Schichten (tf.layers) zu arbeiten. - Für Anfänger oder typische Aufgaben wird empfohlen, Keras zu verwenden, da es ermöglicht, Netzwerke aus Schichten zu konstruieren.
- Wenn eine nicht-standardmäßige Architektur benötigt wird, kann man eine eigene Keras-Schicht implementieren und diese dann in Keras-Modellen verwenden.
- Es ist eine gute Idee, sich auch PyTorch anzusehen und die Ansätze zu vergleichen.
Ein gutes Beispiel-Notebook vom Ersteller von Keras zu Keras und Tensorflow 2.0 findet sich hier.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in PyTorch
> Dieses Notebook ist Teil des AI for Beginners Curricula. Besuchen Sie das Repository für das vollständige Lernmaterial.
Neuronale Frameworks
Wir haben gelernt, dass man zum Trainieren von neuronalen Netzwerken Folgendes benötigt: * Schnelles Multiplizieren von Matrizen (Tensors) * Gradientenberechnung, um die Optimierung mittels Gradientenabstieg durchzuführen
Was neuronale Netzwerk-Frameworks ermöglichen: * Arbeiten mit Tensors auf beliebiger verfügbarer Hardware, sei es CPU, GPU oder sogar TPU * Automatische Berechnung von Gradienten (sie sind für alle eingebauten Tensor-Funktionen explizit programmiert)
Optional:
* Konstruktor für neuronale Netzwerke / höherwertige API (Netzwerk als Abfolge von Schichten beschreiben)
* Einfache Trainingsfunktionen (fit, wie in Scikit Learn)
* Eine Vielzahl von Optimierungsalgorithmen zusätzlich zum Gradientenabstieg
* Abstraktionen für Datenverarbeitung (die idealerweise auch auf der GPU funktionieren)
Beliebteste Frameworks
- Tensorflow 1.x - erstes weit verbreitetes Framework (Google). Ermöglichte es, einen statischen Berechnungsgraphen zu definieren, ihn auf die GPU zu übertragen und explizit auszuwerten
- PyTorch - ein Framework von Facebook, das immer beliebter wird
- Keras - eine höherstufige API, die auf Tensorflow/PyTorch aufbaut, um die Nutzung neuronaler Netze zu vereinheitlichen und zu vereinfachen (Francois Chollet)
- Tensorflow 2.x + Keras - neue Version von Tensorflow mit integrierter Keras-Funktionalität, die dynamische Berechnungsgraphen unterstützt und Tensoroperationen ermöglicht, die sehr ähnlich zu numpy (und PyTorch) sind
In diesem Notebook lernen wir, wie man PyTorch verwendet. Stellen Sie sicher, dass Sie eine aktuelle Version von PyTorch installiert haben – um dies zu überprüfen, folgen Sie den Anweisungen auf ihrer Website. Normalerweise ist es so einfach wie
pip install torch torchvision
oder
conda install pytorch -c pytorch
import torch
torch.__version__
Grundkonzepte: Tensor
Ein Tensor ist ein mehrdimensionales Array. Es ist sehr praktisch, Tensoren zu verwenden, um verschiedene Arten von Daten darzustellen: * 400x400 - Schwarz-Weiß-Bild * 400x400x3 - Farbbild * 16x400x400x3 - Minibatch von 16 Farbbildern * 25x400x400x3 - Eine Sekunde eines Videos mit 25 Bildern pro Sekunde * 8x25x400x400x3 - Minibatch von 8 einsekündigen Videos
Einfache Tensors
Sie können ganz einfach einfache Tensors aus Listen von np-Arrays erstellen oder zufällige generieren:
a = torch.tensor([[1,2],[3,4]])
print(a)
a = torch.randn(size=(10,3))
print(a)
Sie können arithmetische Operationen auf Tensoren verwenden, die elementweise wie in numpy ausgeführt werden. Tensoren werden bei Bedarf automatisch auf die erforderliche Dimension erweitert. Um ein numpy-Array aus einem Tensor zu extrahieren, verwenden Sie .numpy():
print(a-a[0])
print(torch.exp(a)[0].numpy())
In-place- und out-of-place-Operationen
Tensor-Operationen wie +/add geben neue Tensoren zurück. Manchmal ist es jedoch notwendig, den bestehenden Tensor direkt zu verändern. Die meisten Operationen haben ihre in-place-Gegenstücke, die mit _ enden:
u = torch.tensor(5)
print("Result when adding out-of-place:",u.add(torch.tensor(3)))
u.add_(torch.tensor(3))
print("Result after adding in-place:", u)
So können wir die Summe aller Zeilen in einer Matrix auf naive Weise berechnen:
s = torch.zeros_like(a[0])
for i in a:
s.add_(i)
print(s)
torch.sum(a,axis=0)
Du kannst mehr über PyTorch-Tensoren in der offiziellen Dokumentation lesen.
Gradienten berechnen
Für das Backpropagation-Verfahren müssen Gradienten berechnet werden. Wir können das Attribut requires_grad eines beliebigen PyTorch-Tensors auf True setzen. Dadurch werden alle Operationen mit diesem Tensor für die Gradientenberechnung nachverfolgt. Um die Gradienten zu berechnen, muss die Methode backward() aufgerufen werden. Danach sind die Gradienten über das Attribut grad verfügbar:
a = torch.randn(size=(2, 2), requires_grad=True)
b = torch.randn(size=(2, 2))
c = torch.mean(torch.sqrt(torch.square(a) + torch.square(b))) # Do some math using `a`
c.backward() # call backward() to compute all gradients
# What's the gradient of `c` with respect to `a`?
print(a.grad)
Um genauer zu sein, PyTorch akkumuliert Gradienten automatisch. Wenn Sie retain_graph=True angeben, wenn Sie backward aufrufen, wird der Berechnungsgraph beibehalten, und ein neuer Gradient wird dem grad-Feld hinzugefügt. Um die Berechnung der Gradienten von Grund auf neu zu starten, müssen wir das grad-Feld explizit auf 0 zurücksetzen, indem wir zero_() aufrufen:
c = torch.mean(torch.sqrt(torch.square(a) + torch.square(b)))
c.backward(retain_graph=True)
c.backward(retain_graph=True)
print(a.grad)
a.grad.zero_()
c.backward()
print(a.grad)
Um Gradienten zu berechnen, erstellt und verwaltet PyTorch einen Berechnungsgraphen. Für jeden Tensor, der das requires_grad-Flag auf True gesetzt hat, verwaltet PyTorch eine spezielle Funktion namens grad_fn, die die Ableitung des Ausdrucks gemäß der Kettenregel der Differentiation berechnet:
print(c)
Hier wird c mit der Funktion mean berechnet, daher verweist grad_fn auf eine Funktion namens MeanBackward.
In den meisten Fällen möchten wir, dass PyTorch den Gradienten einer Skalarfunktion (wie z. B. einer Verlustfunktion) berechnet. Wenn wir jedoch den Gradienten eines Tensors in Bezug auf einen anderen Tensor berechnen möchten, ermöglicht uns PyTorch, das Produkt einer Jacobimatrix mit einem gegebenen Vektor zu berechnen.
Angenommen, wir haben eine Vektorfunktion $\vec{y}=f(\vec{x})$, wobei $\vec{x}=\langle x_1,\dots,x_n\rangle$ und $\vec{y}=\langle y_1,\dots,y_m\rangle$, dann wird der Gradient von $\vec{y}$ in Bezug auf $\vec{x}$ durch eine Jacobian-Matrix definiert:
$$ \begin{align}J=\left(\begin{array}{ccc} \frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{1}}{\partial x_{n}}\ \vdots & \ddots & \vdots\ \frac{\partial y_{m}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}} \end{array}\right)\end{align} $$
Anstatt uns Zugriff auf die gesamte Jacobimatrix zu geben, berechnet PyTorch das Produkt $v^T\cdot J$ der Jacobimatrix mit einem Vektor
$v=(v_1 \dots v_m)$. Um dies zu tun, müssen wir backward aufrufen und v als Argument übergeben. Die Größe von v sollte mit der Größe des ursprünglichen Tensors übereinstimmen, in Bezug auf den wir den Gradienten berechnen.
c = torch.sqrt(torch.square(a) + torch.square(b))
c.backward(torch.eye(2)) # eye(2) means 2x2 identity matrix
print(a.grad)
Mehr über die Berechnung von Jakobianern in PyTorch finden Sie in der offiziellen Dokumentation
Beispiel 0: Optimierung mit Gradientenabstieg
Versuchen wir, mithilfe der automatischen Differenzierung ein Minimum einer einfachen Funktion mit zwei Variablen $f(x_1,x_2)=(x_1-3)^2+(x_2+2)^2$ zu finden. Lassen Sie den Tensor x die aktuellen Koordinaten eines Punktes halten. Wir beginnen mit einem Startpunkt $x^{(0)}=(0,0)$ und berechnen den nächsten Punkt in der Sequenz mithilfe der Gradientenabstiegsformel:
$$
x^{(n+1)} = x^{(n)} - \eta\nabla f
$$
Hier ist $\eta$ die sogenannte Lernrate (wir werden sie im Code mit lr bezeichnen), und $\nabla f = (\frac{\partial f}{\partial x_1},\frac{\partial f}{\partial x_2})$ - der Gradient von $f$.
Beginnen wir damit, den Startwert von x und die Funktion f zu definieren:
x = torch.zeros(2,requires_grad=True)
f = lambda x : (x-torch.tensor([3,-2])).pow(2).sum()
lr = 0.1
Jetzt führen wir 15 Iterationen des Gradientenabstiegs durch. In jeder Iteration werden wir die x-Koordinaten aktualisieren und sie ausgeben, um sicherzustellen, dass wir uns dem Minimum bei (3,-2) nähern:
for i in range(15):
y = f(x)
y.backward()
gr = x.grad
x.data.add_(-lr*gr)
x.grad.zero_()
print("Step {}: x[0]={}, x[1]={}".format(i,x[0],x[1]))
Beispiel 1: Lineare Regression
Jetzt wissen wir genug, um das klassische Problem der linearen Regression zu lösen. Lassen Sie uns ein kleines synthetisches Dataset erstellen:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification, make_regression
from sklearn.model_selection import train_test_split
import random
np.random.seed(13) # pick the seed for reproducibility - change it to explore the effects of random variations
train_x = np.linspace(0, 3, 120)
train_labels = 2 * train_x + 0.9 + np.random.randn(*train_x.shape) * 0.5
plt.scatter(train_x,train_labels)
Lineare Regression wird durch eine gerade Linie $f_{W,b}(x) = Wx+b$ definiert, wobei $W, b$ Modellparameter sind, die wir bestimmen müssen. Ein Fehler auf unserem Datensatz ${x_i,y_i}{i=1}^N$ (auch als Verlustfunktion bezeichnet) kann als mittlere quadratische Abweichung definiert werden: $$ \mathcal{L}(W,b) = {1\over N}\sum{i=1}^N (f_{W,b}(x_i)-y_i)^2 $$
Lassen Sie uns unser Modell und die Verlustfunktion definieren:
input_dim = 1
output_dim = 1
learning_rate = 0.1
# This is our weight matrix
w = torch.tensor([100.0],requires_grad=True,dtype=torch.float32)
# This is our bias vector
b = torch.zeros(size=(output_dim,),requires_grad=True)
def f(x):
return torch.matmul(x,w) + b
def compute_loss(labels, predictions):
return torch.mean(torch.square(labels - predictions))
Wir werden das Modell mit einer Reihe von Minibatches trainieren. Wir verwenden Gradientenabstieg, um die Modellparameter mit den folgenden Formeln anzupassen: $$ \begin{array}{l} W^{(n+1)}=W^{(n)}-\eta\frac{\partial\mathcal{L}}{\partial W} \ b^{(n+1)}=b^{(n)}-\eta\frac{\partial\mathcal{L}}{\partial b} \ \end{array} $$
def train_on_batch(x, y):
predictions = f(x)
loss = compute_loss(y, predictions)
loss.backward()
w.data.sub_(learning_rate * w.grad)
b.data.sub_(learning_rate * b.grad)
w.grad.zero_()
b.grad.zero_()
return loss
Lass uns mit dem Training beginnen. Wir werden mehrere Durchläufe durch den Datensatz machen (sogenannte Epochen), ihn in Minibatches aufteilen und die oben definierte Funktion aufrufen:
# Shuffle the data.
indices = np.random.permutation(len(train_x))
features = torch.tensor(train_x[indices],dtype=torch.float32)
labels = torch.tensor(train_labels[indices],dtype=torch.float32)
batch_size = 4
for epoch in range(10):
for i in range(0,len(features),batch_size):
loss = train_on_batch(features[i:i+batch_size].view(-1,1),labels[i:i+batch_size])
print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))
Wir haben nun optimierte Parameter $W$ und $b$ erhalten. Beachten Sie, dass ihre Werte den ursprünglichen Werten ähnlich sind, die bei der Erstellung des Datensatzes verwendet wurden ($W=2, b=1$).
w,b
plt.scatter(train_x,train_labels)
x = np.array([min(train_x),max(train_x)])
with torch.no_grad():
y = w.numpy()*x+b.numpy()
plt.plot(x,y,color='red')
Berechnungen auf der GPU
Um die GPU für Berechnungen zu nutzen, unterstützt PyTorch das Verschieben von Tensoren auf die GPU und das Erstellen eines Berechnungsgraphen für die GPU. Üblicherweise definieren wir zu Beginn unseres Codes das verfügbare Berechnungsgerät device (entweder cpu oder cuda) und verschieben dann alle Tensoren mit einem Aufruf .to(device) auf dieses Gerät. Alternativ können wir Tensoren direkt auf dem angegebenen Gerät erstellen, indem wir den Parameter device=... an den Tensor-Erstellungs-Code übergeben. Solcher Code funktioniert ohne Änderungen sowohl auf der CPU als auch auf der GPU:
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('Doing computations on '+device)
### Changes here: indicate device
w = torch.tensor([100.0],requires_grad=True,dtype=torch.float32,device=device)
b = torch.zeros(size=(output_dim,),requires_grad=True,device=device)
def f(x):
return torch.matmul(x,w) + b
def compute_loss(labels, predictions):
return torch.mean(torch.square(labels - predictions))
def train_on_batch(x, y):
predictions = f(x)
loss = compute_loss(y, predictions)
loss.backward()
w.data.sub_(learning_rate * w.grad)
b.data.sub_(learning_rate * b.grad)
w.grad.zero_()
b.grad.zero_()
return loss
batch_size = 4
for epoch in range(10):
for i in range(0,len(features),batch_size):
### Changes here: move data to required device
loss = train_on_batch(features[i:i+batch_size].view(-1,1).to(device),labels[i:i+batch_size].to(device))
print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))
Beispiel 2: Klassifikation
Nun betrachten wir ein Problem der binären Klassifikation. Ein gutes Beispiel für ein solches Problem wäre die Klassifikation eines Tumors als bösartig oder gutartig basierend auf seiner Größe und seinem Alter.
Das Kernmodell ähnelt der Regression, aber wir müssen eine andere Verlustfunktion verwenden. Beginnen wir mit der Generierung von Beispieldaten:
np.random.seed(0) # pick the seed for reproducibility - change it to explore the effects of random variations
n = 100
X, Y = make_classification(n_samples = n, n_features=2,
n_redundant=0, n_informative=2, flip_y=0.1,class_sep=1.5)
X = X.astype(np.float32)
Y = Y.astype(np.int32)
split = [ 70*n//100, (15+70)*n//100 ]
train_x, valid_x, test_x = np.split(X, split)
train_labels, valid_labels, test_labels = np.split(Y, split)
def plot_dataset(features, labels, W=None, b=None):
# prepare the plot
fig, ax = plt.subplots(1, 1)
ax.set_xlabel('$x_i[0]$ -- (feature 1)')
ax.set_ylabel('$x_i[1]$ -- (feature 2)')
colors = ['r' if l else 'b' for l in labels]
ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)
if W is not None:
min_x = min(features[:,0])
max_x = max(features[:,1])
min_y = min(features[:,1])*(1-.1)
max_y = max(features[:,1])*(1+.1)
cx = np.array([min_x,max_x],dtype=np.float32)
cy = (0.5-W[0]*cx-b)/W[1]
ax.plot(cx,cy,'g')
ax.set_ylim(min_y,max_y)
fig.show()
plot_dataset(train_x, train_labels)
Training eines Ein-Schicht-Perzeptrons
Lassen Sie uns die Gradientenberechnungsmechanismen von PyTorch nutzen, um ein Ein-Schicht-Perzeptron zu trainieren.
Unser neuronales Netzwerk wird 2 Eingaben und 1 Ausgabe haben. Die Gewichtsmatrix $W$ wird die Größe $2\times1$ haben, und der Bias-Vektor $b$ -- $1$.
Um unseren Code übersichtlicher zu gestalten, fassen wir alle Parameter in einer einzigen Klasse zusammen:
class Network():
def __init__(self):
self.W = torch.randn(size=(2,1),requires_grad=True)
self.b = torch.zeros(size=(1,),requires_grad=True)
def forward(self,x):
return torch.matmul(x,self.W)+self.b
def zero_grad(self):
self.W.data.zero_()
self.b.data.zero_()
def update(self,lr=0.1):
self.W.data.sub_(lr*self.W.grad)
self.b.data.sub_(lr*self.b)
net = Network()
> Beachten Sie, dass wir W.data.zero_() anstelle von W.zero_() verwenden. Das ist notwendig, da wir einen Tensor, der durch den Autograd-Mechanismus verfolgt wird, nicht direkt ändern können.
Das Kernmodell bleibt dasselbe wie im vorherigen Beispiel, aber die Verlustfunktion wird ein logistischer Verlust sein. Um den logistischen Verlust anzuwenden, müssen wir den Wert der Wahrscheinlichkeit als Ausgabe unseres Netzwerks erhalten, d.h. wir müssen die Ausgabe $z$ mit der sigmoid-Aktivierungsfunktion in den Bereich [0,1] bringen: $p=\sigma(z)$.
Wenn wir die Wahrscheinlichkeit $p_i$ für den i-ten Eingabewert erhalten, der der tatsächlichen Klasse $y_i\in{0,1}$ entspricht, berechnen wir den Verlust als $\mathcal{L_i}=-(y_i\log p_i + (1-y_i)log(1-p_i))$.
In PyTorch können beide Schritte (Anwendung von Sigmoid und anschließend logistischer Verlust) mit einem einzigen Aufruf der Funktion binary_cross_entropy_with_logits durchgeführt werden. Da wir unser Netzwerk in Minibatches trainieren, müssen wir den Verlust über alle Elemente eines Minibatches mitteln – und das wird ebenfalls automatisch von der Funktion binary_cross_entropy_with_logits erledigt:
> Der Aufruf von binary_crossentropy_with_logits entspricht einem Aufruf von sigmoid, gefolgt von einem Aufruf von binary_crossentropy.
def train_on_batch(net, x, y):
z = net.forward(x).flatten()
loss = torch.nn.functional.binary_cross_entropy_with_logits(input=z,target=y)
net.zero_grad()
loss.backward()
net.update()
return loss
Um durch unsere Daten zu iterieren, verwenden wir den eingebauten PyTorch-Mechanismus zur Verwaltung von Datensätzen. Dieser basiert auf zwei Konzepten: * Dataset ist die Hauptquelle der Daten, es kann entweder Iterable oder Map-style sein. * Dataloader ist dafür verantwortlich, die Daten aus einem Dataset zu laden und sie in Minibatches aufzuteilen.
In unserem Fall definieren wir ein Dataset basierend auf einem Tensor und teilen es in Minibatches mit jeweils 16 Elementen auf. Jedes Minibatch enthält zwei Tensoren: Eingabedaten (Größe=16x2) und Labels (einen Vektor der Länge 16 vom Typ Integer - Klassennummer).
# Create a tf.data.Dataset object for easy batched iteration
dataset = torch.utils.data.TensorDataset(torch.tensor(train_x),torch.tensor(train_labels,dtype=torch.float32))
dataloader = torch.utils.data.DataLoader(dataset,batch_size=16)
list(dataloader)[0]
Jetzt können wir den gesamten Datensatz durchlaufen, um unser Netzwerk für 15 Epochen zu trainieren:
for epoch in range(15):
for (x, y) in dataloader:
loss = train_on_batch(net,x,y)
print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))
Erhaltene Parameter:
print(net.W,net.b)
Um sicherzustellen, dass unser Training funktioniert hat, lassen Sie uns die Linie zeichnen, die zwei Klassen trennt. Die Trennlinie wird durch die Gleichung $W\times x + b = 0.5$ definiert.
plot_dataset(train_x,train_labels,net.W.detach().numpy(),net.b.detach().numpy())
pred = torch.sigmoid(net.forward(torch.tensor(valid_x)))
torch.mean(((pred.view(-1)>0.5)==(torch.tensor(valid_labels)>0.5)).type(torch.float32))
Lassen Sie uns erklären, was hier vor sich geht:
* pred ist der Vektor der vorhergesagten Wahrscheinlichkeiten für den gesamten Validierungsdatensatz. Wir berechnen ihn, indem wir die ursprünglichen Validierungsdaten valid_x durch unser Netzwerk laufen lassen und sigmoid anwenden, um Wahrscheinlichkeiten zu erhalten.
* pred.view(-1) erstellt eine abgeflachte Ansicht des ursprünglichen Tensors. view ist ähnlich der reshape-Funktion in numpy.
* pred.view(-1)>0.5 gibt einen booleschen Tensor oder Wahrheitswert zurück, der die vorhergesagte Klasse zeigt (False = Klasse 0, True = Klasse 1).
* Ebenso erstellt torch.tensor(valid_labels)>0.5) den booleschen Tensor der Wahrheitswerte für die Validierungslabels.
* Wir vergleichen diese beiden Tensoren elementweise und erhalten einen weiteren booleschen Tensor, bei dem True einer korrekten Vorhersage entspricht und False einer falschen.
* Wir konvertieren diesen Tensor in einen Gleitkommawert und berechnen seinen Mittelwert mit torch.mean - das ist die gewünschte Genauigkeit.
Neuronale Netzwerke und Optimierer
In PyTorch wird ein spezielles Modul torch.nn.Module definiert, um ein neuronales Netzwerk darzustellen. Es gibt zwei Methoden, um ein eigenes neuronales Netzwerk zu definieren:
* Sequential, bei dem Sie einfach eine Liste von Schichten angeben, die Ihr Netzwerk bilden
* Als Klasse, die von torch.nn.Module erbt
Die erste Methode ermöglicht es Ihnen, standardisierte Netzwerke mit einer sequentiellen Zusammensetzung von Schichten zu definieren, während die zweite Methode flexibler ist und die Möglichkeit bietet, Netzwerke mit beliebig komplexen Architekturen auszudrücken.
Innerhalb von Modulen können Sie standardmäßige Schichten verwenden, wie zum Beispiel:
* Linear - dichte lineare Schicht, äquivalent zu einem einlagigen Perzeptron. Sie hat dieselbe Architektur, wie wir sie oben für unser Netzwerk definiert haben
* Softmax, Sigmoid, ReLU - Schichten, die den Aktivierungsfunktionen entsprechen
* Es gibt auch andere Schichten für spezielle Netzwerktypen - Faltungsnetzwerke, rekurrente Netzwerke usw. Viele davon werden wir später im Kurs erneut betrachten.
> Die meisten Aktivierungs- und Verlustfunktionen in PyTorch sind in zwei Formen verfügbar: als Funktion (im Namespace torch.nn.functional) und als Schicht (im Namespace torch.nn). Für Aktivierungsfunktionen ist es oft einfacher, funktionale Elemente aus torch.nn.functional zu verwenden, ohne ein separates Schichtobjekt zu erstellen.
Wenn wir ein einlagiges Perzeptron trainieren möchten, können wir einfach eine eingebaute Linear-Schicht verwenden:
net = torch.nn.Linear(2,1) # 2 inputs, 1 output
print(list(net.parameters()))
Wie Sie sehen, gibt die Methode parameters() alle Parameter zurück, die während des Trainings angepasst werden müssen. Sie entsprechen der Gewichtsmatrix $W$ und dem Bias $b$. Sie werden feststellen, dass requires_grad auf True gesetzt ist, da wir die Gradienten in Bezug auf die Parameter berechnen müssen.
PyTorch enthält auch integrierte Optimierer, die Optimierungsmethoden wie Gradientenabstieg implementieren. So können wir einen stochastischen Gradientenabstiegs-Optimierer definieren:
optim = torch.optim.SGD(net.parameters(),lr=0.05)
Mit dem Optimierer wird unsere Trainingsschleife so aussehen:
val_x = torch.tensor(valid_x)
val_lab = torch.tensor(valid_labels)
for ep in range(10):
for (x,y) in dataloader:
z = net(x).flatten()
loss = torch.nn.functional.binary_cross_entropy_with_logits(z,y)
optim.zero_grad()
loss.backward()
optim.step()
acc = ((torch.sigmoid(net(val_x).flatten())>0.5).float()==val_lab).float().mean()
print(f"Epoch {ep}: last batch loss = {loss}, val acc = {acc}")
> Sie werden feststellen, dass wir, um unser Netzwerk auf Eingabedaten anzuwenden, net(x) anstelle von net.forward(x) verwenden können, da nn.Module die Python-Funktion __call__() implementiert.
Unter Berücksichtigung dessen können wir eine generische train-Funktion definieren:
def train(net, dataloader, val_x, val_lab, epochs=10, lr=0.05):
optim = torch.optim.Adam(net.parameters(),lr=lr)
for ep in range(epochs):
for (x,y) in dataloader:
z = net(x).flatten()
loss = torch.nn.functional.binary_cross_entropy_with_logits(z,y)
optim.zero_grad()
loss.backward()
optim.step()
acc = ((torch.sigmoid(net(val_x).flatten())>0.5).float()==val_lab).float().mean()
print(f"Epoch {ep}: last batch loss = {loss}, val acc = {acc}")
net = torch.nn.Linear(2,1)
train(net,dataloader,val_x,val_lab,lr=0.03)
Definition eines Netzwerks als Abfolge von Schichten
Nun trainieren wir ein mehrschichtiges Perzeptron. Es kann einfach durch die Angabe einer Abfolge von Schichten definiert werden. Das resultierende Objekt wird automatisch von Module erben, z. B. wird es auch die Methode parameters besitzen, die alle Parameter des gesamten Netzwerks zurückgibt.
net = torch.nn.Sequential(torch.nn.Linear(2,5),torch.nn.Sigmoid(),torch.nn.Linear(5,1))
print(net)
Wir können dieses mehrschichtige Netzwerk mit der Funktion train trainieren, die wir oben definiert haben:
train(net,dataloader,val_x,val_lab)
Ein Netzwerk als Klasse definieren
Die Verwendung einer von torch.nn.Module abgeleiteten Klasse ist eine flexiblere Methode, da wir beliebige Berechnungen darin definieren können. Module automatisiert viele Dinge, z. B. erkennt es automatisch alle internen Variablen, die PyTorch-Schichten sind, und sammelt deren Parameter für die Optimierung. Sie müssen lediglich alle Schichten des Netzwerks als Mitglieder der Klasse definieren:
class MyNet(torch.nn.Module):
def __init__(self,hidden_size=10,func=torch.nn.Sigmoid()):
super().__init__()
self.fc1 = torch.nn.Linear(2,hidden_size)
self.func = func
self.fc2 = torch.nn.Linear(hidden_size,1)
def forward(self,x):
x = self.fc1(x)
x = self.func(x)
x = self.fc2(x)
return x
net = MyNet(func=torch.nn.ReLU())
print(net)
train(net,dataloader,val_x,val_lab,lr=0.005)
Aufgabe 1: Zeichne die Graphen der Verlustfunktion und der Genauigkeit für die Trainings- und Validierungsdaten während des Trainings.
Aufgabe 2: Versuche, das MNIST-Klassifikationsproblem mit diesem Code zu lösen. Hinweis: Verwende crossentropy_with_logits als Verlustfunktion.
Lassen Sie uns den geschriebenen PyTorch-Modellcode in ein PyTorch-Lightning-Modul einbetten. Dies ermöglicht es, mit Ihrem Modell bequemer und flexibler zu arbeiten, indem verschiedene Lightning-Methoden für das Training und die Genauigkeitsprüfung verwendet werden.
Zuerst müssen wir PyTorch Lightning installieren und importieren. Dies kann mit dem Befehl
pip install pytorch-lightning
oder
conda install -c conda-forge pytorch-lightning
import pytorch_lightning as pl
Damit unser Code in Lightning funktioniert, müssen wir Folgendes tun:
- Eine Unterklasse von
pl.LightningModuleerstellen und darin die Modellarchitektur in der__init__-Methode sowie dieforward-Methode hinzufügen. - Den verwendeten Optimierer in die Methode
configure_optimizers()verschieben. - Den Trainings- und Validierungsprozess in den Methoden
training_stepbzw.validation_stepdefinieren. - (Optional) Einen Testprozess (
test_step-Methode) und einen Vorhersageprozess (predict_step-Methode) implementieren.
Es sollte auch verstanden werden, dass PyTorch Lightning eine eingebaute Übersetzung von Modellen auf verschiedene Geräte bietet, abhängig davon, wo sich die eingehenden Daten aus den DataLoaders befinden. Daher sollten alle Aufrufe von .cuda() oder .to(device) aus dem Code entfernt werden.
class MyNetPL(pl.LightningModule):
def __init__(self, hidden_size = 10, func = torch.nn.Sigmoid()):
super().__init__()
self.fc1 = torch.nn.Linear(2,hidden_size)
self.func = func
self.fc2 = torch.nn.Linear(hidden_size,1)
self.val_epoch_num = 0 # for logging
def forward(self, x):
x = self.fc1(x)
x = self.func(x)
x = self.fc2(x)
return x
def training_step(self, batch, batch_nb):
x, y = batch
y_res = self(x).view(-1)
loss = torch.nn.functional.binary_cross_entropy_with_logits(y_res, y)
return loss
def configure_optimizers(self):
optimizer = torch.optim.SGD(self.parameters(), lr = 0.005)
return optimizer
def validation_step(self, batch, batch_nb):
x, y = batch
y_res = self(x).view(-1)
val_loss = torch.nn.functional.binary_cross_entropy_with_logits(y_res, y)
print("Epoch ", self.val_epoch_num, ": val loss = ", val_loss.item(), " val acc = ",((torch.sigmoid(y_res.flatten())>0.5).float()==y).float().mean().item(), sep = "")
self.val_epoch_num += 1
Lassen Sie uns auch Dataset und DataLoader für die Validierung hinzufügen:
valid_dataset = torch.utils.data.TensorDataset(torch.tensor(valid_x),torch.tensor(valid_labels,dtype=torch.float32))
valid_dataloader = torch.utils.data.DataLoader(valid_dataset, batch_size = 16)
Jetzt ist unser Modell bereit für das Training. In Pytorch Lightning wird dieser Prozess durch ein Objekt der Trainer-Klasse implementiert, das im Wesentlichen das Modell mit beliebigen Datensätzen "mischt".
net = MyNetPL(func=torch.nn.ReLU())
trainer = pl.Trainer(max_epochs = 30, log_every_n_steps = 1, accelerator='gpu', devices=1)
trainer.fit(model = net, train_dataloaders = dataloader, val_dataloaders = valid_dataloader)
Erkenntnisse
- PyTorch ermöglicht es Ihnen, auf niedrigem Niveau mit Tensors zu arbeiten, was Ihnen maximale Flexibilität bietet.
- Es gibt praktische Werkzeuge zur Arbeit mit Daten, wie Datasets und Dataloaders.
- Sie können neuronale Netzwerkarchitekturen entweder mit der
Sequential-Syntax definieren oder eine Klasse vontorch.nn.Moduleableiten. - Für einen noch einfacheren Ansatz zur Definition und zum Training eines Netzwerks sollten Sie sich PyTorch Lightning ansehen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Klassifikation mit PyTorch/TensorFlow
Laboraufgabe aus dem AI for Beginners Curriculum.
Teil 1: Iris-Klassifikation
Der Iris-Datensatz enthält 150 Datensätze von 3 verschiedenen Iris-Klassen. Jeder Datensatz enthält 4 numerische Parameter: Kelchlänge/-breite und Blütenblattlänge/-breite. Es handelt sich um ein einfaches Dataset, für das kein leistungsstarkes neuronales Netzwerk erforderlich ist.
Abrufen des Datensatzes
Der Iris-Datensatz ist in Scikit Learn integriert, sodass wir ihn leicht abrufen können:
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris = load_iris()
features = iris['data']
labels = iris['target']
class_names = iris['target_names']
feature_names = iris['feature_names']
print(f"Features: {feature_names}, Classes: {class_names}")
Daten visualisieren
In vielen Fällen ist es sinnvoll, die Daten zu visualisieren, um zu sehen, ob sie trennbar erscheinen – das würde uns bestätigen, dass wir ein gutes Klassifikationsmodell erstellen können. Da wir nur wenige Merkmale haben, können wir eine Reihe von paarweisen 2D-Streudiagrammen erstellen, bei denen die verschiedenen Klassen durch unterschiedliche Punktfarben dargestellt werden. Dies kann automatisch mit einem Paket namens seaborn erledigt werden:
import seaborn as sns
import pandas as pd
df = pd.DataFrame(features,columns=feature_names).join(pd.DataFrame(labels,columns=['Label']))
df
sns.pairplot(df,hue='Label')
Daten normalisieren und kodieren
Um Daten für das Training eines neuronalen Netzwerks vorzubereiten, müssen die Eingaben in den Bereich [0..1] normalisiert werden. Dies kann entweder mit einfachen numpy-Operationen oder mit Scikit Learn-Methoden durchgeführt werden.
Außerdem müssen Sie entscheiden, ob das Ziel-Label als One-Hot-Encoding vorliegen soll oder nicht. PyTorch und TensorFlow erlauben es, die Klassennummer entweder als Ganzzahl (von 0 bis N-1) oder als One-Hot-encodierten Vektor zu übergeben. Beim Erstellen der Struktur des neuronalen Netzwerks müssen Sie die Verlustfunktion entsprechend angeben (z. B. sparse categorical crossentropy für die numerische Darstellung und crossentropy loss für One-Hot-Encoding). One-Hot-Encoding kann ebenfalls mit Sklearn durchgeführt werden oder mit diesem Code-Snippet:
n_values = np.max(labels) + 1
labels_onehot = np.eye(n_values)[labels]
# Code to normalize and encode the data
Daten in Training und Test aufteilen
Da wir kein separates Trainings- und Test-Dataset haben, müssen wir es in Trainings- und Test-Dataset mit Sklearn aufteilen.
# Split the data
Definieren und Trainieren eines neuronalen Netzwerks
Jetzt können Sie loslegen: Importieren Sie Ihr bevorzugtes Framework, definieren Sie das neuronale Netzwerk und beginnen Sie mit dem Training, während Sie das Verhalten der Trainings- und Validierungsgenauigkeit beobachten.
# Define the network
# Train the network
# Visualize train/validation accuracy graph
Experiment
Jetzt können Sie mit verschiedenen Netzwerkarchitekturen experimentieren, um zu sehen, wie sich dies auf das Ergebnis auswirkt. Versuchen Sie: 1. Ein Netzwerk mit einer Schicht und 3 Neuronen (entspricht der Anzahl der Klassen) 1. Ein Netzwerk mit zwei Schichten und einer kleinen/mittleren/großen versteckten Schicht 1. Die Verwendung von mehr Schichten
Achten Sie darauf, Überanpassung zu beobachten, wenn Sie ein komplexes Modell mit vielen Neuronen (Parametern) verwenden.
# Experiment
Teil 2: MNIST-Training
Sowohl Keras als auch PyTorch enthalten MNIST als integrierten Datensatz, sodass du ihn mit nur wenigen Zeilen Code einfach abrufen kannst (Keras, PyTorch). Du kannst außerdem sowohl die Trainings- als auch die Testdatensätze laden, ohne sie manuell aufteilen zu müssen.
# Load the dataset
Jetzt müssen Sie die oben genannten Schritte ausführen, um sicherzustellen, dass der Datensatz normalisiert ist (er ist wahrscheinlich bereits normalisiert), und ein neuronales Netzwerk definieren und trainieren.
Wichtige Erkenntnisse
- Neuronale Netzwerke können für traditionelle maschinelle Lernaufgaben verwendet werden. Allerdings sind sie in vielen Fällen zu leistungsstark und können zu Überanpassung führen.
- Es ist wichtig, dass Sie in dieser Aufgabe das Überanpassungsverhalten beobachten und versuchen, es zu vermeiden.
- Mit Frameworks wie Keras ist das Training eines neuronalen Netzwerks manchmal recht unkompliziert. Aber Sie müssen verstehen, was dabei passiert.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Klassifikation mit PyTorch/TensorFlow
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
Lösen Sie zwei Klassifikationsprobleme mit ein- und mehrschichtigen vollständig verbundenen Netzwerken unter Verwendung von PyTorch oder TensorFlow:
- Iris-Klassifikation - ein Beispiel für ein Problem mit tabellarischen Eingabedaten, das durch klassische maschinelle Lernmethoden gelöst werden kann. Ihr Ziel ist es, Iris-Blumen basierend auf 4 numerischen Parametern in 3 Klassen zu klassifizieren.
- MNIST-Handschriftenerkennung, ein Problem, das wir bereits zuvor behandelt haben.
Probieren Sie verschiedene Netzwerkarchitekturen aus, um die bestmögliche Genauigkeit zu erzielen.
Start-Notebook
Beginnen Sie das Labor, indem Sie LabFrameworks.ipynb öffnen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Neuronale Netzwerk-Frameworks
Wie wir bereits gelernt haben, müssen wir zwei Dinge tun, um neuronale Netzwerke effizient trainieren zu können:
- Mit Tensoren arbeiten, z. B. multiplizieren, addieren und Funktionen wie Sigmoid oder Softmax berechnen.
- Gradienten aller Ausdrücke berechnen, um die Gradientenabstiegsoptimierung durchzuführen.
Quiz vor der Vorlesung
Während die Bibliothek numpy den ersten Teil übernehmen kann, benötigen wir einen Mechanismus, um Gradienten zu berechnen. In unserem Framework, das wir im vorherigen Abschnitt entwickelt haben, mussten wir alle Ableitungsfunktionen manuell in der Methode backward programmieren, die die Rückwärtsausbreitung durchführt. Idealerweise sollte ein Framework uns die Möglichkeit geben, Gradienten für jeden Ausdruck zu berechnen, den wir definieren können.
Ein weiterer wichtiger Punkt ist die Möglichkeit, Berechnungen auf der GPU oder anderen spezialisierten Recheneinheiten wie TPU durchzuführen. Das Training tiefer neuronaler Netzwerke erfordert sehr viele Berechnungen, und die Möglichkeit, diese Berechnungen auf GPUs zu parallelisieren, ist von großer Bedeutung.
> ✅ Der Begriff 'parallelisieren' bedeutet, die Berechnungen auf mehrere Geräte zu verteilen.
Derzeit sind die beiden beliebtesten neuronalen Frameworks: TensorFlow und PyTorch. Beide bieten eine Low-Level-API, um mit Tensoren sowohl auf der CPU als auch auf der GPU zu arbeiten. Zusätzlich zur Low-Level-API gibt es auch eine High-Level-API, die Keras bzw. PyTorch Lightning genannt wird.
| Low-Level API | TensorFlow | PyTorch |
|---|---|---|
| High-Level API | Keras | PyTorch Lightning |
Low-Level-APIs in beiden Frameworks ermöglichen es, sogenannte Rechengraphen zu erstellen. Dieser Graph definiert, wie die Ausgabe (normalerweise die Verlustfunktion) mit gegebenen Eingabeparametern berechnet wird, und kann zur Berechnung auf die GPU übertragen werden, falls verfügbar. Es gibt Funktionen, um diesen Rechengraphen zu differenzieren und Gradienten zu berechnen, die dann zur Optimierung der Modellparameter verwendet werden können.
High-Level-APIs betrachten neuronale Netzwerke im Wesentlichen als eine Abfolge von Schichten und erleichtern den Aufbau der meisten neuronalen Netzwerke erheblich. Das Training des Modells erfordert in der Regel die Vorbereitung der Daten und dann das Aufrufen einer fit-Funktion, um die Arbeit zu erledigen.
Die High-Level-API ermöglicht es, typische neuronale Netzwerke sehr schnell zu erstellen, ohne sich um viele Details kümmern zu müssen. Gleichzeitig bieten Low-Level-APIs viel mehr Kontrolle über den Trainingsprozess und werden daher häufig in der Forschung verwendet, wenn es um neue Architekturen neuronaler Netzwerke geht.
Es ist auch wichtig zu verstehen, dass beide APIs zusammen verwendet werden können. Zum Beispiel können Sie Ihre eigene Schichtarchitektur mit der Low-Level-API entwickeln und diese dann in ein größeres Netzwerk einfügen, das mit der High-Level-API erstellt und trainiert wird. Oder Sie definieren ein Netzwerk mit der High-Level-API als Abfolge von Schichten und verwenden dann Ihre eigene Low-Level-Trainingsschleife zur Optimierung. Beide APIs basieren auf denselben grundlegenden Konzepten und sind so konzipiert, dass sie gut zusammenarbeiten.
Lernen
In diesem Kurs bieten wir die meisten Inhalte sowohl für PyTorch als auch für TensorFlow an. Sie können Ihr bevorzugtes Framework auswählen und nur die entsprechenden Notebooks durchgehen. Wenn Sie sich nicht sicher sind, welches Framework Sie wählen sollen, lesen Sie einige Diskussionen im Internet über PyTorch vs. TensorFlow. Sie können sich auch beide Frameworks ansehen, um ein besseres Verständnis zu bekommen.
Wo möglich, verwenden wir High-Level-APIs, um die Dinge zu vereinfachen. Wir glauben jedoch, dass es wichtig ist, zu verstehen, wie neuronale Netzwerke von Grund auf funktionieren. Daher beginnen wir zunächst mit der Arbeit mit der Low-Level-API und Tensoren. Wenn Sie jedoch schnell loslegen möchten und nicht viel Zeit mit diesen Details verbringen wollen, können Sie diese überspringen und direkt zu den High-Level-API-Notebooks gehen.
✍️ Übungen: Frameworks
Setzen Sie Ihr Lernen in den folgenden Notebooks fort:
| Low-Level API | TensorFlow+Keras Notebook | PyTorch |
|---|---|---|
| High-Level API | Keras | PyTorch Lightning |
Nachdem Sie die Frameworks gemeistert haben, lassen Sie uns das Konzept des Overfittings rekapitulieren.
Overfitting
Overfitting ist ein äußerst wichtiges Konzept im maschinellen Lernen, und es ist sehr wichtig, es richtig zu verstehen!
Betrachten Sie das folgende Problem der Annäherung an 5 Punkte (dargestellt durch x in den untenstehenden Diagrammen):
![]() |
![]() |
|---|---|
| Lineares Modell, 2 Parameter | Nicht-lineares Modell, 7 Parameter |
| Trainingsfehler = 5.3 | Trainingsfehler = 0 |
| Validierungsfehler = 5.1 | Validierungsfehler = 20 |
- Links sehen wir eine gute lineare Annäherung. Da die Anzahl der Parameter angemessen ist, erfasst das Modell die Verteilung der Punkte korrekt.
- Rechts ist das Modell zu mächtig. Da wir nur 5 Punkte haben und das Modell 7 Parameter hat, kann es sich so anpassen, dass es durch alle Punkte verläuft, wodurch der Trainingsfehler 0 wird. Dies verhindert jedoch, dass das Modell das richtige Muster in den Daten versteht, was zu einem sehr hohen Validierungsfehler führt.
Es ist sehr wichtig, ein korrektes Gleichgewicht zwischen der Komplexität des Modells (Anzahl der Parameter) und der Anzahl der Trainingsdaten zu finden.
Warum tritt Overfitting auf?
- Zu wenig Trainingsdaten
- Zu mächtiges Modell
- Zu viel Rauschen in den Eingabedaten
Wie erkennt man Overfitting?
Wie Sie aus dem obigen Diagramm sehen können, kann Overfitting durch einen sehr niedrigen Trainingsfehler und einen hohen Validierungsfehler erkannt werden. Normalerweise sehen wir während des Trainings, dass sowohl der Trainings- als auch der Validierungsfehler abnehmen. An einem bestimmten Punkt könnte der Validierungsfehler jedoch aufhören zu sinken und anfangen zu steigen. Dies ist ein Zeichen für Overfitting und ein Hinweis darauf, dass wir das Training an diesem Punkt wahrscheinlich stoppen sollten (oder zumindest einen Schnappschuss des Modells machen sollten).

Wie verhindert man Overfitting?
Wenn Sie feststellen, dass Overfitting auftritt, können Sie Folgendes tun:
- Die Menge der Trainingsdaten erhöhen
- Die Komplexität des Modells verringern
- Eine Regularisierungstechnik verwenden, wie z. B. Dropout, die wir später betrachten werden.
Overfitting und Bias-Varianz-Abwägung
Overfitting ist eigentlich ein Fall eines allgemeineren Problems in der Statistik, das als Bias-Varianz-Abwägung bekannt ist. Wenn wir die möglichen Fehlerquellen in unserem Modell betrachten, können wir zwei Arten von Fehlern erkennen:
- Bias-Fehler entstehen, wenn unser Algorithmus die Beziehung zwischen den Trainingsdaten nicht korrekt erfassen kann. Dies kann darauf zurückzuführen sein, dass unser Modell nicht mächtig genug ist (Underfitting).
- Varianz-Fehler, die dadurch entstehen, dass das Modell Rauschen in den Eingabedaten anstelle einer sinnvollen Beziehung approximiert (Overfitting).
Während des Trainings nimmt der Bias-Fehler ab (da unser Modell lernt, die Daten zu approximieren), und der Varianz-Fehler nimmt zu. Es ist wichtig, das Training zu stoppen - entweder manuell (wenn wir Overfitting feststellen) oder automatisch (durch Einführung von Regularisierung) -, um Overfitting zu verhindern.
Fazit
In dieser Lektion haben Sie die Unterschiede zwischen den verschiedenen APIs der beiden beliebtesten KI-Frameworks, TensorFlow und PyTorch, kennengelernt. Außerdem haben Sie ein sehr wichtiges Thema, Overfitting, behandelt.
🚀 Herausforderung
In den begleitenden Notebooks finden Sie 'Aufgaben' am Ende; arbeiten Sie die Notebooks durch und erledigen Sie die Aufgaben.
Quiz nach der Vorlesung
Rückblick & Selbststudium
Recherchieren Sie zu den folgenden Themen:
- TensorFlow
- PyTorch
- Overfitting
Stellen Sie sich die folgenden Fragen:
- Was ist der Unterschied zwischen TensorFlow und PyTorch?
- Was ist der Unterschied zwischen Overfitting und Underfitting?
Aufgabe
In diesem Labor sollen Sie zwei Klassifikationsprobleme mit ein- und mehrschichtigen vollständig verbundenen Netzwerken mithilfe von PyTorch oder TensorFlow lösen.
Einführung in Neuronale Netzwerke

Wie wir in der Einführung besprochen haben, besteht eine Möglichkeit, Intelligenz zu erreichen, darin, ein Computermodell oder ein künstliches Gehirn zu trainieren. Seit Mitte des 20. Jahrhunderts haben Forscher verschiedene mathematische Modelle ausprobiert, bis sich in den letzten Jahren dieser Ansatz als äußerst erfolgreich erwiesen hat. Solche mathematischen Modelle des Gehirns werden als neuronale Netzwerke bezeichnet.
> Manchmal werden neuronale Netzwerke als Künstliche Neuronale Netzwerke (Artificial Neural Networks, ANNs) bezeichnet, um klarzustellen, dass es sich um Modelle handelt und nicht um echte Netzwerke von Neuronen.
Maschinelles Lernen
Neuronale Netzwerke sind Teil einer größeren Disziplin namens Maschinelles Lernen, deren Ziel es ist, Daten zu nutzen, um Computermodelle zu trainieren, die Probleme lösen können. Maschinelles Lernen macht einen großen Teil der Künstlichen Intelligenz aus, jedoch behandeln wir in diesem Lehrplan nicht das klassische ML.
> Besuchen Sie unseren separaten Maschinelles Lernen für Anfänger Lehrplan, um mehr über klassisches Maschinelles Lernen zu erfahren.
Im Maschinellen Lernen gehen wir davon aus, dass wir einen Datensatz mit Beispielen X und den entsprechenden Ausgabewerten Y haben. Beispiele sind oft N-dimensionale Vektoren, die aus Merkmalen bestehen, und Ausgaben werden als Labels bezeichnet.
Wir betrachten die zwei häufigsten Probleme des Maschinellen Lernens:
- Klassifikation, bei der wir ein Eingabeobjekt in zwei oder mehr Klassen einordnen müssen.
- Regression, bei der wir für jede Eingabeprobe eine numerische Zahl vorhersagen müssen.
> Wenn Eingaben und Ausgaben als Tensoren dargestellt werden, ist der Eingabedatensatz eine Matrix der Größe M×N, wobei M die Anzahl der Proben und N die Anzahl der Merkmale ist. Die Ausgabelabels Y sind ein Vektor der Größe M.
In diesem Lehrplan konzentrieren wir uns ausschließlich auf Modelle neuronaler Netzwerke.
Ein Modell eines Neurons
Aus der Biologie wissen wir, dass unser Gehirn aus Nervenzellen (Neuronen) besteht, von denen jede mehrere "Eingänge" (Dendriten) und einen einzigen "Ausgang" (Axon) hat. Sowohl Dendriten als auch Axone können elektrische Signale leiten, und die Verbindungen zwischen ihnen — bekannt als Synapsen — können unterschiedliche Grade der Leitfähigkeit aufweisen, die durch Neurotransmitter reguliert werden.
![]() |
![]() |
|---|---|
| Echtes Neuron (Bild von Wikipedia) | Künstliches Neuron (Bild vom Autor) |
Das einfachste mathematische Modell eines Neurons enthält daher mehrere Eingänge X<sub>1</sub>, ..., X<sub>N</sub> und einen Ausgang Y sowie eine Reihe von Gewichten W<sub>1</sub>, ..., W<sub>N</sub>. Der Ausgang wird berechnet als:
<img src="../../../../translated_images/de/netout.1eb15eb76fd76731.webp" alt="Y = f\left(\sum_{i=1}^N X_iW_i\right)" width="131" height="53" align="center"/>
wobei f eine nichtlineare Aktivierungsfunktion ist.
> Frühe Modelle von Neuronen wurden in dem klassischen Artikel A logical calculus of the ideas immanent in nervous activity von Warren McCullock und Walter Pitts im Jahr 1943 beschrieben. Donald Hebb schlug in seinem Buch "The Organization of Behavior: A Neuropsychological Theory" vor, wie solche Netzwerke trainiert werden können.
In diesem Abschnitt
In diesem Abschnitt lernen wir: * Perceptron, eines der frühesten neuronalen Netzwerkmodelle für Zwei-Klassen-Klassifikation * Mehrschichtige Netzwerke mit einem zugehörigen Notebook wie man unser eigenes Framework erstellt * Frameworks für neuronale Netzwerke, mit diesen Notebooks: PyTorch und Keras/Tensorflow * Overfitting
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Ihr Ziel ist es, mithilfe von Optical Flow zu bestimmen, welche Teile des Videos Bewegungen nach oben/unten/links/rechts enthalten.
Beginnen Sie damit, die Videobilder wie in der Vorlesung beschrieben zu erhalten:
# Code here
Berechnen Sie nun dichte optische Flussrahmen wie in der Vorlesung beschrieben und konvertieren Sie den dichten optischen Fluss in Polarkoordinaten:
# Code here
Erstelle ein Histogramm der Richtungen für jedes optische Fluss-Frame. Ein Histogramm zeigt, wie viele Vektoren in bestimmte Kategorien fallen, und es sollte die verschiedenen Bewegungsrichtungen im Frame voneinander trennen.
> Es könnte sinnvoll sein, alle Vektoren mit einer Magnitude unterhalb eines bestimmten Schwellenwerts auf null zu setzen. Dadurch werden kleine, unerwünschte Bewegungen im Video, wie Augen- und Kopfbewegungen, entfernt.
Zeichne die Histogramme für einige der Frames.
# Code here
Beim Betrachten von Histogrammen sollte es ziemlich einfach sein, die Bewegungsrichtung zu bestimmen. Sie müssen diejenigen Balken auswählen, die den Richtungen oben/unten/links/rechts entsprechen und die über einem bestimmten Schwellenwert liegen.
# Code here
Herzlichen Glückwunsch! Wenn Sie alle oben genannten Schritte durchgeführt haben, haben Sie das Labor abgeschlossen!
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Bewegungen mit Optical Flow erkennen
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
Betrachten Sie dieses Video, in dem sich die Handfläche einer Person auf einem stabilen Hintergrund nach links/rechts/oben/unten bewegt.
Ihr Ziel ist es, mithilfe von Optical Flow zu bestimmen, welche Teile des Videos Bewegungen nach oben/unten/links/rechts enthalten.
Erweiterungsziel wäre es, die Bewegung der Handfläche/Finger tatsächlich zu verfolgen, indem Sie den Hautton verwenden, wie in diesem Blogbeitrag oder hier beschrieben.
Start-Notebook
Beginnen Sie das Labor, indem Sie MovementDetection.ipynb öffnen.
Erkenntnis
Manchmal können relativ komplexe Aufgaben wie Bewegungserkennung oder Fingerspitzenerkennung rein durch Computer Vision gelöst werden. Daher ist es sehr hilfreich zu wissen, was Bibliotheken wie OpenCV leisten können.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Computer Vision und OpenCV
Dieses Notebook ist Teil des AI for Beginners Curriculum.
OpenCV gilt als de facto Standard für Bildverarbeitung. Es enthält viele nützliche Algorithmen, die in C++ implementiert sind. OpenCV kann auch in Python verwendet werden.
In diesem Notebook zeigen wir Ihnen einige Beispiele für die Nutzung von OpenCV. Für weitere Details können Sie den Online-Kurs Learn OpenCV besuchen.
Zuerst importieren wir cv2 sowie einige andere nützliche Bibliotheken:
import cv2
import matplotlib.pyplot as plt
import numpy as np
def display_images(l,titles=None,fontsize=12):
n=len(l)
fig,ax = plt.subplots(1,n)
for i,im in enumerate(l):
ax[i].imshow(im)
ax[i].axis('off')
if titles is not None:
ax[i].set_title(titles[i],fontsize=fontsize)
fig.set_size_inches(fig.get_size_inches()*n)
plt.tight_layout()
plt.show()
Bilder laden
Bilder in Python können bequem durch NumPy-Arrays dargestellt werden. Zum Beispiel würde ein Graustufenbild mit einer Größe von 320x200 Pixeln in einem 200x320-Array gespeichert werden, und ein Farbbild mit denselben Abmessungen hätte die Form 200x320x3 (für 3 Farbkanäle).
Beginnen wir mit dem Laden eines Bildes:
im = cv2.imread('data/braille.jpeg')
print(im.shape)
plt.imshow(im)
Wie Sie sehen, handelt es sich um ein Bild von Braille-Schrift. Da wir uns nicht besonders für die tatsächliche Farbe interessieren, können wir es in Schwarz-Weiß umwandeln:
bw_im = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
print(bw_im.shape)
plt.imshow(bw_im, cmap='gray')
Braille-Bildverarbeitung
Wenn wir Bildklassifikation anwenden möchten, um den Text zu erkennen, müssen wir einzelne Symbole ausschneiden, damit sie den MNIST-Bildern ähneln, die wir zuvor gesehen haben. Dies kann mit der Objekterkennung erreicht werden, die wir später besprechen werden. Aber wir können auch versuchen, dafür reine Computer-Vision-Techniken zu verwenden. Eine gute Beschreibung, wie Computer Vision für die Zeichen-Trennung genutzt werden kann, findet sich in diesem Blogbeitrag – wir konzentrieren uns hier nur auf einige Computer-Vision-Techniken.
Zunächst versuchen wir, das Bild ein wenig zu verbessern. Wir können die Idee des Thresholdings verwenden (gut beschrieben in diesem OpenCV-Artikel):
im = cv2.blur(bw_im,(3,3))
im = cv2.adaptiveThreshold(im, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY_INV, 5, 4)
im = cv2.medianBlur(im, 3)
_,im = cv2.threshold(im, 0, 255, cv2.THRESH_OTSU)
im = cv2.GaussianBlur(im, (3,3), 0)
_,im = cv2.threshold(im, 0, 255, cv2.THRESH_OTSU)
plt.imshow(im)
Um mit Bildern zu arbeiten, müssen wir einzelne Punkte "extrahieren", d. h. die Bilder in eine Menge von Koordinaten einzelner Punkte umwandeln. Das können wir mit Merkmalsextraktion-Techniken wie SIFT, SURF oder ORB tun:
orb = cv2.ORB_create(5000)
f,d = orb.detectAndCompute(im,None)
print(f"First 5 points: { [f[i].pt for i in range(5)]}")
def plot_dots(dots):
img = np.zeros((250,500))
for x in dots:
cv2.circle(img,(int(x[0]),int(x[1])),3,(255,0,0))
plt.imshow(img)
pts = [x.pt for x in f]
plot_dots(pts)
Um einzelne Zeichen zu trennen, müssen wir die Begrenzungsbox des gesamten Textes kennen. Um diese zu ermitteln, können wir einfach die minimalen und maximalen Koordinaten berechnen:
min_x, min_y, max_x, max_y = [int(f([z[i] for z in pts])) for f in (min,max) for i in (0,1)]
min_y+=13
plt.imshow(im[min_y:max_y,min_x:max_x])
Außerdem kann dieser Text teilweise gedreht werden, und um ihn perfekt auszurichten, müssen wir eine sogenannte Perspektivtransformation durchführen. Wir nehmen ein Rechteck, das durch die Punkte $(x_{min},y_{min}), (x_{min},y_{max}), (x_{max},y_{min}), (x_{max},y_{max})$ definiert ist, und richten es an einem neuen Bild mit proportionalen Abmessungen aus:
off = 5
src_pts = np.array([(min_x-off,min_y-off),(min_x-off,max_y+off),
(max_x+off,min_y-off),(max_x+off,max_y+off)])
w = int(max_x-min_x+off*2)
h = int(max_y-min_y+off*2)
dst_pts = np.array([(0,0),(0,h),(w,0),(w,h)])
ho,m = cv2.findHomography(src_pts,dst_pts)
trim = cv2.warpPerspective(im,ho,(w,h))
plt.imshow(trim)
Nachdem wir dieses gut ausgerichtete Bild haben, sollte es relativ einfach sein, es in Stücke zu schneiden:
char_h = 36
char_w = 24
def slice(img):
dy,dx = img.shape
y = 0
while y+char_h<dy:
x=0
while x+char_w<dx:
# Skip empty lines
if np.max(img[y:y+char_h,x:x+char_w])>0:
yield img[y:y+char_h,x:x+char_w]
x+=char_w
y+=char_h
sliced = list(slice(trim))
display_images(sliced)
Sie haben gesehen, dass viele Aufgaben mit reiner Bildverarbeitung erledigt werden können, ohne künstliche Intelligenz. Wenn wir Computer-Vision-Techniken nutzen können, um die Arbeit eines neuronalen Netzwerks zu vereinfachen, sollten wir das auf jeden Fall tun, da es uns ermöglicht, Probleme mit einer geringeren Menge an Trainingsdaten zu lösen.
Bewegungserkennung mit Frame-Differenz
Die Erkennung von Bewegungen in einem Videostream ist eine sehr häufige Aufgabe. Zum Beispiel ermöglicht sie uns, Benachrichtigungen zu erhalten, wenn etwas auf einer Überwachungskamera passiert. Wenn wir verstehen möchten, was auf der Kamera geschieht, können wir ein neuronales Netzwerk verwenden – aber es ist wesentlich kostengünstiger, ein neuronales Netzwerk erst dann einzusetzen, wenn wir wissen, dass tatsächlich etwas passiert.
Die Hauptidee der Bewegungserkennung ist einfach. Wenn die Kamera fest installiert ist, sollten die Frames der Kamera ziemlich ähnlich zueinander sein. Da Frames als Arrays dargestellt werden, können wir durch das Subtrahieren dieser Arrays von zwei aufeinanderfolgenden Frames die Pixelunterschiede erhalten. Diese sollten bei statischen Frames gering sein und bei erheblicher Bewegung im Bild größer werden.
Wir beginnen damit, zu lernen, wie man ein Video öffnet und es in eine Sequenz von Frames umwandelt:
vid = cv2.VideoCapture('data/motionvideo.mp4')
c = 0
frames = []
while vid.isOpened():
ret, frame = vid.read()
if not ret:
break
frames.append(frame)
c+=1
vid.release()
print(f"Total frames: {c}")
display_images(frames[::150])
Da Farbe für die Bewegungserkennung nicht so wichtig ist, werden wir alle Frames in Graustufen umwandeln. Anschließend berechnen wir die Frame-Differenzen und plotten ihre Normen, um die Menge der Aktivitäten visuell zu erkennen:
bwframes = [cv2.cvtColor(x,cv2.COLOR_BGR2GRAY) for x in frames]
diffs = [(p2-p1) for p1,p2 in zip(bwframes[:-1],bwframes[1:])]
diff_amps = np.array([np.linalg.norm(x) for x in diffs])
plt.plot(diff_amps)
display_images(diffs[::150],titles=diff_amps[::150])
Angenommen, wir möchten einen Bericht erstellen, der zeigt, was vor der Kamera passiert ist, indem jedes Mal das passende Bild angezeigt wird, wenn etwas passiert. Dazu möchten wir wahrscheinlich den Start- und Endframe eines "Ereignisses" herausfinden und den mittleren Frame anzeigen. Um etwas Rauschen zu entfernen, werden wir die Kurve oben außerdem mit einer gleitenden Durchschnittsfunktion glätten:
def moving_average(x, w):
return np.convolve(x, np.ones(w), 'valid') / w
threshold = 13000
plt.plot(moving_average(diff_amps,10))
plt.axhline(y=threshold, color='r', linestyle='-')
Jetzt können wir mit np.where herausfinden, welche Frames Änderungen über dem Schwellenwert aufweisen, und eine Sequenz aufeinanderfolgender Frames extrahieren, die länger als 30 Frames ist:
active_frames = np.where(diff_amps>threshold)[0]
def subsequence(seq,min_length=30):
ss = []
for i,x in enumerate(seq[:-1]):
ss.append(x)
if x+1 != seq[i+1]:
if len(ss)>min_length:
return ss
ss.clear()
sub = subsequence(active_frames)
print(sub)
Und schließlich können wir das Bild anzeigen:
plt.imshow(frames[(sub[0]+sub[-1])//2])
Sie werden feststellen, dass das Farbschema auf diesem Bild nicht richtig aussieht! Dies liegt daran, dass OpenCV aus historischen Gründen Bilder im BGR-Farbraum lädt, während Matplotlib die traditionellere RGB-Farbreihenfolge verwendet. Meistens ist es sinnvoll, Bilder direkt nach dem Laden in RGB umzuwandeln.
plt.imshow(cv2.cvtColor(frames[(sub[0]+sub[-1])//2],cv2.COLOR_BGR2RGB))
Bewegung mit optischem Fluss extrahieren
Das bloße Vergleichen von zwei aufeinanderfolgenden Frames zeigt zwar die Menge der Änderungen, liefert jedoch keine Informationen darüber, was sich tatsächlich bewegt und wo. Um diese Informationen zu erhalten, gibt es eine Technik namens optischer Fluss:
- Dichter optischer Fluss berechnet das Vektorfeld, das für jedes Pixel zeigt, wohin es sich bewegt.
- Spärlicher optischer Fluss basiert darauf, einige markante Merkmale im Bild (z. B. Kanten) zu identifizieren und deren Bewegung von Frame zu Frame nachzuverfolgen.
Lies mehr über optischen Fluss in diesem großartigen Tutorial.
Lass uns den dichten optischen Fluss zwischen unseren Frames berechnen:
flows = [cv2.calcOpticalFlowFarneback(f1, f2, None, 0.5, 3, 15, 3, 5, 1.2, 0)
for f1,f2 in zip(bwframes[:-1],bwframes[1:])]
flows[0].shape
Wie Sie sehen, hat der Fluss für jedes Frame die Dimension des Frames und 2 Kanäle, die den x- und y-Komponenten des optischen Flussvektors entsprechen.
Das Anzeigen des optischen Flusses in 2D ist etwas herausfordernd, aber wir können eine clevere Idee nutzen. Wenn wir den optischen Fluss in Polarkoordinaten umwandeln, erhalten wir zwei Komponenten für jedes Pixel: Richtung und Intensität. Die Intensität können wir durch die Pixelhelligkeit darstellen und die Richtung durch verschiedene Farben. Wir werden ein Bild im HSV (Hue-Saturation-Value)-Farbraum erstellen, wobei der Farbton durch die Richtung definiert wird, der Wert durch die Intensität und die Sättigung auf 255 gesetzt wird.
def flow_to_hsv(flow):
hsvImg = np.zeros((flow.shape[0],flow.shape[1],3),dtype=np.uint8)
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
hsvImg[..., 0] = 0.5 * ang * 180 / np.pi
hsvImg[..., 1] = 255
hsvImg[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
return cv2.cvtColor(hsvImg, cv2.COLOR_HSV2BGR)
start = sub[0]
stop = sub[-1]
print(start,stop)
frms = [flow_to_hsv(x) for x in flows[start:stop]]
display_images(frms[::25])
In diesen Frames entspricht die grünliche Farbe einer Bewegung nach links, während die blaue Farbe eine Bewegung nach rechts anzeigt.
Optischer Fluss kann ein großartiges Werkzeug sein, um Rückschlüsse auf die allgemeine Bewegungsrichtung zu ziehen. Zum Beispiel, wenn Sie sehen, dass sich alle Pixel in einem Frame mehr oder weniger in eine Richtung bewegen, können Sie daraus schließen, dass es eine Kamerabewegung gibt, und versuchen, diese auszugleichen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einführung in Computer Vision
Computer Vision ist ein Fachgebiet, dessen Ziel es ist, Computern ein hochentwickeltes Verständnis von digitalen Bildern zu ermöglichen. Dies ist eine recht breite Definition, da Verständnis viele verschiedene Dinge bedeuten kann, wie z. B. das Finden eines Objekts auf einem Bild (Objekterkennung), das Verstehen, was passiert (Ereigniserkennung), das Beschreiben eines Bildes in Text oder die Rekonstruktion einer Szene in 3D. Es gibt auch spezielle Aufgaben im Zusammenhang mit menschlichen Bildern: Alter- und Emotionserkennung, Gesichtserkennung und -identifikation sowie 3D-Pose-Schätzung, um nur einige zu nennen.
Quiz vor der Vorlesung
Eine der einfachsten Aufgaben von Computer Vision ist die Bildklassifikation.
Computer Vision wird oft als ein Teilbereich der KI betrachtet. Heutzutage werden die meisten Aufgaben in der Computer Vision mit neuronalen Netzwerken gelöst. Wir werden mehr über die spezielle Art von neuronalen Netzwerken lernen, die für Computer Vision verwendet werden, Convolutional Neural Networks, im Verlauf dieses Abschnitts.
Bevor Sie jedoch ein Bild an ein neuronales Netzwerk weitergeben, macht es in vielen Fällen Sinn, einige algorithmische Techniken anzuwenden, um das Bild zu verbessern.
Es gibt mehrere Python-Bibliotheken für die Bildverarbeitung:
- imageio kann verwendet werden, um verschiedene Bildformate zu lesen/schreiben. Es unterstützt auch ffmpeg, ein nützliches Tool, um Videobilder in Einzelbilder umzuwandeln.
- Pillow (auch bekannt als PIL) ist etwas leistungsfähiger und unterstützt auch einige Bildmanipulationen wie Morphing, Farbpalettenanpassungen und mehr.
- OpenCV ist eine leistungsstarke Bildverarbeitungsbibliothek, die in C++ geschrieben wurde und zum de facto Standard für Bildverarbeitung geworden ist. Sie verfügt über eine praktische Python-Schnittstelle.
- dlib ist eine C++-Bibliothek, die viele maschinelle Lernalgorithmen implementiert, einschließlich einiger Computer-Vision-Algorithmen. Sie verfügt ebenfalls über eine Python-Schnittstelle und kann für anspruchsvolle Aufgaben wie Gesichts- und Gesichtspunkt-Erkennung verwendet werden.
OpenCV
OpenCV gilt als der de facto Standard für Bildverarbeitung. Es enthält viele nützliche Algorithmen, die in C++ implementiert sind. Sie können OpenCV auch von Python aus verwenden.
Eine gute Einführung in OpenCV bietet dieser Learn OpenCV Kurs. In unserem Lehrplan ist es nicht unser Ziel, OpenCV zu lernen, sondern Ihnen einige Beispiele zu zeigen, wann und wie es verwendet werden kann.
Bilder laden
Bilder in Python können bequem durch NumPy-Arrays dargestellt werden. Zum Beispiel würden Graustufenbilder mit einer Größe von 320x200 Pixeln in einem 200x320-Array gespeichert, und Farbbilder derselben Dimension hätten die Form 200x320x3 (für 3 Farbkanäle). Um ein Bild zu laden, können Sie den folgenden Code verwenden:
import cv2
import matplotlib.pyplot as plt
im = cv2.imread('image.jpeg')
plt.imshow(im)
Traditionell verwendet OpenCV BGR (Blau-Grün-Rot) Kodierung für Farbbilder, während die meisten anderen Python-Tools die traditionellere RGB (Rot-Grün-Blau) Kodierung verwenden. Damit das Bild korrekt angezeigt wird, müssen Sie es in den RGB-Farbraum konvertieren, entweder durch das Tauschen der Dimensionen im NumPy-Array oder durch Aufrufen einer OpenCV-Funktion:
im = cv2.cvtColor(im,cv2.COLOR_BGR2RGB)
Die gleiche cvtColor-Funktion kann verwendet werden, um andere Farbraumtransformationen durchzuführen, wie z. B. die Umwandlung eines Bildes in Graustufen oder in den HSV-Farbraum (Farbton-Sättigung-Helligkeit).
Sie können OpenCV auch verwenden, um Video Bild für Bild zu laden – ein Beispiel finden Sie in der Übung OpenCV Notebook.
Bildverarbeitung
Bevor Sie ein Bild an ein neuronales Netzwerk weitergeben, möchten Sie möglicherweise mehrere Vorverarbeitungsschritte anwenden. OpenCV kann viele Dinge tun, darunter:
- Größenänderung des Bildes mit
im = cv2.resize(im, (320,200),interpolation=cv2.INTER_LANCZOS) - Unschärfe des Bildes mit
im = cv2.medianBlur(im,3)oderim = cv2.GaussianBlur(im, (3,3), 0) - Änderung der Helligkeit und des Kontrasts des Bildes durch NumPy-Array-Manipulationen, wie in dieser Stackoverflow-Notiz beschrieben.
- Verwendung von Thresholding durch Aufrufen der Funktionen
cv2.threshold/cv2.adaptiveThreshold, was oft vorzuziehen ist gegenüber der Anpassung von Helligkeit oder Kontrast. - Anwendung verschiedener Transformationen auf das Bild:
- Affine Transformationen können nützlich sein, wenn Sie Rotation, Größenänderung und Verzerrung des Bildes kombinieren müssen und die Quell- und Zielposition von drei Punkten im Bild kennen. Affine Transformationen halten parallele Linien parallel.
- Perspektivische Transformationen können nützlich sein, wenn Sie die Quell- und Zielpositionen von 4 Punkten im Bild kennen. Zum Beispiel, wenn Sie ein rechteckiges Dokument mit einer Smartphone-Kamera aus einem Winkel fotografieren und ein rechteckiges Bild des Dokuments selbst erstellen möchten.
- Bewegungserkennung im Bild durch Optischen Fluss.
Beispiele für die Verwendung von Computer Vision
In unserem OpenCV Notebook geben wir einige Beispiele, wann Computer Vision verwendet werden kann, um spezifische Aufgaben zu erfüllen:
- Vorverarbeitung eines Fotos eines Braille-Buchs. Wir konzentrieren uns darauf, wie wir Thresholding, Merkmalserkennung, perspektivische Transformation und NumPy-Manipulationen verwenden können, um einzelne Braille-Symbole für die weitere Klassifikation durch ein neuronales Netzwerk zu trennen.
![]() |
![]() |
![]() |
|---|---|---|
> Bild aus OpenCV.ipynb
- Bewegungserkennung in Videos durch Frame-Differenz. Wenn die Kamera fixiert ist, sollten die Frames des Kamerafeeds ziemlich ähnlich zueinander sein. Da Frames als Arrays dargestellt werden, erhalten wir durch das Subtrahieren dieser Arrays für zwei aufeinanderfolgende Frames die Pixelunterschiede, die bei statischen Frames gering sein sollten und bei erheblicher Bewegung im Bild höher werden.

> Bild aus OpenCV.ipynb
-
Bewegungserkennung mit Optischem Fluss. Optischer Fluss ermöglicht es uns zu verstehen, wie sich einzelne Pixel in Video-Frames bewegen. Es gibt zwei Arten von optischem Fluss:
-
Dichter Optischer Fluss berechnet das Vektorfeld, das zeigt, wohin sich jeder Pixel bewegt.
- Spärlicher Optischer Fluss basiert darauf, einige markante Merkmale im Bild (z. B. Kanten) zu nehmen und deren Trajektorie von Frame zu Frame zu erstellen.

> Bild aus OpenCV.ipynb
✍️ Beispiel-Notebooks: OpenCV OpenCV in Aktion ausprobieren
Lassen Sie uns einige Experimente mit OpenCV durchführen, indem wir OpenCV Notebook erkunden.
Fazit
Manchmal können relativ komplexe Aufgaben wie Bewegungserkennung oder Fingerspitzen-Erkennung rein durch Computer Vision gelöst werden. Daher ist es sehr hilfreich, die grundlegenden Techniken der Computer Vision zu kennen und zu wissen, was Bibliotheken wie OpenCV leisten können.
🚀 Herausforderung
Sehen Sie sich dieses Video aus der AI-Show an, um mehr über das Cortic Tigers-Projekt zu erfahren und wie sie eine blockbasierte Lösung entwickelt haben, um Computer-Vision-Aufgaben über einen Roboter zu demokratisieren. Recherchieren Sie weitere Projekte wie dieses, die neuen Lernenden den Einstieg in das Fachgebiet erleichtern.
Quiz nach der Vorlesung
Überprüfung & Selbststudium
Lesen Sie mehr über optischen Fluss in diesem großartigen Tutorial.
Aufgabe
In diesem Labor werden Sie ein Video mit einfachen Gesten aufnehmen, und Ihr Ziel ist es, Aufwärts-/Abwärts-/Links-/Rechts-Bewegungen mithilfe des optischen Flusses zu extrahieren.
<img src="../../../../../translated_images/de/palm-movement.341495f0e9c47da3.webp" width="30%" alt="Palm Movement Frame"/>
Bekannte CNN-Architekturen
VGG-16
VGG-16 ist ein Netzwerk, das 2014 eine Genauigkeit von 92,7 % bei der ImageNet-Top-5-Klassifikation erreichte. Es hat die folgende Schichtstruktur:

Wie man sehen kann, folgt VGG einer traditionellen Pyramidenarchitektur, die aus einer Abfolge von Convolution-Pooling-Schichten besteht.

> Bild von Researchgate
ResNet
ResNet ist eine Modellfamilie, die 2015 von Microsoft Research vorgeschlagen wurde. Die Hauptidee von ResNet ist die Verwendung von Residual Blocks:
<img src="../../../../../translated_images/de/resnet-block.aba4ccbcc0944434.webp" width="300"/>
> Bild aus diesem Paper
Der Grund für die Verwendung von Identity-Pass-Through ist, dass die Schicht die Differenz zwischen dem Ergebnis einer vorherigen Schicht und dem Output des Residual Blocks vorhersagen soll – daher der Name residual. Diese Blöcke sind viel einfacher zu trainieren, und man kann Netzwerke mit mehreren Hunderten dieser Blöcke konstruieren (die häufigsten Varianten sind ResNet-52, ResNet-101 und ResNet-152).
Man kann sich dieses Netzwerk auch so vorstellen, dass es seine Komplexität an den Datensatz anpassen kann. Zu Beginn des Trainings sind die Gewichtswerte klein, und die meisten Signale gehen durch die Identity-Layer. Im Laufe des Trainings, wenn die Gewichte größer werden, steigt die Bedeutung der Netzwerkparameter, und das Netzwerk passt sich an, um die erforderliche Ausdruckskraft zu erreichen, um die Trainingsbilder korrekt zu klassifizieren.
Google Inception
Die Google Inception-Architektur geht einen Schritt weiter und baut jede Netzwerkschicht als Kombination aus mehreren verschiedenen Pfaden:
<img src="../../../../../translated_images/de/inception.a6605b85bcbc6f52.webp" width="400"/>
> Bild von Researchgate
Hier müssen wir die Rolle der 1x1-Convolutions hervorheben, da sie zunächst keinen Sinn ergeben. Warum sollte man ein Bild mit einem 1x1-Filter durchlaufen? Man muss jedoch bedenken, dass Convolution-Filter auch mit mehreren Tiefenkanälen arbeiten (ursprünglich RGB-Farben, in nachfolgenden Schichten Kanäle für verschiedene Filter), und die 1x1-Convolution wird verwendet, um diese Eingabekanäle mit unterschiedlichen trainierbaren Gewichten zu mischen. Sie kann auch als Downsampling (Pooling) über die Kanaldimension betrachtet werden.
Hier ist ein guter Blogbeitrag zu diesem Thema und das Original-Paper.
MobileNet
MobileNet ist eine Modellfamilie mit reduzierter Größe, die für mobile Geräte geeignet ist. Verwenden Sie sie, wenn Sie wenig Ressourcen haben und ein wenig Genauigkeit opfern können. Die Hauptidee dahinter ist die sogenannte Depthwise Separable Convolution, die es ermöglicht, Convolution-Filter durch eine Zusammensetzung von räumlichen Convolutions und 1x1-Convolution über Tiefenkanäle darzustellen. Dies reduziert die Anzahl der Parameter erheblich, wodurch das Netzwerk kleiner wird und auch mit weniger Daten leichter zu trainieren ist.
Hier ist ein guter Blogbeitrag über MobileNet.
Fazit
In dieser Einheit haben Sie das Hauptkonzept hinter neuronalen Netzwerken für Computer Vision gelernt – Convolutional Networks. Realitätsnahe Architekturen, die Bildklassifikation, Objekterkennung und sogar Bildgenerierungsnetzwerke antreiben, basieren alle auf CNNs, nur mit mehr Schichten und einigen zusätzlichen Trainingstricks.
🚀 Herausforderung
In den begleitenden Notebooks gibt es am Ende Hinweise darauf, wie man eine höhere Genauigkeit erzielen kann. Führen Sie einige Experimente durch, um zu sehen, ob Sie eine höhere Genauigkeit erreichen können.
Quiz nach der Vorlesung
Rückblick & Selbststudium
Während CNNs am häufigsten für Aufgaben im Bereich Computer Vision verwendet werden, eignen sie sich im Allgemeinen gut für die Extraktion von Mustern fester Größe. Wenn wir beispielsweise mit Geräuschen arbeiten, möchten wir möglicherweise auch CNNs verwenden, um nach bestimmten Mustern im Audiosignal zu suchen – in diesem Fall wären die Filter eindimensional (und dieses CNN würde als 1D-CNN bezeichnet). Außerdem wird manchmal 3D-CNN verwendet, um Merkmale in einem mehrdimensionalen Raum zu extrahieren, wie bestimmte Ereignisse, die in Videos auftreten – CNN kann bestimmte Muster von Merkmalsänderungen über die Zeit erfassen. Machen Sie eine Rückschau und ein Selbststudium über andere Aufgaben, die mit CNNs erledigt werden können.
Aufgabe
In diesem Labor sollen Sie verschiedene Katzen- und Hunderassen klassifizieren. Diese Bilder sind komplexer als der MNIST-Datensatz, haben höhere Dimensionen und es gibt mehr als 10 Klassen.
Convolutional Neural Networks
Im vorherigen Abschnitt haben wir gelernt, wie man ein mehrschichtiges neuronales Netzwerk mithilfe einer Klassendefinition erstellt. Diese Netzwerke waren jedoch allgemein gehalten und nicht speziell für Aufgaben der Computer Vision optimiert. In diesem Abschnitt werden wir Convolutional Neural Networks (CNNs) kennenlernen, die speziell für Computer Vision entwickelt wurden.
Computer Vision unterscheidet sich von allgemeiner Klassifikation, da wir beim Versuch, ein bestimmtes Objekt in einem Bild zu finden, das Bild nach spezifischen Mustern und deren Kombinationen durchsuchen. Zum Beispiel: Wenn wir nach einer Katze suchen, könnten wir zunächst nach horizontalen Linien suchen, die Schnurrhaare bilden könnten. Eine bestimmte Kombination von Schnurrhaaren könnte uns dann sagen, dass es sich tatsächlich um ein Bild einer Katze handelt. Die relative Position und das Vorhandensein bestimmter Muster sind wichtig, nicht jedoch ihre genaue Position im Bild.
Um Muster zu extrahieren, verwenden wir das Konzept der konvolutionalen Filter. Aber zuerst laden wir alle Abhängigkeiten und Funktionen, die wir in den vorherigen Abschnitten definiert haben.
import torch
import torch.nn as nn
import torchvision
import matplotlib.pyplot as plt
from torchinfo import summary
import numpy as np
from pytorchcv import load_mnist, train, plot_results, plot_convolution, display_dataset
load_mnist(batch_size=128)
Faltungsmatrizen
Faltungsmatrizen sind kleine Fenster, die über jedes Pixel des Bildes laufen und den gewichteten Durchschnitt der benachbarten Pixel berechnen.
Sie werden durch Matrizen von Gewichtungskoeffizienten definiert. Schauen wir uns Beispiele an, wie zwei verschiedene Faltungsmatrizen auf unsere handgeschriebenen MNIST-Ziffern angewendet werden:
plot_convolution(torch.tensor([[-1.,0.,1.],[-1.,0.,1.],[-1.,0.,1.]]),'Vertical edge filter')
plot_convolution(torch.tensor([[-1.,-1.,-1.],[0.,0.,0.],[1.,1.,1.]]),'Horizontal edge filter')
Der erste Filter wird als vertikaler Kantenfilter bezeichnet und ist durch die folgende Matrix definiert: $$ \left( \begin{matrix} -1 & 0 & 1 \cr -1 & 0 & 1 \cr -1 & 0 & 1 \cr \end{matrix} \right) $$ Wenn dieser Filter über ein relativ gleichmäßiges Pixel-Feld läuft, summieren sich alle Werte zu 0. Trifft er jedoch auf eine vertikale Kante im Bild, wird ein hoher Spitzenwert erzeugt. Aus diesem Grund sind in den obigen Bildern vertikale Kanten durch hohe und niedrige Werte dargestellt, während horizontale Kanten ausgeglichen werden.
Das Gegenteil passiert, wenn wir einen horizontalen Kantenfilter anwenden – horizontale Linien werden verstärkt, und vertikale Linien werden ausgeglichen.
In der klassischen Computer Vision wurden mehrere Filter auf das Bild angewendet, um Merkmale zu erzeugen, die dann von einem Machine-Learning-Algorithmus genutzt wurden, um einen Klassifikator zu erstellen. Im Deep Learning hingegen konstruieren wir Netzwerke, die die besten Faltungsfilter lernen, um das Klassifikationsproblem zu lösen.
Um dies zu erreichen, führen wir Faltungsschichten ein.
Faltungsschichten
Faltungsschichten werden mit der nn.Conv2d-Konstruktion definiert. Wir müssen Folgendes festlegen:
* in_channels - Anzahl der Eingabekanäle. In unserem Fall handelt es sich um ein Graustufenbild, daher beträgt die Anzahl der Eingabekanäle 1.
* out_channels - Anzahl der zu verwendenden Filter. Wir werden 9 verschiedene Filter verwenden, was dem Netzwerk viele Möglichkeiten gibt, herauszufinden, welche Filter für unser Szenario am besten geeignet sind.
* kernel_size ist die Größe des gleitenden Fensters. Üblicherweise werden Filter der Größe 3x3 oder 5x5 verwendet.
Das einfachste CNN enthält eine Faltungsschicht. Bei einer Eingangsgröße von 28x28 erhalten wir nach Anwendung von neun 5x5-Filtern einen Tensor der Größe 9x24x24 (die räumliche Größe ist kleiner, da es nur 24 Positionen gibt, an denen ein gleitendes Intervall der Länge 5 in 28 Pixel passt).
Nach der Faltung flachen wir den 9x24x24-Tensor zu einem Vektor der Größe 5184 ab und fügen dann eine lineare Schicht hinzu, um 10 Klassen zu erzeugen. Zwischen den Schichten verwenden wir außerdem die relu-Aktivierungsfunktion.
class OneConv(nn.Module):
def __init__(self):
super(OneConv, self).__init__()
self.conv = nn.Conv2d(in_channels=1,out_channels=9,kernel_size=(5,5))
self.flatten = nn.Flatten()
self.fc = nn.Linear(5184,10)
def forward(self, x):
x = nn.functional.relu(self.conv(x))
x = self.flatten(x)
x = nn.functional.log_softmax(self.fc(x),dim=1)
return x
net = OneConv()
summary(net,input_size=(1,1,28,28))
Sie können sehen, dass dieses Netzwerk etwa 50k trainierbare Parameter enthält, verglichen mit etwa 80k in vollständig verbundenen mehrschichtigen Netzwerken. Dies ermöglicht es uns, auch bei kleineren Datensätzen gute Ergebnisse zu erzielen, da Faltungsnetzwerke viel besser generalisieren.
hist = train(net,train_loader,test_loader,epochs=5)
plot_results(hist)
Wie Sie sehen können, erreichen wir eine höhere Genauigkeit und sind dabei deutlich schneller im Vergleich zu den vollständig verbundenen Netzwerken aus der vorherigen Einheit.
Wir können auch die Gewichte unserer trainierten Convolutional Layers visualisieren, um besser zu verstehen, was vor sich geht:
fig,ax = plt.subplots(1,9)
with torch.no_grad():
p = next(net.conv.parameters())
for i,x in enumerate(p):
ax[i].imshow(x.detach().cpu()[0,...])
ax[i].axis('off')
Man kann sehen, dass einige dieser Filter scheinbar schräge Linien erkennen können, während andere eher zufällig wirken.
Mehrschichtige CNNs und Pooling-Schichten
Die ersten Convolutional Layers suchen nach einfachen Mustern, wie horizontalen oder vertikalen Linien. Wir können jedoch weitere Convolutional Layers darauf anwenden, um nach komplexeren Mustern zu suchen, wie beispielsweise einfachen Formen. Noch mehr Convolutional Layers können diese Formen dann zu Teilen eines Bildes kombinieren, bis hin zum finalen Objekt, das wir klassifizieren möchten.
Dabei können wir auch einen Trick anwenden: die räumliche Größe des Bildes reduzieren. Sobald wir erkannt haben, dass innerhalb eines gleitenden 3x3-Fensters ein horizontaler Strich vorhanden ist, ist es nicht mehr so wichtig, an welchem genauen Pixel er aufgetreten ist. Daher können wir die Größe des Bildes "herunterskalieren", was mit einer der Pooling-Schichten geschieht:
- Average Pooling nimmt ein gleitendes Fenster (zum Beispiel 2x2 Pixel) und berechnet den Durchschnitt der Werte innerhalb des Fensters.
- Max Pooling ersetzt das Fenster durch den maximalen Wert. Die Idee hinter Max Pooling ist, das Vorhandensein eines bestimmten Musters innerhalb des gleitenden Fensters zu erkennen.
In einem typischen CNN gibt es daher mehrere Convolutional Layers, mit Pooling-Schichten dazwischen, um die Dimensionen des Bildes zu reduzieren. Gleichzeitig erhöhen wir die Anzahl der Filter, da die Muster komplexer werden und es mehr mögliche interessante Kombinationen gibt, nach denen wir suchen müssen.

Aufgrund der abnehmenden räumlichen Dimensionen und der zunehmenden Feature-/Filter-Dimensionen wird diese Architektur auch als Pyramidenarchitektur bezeichnet.
class MultiLayerCNN(nn.Module):
def __init__(self):
super(MultiLayerCNN, self).__init__()
self.conv1 = nn.Conv2d(1, 10, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(10, 20, 5)
self.fc = nn.Linear(320,10)
def forward(self, x):
x = self.pool(nn.functional.relu(self.conv1(x)))
x = self.pool(nn.functional.relu(self.conv2(x)))
x = x.view(-1, 320)
x = nn.functional.log_softmax(self.fc(x),dim=1)
return x
net = MultiLayerCNN()
summary(net,input_size=(1,1,28,28))
Beachten Sie einige Dinge zu dieser Definition:
* Anstatt die Flatten-Schicht zu verwenden, wird der Tensor innerhalb der forward-Funktion mit der view-Funktion abgeflacht. Da die Flatten-Schicht keine trainierbaren Gewichte hat, ist es nicht zwingend erforderlich, eine separate Schichtinstanz innerhalb unserer Klasse zu erstellen.
* Wir verwenden nur eine Instanz der Pooling-Schicht in unserem Modell, auch weil sie keine trainierbaren Parameter enthält und diese eine Instanz effektiv wiederverwendet werden kann.
* Die Anzahl der trainierbaren Parameter (~8.5K) ist deutlich geringer als in früheren Fällen. Dies liegt daran, dass Convolutional-Schichten im Allgemeinen wenige Parameter haben und die Dimensionalität des Bildes vor der Anwendung der finalen Dense-Schicht erheblich reduziert wird. Eine geringe Anzahl von Parametern wirkt sich positiv auf unsere Modelle aus, da sie hilft, Überanpassung selbst bei kleineren Datensatzgrößen zu verhindern.
hist = train(net,train_loader,test_loader,epochs=5)
Was Sie wahrscheinlich beobachten können, ist, dass wir eine höhere Genauigkeit erreichen können als mit nur einer Schicht, und das viel schneller - bereits nach 1 oder 2 Epochen. Das bedeutet, dass eine ausgeklügelte Netzwerkarchitektur viel weniger Daten benötigt, um zu verstehen, was vor sich geht, und um generische Muster aus unseren Bildern zu extrahieren.
Arbeiten mit echten Bildern aus dem CIFAR-10-Datensatz
Während unser Problem der handgeschriebenen Ziffernerkennung wie ein Spielzeugproblem erscheinen mag, sind wir jetzt bereit, etwas Ernsthafteres zu tun. Lassen Sie uns einen fortgeschritteneren Datensatz mit Bildern verschiedener Objekte erkunden, genannt CIFAR-10. Er enthält 60.000 Bilder mit einer Größe von 32x32, die in 10 Klassen unterteilt sind.
transform = torchvision.transforms.Compose(
[torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=14, shuffle=True)
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=14, shuffle=False)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
display_dataset(trainset,classes=classes)
Eine bekannte Architektur für CIFAR-10 wird LeNet genannt und wurde von Yann LeCun vorgeschlagen. Sie folgt denselben Prinzipien, die wir oben beschrieben haben, mit dem Hauptunterschied, dass sie 3 Eingabefarbkanäle anstelle von 1 verwendet.
Wir nehmen außerdem eine weitere Vereinfachung an diesem Modell vor – wir verwenden log_softmax nicht als Ausgabefunktion und geben stattdessen einfach die Ausgabe der letzten vollständig verbundenen Schicht zurück. In diesem Fall können wir einfach die Verlustfunktion CrossEntropyLoss verwenden, um das Modell zu optimieren.
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.conv3 = nn.Conv2d(16,120,5)
self.flat = nn.Flatten()
self.fc1 = nn.Linear(120,64)
self.fc2 = nn.Linear(64,10)
def forward(self, x):
x = self.pool(nn.functional.relu(self.conv1(x)))
x = self.pool(nn.functional.relu(self.conv2(x)))
x = nn.functional.relu(self.conv3(x))
x = self.flat(x)
x = nn.functional.relu(self.fc1(x))
x = self.fc2(x)
return x
net = LeNet()
summary(net,input_size=(1,3,32,32))
Das ordnungsgemäße Training dieses Netzwerks wird beträchtliche Zeit in Anspruch nehmen und sollte vorzugsweise auf GPU-fähigen Rechnern durchgeführt werden.
opt = torch.optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
hist = train(net, trainloader, testloader, epochs=3, optimizer=opt, loss_fn=nn.CrossEntropyLoss())
Die Genauigkeit, die wir mit 3 Trainings-Epochen erreichen konnten, scheint nicht besonders hoch zu sein. Allerdings sollten wir bedenken, dass blindes Raten nur eine Genauigkeit von 10 % ergeben würde und unser Problem tatsächlich deutlich schwieriger ist als die MNIST-Ziffernklassifikation. Eine Genauigkeit von über 50 % in so kurzer Trainingszeit zu erreichen, ist durchaus eine gute Leistung.
Erkenntnisse
In dieser Einheit haben wir das Hauptkonzept hinter neuronalen Netzwerken für Computer Vision kennengelernt – die Convolutional Networks. Reale Architekturen, die Bildklassifikation, Objekterkennung und sogar Netzwerke zur Bildgenerierung ermöglichen, basieren alle auf CNNs, nur mit mehr Schichten und einigen zusätzlichen Trainingstricks.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Convolutional Neural Networks
Wir haben zuvor gesehen, dass neuronale Netzwerke ziemlich gut mit Bildern umgehen können, und sogar ein Ein-Schicht-Perzeptron ist in der Lage, handgeschriebene Ziffern aus dem MNIST-Datensatz mit angemessener Genauigkeit zu erkennen. Der MNIST-Datensatz ist jedoch sehr speziell, da alle Ziffern im Bild zentriert sind, was die Aufgabe vereinfacht.
Im echten Leben möchten wir Objekte auf einem Bild unabhängig von ihrer genauen Position im Bild erkennen können. Computer Vision unterscheidet sich von generischer Klassifikation, da wir, wenn wir versuchen, ein bestimmtes Objekt im Bild zu finden, das Bild nach spezifischen Mustern und deren Kombinationen durchsuchen. Zum Beispiel, wenn wir nach einer Katze suchen, könnten wir zunächst nach horizontalen Linien suchen, die Schnurrhaare bilden können, und dann kann eine bestimmte Kombination von Schnurrhaaren uns sagen, dass es sich tatsächlich um ein Bild einer Katze handelt. Die relative Position und das Vorhandensein bestimmter Muster sind wichtig, nicht jedoch ihre genaue Position im Bild.
Um Muster zu extrahieren, verwenden wir das Konzept der Faltungsfilter. Aber zuerst laden wir alle Abhängigkeiten und Funktionen, die wir in den vorherigen Einheiten definiert haben. Wir importieren auch die tfcv-Hilfsbibliothek, die einige nützliche Funktionen enthält, die wir nicht in diesem Notebook definieren möchten, um den Code kurz und übersichtlich zu halten.
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import numpy as np
from tfcv import *
In diesem Beispiel konzentrieren wir uns auf den MNIST-Datensatz, den wir zuvor gesehen haben, und auf die Bildklassifikation. Wir beginnen damit, den Datensatz mit den integrierten Funktionen von Keras zu laden.
(x_train,y_train),(x_test,y_test) = keras.datasets.mnist.load_data()
x_train = x_train.astype(np.float32) / 255.0
x_test = x_test.astype(np.float32) / 255.0
Faltungsmatrizen
Faltungsmatrizen sind kleine Fenster, die über jedes Pixel des Bildes laufen und den gewichteten Durchschnitt der benachbarten Pixel berechnen.
Sie werden durch Matrizen von Gewichtungskoeffizienten definiert. Schauen wir uns Beispiele an, wie zwei verschiedene Faltungsmatrizen auf unsere handgeschriebenen MNIST-Ziffern angewendet werden:
plot_convolution(x_train[:5],[[-1.,0.,1.],[-1.,0.,1.],[-1.,0.,1.]],'Vertical edge filter')
plot_convolution(x_train[:5],[[-1.,-1.,-1.],[0.,0.,0.],[1.,1.,1.]],'Horizontal edge filter')
Der erste Filter wird als vertikaler Kantenfilter bezeichnet und ist durch die folgende Matrix definiert: $$ \left( \begin{matrix} -1 & 0 & 1 \cr -1 & 0 & 1 \cr -1 & 0 & 1 \cr \end{matrix} \right) $$ Wenn dieser Filter über ein relativ gleichmäßiges Pixel-Feld läuft, summieren sich alle Werte zu 0. Trifft er jedoch auf eine vertikale Kante im Bild, wird ein hoher Spitzenwert erzeugt. Deshalb sind in den obigen Bildern vertikale Kanten durch hohe und niedrige Werte dargestellt, während horizontale Kanten ausgeglichen werden.
Das Gegenteil passiert, wenn wir einen horizontalen Kantenfilter anwenden – horizontale Linien werden verstärkt, während vertikale ausgeglichen werden.
In der klassischen Computer Vision wurden mehrere Filter auf das Bild angewendet, um Merkmale zu erzeugen, die dann von einem Machine-Learning-Algorithmus genutzt wurden, um einen Klassifikator zu erstellen. Diese Filter ähneln tatsächlich den neuronalen Strukturen, die im visuellen System einiger Tiere vorhanden sind.
<img src="images/lmfilters.jpg" width="400"/>
Im Deep Learning hingegen konstruieren wir Netzwerke, die die besten Faltungsfilter lernen, um ein Klassifikationsproblem zu lösen. Dazu führen wir Faltungsschichten ein.
Faltungsschichten
Um die Gewichte einer Faltungsschicht trainierbar zu machen, müssen wir den Prozess der Anwendung eines Faltungsfilterfensters auf das Bild irgendwie auf Matrixoperationen reduzieren, die dann dem Training durch Rückwärtspropagation unterzogen werden können. Dafür verwenden wir eine clevere Matrixtransformation, die wir im2col nennen.
Angenommen, wir haben ein kleines Bild $\mathbf{x}$ mit den folgenden Pixeln:
$$ \mathbf{x} = \left( \begin{array}{ccccc} a & b & c & d & e \ f & g & h & i & j \ k & l & m & n & o \ p & q & r & s & t \ u & v & w & x & y \ \end{array} \right) $$
Und wir möchten zwei Faltungsfilter mit den folgenden Gewichten anwenden: $$ W^{(i)} = \left(\begin{array}{ccc} w^{(i)}{00} & w^{(i)}{01} & w^{(i)}{02} \ w^{(i)}{10} & w^{(i)}{11} & w^{(i)}{12} \ w^{(i)}{20} & w^{(i)}{21} & w^{(i)}_{22} \ \end{array}\right) $$
Bei der Anwendung der Faltung wird das erste Pixel des Ergebnisses durch elementweise Multiplikation von $\left(\begin{array}{ccc} a & b & c \ f & g & h \ k & l & m \ \end{array}\right)$ und $W^{(i)}$ berechnet, das zweite Element durch Multiplikation von $\left(\begin{array}{ccc} b & c & d \ g & h & i \ l & m & n \ \end{array}\right)$ mit $W^{(i)}$, und so weiter.
Um diesen Prozess zu formalisieren, extrahieren wir alle $3\times3$ Fragmente des ursprünglichen Bildes $x$ in die folgende Matrix:
$$ \mathrm{im2col}(x) = \left[ \begin{array}{cccccc} a & b & \ldots & g & \ldots & m \ b & c & \ldots & h & \ldots & n \ c & d & \ldots & i & \ldots & o \ f & g & \ldots & l & \ldots & r \ g & h & \ldots & m & \ldots & s \ h & i & \ldots & n & \ldots & t \ k & l & \ldots & q & \ldots & w \ l & m & \ldots & r & \ldots & x \ m & n & \ldots & s & \ldots & y \ \end{array} \right] $$
Jede Spalte dieser Matrix entspricht einem $3\times3$ Unterbereich des ursprünglichen Bildes. Um das Ergebnis der Faltung zu erhalten, müssen wir diese Matrix nur mit der Gewichtsmatrix multiplizieren: $$ \mathbf{W} = \left[ \begin{array}{cccccccc} w^{(0)}{00} & w^{(0)}{01} & w^{(0)}{02} & w^{(0)}{10} & w^{(0)}{11} & \ldots & w^{(0)}{21} & w^{(0)}{22} \ w^{(1)}{00} & w^{(1)}{01} & w^{(1)}{02} & w^{(1)}{10} & w^{(1)}{11} & \ldots & w^{(1)}{21} & w^{(1)}{22} \ \end{array} \right] $$ (Jede Zeile dieser Matrix enthält die Gewichte des $i$-ten Filters, abgeflacht in eine Zeile.)
Die Anwendung eines Faltungsfilters auf das ursprüngliche Bild kann also durch eine Matrixmultiplikation ersetzt werden, die wir bereits mit Rückwärtspropagation handhaben können: $$ C(x) = W\times\mathbf{im2col}(x) $$
Faltungsschichten werden mit der Conv2d-Klasse definiert. Wir müssen Folgendes angeben:
* filters - Anzahl der zu verwendenden Filter. Wir werden 9 verschiedene Filter verwenden, die dem Netzwerk viele Möglichkeiten geben, herauszufinden, welche Filter für unser Szenario am besten geeignet sind.
* kernel_size ist die Größe des gleitenden Fensters. Üblicherweise werden 3x3- oder 5x5-Filter verwendet.
Das einfachste CNN enthält eine Faltungsschicht. Bei einer Eingangsgröße von 28x28 erhalten wir nach Anwendung von neun 5x5-Filtern einen Tensor der Größe 24x24x9. Die räumliche Dimension ist kleiner, da es nur 24 Positionen gibt, an denen ein gleitendes Intervall der Länge 5 in 28 Pixel passt.
Nach der Faltung flachen wir den 24x24x9-Tensor zu einem Vektor der Größe 5184 ab und fügen dann eine lineare Schicht hinzu, um 10 Klassen zu erzeugen. Zwischen den Schichten verwenden wir auch die relu-Aktivierungsfunktion.
model = keras.models.Sequential([
keras.layers.Conv2D(filters=9, kernel_size=(5,5), input_shape=(28,28,1),activation='relu'),
keras.layers.Flatten(),
keras.layers.Dense(10)
])
model.compile(loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['acc'])
model.summary()
Dieses Netzwerk enthält etwa 50.000 trainierbare Parameter, verglichen mit etwa 80.000 in vollständig verbundenen mehrschichtigen Netzwerken. Dadurch können wir auch bei kleineren Datensätzen gute Ergebnisse erzielen, da Faltungsnetzwerke viel besser generalisieren.
> Hinweis: In den meisten praktischen Fällen möchten wir Faltungsschichten auf Farbbilder anwenden. Daher erwartet die Conv2D-Schicht, dass die Eingabe die Form $W\times H\times C$ hat, wobei $W$ und $H$ die Breite und Höhe des Bildes sind und $C$ die Anzahl der Farbkanäle. Für Graustufenbilder benötigen wir die gleiche Form mit $C=1$.
Wir müssen unsere Daten vor Beginn des Trainings umformen:
x_train_c = np.expand_dims(x_train,3)
x_test_c = np.expand_dims(x_test,3)
hist = model.fit(x_train_c,y_train,validation_data=(x_test_c,y_test),epochs=5)
plot_results(hist)
Wie Sie sehen können, erreichen wir eine höhere Genauigkeit und das in deutlich weniger Epochen im Vergleich zu den vollständig verbundenen Netzwerken aus der vorherigen Einheit. Allerdings erfordert das Training selbst mehr Ressourcen und kann auf Computern ohne GPU langsamer sein.
Visualisierung von Convolutional Layers
Wir können auch die Gewichte unserer trainierten Convolutional Layers visualisieren, um besser zu verstehen, was genau vor sich geht:
fig,ax = plt.subplots(1,9)
l = model.layers[0].weights[0]
for i in range(9):
ax[i].imshow(l[...,0,i])
ax[i].axis('off')
Man kann sehen, dass einige dieser Filter anscheinend schräge Linien erkennen können, während andere ziemlich zufällig wirken.
> Aufgabe: Trainieren Sie dasselbe Netzwerk mit 3x3-Filtern und visualisieren Sie diese. Sehen Sie vertrautere Muster?
Mehrschichtige CNNs und Pooling-Schichten
Die ersten Convolutional Layers suchen nach einfachen Mustern, wie horizontalen oder vertikalen Linien. Aber wir können weitere Convolutional Layers darauf anwenden, um nach höherwertigen Mustern zu suchen, wie einfachen Formen. Noch mehr Convolutional Layers können diese Formen zu Teilen des Bildes kombinieren, bis hin zum finalen Objekt, das wir klassifizieren möchten.
Dabei können wir auch einen Trick anwenden: die räumliche Größe des Bildes reduzieren. Sobald wir erkannt haben, dass sich ein horizontaler Strich innerhalb eines gleitenden 3x3-Fensters befindet, ist es nicht mehr so wichtig, an welchem genauen Pixel er aufgetreten ist. Daher können wir die Größe des Bildes "verkleinern", was mit einer der Pooling-Schichten geschieht:
- Average Pooling nimmt ein gleitendes Fenster (zum Beispiel 2x2 Pixel) und berechnet den Durchschnitt der Werte innerhalb des Fensters.
- Max Pooling ersetzt das Fenster durch den Maximalwert. Die Idee hinter Max Pooling ist, das Vorhandensein eines bestimmten Musters innerhalb des gleitenden Fensters zu erkennen.
In einem typischen CNN gibt es daher mehrere Convolutional Layers, mit Pooling-Schichten dazwischen, um die Dimensionen des Bildes zu reduzieren. Gleichzeitig erhöhen wir die Anzahl der Filter, da die Muster komplexer werden und es mehr mögliche interessante Kombinationen gibt, nach denen wir suchen müssen.

Aufgrund der abnehmenden räumlichen Dimensionen und der zunehmenden Feature-/Filter-Dimensionen wird diese Architektur auch als Pyramidenarchitektur bezeichnet.
model = keras.models.Sequential([
keras.layers.Conv2D(filters=10, kernel_size=(5,5), input_shape=(28,28,1),activation='relu'),
keras.layers.MaxPooling2D(),
keras.layers.Conv2D(filters=20, kernel_size=(5,5), activation='relu'),
keras.layers.MaxPooling2D(),
keras.layers.Flatten(),
keras.layers.Dense(10)
])
model.compile(loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['acc'])
model.summary()
Beachten Sie, dass die Anzahl der trainierbaren Parameter (~8,5K) deutlich geringer ist als in früheren Fällen. Dies liegt daran, dass Faltungsschichten im Allgemeinen wenige Parameter haben und die Dimensionalität des Bildes vor der Anwendung der endgültigen dichten Schicht erheblich reduziert wird. Eine geringe Anzahl von Parametern wirkt sich positiv auf unsere Modelle aus, da sie hilft, Überanpassung selbst bei kleineren Datensatzgrößen zu verhindern.
hist = model.fit(x_train_c,y_train,validation_data=(x_test_c,y_test),epochs=5)
plot_results(hist)
Was Sie wahrscheinlich beobachten werden, ist, dass wir eine höhere Genauigkeit erreichen können als mit nur einer Schicht, und das viel schneller in Bezug auf die Anzahl der Epochen – oft schon nach 1 oder 2 Epochen. Das bedeutet, dass eine ausgeklügelte Netzwerkarchitektur viel weniger Daten benötigt, um zu verstehen, was vor sich geht, und um generische Muster aus unseren Bildern zu extrahieren. Allerdings dauert das Training auch länger und erfordert eine GPU.
Arbeiten mit echten Bildern aus dem CIFAR-10-Datensatz
Während unser Problem der handschriftlichen Ziffernerkennung wie ein Spielzeugproblem erscheinen mag, sind wir jetzt bereit, etwas Ernsteres anzugehen. Lassen Sie uns einen fortgeschritteneren Datensatz mit Bildern verschiedener Objekte erkunden, genannt CIFAR-10. Er enthält 60.000 Bilder mit einer Auflösung von 32x32, aufgeteilt in 10 Klassen.
(x_train,y_train),(x_test,y_test) = keras.datasets.cifar10.load_data()
x_train = x_train.astype(np.float32) / 255.0
x_test = x_test.astype(np.float32) / 255.0
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
display_dataset(x_train,y_train,classes=classes)
Eine bekannte Architektur für CIFAR-10 wird LeNet genannt und wurde von Yann LeCun vorgeschlagen. Sie folgt den gleichen Prinzipien, wie wir sie oben beschrieben haben, wobei der Hauptunterschied darin besteht, dass es 3 Eingabefarbkanäle anstelle von 1 gibt.
model = keras.models.Sequential([
keras.layers.Conv2D(filters = 6, kernel_size = 5, strides = 1, activation = 'relu', input_shape = (32,32,3)),
keras.layers.MaxPooling2D(pool_size = 2, strides = 2),
keras.layers.Conv2D(filters = 16, kernel_size = 5, strides = 1, activation = 'relu'),
keras.layers.MaxPooling2D(pool_size = 2, strides = 2),
keras.layers.Flatten(),
keras.layers.Dense(120, activation = 'relu'),
keras.layers.Dense(84, activation = 'relu'),
keras.layers.Dense(10, activation = 'softmax')])
model.summary()
Das ordnungsgemäße Training dieses Netzwerks wird beträchtliche Zeit in Anspruch nehmen und sollte vorzugsweise auf GPU-fähigen Rechnern durchgeführt werden.
model.compile(optimizer = 'adam', loss = 'sparse_categorical_crossentropy', metrics = ['acc'])
hist = model.fit(x_train,y_train,validation_data=(x_test,y_test),epochs=10)
plot_results(hist)
Die Genauigkeit, die wir mit wenigen Trainings-Epochen erreichen konnten, scheint nicht besonders hoch zu sein. Dennoch sollten wir bedenken, dass reines Raten nur eine Genauigkeit von 10 % ergeben würde und unser Problem tatsächlich deutlich schwieriger ist als die Klassifikation von MNIST-Ziffern. Eine Genauigkeit von über 50 % in so kurzer Trainingszeit zu erreichen, ist daher eine beachtliche Leistung.
Erkenntnisse
In dieser Einheit haben wir das Hauptkonzept hinter neuronalen Netzwerken für Computer Vision kennengelernt – die sogenannten Convolutional Networks. Reale Architekturen, die Bildklassifikation, Objekterkennung und sogar Netzwerke zur Bildgenerierung ermöglichen, basieren alle auf CNNs, allerdings mit mehr Schichten und einigen zusätzlichen Trainingskniffen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Klassifikation von Haustiergesichtern
Laboraufgabe aus dem AI for Beginners Curriculum.
Datenbeschaffung
In dieser Aufgabe konzentrieren wir uns auf eine relativ einfache Klassifikationsaufgabe – die Klassifikation von Haustiergesichtern. Wir verwenden das Oxford-IIIT Pet Dataset, das Bilder von 37 verschiedenen Hunderassen und Katzenrassen enthält. Beginnen wir mit dem Herunterladen und Visualisieren des Datensatzes.
Hinweis: Das Oxford-IIIT Pet Dataset enthält vollständige Bilder von Haustieren. Die Bilder werden im extrahierten Ordner nach Rassen organisiert.
!wget https://thor.robots.ox.ac.uk/~vgg/data/pets/images.tar.gz
!tar xfz images.tar.gz
!rm images.tar.gz
Wir werden eine generische Funktion definieren, um eine Reihe von Bildern aus einer Liste anzuzeigen:
import matplotlib.pyplot as plt
import os
from PIL import Image
import numpy as np
def display_images(l,titles=None,fontsize=12):
n=len(l)
fig,ax = plt.subplots(1,n)
for i,im in enumerate(l):
ax[i].imshow(im)
ax[i].axis('off')
if titles is not None:
ax[i].set_title(titles[i],fontsize=fontsize)
fig.set_size_inches(fig.get_size_inches()*n)
plt.tight_layout()
plt.show()
Lassen Sie uns nun alle Klassensubverzeichnisse durchlaufen und die ersten Bilder jeder Klasse plotten:
# Note: The Oxford-IIIT Pet Dataset extracts to a folder named 'images'
# Images are named by breed (e.g., 'Abyssinian_1.jpg')
# We need to organize them into breed-specific subdirectories
import os
from collections import defaultdict
# Organize images by breed
if not os.path.exists('petfaces'):
os.makedirs('petfaces')
for img_file in os.listdir('images'):
if img_file.endswith(('.jpg', '.png')):
# Extract breed name from filename (everything before the last underscore and number)
breed = '_'.join(img_file.split('_')[:-1])
breed_dir = os.path.join('petfaces', breed)
if not os.path.exists(breed_dir):
os.makedirs(breed_dir)
os.rename(os.path.join('images', img_file), os.path.join(breed_dir, img_file))
for cls in os.listdir('petfaces'):
print(cls)
display_images([Image.open(os.path.join('petfaces',cls,x))
for x in os.listdir(os.path.join('petfaces',cls))[:10]])
Lassen Sie uns auch die Anzahl der Klassen in unserem Datensatz definieren:
num_classes = len(os.listdir('petfaces'))
num_classes
Vorbereitung des Datensatzes für Deep Learning
Um mit dem Training unseres neuronalen Netzwerks zu beginnen, müssen wir alle Bilder in Tensoren umwandeln und auch Tensoren erstellen, die den Labels (Klassennummern) entsprechen. Die meisten Frameworks für neuronale Netzwerke bieten einfache Werkzeuge zur Verarbeitung von Bildern:
* In Tensorflow: tf.keras.preprocessing.image_dataset_from_directory
* In PyTorch: torchvision.datasets.ImageFolder
Wie Sie anhand der obigen Bilder gesehen haben, haben alle ein nahezu quadratisches Seitenverhältnis. Daher müssen wir alle Bilder auf eine quadratische Größe skalieren. Außerdem können wir die Bilder in Minibatches organisieren.
# CODE TO LOAD DATASET
Jetzt müssen wir den Datensatz in Trainings- und Testabschnitte aufteilen:
# CODE TO DO TRAIN/TEST SPLIT
Jetzt lassen wir uns die Größe der Tensoren in unserem Datensatz ausgeben. Wenn alles korrekt umgesetzt wurde, sollte die Größe der Trainingselemente wie folgt sein:
* (batch_size,image_size,image_size,3) für Tensorflow, batch_size,3,image_size,image_size für PyTorch
* batch_size für Labels
Die Labels sollten die Klassennummern enthalten.
# Print tensor sizes
# Display the data
Definiere ein neuronales Netzwerk
Für die Bildklassifikation solltest du wahrscheinlich ein Convolutional Neural Network mit mehreren Schichten definieren. Worauf du achten solltest: * Denke an die Pyramidenarchitektur, d.h. die Anzahl der Filter sollte mit zunehmender Tiefe steigen. * Vergiss nicht die Aktivierungsfunktionen zwischen den Schichten (ReLU) und Max Pooling. * Der finale Klassifikator kann mit oder ohne versteckte Schichten sein, aber die Anzahl der Ausgabeneuronen sollte der Anzahl der Klassen entsprechen.
Ein wichtiger Punkt ist, die Aktivierungsfunktion in der letzten Schicht + die Verlustfunktion korrekt zu wählen:
* In Tensorflow kannst du softmax als Aktivierungsfunktion und sparse_categorical_crossentropy als Verlustfunktion verwenden. Der Unterschied zwischen sparse categorical cross-entropy und der nicht-sparschen Variante ist, dass erstere die Ausgabe als Klassenindex erwartet und nicht als One-Hot-Vektor.
* In PyTorch kannst du die letzte Schicht ohne Aktivierungsfunktion belassen und die Verlustfunktion CrossEntropyLoss verwenden. Diese Funktion wendet automatisch softmax an.
# CODE TO DEFINE NEURAL NETWORK
Trainieren des neuronalen Netzwerks
Jetzt sind wir bereit, das neuronale Netzwerk zu trainieren. Während des Trainings sollten Sie die Genauigkeit auf den Trainings- und Testdaten in jeder Epoche erfassen und anschließend die Genauigkeit plotten, um zu überprüfen, ob Überanpassung vorliegt.
> Um das Training zu beschleunigen, sollten Sie eine GPU verwenden, falls verfügbar. Während TensorFlow/Keras automatisch die GPU nutzt, müssen Sie in PyTorch sowohl das Modell als auch die Daten während des Trainings mit der Methode .to() auf die GPU verschieben, um von der GPU-Beschleunigung zu profitieren.
# TRAIN THE NETWORK
# PLOT THE ACCURACY on train and validation dataset
Was kann man über Overfitting sagen? Was kann getan werden, um die Genauigkeit des Modells zu verbessern?
Optional: Berechnung der Top-3-Genauigkeit
In dieser Übung haben wir uns mit einer Klassifikation mit einer ziemlich hohen Anzahl von Klassen (35) beschäftigt, sodass unser Ergebnis – etwa 50 % Validierungsgenauigkeit – ziemlich gut ist. Der Standard-ImageNet-Datensatz hat sogar noch mehr – 1000 Klassen.
In solchen Fällen ist es schwierig sicherzustellen, dass das Modell immer die Klasse korrekt vorhersagt. Es gibt Fälle, in denen zwei Rassen einander sehr ähnlich sind und das Modell sehr ähnliche Wahrscheinlichkeiten zurückgibt (z. B. 0,45 und 0,43). Wenn wir die Standardgenauigkeit messen, wird dies als falscher Fall betrachtet, obwohl das Modell nur einen sehr kleinen Fehler gemacht hat. Daher messen wir oft eine andere Metrik – die Genauigkeit innerhalb der Top-3 der wahrscheinlichsten Vorhersagen des Modells.
Wir betrachten den Fall als korrekt, wenn das Ziel-Label innerhalb der Top-3-Vorhersagen des Modells enthalten ist.
Um die Top-3-Genauigkeit auf dem Testdatensatz zu berechnen, müssen Sie den Datensatz manuell durchgehen, das neuronale Netzwerk anwenden, um die Vorhersage zu erhalten, und dann die Berechnungen durchführen. Einige Hinweise:
- In Tensorflow können Sie die Funktion
tf.nn.in_top_kverwenden, um zu überprüfen, ob diepredictions(Ausgabe des Modells) in den Top-k enthalten sind (übergeben Siek=3als Parameter) in Bezug auf dietargets. Diese Funktion gibt einen Tensor mit booleschen Werten zurück, der mittf.castinintumgewandelt und dann mittf.reduce_sumakkumuliert werden kann. - In PyTorch können Sie die Funktion
torch.topkverwenden, um die Indizes der Klassen mit den höchsten Wahrscheinlichkeiten zu erhalten, und dann überprüfen, ob die richtige Klasse zu diesen gehört. Weitere Hinweise finden Sie hier.
# CALCULATE TOP-3 ACCURACY
Optional: Erstellen einer Klassifikation für Katzen vs. Hunde
Wir möchten auch sehen, wie genau unsere binäre Klassifikation von Katzen vs. Hunde auf demselben Datensatz wäre. Dafür müssen wir die Labels anpassen:
# Define dataset that contains only two labels: 0 = cat, 1 = dog
# Hint: use class name prefix to figure out which one is which
# Define neural network architecture and train
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Klassifikation von Haustiergesichtern
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
Stellen Sie sich vor, Sie müssen eine Anwendung für eine Tierpension entwickeln, um alle Haustiere zu katalogisieren. Eine großartige Funktion einer solchen Anwendung wäre die automatische Erkennung der Rasse anhand eines Fotos. Dies kann erfolgreich mit neuronalen Netzwerken durchgeführt werden.
Sie müssen ein konvolutionales neuronales Netzwerk trainieren, um verschiedene Katzen- und Hunderassen mithilfe des Pet Faces-Datensatzes zu klassifizieren.
Der Datensatz
Wir verwenden den Oxford-IIIT Pet Dataset, der Bilder von 37 verschiedenen Hunde- und Katzenrassen enthält.

Um den Datensatz herunterzuladen, verwenden Sie diesen Code-Schnipsel:
!wget https://thor.robots.ox.ac.uk/~vgg/data/pets/images.tar.gz
!tar xfz images.tar.gz
!rm images.tar.gz
Hinweis: Die Bilder des Oxford-IIIT Pet Dataset sind nach Dateinamen organisiert (z. B. Abyssinian_1.jpg, Bengal_2.jpg). Das Notebook enthält Code, um diese Bilder in rassespezifische Unterverzeichnisse zu organisieren, um die Klassifikation zu erleichtern.
Start-Notebook
Beginnen Sie das Labor, indem Sie PetFaces.ipynb öffnen.
Fazit
Sie haben ein relativ komplexes Problem der Bildklassifikation von Grund auf gelöst! Es gab eine Vielzahl von Klassen, und dennoch konnten Sie eine angemessene Genauigkeit erzielen! Es ist auch sinnvoll, die Top-k-Genauigkeit zu messen, da es leicht ist, einige Klassen zu verwechseln, die selbst für Menschen nicht eindeutig unterscheidbar sind.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Convolutional Neural Networks
Wir haben bereits gesehen, dass neuronale Netze recht gut mit Bildern umgehen können, und selbst ein Ein-Schicht-Perzeptron ist in der Lage, handgeschriebene Ziffern aus dem MNIST-Datensatz mit einer akzeptablen Genauigkeit zu erkennen. Der MNIST-Datensatz ist jedoch etwas Besonderes, da alle Ziffern zentriert im Bild dargestellt sind, was die Aufgabe vereinfacht.
Quiz vor der Vorlesung
Im echten Leben möchten wir Objekte auf einem Bild unabhängig von ihrer genauen Position im Bild erkennen können. Computer Vision unterscheidet sich von allgemeiner Klassifikation, da wir beim Versuch, ein bestimmtes Objekt im Bild zu finden, das Bild nach spezifischen Mustern und deren Kombinationen durchsuchen. Zum Beispiel, wenn wir nach einer Katze suchen, könnten wir zunächst nach horizontalen Linien suchen, die Schnurrhaare bilden können, und dann kann eine bestimmte Kombination von Schnurrhaaren uns sagen, dass es sich tatsächlich um ein Bild einer Katze handelt. Die relative Position und das Vorhandensein bestimmter Muster sind wichtig, nicht jedoch deren exakte Position im Bild.
Um Muster zu extrahieren, verwenden wir den Begriff der Faltung (Convolutional Filters). Wie du weißt, wird ein Bild durch eine 2D-Matrix oder einen 3D-Tensor mit Farbtiefe dargestellt. Das Anwenden eines Filters bedeutet, dass wir eine relativ kleine Filterkern-Matrix nehmen und für jedes Pixel im Originalbild den gewichteten Durchschnitt mit benachbarten Punkten berechnen. Man kann sich das wie ein kleines Fenster vorstellen, das über das gesamte Bild gleitet und alle Pixel gemäß den Gewichten in der Filterkern-Matrix mittelt.
![]() |
![]() |
|---|---|
> Bild von Dmitry Soshnikov
Wenn wir beispielsweise 3x3-Filter für vertikale und horizontale Kanten auf die MNIST-Ziffern anwenden, können wir Bereiche hervorheben (z. B. hohe Werte), in denen es vertikale und horizontale Kanten im Originalbild gibt. Diese beiden Filter können also verwendet werden, um "nach" Kanten zu suchen. Ebenso können wir verschiedene Filter entwerfen, um nach anderen grundlegenden Mustern zu suchen:
<img src="../../../../../translated_images/de/lmfilters.ea9e4868a82cf74c.webp" width="500" align="center"/>
> Bild des Leung-Malik Filter Bank
Während wir die Filter manuell entwerfen können, um bestimmte Muster zu extrahieren, können wir das Netzwerk auch so gestalten, dass es die Muster automatisch lernt. Dies ist eine der Hauptideen hinter CNNs.
Hauptideen hinter CNNs
Die Funktionsweise von CNNs basiert auf den folgenden wichtigen Konzepten:
- Faltungsfilter können Muster extrahieren.
- Wir können das Netzwerk so gestalten, dass die Filter automatisch trainiert werden.
- Wir können denselben Ansatz verwenden, um Muster in hochrangigen Merkmalen zu finden, nicht nur im Originalbild. Die Merkmalsextraktion in CNNs arbeitet also mit einer Hierarchie von Merkmalen, beginnend mit einfachen Pixelkombinationen bis hin zu komplexeren Kombinationen von Bildteilen.

> Bild aus einem Paper von Hislop-Lynch, basierend auf ihrer Forschung
✍️ Übungen: Convolutional Neural Networks
Lass uns weiter erkunden, wie Convolutional Neural Networks funktionieren und wie wir trainierbare Filter erreichen können, indem wir die entsprechenden Notebooks durcharbeiten:
Pyramidenarchitektur
Die meisten CNNs, die für die Bildverarbeitung verwendet werden, folgen einer sogenannten Pyramidenarchitektur. Die erste Faltungsschicht, die auf die Originalbilder angewendet wird, hat typischerweise eine relativ geringe Anzahl von Filtern (8-16), die verschiedenen Pixelkombinationen entsprechen, wie z. B. horizontalen/vertikalen Linien oder Strichen. Auf der nächsten Ebene reduzieren wir die räumliche Dimension des Netzwerks und erhöhen die Anzahl der Filter, was mehr mögliche Kombinationen einfacher Merkmale ermöglicht. Mit jeder Schicht, die wir uns dem finalen Klassifikator nähern, nehmen die räumlichen Dimensionen des Bildes ab, während die Anzahl der Filter zunimmt.
Als Beispiel betrachten wir die Architektur von VGG-16, einem Netzwerk, das 2014 eine Genauigkeit von 92,7 % in der Top-5-Klassifikation von ImageNet erreichte:


> Bild von Researchgate
Bekannteste CNN-Architekturen
Setze dein Studium über die bekanntesten CNN-Architekturen fort
Wie ein neuronales Netzwerk eine Katze sieht
Ein vortrainiertes neuronales Netzwerk auf ImageNet ist in der Lage, 1000 verschiedene Objektklassen zu erkennen, darunter Katzen verschiedener Rassen. Es wäre interessant zu sehen, wie die ideale Siamkatze für ein neuronales Netzwerk aussieht.
> Natürlich können Sie Siamkatze durch jede andere ImageNet-Klasse ersetzen.
Beginnen wir damit, das VGG-Netzwerk zu laden:
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import numpy as np
from IPython.display import clear_output
from PIL import Image
import json
np.set_printoptions(precision=3,suppress=True)
model = keras.applications.VGG16(weights='imagenet',include_top=True)
classes = json.loads(open('imagenet_classes.json','r').read())
Optimierung für das Ergebnis
Um die ideale Katze zu visualisieren, beginnen wir mit einem zufälligen Rauschbild und versuchen, die Gradientenabstiegs-Optimierungstechnik zu verwenden, um das Bild anzupassen, damit ein Netzwerk eine Katze erkennt.

Hier ist unser Ausgangsbild:
x = tf.Variable(tf.random.normal((1,224,224,3)))
def normalize(img):
return (img-tf.reduce_min(img))/(tf.reduce_max(img)-tf.reduce_min(img))
plt.imshow(normalize(x[0]))
> Wir verwenden die Funktion normalize, um unsere Werte in den Bereich von 0 bis 1 zu bringen.
Wenn wir unser VGG-Netzwerk auf dieses Bild anwenden, erhalten wir mehr oder weniger eine zufällige Verteilung von Wahrscheinlichkeiten:
def plot_result(x):
res = model(x)[0]
cls = tf.argmax(res)
print(f"Predicted class: {cls} ({classes[cls]})")
print(f"Probability of predicted class = {res[cls]}")
fig,ax = plt.subplots(1,2,figsize=(15,2.5),gridspec_kw = { "width_ratios" : [1,5]} )
ax[0].imshow(normalize(x[0]))
ax[0].axis('off')
ax[1].bar(range(1000),res,width=3)
plt.show()
plot_result(x)
> Auch wenn es so aussieht, als ob die Wahrscheinlichkeit einer der Klassen viel höher ist als die der anderen, ist sie dennoch sehr gering – schauen Sie sich die Skala an, um zu sehen, dass die tatsächliche Wahrscheinlichkeit immer noch bei etwa 5 % liegt.
Wählen wir nun eine Zielkategorie aus (z. B. Siamkatze) und beginnen, das Bild mithilfe des Gradientenabstiegs anzupassen. Wenn $x$ das Eingabebild ist und $V$ das VGG-Netzwerk, berechnen wir die Verlustfunktion $\mathcal{L} = \mathcal{L}(c,V(x))$ (wobei $c$ die Zielkategorie ist) und passen $x$ mit der folgenden Formel an: $$ x^{(i+1)} = x^{(i)} - \eta{\partial \mathcal{L}\over\partial x} $$ Die Verlustfunktion wäre die Kreuzentropieverlustfunktion, da wir zwei Wahrscheinlichkeitsverteilungen vergleichen. In unserem Fall, da die Klasse durch eine Zahl und nicht durch einen One-Hot-encodierten Vektor dargestellt wird, verwenden wir sparse categorical cross-entropy.
Diesen Prozess werden wir über mehrere Epochen wiederholen und das Bild dabei schrittweise ausgeben.
> Es ist besser, diesen Code auf einer GPU-fähigen Rechenumgebung auszuführen oder die Anzahl der Epochen zu reduzieren, um die Wartezeit zu minimieren.
target = [284] # Siamese cat
def cross_entropy_loss(target,res):
return tf.reduce_mean(keras.metrics.sparse_categorical_crossentropy(target,res))
def optimize(x,target,epochs=1000,show_every=None,loss_fn=cross_entropy_loss, eta=1.0):
if show_every is None:
show_every = epochs // 10
for i in range(epochs):
with tf.GradientTape() as t:
res = model(x)
loss = loss_fn(target,res)
grads = t.gradient(loss,x)
x.assign_sub(eta*grads)
if i%show_every == 0:
clear_output(wait=True)
print(f"Epoch: {i}, loss: {loss}")
plt.imshow(normalize(x[0]))
plt.show()
optimize(x,target)
plot_result(x)
Wir haben nun ein Bild erhalten, das für ein neuronales Netzwerk wie eine Katze aussieht, obwohl es für uns immer noch wie ein Rauschen wirkt. Wenn wir die Optimierung noch ein wenig länger fortsetzen, erhalten wir wahrscheinlich das Bild einer idealen rauschenden Katze, deren Wahrscheinlichkeit nahe bei 1 liegt.
Rauschen verstehen
Dieses Rauschen ergibt für uns nicht viel Sinn, enthält aber höchstwahrscheinlich viele niedrigstufige Filter, die typisch für eine Katze sind. Da es jedoch sehr viele Möglichkeiten gibt, den Input für das ideale Ergebnis zu optimieren, ist der Optimierungsalgorithmus nicht darauf ausgerichtet, Muster zu finden, die visuell verständlich sind.
Um das Bild weniger wie Rauschen aussehen zu lassen, können wir einen zusätzlichen Term in die Verlustfunktion einführen - den Variationsverlust. Dieser misst, wie ähnlich benachbarte Pixel des Bildes sind. Wenn wir diesen Term zu unserer Verlustfunktion hinzufügen, zwingt dies den Optimierer, Lösungen mit weniger Rauschen zu finden, wodurch mehr erkennbare Details entstehen.
> In der Praxis müssen wir zwischen Kreuzentropieverlust und Variationsverlust abwägen, um gute Ergebnisse zu erzielen. In unserer Funktion führen wir einige numerische Koeffizienten ein, mit denen Sie experimentieren können, um zu beobachten, wie sich das Bild verändert.
def total_loss(target,res):
return 10*tf.reduce_mean(keras.metrics.sparse_categorical_crossentropy(target,res)) + \
0.005*tf.image.total_variation(x,res)
optimize(x,target,loss_fn=total_loss)
Dies ist das ideale Bild einer Katze für unser neuronales Netzwerk, und wir können auch einige der vertrauten Merkmale wie Augen und Ohren erkennen. Es gibt viele davon, was das neuronale Netzwerk noch sicherer macht, dass dies eine Katze ist.
plot_result(x)
Lass uns auch sehen, wie einige andere Objekte für die VGG aussehen:
x = tf.Variable(tf.random.normal((1,224,224,3)))
optimize(x,[340],loss_fn=total_loss) # zebra
Adversarielle Angriffe
Da das Bild einer idealen Katze wie ein zufälliges Rauschen aussehen kann, deutet dies darauf hin, dass wir möglicherweise jedes Bild ein wenig verändern können, sodass es seine Klasse ändert. Lassen Sie uns ein wenig damit experimentieren. Wir beginnen mit einem Bild eines Hundes:
img = Image.open('images/dog-from-unsplash.jpg')
img = img.crop((200,20,600,420)).resize((224,224))
img = np.array(img)
plt.imshow(img)
plot_result(np.expand_dims(img,axis=0))
Nun, wir werden dieses Bild als Ausgangspunkt verwenden und versuchen, es zu optimieren, um eine Katze zu werden:
x = tf.Variable(np.expand_dims(img,axis=0).astype(np.float32)/255.0)
optimize(x,target,epochs=100)
plot_result(x)
Das Bild oben zeigt eine perfekte Katze, aus Sicht des VGG-Netzwerks!
Experimentieren mit ResNet
Schauen wir uns nun an, wie dasselbe Bild von einem anderen Modell, beispielsweise ResNet, klassifiziert wird:
model = keras.applications.ResNet50(weights='imagenet',include_top=True)
Da wir model als globale Variable verwendet haben, werden ab jetzt alle Funktionen ResNet anstelle von VGG verwenden.
plot_result(x)
Offenbar ist das Ergebnis ziemlich anders. Das ist jedoch zu erwarten, da wir bei der Optimierung für eine Katze die Eigenschaften des VGG-Netzwerks, seine Low-Level-Filter usw. berücksichtigt haben. Da ResNet andere Filter verwendet, liefert es unterschiedliche Ergebnisse. Das gibt uns eine Vorstellung davon, wie wir uns vor adversarialen Angriffen schützen können – indem wir ein Ensemble verschiedener Modelle verwenden.
Schauen wir uns an, wie das ideale Zebra für ResNet aussieht:
x = tf.Variable(tf.random.normal((1,224,224,3)))
optimize(x,target=[340],epochs=500,loss_fn=total_loss)
plot_result(x)
Dieses Bild ist ziemlich anders, was uns zeigt, dass die Architektur eines neuronalen Netzwerks wahrscheinlich eine wichtige Rolle dabei spielt, wie es Objekte erkennt.
> Aufgabe: Versuche, einen adversarialen Angriff auf ResNet durchzuführen, und vergleiche die Ergebnisse.
Verwendung verschiedener Optimierer
In unserem Beispiel haben wir die einfachste Optimierungstechnik verwendet - den Gradientenabstieg. Allerdings enthält das Keras-Framework verschiedene eingebaute Optimierer, die wir anstelle des Gradientenabstiegs verwenden können. Dies erfordert nur sehr geringe Änderungen an unserem Code - wir ersetzen den Teil, in dem wir das Eingabebild anpassen x.assign_sub(eta*grads), durch einen Aufruf der Funktion apply_gradients des Optimierers:
def optimize(x,target,epochs=1000,show_every=None,loss_fn=cross_entropy_loss,optimizer=keras.optimizers.SGD(learning_rate=1)):
if show_every is None:
show_every = epochs // 10
for i in range(epochs):
with tf.GradientTape() as t:
res = model(x)
loss = loss_fn(target,res)
grads = t.gradient(loss,x)
optimizer.apply_gradients([(grads,x)])
if i%show_every == 0:
clear_output(wait=True)
print(f"Epoch: {i}, loss: {loss}")
plt.imshow(normalize(x[0]))
plt.show()
x = tf.Variable(tf.random.normal((1,224,224,3)))
optimize(x,[898],loss_fn=total_loss) # water bottle
Fazit
Wir konnten das ideale Bild einer Katze (sowie anderer Objekte) innerhalb eines vortrainierten CNN visualisieren, indem wir die Gradientenabstiegsoptimierung nutzten, um das Eingabebild anstelle der Gewichte anzupassen. Der Hauptkniff, um ein Bild zu erhalten, das einigermaßen sinnvoll aussieht, war die Verwendung eines Variationsverlusts als zusätzliche Verlustfunktion, die das Bild dazu zwingt, glatter auszusehen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Die Wirkung von Dropout
Lassen Sie uns selbst sehen, wie Dropout das Training tatsächlich beeinflusst. Wir werden dazu den MNIST-Datensatz und ein einfaches Convolutional Network verwenden:
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.astype("float32") / 255
x_test = x_test.astype("float32") / 255
x_train = np.expand_dims(x_train, -1)
x_test = np.expand_dims(x_test, -1)
Wir definieren die Funktion train, die den gesamten Trainingsprozess übernimmt, einschließlich:
* Festlegen der Architektur des neuronalen Netzwerks mit einer gegebenen Dropout-Rate d
* Spezifizieren geeigneter Trainingsparameter (Optimizer und Verlustfunktion)
* Durchführen des Trainings und Sammeln der Historie
Anschließend führen wir diese Funktion für eine Reihe verschiedener Dropout-Werte aus:
def train(d):
print(f"Training with dropout = {d}")
model = keras.Sequential([
keras.layers.Conv2D(32, kernel_size=(3, 3), activation="relu", input_shape=(28,28,1)),
keras.layers.MaxPooling2D(pool_size=(2, 2)),
keras.layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
keras.layers.MaxPooling2D(pool_size=(2, 2)),
keras.layers.Flatten(),
keras.layers.Dropout(d),
keras.layers.Dense(10, activation="softmax")
])
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])
hist = model.fit(x_train,y_train,validation_data=(x_test,y_test),epochs=5,batch_size=64)
return hist
res = { d : train(d) for d in [0,0.2,0.5,0.8] }
Lassen Sie uns nun Validierungsgenauigkeitsdiagramme für verschiedene Dropout-Werte zeichnen, um zu sehen, wie schnell das Training verläuft:
for d,h in res.items():
plt.plot(h.history['val_acc'],label=str(d))
plt.legend()
Aus diesem Diagramm können Sie wahrscheinlich Folgendes erkennen:
Bei Dropout-Werten im Bereich von 0,2-0,5 sehen Sie das schnellste Training und die besten Gesamtergebnisse
Ohne Dropout ($d=0$) werden Sie wahrscheinlich einen weniger stabilen und langsameren Trainingsprozess beobachten
* Ein hoher Dropout-Wert (0,8) verschlechtert die Ergebnisse
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Klassifizierung von echten Bildern von Haustieren
Laboraufgabe aus dem AI for Beginners Curriculum.
Jetzt ist es an der Zeit, sich einer anspruchsvolleren Aufgabe zu widmen – der Klassifizierung des originalen Oxford-IIIT Datensatzes. Beginnen wir damit, den Datensatz zu laden und zu visualisieren.
!wget https://www.robots.ox.ac.uk/~vgg/data/pets/data/images.tar.gz
!tar xfz images.tar.gz
!rm images.tar.gz
Wir werden eine generische Funktion definieren, um eine Reihe von Bildern aus einer Liste anzuzeigen:
import matplotlib.pyplot as plt
import os
from PIL import Image
import numpy as np
def display_images(l,titles=None,fontsize=12):
n=len(l)
fig,ax = plt.subplots(1,n)
for i,im in enumerate(l):
ax[i].imshow(im)
ax[i].axis('off')
if titles is not None:
ax[i].set_title(titles[i],fontsize=fontsize)
fig.set_size_inches(fig.get_size_inches()*n)
plt.tight_layout()
plt.show()
Sie können sehen, dass alle Bilder in einem Verzeichnis namens images gespeichert sind und ihr Name den Namen der Klasse (Rasse) enthält:
fnames = os.listdir('images')[:5]
display_images([Image.open(os.path.join('images',x)) for x in fnames],titles=fnames,fontsize=30)
Um die Klassifizierung zu vereinfachen und denselben Ansatz zum Laden von Bildern wie im vorherigen Teil zu verwenden, lassen Sie uns alle Bilder in die entsprechenden Verzeichnisse sortieren:
for fn in os.listdir('images'):
cls = fn[:fn.rfind('_')].lower()
os.makedirs(os.path.join('images',cls),exist_ok=True)
os.replace(os.path.join('images',fn),os.path.join('images',cls,fn))
Lassen Sie uns auch die Anzahl der Klassen in unserem Datensatz definieren:
num_classes = len(os.listdir('images'))
num_classes
Vorbereitung des Datensatzes für Deep Learning
Um mit dem Training unseres neuronalen Netzwerks zu beginnen, müssen wir alle Bilder in Tensoren umwandeln und auch Tensoren erstellen, die den Labels (Klassennummern) entsprechen. Die meisten Frameworks für neuronale Netzwerke bieten einfache Werkzeuge zur Verarbeitung von Bildern:
* In Tensorflow verwenden Sie tf.keras.preprocessing.image_dataset_from_directory
* In PyTorch verwenden Sie torchvision.datasets.ImageFolder
Wie Sie an den obigen Bildern gesehen haben, haben alle ein nahezu quadratisches Seitenverhältnis. Daher müssen wir alle Bilder auf eine quadratische Größe skalieren. Außerdem können wir die Bilder in Minibatches organisieren.
# PREPARE THE DATASET
Jetzt müssen wir den Datensatz in Trainings- und Testanteile aufteilen:
# SPLIT INTO TRAIN-TEST DATASETS
Definieren Sie nun Datenlader:
# DEFINE DATA LOADERS if needed
# [OPTIONAL] Plot the dataset
Definiere ein neuronales Netzwerk
Für die Bildklassifikation solltest du wahrscheinlich ein konvolutionales neuronales Netzwerk mit mehreren Schichten definieren. Worauf du achten solltest: * Denke an die Pyramidenarchitektur, d.h. die Anzahl der Filter sollte mit zunehmender Tiefe steigen. * Vergiss nicht die Aktivierungsfunktionen zwischen den Schichten (ReLU) und Max Pooling. * Der finale Klassifikator kann mit oder ohne versteckte Schichten sein, aber die Anzahl der Ausgabeneuronen sollte der Anzahl der Klassen entsprechen.
Ein wichtiger Punkt ist, die Aktivierungsfunktion in der letzten Schicht + Verlustfunktion korrekt zu wählen:
* In Tensorflow kannst du softmax als Aktivierungsfunktion und sparse_categorical_crossentropy als Verlustfunktion verwenden. Der Unterschied zwischen sparse kategorischer Kreuzentropie und der nicht-sparse Variante ist, dass die erstere die Ausgabe als Klassenindex erwartet und nicht als One-Hot-Vektor.
* In PyTorch kannst du die letzte Schicht ohne Aktivierungsfunktion haben und die Verlustfunktion CrossEntropyLoss verwenden. Diese Funktion wendet automatisch softmax an.
> Tipp: In PyTorch kannst du die LazyLinear-Schicht anstelle von Linear verwenden, um die Berechnung der Anzahl der Eingaben zu vermeiden. Sie benötigt nur einen Parameter n_out, der die Anzahl der Neuronen in der Schicht angibt, und die Dimension der Eingabedaten wird automatisch beim ersten forward-Durchlauf übernommen.
# DEFINE NEURAL NETWORK ARCHITECTURE
Trainiere das neuronale Netzwerk
Jetzt sind wir bereit, das neuronale Netzwerk zu trainieren. Während des Trainings bitte die Genauigkeit auf den Trainings- und Testdaten in jeder Epoche erfassen und anschließend die Genauigkeit plotten, um zu überprüfen, ob Overfitting vorliegt.
# TRAIN THE NEURAL NETWORK
# PLOT THE RESULT: Train and Test Accuracy
Transfer-Learning
Um die Genauigkeit zu verbessern, verwenden wir ein vortrainiertes neuronales Netzwerk als Feature-Extraktor. Experimentieren Sie gerne mit Modellen wie VGG-16/VGG-19, ResNet50 usw.
> Da dieses Training langsamer ist, können Sie zunächst das Modell für eine geringe Anzahl von Epochen trainieren, z. B. 3. Sie können das Training jederzeit fortsetzen, um die Genauigkeit bei Bedarf weiter zu verbessern.
Für Transfer-Learning müssen wir unsere Daten anders normalisieren, daher laden wir den Datensatz erneut mit einem anderen Satz von Transformationen:
# LOAD THE DATASET
# Perform standard transformations for VGG-16/VGG-19 if needed
# vgg = ...
Definieren Sie nun das Klassifikationsmodell für Ihr Problem:
* In PyTorch gibt es einen Slot namens classifier, den Sie durch Ihren eigenen Klassifikator für die gewünschte Anzahl von Klassen ersetzen können.
* In TensorFlow verwenden Sie das VGG-Netzwerk als Merkmalsextraktor und bauen ein Sequential-Modell, bei dem VGG die erste Schicht ist und Ihr eigener Klassifikator darauf aufbaut.
# BUILD MODEL for your problem with your own linear layers
Stellen Sie sicher, dass alle Parameter des VGG-Feature-Extractors nicht trainierbar sind.
# MAKE VGG Layers not trainable
Jetzt können wir mit dem Training beginnen. Seien Sie sehr geduldig, da das Training lange dauert und unsere Trainingsfunktion nicht dafür ausgelegt ist, vor dem Ende der Epoche etwas auszugeben.
# TRAIN THE MODEL
Es scheint jetzt viel besser zu sein!
Optional: Berechnung der Top-3-Genauigkeit
Wir können die Top-3-Genauigkeit auch mit demselben Code wie im vorherigen Beispiel berechnen.
# CALCULATE TOP-3 Accuracy of the model
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Klassifikation von Oxford-Haustieren mit Transfer-Learning
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
Stellen Sie sich vor, Sie müssen eine Anwendung für eine Tierpension entwickeln, um alle Haustiere zu katalogisieren. Eine großartige Funktion einer solchen Anwendung wäre die automatische Erkennung der Rasse anhand eines Fotos. In dieser Aufgabe werden wir Transfer-Learning verwenden, um echte Bilder von Haustieren aus dem Oxford-IIIT Haustier-Datensatz zu klassifizieren.
Der Datensatz
Wir verwenden den originalen Oxford-IIIT Haustier-Datensatz, der 35 verschiedene Rassen von Hunden und Katzen enthält.
Um den Datensatz herunterzuladen, verwenden Sie diesen Code-Schnipsel:
!wget https://www.robots.ox.ac.uk/~vgg/data/pets/data/images.tar.gz
!tar xfz images.tar.gz
!rm images.tar.gz
Start des Notebooks
Beginnen Sie das Labor, indem Sie OxfordPets.ipynb öffnen.
Erkenntnis
Transfer-Learning und vortrainierte Netzwerke ermöglichen es uns, reale Bildklassifikationsprobleme relativ einfach zu lösen. Allerdings funktionieren vortrainierte Netzwerke gut bei Bildern ähnlicher Art, und wenn wir anfangen, sehr unterschiedliche Bilder zu klassifizieren (z. B. medizinische Bilder), werden die Ergebnisse wahrscheinlich deutlich schlechter ausfallen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Vorgefertigte Netzwerke und Transfer-Learning
Das Training von CNNs kann viel Zeit in Anspruch nehmen, und es wird eine große Menge an Daten dafür benötigt. Ein Großteil der Zeit wird jedoch darauf verwendet, die besten Low-Level-Filter zu lernen, die ein Netzwerk nutzen kann, um Muster aus Bildern zu extrahieren. Eine natürliche Frage stellt sich: Können wir ein neuronales Netzwerk, das auf einem Datensatz trainiert wurde, verwenden und anpassen, um andere Bilder zu klassifizieren, ohne den gesamten Trainingsprozess erneut durchlaufen zu müssen?
Quiz vor der Vorlesung
Dieser Ansatz wird als Transfer-Learning bezeichnet, da wir Wissen von einem neuronalen Netzwerkmodell auf ein anderes übertragen. Beim Transfer-Learning beginnen wir typischerweise mit einem vortrainierten Modell, das auf einem großen Bilddatensatz wie ImageNet trainiert wurde. Diese Modelle können bereits verschiedene Merkmale aus generischen Bildern gut extrahieren, und in vielen Fällen reicht es aus, einen Klassifikator auf diesen extrahierten Merkmalen aufzubauen, um gute Ergebnisse zu erzielen.
> ✅ Transfer-Learning ist ein Begriff, den man auch in anderen akademischen Bereichen wie der Pädagogik findet. Er bezieht sich auf den Prozess, Wissen aus einem Bereich zu nehmen und in einem anderen anzuwenden.
Vorgefertigte Modelle als Merkmalsextraktoren
Die in der vorherigen Sektion besprochenen Convolutional Networks enthalten eine Reihe von Schichten, die jeweils Merkmale aus dem Bild extrahieren sollen – angefangen bei Low-Level-Pixelkombinationen (wie horizontalen/vertikalen Linien oder Strichen) bis hin zu höherwertigen Kombinationen von Merkmalen, die beispielsweise einem Auge oder einer Flamme entsprechen. Wenn wir ein CNN auf einem ausreichend großen Datensatz mit generischen und vielfältigen Bildern trainieren, sollte das Netzwerk lernen, diese allgemeinen Merkmale zu extrahieren.
Sowohl Keras als auch PyTorch enthalten Funktionen, um vortrainierte neuronale Netzwerkgewichte für einige gängige Architekturen einfach zu laden, von denen die meisten auf ImageNet-Bildern trainiert wurden. Die am häufigsten verwendeten Architekturen sind auf der Seite CNN Architectures aus der vorherigen Lektion beschrieben. Insbesondere könnten Sie eine der folgenden in Betracht ziehen:
- VGG-16/VGG-19, relativ einfache Modelle, die dennoch gute Genauigkeit liefern. Oft ist es eine gute Wahl, VGG als ersten Versuch zu verwenden, um zu sehen, wie Transfer-Learning funktioniert.
- ResNet, eine Modellfamilie, die 2015 von Microsoft Research vorgeschlagen wurde. Sie haben mehr Schichten und benötigen daher mehr Ressourcen.
- MobileNet, eine Modellfamilie mit reduzierter Größe, geeignet für mobile Geräte. Verwenden Sie sie, wenn Sie wenig Ressourcen haben und bereit sind, ein wenig Genauigkeit zu opfern.
Hier sind Beispielmerkmale, die von einem Bild einer Katze durch das VGG-16-Netzwerk extrahiert wurden:

Cats vs. Dogs Datensatz
In diesem Beispiel verwenden wir einen Datensatz von Cats and Dogs, der einem realen Szenario der Bildklassifikation sehr nahe kommt.
✍️ Übung: Transfer-Learning
Lassen Sie uns Transfer-Learning in Aktion in den entsprechenden Notebooks sehen:
Visualisierung einer adversarialen Katze
Ein vortrainiertes neuronales Netzwerk enthält verschiedene Muster in seinem Gehirn, einschließlich Vorstellungen von einer idealen Katze (sowie einem idealen Hund, idealen Zebra usw.). Es wäre interessant, dieses Bild irgendwie zu visualisieren. Allerdings ist das nicht einfach, da die Muster über die Netzwerkgewichte verteilt sind und in einer hierarchischen Struktur organisiert sind.
Ein Ansatz, den wir verfolgen können, besteht darin, mit einem zufälligen Bild zu beginnen und dann die Technik der Gradientenabstiegsoptimierung zu verwenden, um dieses Bild so anzupassen, dass das Netzwerk denkt, es sei eine Katze.

Wenn wir dies jedoch tun, erhalten wir etwas, das einem zufälligen Rauschen sehr ähnlich ist. Dies liegt daran, dass es viele Möglichkeiten gibt, das Netzwerk glauben zu lassen, dass das Eingabebild eine Katze ist, einschließlich solcher, die visuell keinen Sinn ergeben. Während diese Bilder viele für eine Katze typische Muster enthalten, gibt es nichts, das sie visuell unterscheidbar macht.
Um das Ergebnis zu verbessern, können wir einen weiteren Term in die Verlustfunktion einfügen, der als Variationsverlust bezeichnet wird. Dies ist eine Metrik, die zeigt, wie ähnlich benachbarte Pixel des Bildes sind. Die Minimierung des Variationsverlusts macht das Bild glatter und beseitigt Rauschen – wodurch visuell ansprechendere Muster sichtbar werden. Hier ist ein Beispiel für solche "idealen" Bilder, die mit hoher Wahrscheinlichkeit als Katze bzw. Zebra klassifiziert werden:
![]() |
![]() |
|---|---|
| Ideale Katze | Ideales Zebra |
Ein ähnlicher Ansatz kann verwendet werden, um sogenannte adversariale Angriffe auf ein neuronales Netzwerk durchzuführen. Angenommen, wir möchten ein neuronales Netzwerk täuschen und einen Hund wie eine Katze aussehen lassen. Wenn wir das Bild eines Hundes nehmen, das vom Netzwerk als Hund erkannt wird, können wir es mit Hilfe der Gradientenabstiegsoptimierung so lange leicht anpassen, bis das Netzwerk es als Katze klassifiziert:
![]() |
![]() |
|---|---|
| Originalbild eines Hundes | Bild eines Hundes, der als Katze klassifiziert wird |
Sehen Sie sich den Code an, um die oben genannten Ergebnisse in folgendem Notebook zu reproduzieren:
Fazit
Mit Transfer-Learning können Sie schnell einen Klassifikator für eine benutzerdefinierte Objektklassifikationsaufgabe zusammenstellen und eine hohe Genauigkeit erzielen. Sie sehen, dass komplexere Aufgaben, die wir jetzt lösen, eine höhere Rechenleistung erfordern und nicht einfach auf der CPU gelöst werden können. In der nächsten Einheit werden wir versuchen, eine leichtere Implementierung zu verwenden, um dasselbe Modell mit geringeren Rechenressourcen zu trainieren, was nur zu einer geringfügig niedrigeren Genauigkeit führt.
🚀 Herausforderung
In den begleitenden Notebooks gibt es am Ende Hinweise darauf, dass Transfer-Wissen am besten mit einigermaßen ähnlichen Trainingsdaten funktioniert (z. B. eine neue Tierart). Experimentieren Sie mit völlig neuen Bildtypen, um zu sehen, wie gut oder schlecht Ihre Transfer-Wissen-Modelle abschneiden.
Quiz nach der Vorlesung
Rückblick & Selbststudium
Lesen Sie TrainingTricks.md, um Ihr Wissen über andere Möglichkeiten zur Modellschulung zu vertiefen.
Aufgabe
In diesem Labor verwenden wir den realen Oxford-IIIT Haustierdatensatz mit 35 Katzen- und Hunderassen und erstellen einen Transfer-Learning-Klassifikator.
Deep Learning Training Tricks
Je tiefer neuronale Netzwerke werden, desto herausfordernder wird ihr Training. Ein Hauptproblem sind die sogenannten verschwindenden Gradienten oder explodierenden Gradienten. Dieser Artikel bietet eine gute Einführung in diese Probleme.
Um das Training tiefer Netzwerke effizienter zu gestalten, gibt es einige Techniken, die angewendet werden können.
Werte in einem vernünftigen Bereich halten
Um numerische Berechnungen stabiler zu machen, sollten alle Werte innerhalb des neuronalen Netzwerks in einem vernünftigen Bereich liegen, typischerweise [-1..1] oder [0..1]. Dies ist keine strikte Anforderung, aber die Natur von Gleitkomma-Berechnungen ist so, dass Werte unterschiedlicher Größenordnungen nicht genau zusammen verarbeitet werden können. Zum Beispiel, wenn wir 10<sup>-10</sup> und 10<sup>10</sup> addieren, erhalten wir wahrscheinlich 10<sup>10</sup>, da der kleinere Wert auf die gleiche Größenordnung wie der größere "umgerechnet" wird und somit die Mantisse verloren geht.
Die meisten Aktivierungsfunktionen haben Nichtlinearitäten im Bereich von [-1..1], daher macht es Sinn, alle Eingabedaten auf den Bereich [-1..1] oder [0..1] zu skalieren.
Initialisierung der Gewichte
Idealerweise sollten die Werte nach dem Durchlaufen der Netzwerkschichten im gleichen Bereich bleiben. Daher ist es wichtig, die Gewichte so zu initialisieren, dass die Verteilung der Werte erhalten bleibt.
Eine Normalverteilung N(0,1) ist keine gute Idee, da bei n Eingaben die Standardabweichung der Ausgabe n wäre und die Werte wahrscheinlich aus dem Bereich [0..1] herausfallen.
Die folgenden Initialisierungen werden häufig verwendet:
- Gleichverteilung --
uniform - N(0,1/n) --
gaussian - N(0,1/√n_in) garantiert, dass für Eingaben mit einem Mittelwert von 0 und einer Standardabweichung von 1 der gleiche Mittelwert/Standardabweichung erhalten bleibt
- N(0,√2/(n_in+n_out)) -- die sogenannte Xavier-Initialisierung (
glorot), die hilft, die Signale während der Vorwärts- und Rückwärtsausbreitung im Bereich zu halten
Batch-Normalisierung
Selbst bei ordnungsgemäßer Initialisierung der Gewichte können diese während des Trainings beliebig groß oder klein werden und die Signale aus dem richtigen Bereich bringen. Wir können die Signale mit einer der Normalisierungstechniken wieder in den Bereich bringen. Während es mehrere davon gibt (Gewichtsnormierung, Schichtnormierung), wird am häufigsten die Batch-Normalisierung verwendet.
Die Idee der Batch-Normalisierung besteht darin, alle Werte innerhalb des Minibatches zu berücksichtigen und eine Normalisierung (d. h. Mittelwert abziehen und durch Standardabweichung teilen) basierend auf diesen Werten durchzuführen. Sie wird als Netzwerkschicht implementiert, die diese Normalisierung nach der Anwendung der Gewichte, aber vor der Aktivierungsfunktion durchführt. Dadurch erreichen wir in der Regel eine höhere Endgenauigkeit und schnelleres Training.
Hier ist das Originalpapier zur Batch-Normalisierung, die Erklärung auf Wikipedia und ein guter einführender Blogbeitrag (und einer auf Russisch).
Dropout
Dropout ist eine interessante Technik, bei der ein bestimmter Prozentsatz zufälliger Neuronen während des Trainings entfernt wird. Es wird ebenfalls als Schicht mit einem Parameter (Prozentsatz der zu entfernenden Neuronen, typischerweise 10%-50%) implementiert, und während des Trainings werden zufällige Elemente des Eingabevektors auf null gesetzt, bevor sie an die nächste Schicht weitergegeben werden.
Auch wenn dies seltsam klingen mag, können Sie die Wirkung von Dropout beim Training eines MNIST-Ziffernklassifikators im Dropout.ipynb-Notebook sehen. Es beschleunigt das Training und ermöglicht es uns, in weniger Trainingsepochen eine höhere Genauigkeit zu erreichen.
Dieser Effekt kann auf verschiedene Weise erklärt werden:
- Es kann als zufälliger Schockfaktor für das Modell betrachtet werden, der die Optimierung aus einem lokalen Minimum herausführt
- Es kann als implizites Modellmittelwertbilden betrachtet werden, da man sagen kann, dass während des Dropouts leicht unterschiedliche Modelle trainiert werden
> Manche Leute sagen, dass eine betrunkene Person, die versucht, etwas zu lernen, sich dies am nächsten Morgen besser merken kann als eine nüchterne Person, weil ein Gehirn mit einigen fehlerhaften Neuronen besser versucht, den Sinn zu erfassen. Wir haben nie getestet, ob das stimmt oder nicht.
Überanpassung verhindern
Ein sehr wichtiger Aspekt des Deep Learnings ist es, Überanpassung zu verhindern. Auch wenn es verlockend sein mag, ein sehr leistungsstarkes neuronales Netzwerkmodell zu verwenden, sollten wir die Anzahl der Modellparameter immer mit der Anzahl der Trainingsbeispiele in Einklang bringen.
> Stellen Sie sicher, dass Sie das Konzept der Überanpassung verstanden haben, das wir zuvor eingeführt haben!
Es gibt mehrere Möglichkeiten, Überanpassung zu verhindern:
- Frühes Stoppen -- kontinuierliches Überwachen des Fehlers auf dem Validierungsdatensatz und Beenden des Trainings, wenn der Validierungsfehler zu steigen beginnt.
- Expliziter Gewichtsrückgang / Regularisierung -- Hinzufügen einer zusätzlichen Strafe zur Verlustfunktion für hohe absolute Werte der Gewichte, was verhindert, dass das Modell sehr instabile Ergebnisse liefert
- Modellmittelwertbildung -- Training mehrerer Modelle und anschließendes Mitteln der Ergebnisse. Dies hilft, die Varianz zu minimieren.
- Dropout (implizite Modellmittelwertbildung)
Optimierer / Trainingsalgorithmen
Ein weiterer wichtiger Aspekt des Trainings ist die Wahl eines guten Trainingsalgorithmus. Während der klassische Gradientenabstieg eine vernünftige Wahl ist, kann er manchmal zu langsam sein oder andere Probleme verursachen.
Im Deep Learning verwenden wir den stochastischen Gradientenabstieg (SGD), der ein Gradientenabstieg ist, der auf Minibatches angewendet wird, die zufällig aus dem Trainingssatz ausgewählt werden. Die Gewichte werden mit dieser Formel angepasst:
w<sup>t+1</sup> = w<sup>t</sup> - η∇ℒ
Momentum
Beim Momentum-SGD behalten wir einen Teil des Gradienten aus vorherigen Schritten bei. Es ist ähnlich wie bei einer Bewegung mit Trägheit: Wenn wir in eine Richtung unterwegs sind und einen Stoß in eine andere Richtung erhalten, ändert sich unsere Flugbahn nicht sofort, sondern behält einen Teil der ursprünglichen Bewegung bei. Hier führen wir einen weiteren Vektor v ein, um die Geschwindigkeit darzustellen:
- v<sup>t+1</sup> = γ v<sup>t</sup> - η∇ℒ
- w<sup>t+1</sup> = w<sup>t</sup>+v<sup>t+1</sup>
Hier gibt der Parameter γ an, in welchem Maße wir die Trägheit berücksichtigen: γ=0 entspricht dem klassischen SGD; γ=1 ist eine reine Bewegungsgleichung.
Adam, Adagrad, etc.
Da in jeder Schicht Signale mit einer Matrix W<sub>i</sub> multipliziert werden, kann der Gradient je nach ||W<sub>i</sub>|| entweder verschwinden und nahe 0 sein oder unbegrenzt ansteigen. Dies ist das Wesen des Exploding/Vanishing-Gradients-Problems.
Eine Lösung für dieses Problem besteht darin, in der Gleichung nur die Richtung des Gradienten zu verwenden und den absoluten Wert zu ignorieren, d. h.
w<sup>t+1</sup> = w<sup>t</sup> - η(∇ℒ/||∇ℒ||), wobei ||∇ℒ|| = √∑(∇ℒ)<sup>2</sup>
Dieser Algorithmus wird Adagrad genannt. Andere Algorithmen, die dieselbe Idee verwenden: RMSProp, Adam
> Adam gilt als ein sehr effizienter Algorithmus für viele Anwendungen. Wenn Sie sich nicht sicher sind, welchen Sie verwenden sollen, nehmen Sie Adam.
Gradient Clipping
Gradient Clipping ist eine Erweiterung der obigen Idee. Wenn ||∇ℒ|| ≤ θ, verwenden wir den ursprünglichen Gradienten in der Gewichtsoptimierung, und wenn ||∇ℒ|| > θ, teilen wir den Gradienten durch seine Norm. Hier ist θ ein Parameter, in den meisten Fällen können wir θ=1 oder θ=10 wählen.
Lernratenabnahme
Der Erfolg des Trainings hängt oft vom Lernratenparameter η ab. Es ist logisch anzunehmen, dass größere Werte von η zu schnellerem Training führen, was wir typischerweise zu Beginn des Trainings wollen, und dass kleinere Werte von η es uns ermöglichen, das Netzwerk fein abzustimmen. Daher möchten wir in den meisten Fällen η im Verlauf des Trainings verringern.
Dies kann erreicht werden, indem η nach jeder Epoche des Trainings mit einer Zahl (z. B. 0,98) multipliziert wird, oder durch die Verwendung eines komplizierteren Lernratenplans.
Verschiedene Netzwerkarchitekturen
Die Auswahl der richtigen Netzwerkarchitektur für Ihr Problem kann knifflig sein. Normalerweise würden wir eine Architektur wählen, die sich für unsere spezifische Aufgabe (oder eine ähnliche) bewährt hat. Hier ist ein guter Überblick über neuronale Netzwerkarchitekturen für Computer Vision.
> Es ist wichtig, eine Architektur zu wählen, die leistungsstark genug für die Anzahl der Trainingsbeispiele ist, die wir haben. Eine zu leistungsstarke Modellwahl kann zu Überanpassung führen.
Eine weitere gute Möglichkeit wäre die Verwendung einer Architektur, die sich automatisch an die erforderliche Komplexität anpasst. Bis zu einem gewissen Grad sind die ResNet-Architektur und Inception selbstanpassend. Mehr zu Computer-Vision-Architekturen
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Vorgefertigte Modelle und Transferlernen
Das Training von CNNs kann viel Zeit in Anspruch nehmen, und es wird eine große Menge an Daten dafür benötigt. Ein Großteil der Zeit wird jedoch darauf verwendet, die besten Low-Level-Filter zu erlernen, die ein Netzwerk nutzt, um Muster aus Bildern zu extrahieren. Eine naheliegende Frage ist: Können wir ein neuronales Netzwerk, das auf einem Datensatz trainiert wurde, verwenden und anpassen, um andere Bilder zu klassifizieren, ohne den gesamten Trainingsprozess erneut durchlaufen zu müssen?
Dieser Ansatz wird als Transferlernen bezeichnet, da wir Wissen von einem neuronalen Netzwerkmodell auf ein anderes übertragen. Beim Transferlernen beginnen wir typischerweise mit einem vortrainierten Modell, das auf einem großen Bilddatensatz wie ImageNet trainiert wurde. Diese Modelle können bereits verschiedene Merkmale aus generischen Bildern gut extrahieren, und in vielen Fällen kann allein das Erstellen eines Klassifikators auf Basis dieser extrahierten Merkmale zu guten Ergebnissen führen.
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
from torchinfo import summary
import numpy as np
import os
from pytorchcv import train, plot_results, display_dataset, train_long, check_image_dir
Katzen-gegen-Hunde-Datensatz
In dieser Einheit werden wir ein reales Problem lösen: die Klassifizierung von Bildern von Katzen und Hunden. Dafür verwenden wir den Kaggle Katzen-gegen-Hunde-Datensatz, der auch von Microsoft heruntergeladen werden kann.
Lassen Sie uns diesen Datensatz herunterladen und in das Verzeichnis data extrahieren (dieser Vorgang kann einige Zeit in Anspruch nehmen!):
if not os.path.exists('data/kagglecatsanddogs_5340.zip'):
!wget -P data https://download.microsoft.com/download/3/E/1/3E1C3F21-ECDB-4869-8368-6DEBA77B919F/kagglecatsanddogs_5340.zip
import zipfile
if not os.path.exists('data/PetImages'):
with zipfile.ZipFile('data/kagglecatsanddogs_5340.zip', 'r') as zip_ref:
zip_ref.extractall('data')
Leider gibt es einige beschädigte Bilddateien im Datensatz. Wir müssen eine schnelle Bereinigung durchführen, um beschädigte Dateien zu überprüfen. Um dieses Tutorial nicht zu überladen, haben wir den Code zur Überprüfung des Datensatzes in ein Modul verschoben.
check_image_dir('data/PetImages/Cat/*.jpg')
check_image_dir('data/PetImages/Dog/*.jpg')
Als Nächstes laden wir die Bilder in das PyTorch-Dataset, konvertieren sie in Tensoren und führen eine Normalisierung durch. Wir wenden die std_normalize-Transformation an, um die Bilder in den Bereich zu bringen, der vom vortrainierten VGG-Netzwerk erwartet wird:
std_normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
trans = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
std_normalize])
dataset = torchvision.datasets.ImageFolder('data/PetImages',transform=trans)
trainset, testset = torch.utils.data.random_split(dataset,[20000,len(dataset)-20000])
display_dataset(dataset)
Vorgefertigte Modelle
Im torchvision Modul stehen viele verschiedene vorgefertigte Modelle zur Verfügung, und noch mehr Modelle können im Internet gefunden werden. Schauen wir uns an, wie das einfachste VGG-16 Modell geladen und verwendet werden kann:
vgg = torchvision.models.vgg16(pretrained=True)
sample_image = dataset[0][0].unsqueeze(0)
res = vgg(sample_image)
print(res[0].argmax())
Das Ergebnis, das wir erhalten haben, ist eine Nummer einer ImageNet-Klasse, die hier nachgeschlagen werden kann. Wir können den folgenden Code verwenden, um diese Klassentabelle automatisch zu laden und das Ergebnis zurückzugeben:
import json, requests
class_map = json.loads(requests.get("https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json").text)
class_map = { int(k) : v for k,v in class_map.items() }
class_map[res[0].argmax().item()]
Lassen Sie uns auch die Architektur des VGG-16 Netzwerks betrachten:
summary(vgg,input_size=(1,3,224,224))
Zusätzlich zu der Schicht, die wir bereits kennen, gibt es auch einen anderen Schichttyp namens Dropout. Diese Schichten dienen als Regularisierungstechnik. Regularisierung nimmt leichte Anpassungen am Lernalgorithmus vor, damit das Modell besser generalisiert. Während des Trainings werfen Dropout-Schichten einen Teil (etwa 30%) der Neuronen in der vorherigen Schicht weg, und das Training erfolgt ohne sie. Dies hilft, den Optimierungsprozess aus lokalen Minima herauszuführen und die Entscheidungsfähigkeit zwischen verschiedenen neuronalen Pfaden zu verteilen, was die allgemeine Stabilität des Netzwerks verbessert.
GPU-Berechnungen
Tiefe neuronale Netzwerke wie VGG-16 und andere modernere Architekturen erfordern eine beträchtliche Rechenleistung, um ausgeführt zu werden. Es ist sinnvoll, GPU-Beschleunigung zu nutzen, wenn sie verfügbar ist. Um dies zu tun, müssen wir alle an der Berechnung beteiligten Tensoren explizit auf die GPU verschieben.
Normalerweise wird dies so gemacht, dass die Verfügbarkeit der GPU im Code überprüft wird und eine device-Variable definiert wird, die auf das Rechengerät verweist – entweder GPU oder CPU.
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('Doing computations on device = {}'.format(device))
vgg.to(device)
sample_image = sample_image.to(device)
vgg(sample_image).argmax()
Extrahieren von VGG-Features
Wenn wir VGG-16 verwenden möchten, um Features aus unseren Bildern zu extrahieren, benötigen wir das Modell ohne die finalen Klassifikationsschichten. Tatsächlich kann dieser "Feature-Extractor" mit der Methode vgg.features erhalten werden:
res = vgg.features(sample_image).cpu()
plt.figure(figsize=(15,3))
plt.imshow(res.detach().view(512,-1).T)
print(res.size())
Die Dimension des Merkmal-Tensors beträgt 512x7x7, aber um ihn zu visualisieren, mussten wir ihn in eine 2D-Form umformen.
Versuchen wir nun herauszufinden, ob diese Merkmale zur Klassifizierung von Bildern verwendet werden können. Nehmen wir manuell einen Teil der Bilder (in unserem Fall 800) und berechnen ihre Merkmalsvektoren vor. Wir speichern das Ergebnis in einem großen Tensor namens feature_tensor und die Labels in label_tensor:
bs = 8
dl = torch.utils.data.DataLoader(dataset,batch_size=bs,shuffle=True)
num = bs*100
feature_tensor = torch.zeros(num,512*7*7).to(device)
label_tensor = torch.zeros(num).to(device)
i = 0
for x,l in dl:
with torch.no_grad():
f = vgg.features(x.to(device))
feature_tensor[i:i+bs] = f.view(bs,-1)
label_tensor[i:i+bs] = l
i+=bs
print('.',end='')
if i>=num:
break
Jetzt können wir vgg_dataset definieren, das Daten aus diesem Tensor entnimmt, sie mit der Funktion random_split in Trainings- und Testsets aufteilt und ein kleines, einschichtiges dichtes Klassifizierungsnetzwerk auf den extrahierten Merkmalen trainiert:
vgg_dataset = torch.utils.data.TensorDataset(feature_tensor,label_tensor.to(torch.long))
train_ds, test_ds = torch.utils.data.random_split(vgg_dataset,[700,100])
train_loader = torch.utils.data.DataLoader(train_ds,batch_size=32)
test_loader = torch.utils.data.DataLoader(test_ds,batch_size=32)
net = torch.nn.Sequential(torch.nn.Linear(512*7*7,2),torch.nn.LogSoftmax()).to(device)
history = train(net,train_loader,test_loader)
Das Ergebnis ist großartig, wir können mit fast 98% Wahrscheinlichkeit zwischen einer Katze und einem Hund unterscheiden! Allerdings haben wir diesen Ansatz nur an einer kleinen Teilmenge aller Bilder getestet, da die manuelle Merkmalsextraktion anscheinend sehr zeitaufwändig ist.
Transfer Learning mit einem VGG-Netzwerk
Wir können das manuelle Vorberechnen der Merkmale auch vermeiden, indem wir das ursprüngliche VGG-16-Netzwerk während des Trainings als Ganzes verwenden. Schauen wir uns die Objektstruktur von VGG-16 an:
print(vgg)
Sie können sehen, dass das Netzwerk Folgendes enthält:
* einen Feature-Extractor (features), der aus einer Reihe von Convolutional- und Pooling-Schichten besteht
* eine Average-Pooling-Schicht (avgpool)
* einen finalen classifier, der aus mehreren dichten Schichten besteht und 25088 Eingabefeatures in 1000 Klassen umwandelt (was der Anzahl der Klassen in ImageNet entspricht)
Um das End-to-End-Modell zu trainieren, das unser Dataset klassifizieren wird, müssen wir:
* den finalen Classifier ersetzen, durch einen, der die benötigte Anzahl an Klassen erzeugt. In unserem Fall können wir eine Linear-Schicht mit 25088 Eingängen und 2 Ausgabeneuronen verwenden.
* die Gewichte des Convolutional-Feature-Extractors einfrieren, sodass sie nicht trainiert werden. Es wird empfohlen, dieses Einfrieren zunächst durchzuführen, da andernfalls die untrainierte Classifier-Schicht die ursprünglichen vortrainierten Gewichte des Convolutional-Extractors zerstören könnte. Das Einfrieren der Gewichte kann erreicht werden, indem die requires_grad-Eigenschaft aller Parameter auf False gesetzt wird.
vgg.classifier = torch.nn.Linear(25088,2).to(device)
for x in vgg.features.parameters():
x.requires_grad = False
summary(vgg,(1, 3,244,244))
Wie aus der Zusammenfassung ersichtlich, enthält dieses Modell etwa 15 Millionen Gesamtparameter, aber nur 50.000 davon sind trainierbar – das sind die Gewichte der Klassifikationsschicht. Das ist gut, da wir eine kleinere Anzahl von Parametern mit einer kleineren Anzahl von Beispielen feinabstimmen können.
Nun lassen Sie uns das Modell mit unserem ursprünglichen Datensatz trainieren. Dieser Prozess wird viel Zeit in Anspruch nehmen, daher verwenden wir die Funktion train_long, die einige Zwischenergebnisse ausgibt, ohne auf das Ende einer Epoche zu warten. Es wird dringend empfohlen, dieses Training auf einer GPU-fähigen Rechenumgebung durchzuführen!
trainset, testset = torch.utils.data.random_split(dataset,[20000,len(dataset)-20000])
train_loader = torch.utils.data.DataLoader(trainset,batch_size=16)
test_loader = torch.utils.data.DataLoader(testset,batch_size=16)
train_long(vgg,train_loader,test_loader,loss_fn=torch.nn.CrossEntropyLoss(),epochs=1,print_freq=90)
Es sieht so aus, als hätten wir einen einigermaßen genauen Katzen-gegen-Hunde-Klassifikator erhalten! Lassen Sie uns ihn für die zukünftige Verwendung speichern!
torch.save(vgg,'data/cats_dogs.pth')
Wir können das Modell jederzeit aus der Datei laden. Dies könnte nützlich sein, falls das nächste Experiment das Modell zerstört - Sie müssten nicht von vorne beginnen.
vgg = torch.load('data/cats_dogs.pth')
Feinabstimmung des Transfer-Lernens
Im vorherigen Abschnitt haben wir die finale Klassifikationsschicht trainiert, um Bilder in unserem eigenen Datensatz zu klassifizieren. Allerdings haben wir den Feature-Extraktor nicht neu trainiert, und unser Modell hat sich auf die Merkmale verlassen, die es aus den ImageNet-Daten gelernt hat. Wenn sich Ihre Objekte optisch stark von gewöhnlichen ImageNet-Bildern unterscheiden, könnte diese Kombination von Merkmalen nicht optimal funktionieren. Daher macht es Sinn, auch die Faltungsschichten zu trainieren.
Um dies zu tun, können wir die Parameter der Faltungsfilter, die wir zuvor eingefroren haben, wieder freigeben.
> Hinweis: Es ist wichtig, dass Sie die Parameter zuerst einfrieren und mehrere Trainings-Epochen durchführen, um die Gewichte in der Klassifikationsschicht zu stabilisieren. Wenn Sie direkt mit einem End-to-End-Netzwerk mit freigegebenen Parametern beginnen, können große Fehler die vortrainierten Gewichte in den Faltungsschichten zerstören.
for x in vgg.features.parameters():
x.requires_grad = True
Nach dem Entfrieren können wir noch ein paar weitere Epochen trainieren. Du kannst auch eine niedrigere Lernrate wählen, um den Einfluss auf die vortrainierten Gewichte zu minimieren. Allerdings kannst du selbst bei einer niedrigen Lernrate damit rechnen, dass die Genauigkeit zu Beginn des Trainings sinkt, bevor sie schließlich ein etwas höheres Niveau erreicht als im Fall von fixierten Gewichten.
> Hinweis: Dieses Training verläuft deutlich langsamer, da die Gradienten durch viele Schichten des Netzwerks zurückpropagiert werden müssen! Es kann sinnvoll sein, die ersten paar Minibatches zu beobachten, um die Tendenz zu erkennen, und dann die Berechnung zu stoppen.
train_long(vgg,train_loader,test_loader,loss_fn=torch.nn.CrossEntropyLoss(),epochs=1,print_freq=90,lr=0.0001)
Andere Modelle der Computer Vision
VGG-16 ist eine der einfachsten Architekturen für Computer Vision. Das torchvision-Paket bietet viele weitere vortrainierte Netzwerke. Die am häufigsten verwendeten darunter sind die ResNet-Architekturen, entwickelt von Microsoft, und Inception von Google. Schauen wir uns zum Beispiel die Architektur des einfachsten ResNet-18-Modells an (ResNet ist eine Modellfamilie mit unterschiedlicher Tiefe – Sie können mit ResNet-151 experimentieren, wenn Sie sehen möchten, wie ein wirklich tiefes Modell aussieht):
resnet = torchvision.models.resnet18()
print(resnet)
Wie Sie sehen können, enthält das Modell die gleichen Bausteine: Feature Extractor und finaler Klassifikator (fc). Dadurch können wir dieses Modell genau so verwenden, wie wir VGG-16 für Transfer Learning genutzt haben. Sie können mit dem obigen Code experimentieren, indem Sie verschiedene ResNet-Modelle als Basismodell verwenden und beobachten, wie sich die Genauigkeit verändert.
Batch-Normalisierung
Dieses Netzwerk enthält noch eine weitere Art von Schicht: Batch-Normalisierung. Die Idee der Batch-Normalisierung besteht darin, die Werte, die durch das neuronale Netzwerk fließen, in den richtigen Bereich zu bringen. Normalerweise funktionieren neuronale Netzwerke am besten, wenn alle Werte im Bereich von [-1,1] oder [0,1] liegen. Aus diesem Grund skalieren/normieren wir unsere Eingabedaten entsprechend. Während des Trainings eines tiefen Netzwerks kann es jedoch passieren, dass Werte deutlich außerhalb dieses Bereichs liegen, was das Training erschwert. Die Batch-Normalisierungsschicht berechnet den Durchschnitt und die Standardabweichung für alle Werte des aktuellen Minibatches und verwendet diese, um das Signal zu normalisieren, bevor es durch eine Schicht des neuronalen Netzwerks geleitet wird. Dies verbessert die Stabilität tiefer Netzwerke erheblich.
Fazit
Mit Transfer Learning konnten wir schnell einen Klassifikator für unsere benutzerdefinierte Objektklassifizierungsaufgabe erstellen und eine hohe Genauigkeit erzielen. Allerdings war dieses Beispiel nicht ganz fair, da das ursprüngliche VGG-16-Netzwerk bereits darauf trainiert war, Katzen und Hunde zu erkennen. Wir haben also lediglich die meisten Muster wiederverwendet, die bereits im Netzwerk vorhanden waren. Bei exotischeren, domänenspezifischen Objekten, wie Details einer Produktionslinie in einer Fabrik oder verschiedenen Baumblättern, können Sie mit einer geringeren Genauigkeit rechnen.
Sie können sehen, dass komplexere Aufgaben, die wir jetzt lösen, eine höhere Rechenleistung erfordern und nicht einfach auf der CPU gelöst werden können. In der nächsten Einheit werden wir versuchen, eine leichtere Implementierung zu verwenden, um dasselbe Modell mit geringeren Rechenressourcen zu trainieren, was nur zu einer leicht niedrigeren Genauigkeit führt.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Vorgefertigte Modelle und Transferlernen
Das Training von CNNs kann viel Zeit in Anspruch nehmen, und es wird eine große Menge an Daten dafür benötigt. Ein Großteil der Zeit wird jedoch darauf verwendet, die besten Low-Level-Filter zu erlernen, die ein Netzwerk nutzt, um Muster aus Bildern zu extrahieren. Eine naheliegende Frage ist: Können wir ein neuronales Netzwerk, das auf einem Datensatz trainiert wurde, verwenden und es anpassen, um andere Bilder zu klassifizieren, ohne den gesamten Trainingsprozess erneut durchlaufen zu müssen?
Dieser Ansatz wird als Transferlernen bezeichnet, da wir Wissen von einem neuronalen Netzwerkmodell auf ein anderes übertragen. Beim Transferlernen beginnen wir typischerweise mit einem vortrainierten Modell, das auf einem großen Bilddatensatz wie ImageNet trainiert wurde. Diese Modelle können bereits verschiedene Merkmale aus generischen Bildern gut extrahieren, und in vielen Fällen kann allein das Erstellen eines Klassifikators auf Basis dieser extrahierten Merkmale zu guten Ergebnissen führen.
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import numpy as np
import os
from tfcv import *
Katzen- vs. Hunde-Datensatz
In dieser Einheit werden wir ein reales Problem lösen: die Klassifizierung von Bildern von Katzen und Hunden. Dafür verwenden wir den Kaggle Cats vs. Dogs Dataset, der auch von Microsoft heruntergeladen werden kann.
Lassen Sie uns diesen Datensatz herunterladen und in das Verzeichnis data extrahieren (dieser Vorgang kann einige Zeit in Anspruch nehmen!):
if not os.path.exists('data/kagglecatsanddogs_5340.zip'):
!wget -P data https://download.microsoft.com/download/3/E/1/3E1C3F21-ECDB-4869-8368-6DEBA77B919F/kagglecatsanddogs_5340.zip
import zipfile
if not os.path.exists('data/PetImages'):
with zipfile.ZipFile('data/kagglecatsanddogs_5340.zip', 'r') as zip_ref:
zip_ref.extractall('data')
Leider gibt es einige beschädigte Bilddateien im Datensatz. Wir müssen eine schnelle Bereinigung durchführen, um beschädigte Dateien zu überprüfen. Um dieses Tutorial nicht zu überladen, haben wir den Code zur Überprüfung des Datensatzes in ein Modul verschoben.
check_image_dir('data/PetImages/Cat/*.jpg')
check_image_dir('data/PetImages/Dog/*.jpg')
Laden des Datensatzes
In früheren Beispielen haben wir Datensätze geladen, die in Keras integriert sind. Jetzt werden wir mit unserem eigenen Datensatz arbeiten, den wir aus einem Verzeichnis mit Bildern laden müssen.
In der Praxis können Bilddatensätze ziemlich groß sein, und man kann nicht davon ausgehen, dass alle Daten in den Speicher passen. Daher werden Datensätze oft als Generatoren dargestellt, die Daten in Minibatches zurückgeben können, die für das Training geeignet sind.
Um mit der Bildklassifikation umzugehen, enthält Keras die spezielle Funktion image_dataset_from_directory, die Bilder aus Unterverzeichnissen laden kann, die verschiedenen Klassen entsprechen. Diese Funktion skaliert die Bilder automatisch und kann den Datensatz auch in Trainings- und Testuntergruppen aufteilen:
data_dir = 'data/PetImages'
batch_size = 64
ds_train = keras.preprocessing.image_dataset_from_directory(
data_dir,
validation_split = 0.2,
subset = 'training',
seed = 13,
image_size = (224,224),
batch_size = batch_size
)
ds_test = keras.preprocessing.image_dataset_from_directory(
data_dir,
validation_split = 0.2,
subset = 'validation',
seed = 13,
image_size = (224,224),
batch_size = batch_size
)
Es ist wichtig, denselben seed-Wert für beide Aufrufe festzulegen, da dieser die Aufteilung der Bilder zwischen Trainings- und Testdatensatz beeinflusst.
Das Dataset erkennt automatisch die Klassennamen aus den Verzeichnissen, und Sie können darauf zugreifen, falls erforderlich, indem Sie Folgendes aufrufen:
ds_train.class_names
Datensätze, die wir erhalten haben, können direkt an die fit-Funktion übergeben werden, um das Modell zu trainieren. Sie enthalten sowohl entsprechende Bilder als auch Labels, die mit der folgenden Konstruktion durchlaufen werden können:
for x,y in ds_train:
print(f"Training batch shape: features={x.shape}, labels={y.shape}")
x_sample, y_sample = x,y
break
display_dataset(x_sample.numpy().astype(np.int),np.expand_dims(y_sample,1),classes=ds_train.class_names)
> Hinweis: Alle Bilder im Datensatz sind als Gleitkomma-Tensoren mit einem Bereich von 0-255 dargestellt. Bevor wir sie an das neuronale Netzwerk übergeben, müssen wir diese Werte in den Bereich 0-1 skalieren. Beim Plotten von Bildern müssen wir entweder dasselbe tun oder die Werte in den int-Typ konvertieren (was wir im obigen Code tun), um matplotlib zu zeigen, dass wir das ursprüngliche unskalierte Bild plotten möchten.
Vorgefertigte Modelle
Für viele Aufgaben der Bildklassifikation gibt es vorgefertigte neuronale Netzwerkmodelle. Viele dieser Modelle sind im keras.applications-Namespace verfügbar, und noch mehr Modelle können im Internet gefunden werden. Schauen wir uns an, wie das einfachste VGG-16-Modell geladen und verwendet werden kann:
vgg = keras.applications.VGG16()
inp = keras.applications.vgg16.preprocess_input(x_sample[:1])
res = vgg(inp)
print(f"Most probable class = {tf.argmax(res,1)}")
keras.applications.vgg16.decode_predictions(res.numpy())
Es gibt hier ein paar wichtige Punkte:
- Bevor ein Eingabebild an ein vortrainiertes Netzwerk übergeben wird, muss es auf eine bestimmte Weise vorverarbeitet werden. Dies geschieht durch Aufruf der entsprechenden
preprocess_input-Funktion, die einen Stapel von Bildern erhält und deren verarbeitete Form zurückgibt. Im Fall von VGG-16 werden die Bilder normalisiert, und ein vordefinierter Durchschnittswert für jeden Kanal wird abgezogen. Das liegt daran, dass VGG-16 ursprünglich mit dieser Vorverarbeitung trainiert wurde. - Das neuronale Netzwerk wird auf den Eingabestapel angewendet, und als Ergebnis erhalten wir einen Stapel von 1000-elementigen Tensoren, die die Wahrscheinlichkeit jeder Klasse anzeigen. Die wahrscheinlichste Klassennummer können wir durch Aufruf von
argmaxauf diesem Tensor ermitteln. - Das erhaltene Ergebnis ist eine Nummer einer
ImageNet-Klasse. Um dieses Ergebnis zu interpretieren, können wir auch die Funktiondecode_predictionsverwenden, die die Top-n-Klassen zusammen mit ihren Namen zurückgibt.
Lass uns auch die Architektur des VGG-16 Netzwerks betrachten:
vgg.summary()
GPU-Berechnungen
Tiefe neuronale Netzwerke, wie VGG-16 und andere modernere Architekturen, benötigen eine beträchtliche Rechenleistung, um ausgeführt zu werden. Es ist sinnvoll, GPU-Beschleunigung zu nutzen, wenn sie verfügbar ist. Glücklicherweise beschleunigt Keras automatisch die Berechnungen auf der GPU, wenn diese verfügbar ist. Wir können überprüfen, ob Tensorflow die GPU verwenden kann, indem wir den folgenden Code ausführen:
tf.config.list_physical_devices('GPU')
Extrahieren von VGG-Features
Wenn wir VGG-16 verwenden möchten, um Features aus unseren Bildern zu extrahieren, benötigen wir das Modell ohne die finalen Klassifikationsschichten. Wir können das VGG-16-Modell ohne die oberen Schichten mit diesem Code instanziieren:
vgg = keras.applications.VGG16(include_top=False)
inp = keras.applications.vgg16.preprocess_input(x_sample[:1])
res = vgg(inp)
print(f"Shape after applying VGG-16: {res[0].shape}")
plt.figure(figsize=(15,3))
plt.imshow(res[0].numpy().reshape(-1,512))
Die Dimension des Feature-Tensors beträgt 7x7x512, aber um ihn zu visualisieren, mussten wir ihn in eine 2D-Form umformen.
Versuchen wir nun herauszufinden, ob diese Features zur Klassifizierung von Bildern verwendet werden können. Nehmen wir manuell einen Teil der Bilder (in unserem Fall 50 Minibatches) und berechnen ihre Feature-Vektoren vorab. Dafür können wir die dataset-API von Tensorflow verwenden. Die map-Funktion nimmt ein Dataset und wendet eine gegebene Lambda-Funktion an, um es zu transformieren. Mit diesem Mechanismus erstellen wir neue Datasets, ds_features_train und ds_features_test, die die von VGG extrahierten Features anstelle der Originalbilder enthalten.
num = batch_size*50
ds_features_train = ds_train.take(50).map(lambda x,y : (vgg(x),y))
ds_features_test = ds_test.take(10).map(lambda x,y : (vgg(x),y))
for x,y in ds_features_train:
print(x.shape,y.shape)
break
Wir haben die Konstruktion .take(50) verwendet, um die Datensatzgröße zu begrenzen und unsere Demonstration zu beschleunigen. Natürlich können Sie dieses Experiment auch mit dem vollständigen Datensatz durchführen.
Jetzt, da wir einen Datensatz mit extrahierten Merkmalen haben, können wir einen einfachen dichten Klassifikator trainieren, um zwischen Katzen und Hunden zu unterscheiden. Dieses Netzwerk nimmt einen Merkmalsvektor der Form (7,7,512) und erzeugt eine Ausgabe, die entweder einem Hund oder einer Katze entspricht. Da es sich um eine binäre Klassifikation handelt, verwenden wir die sigmoid-Aktivierungsfunktion und den binary_crossentropy-Loss.
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=(7,7,512)),
keras.layers.Dense(1,activation='sigmoid')
])
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
hist = model.fit(ds_features_train, validation_data=ds_features_test)
Das Ergebnis ist großartig, wir können mit fast 95% Wahrscheinlichkeit zwischen einer Katze und einem Hund unterscheiden! Allerdings haben wir diesen Ansatz nur an einem Teil aller Bilder getestet, da die manuelle Merkmalsextraktion scheinbar viel Zeit in Anspruch nimmt.
Transfer Learning mit einem VGG-Netzwerk
Wir können das manuelle Vorberechnen der Merkmale auch vermeiden, indem wir das ursprüngliche VGG-16-Netzwerk während des Trainings vollständig nutzen und einen Merkmalsextraktor als erste Schicht zu unserem Netzwerk hinzufügen.
Das Schöne an der Keras-Architektur ist, dass das oben definierte VGG-16-Modell auch als Schicht in einem anderen neuronalen Netzwerk verwendet werden kann! Wir müssen lediglich ein Netzwerk mit einem dichten Klassifikator darauf aufbauen und dann das gesamte Netzwerk mithilfe von Backpropagation trainieren.
model = keras.models.Sequential()
model.add(keras.applications.VGG16(include_top=False,input_shape=(224,224,3)))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(1,activation='sigmoid'))
model.layers[0].trainable = False
model.summary()
Dieses Modell sieht aus wie ein End-to-End-Klassifikationsnetzwerk, das ein Bild nimmt und die Klasse zurückgibt. Der knifflige Punkt ist jedoch, dass wir möchten, dass VGG16 als Merkmalsextraktor fungiert und nicht neu trainiert wird. Daher müssen wir die Gewichte des konvolutionalen Merkmalsextraktors einfrieren. Wir können auf die erste Schicht des Netzwerks zugreifen, indem wir model.layers[0] aufrufen, und wir müssen lediglich die Eigenschaft trainable auf False setzen.
> Hinweis: Das Einfrieren der Gewichte des Merkmalsextraktors ist notwendig, da ansonsten die untrainierte Klassifikationsschicht die ursprünglichen vortrainierten Gewichte des konvolutionalen Extraktors zerstören könnte.
Man kann feststellen, dass, obwohl die Gesamtanzahl der Parameter in unserem Netzwerk etwa 15 Millionen beträgt, wir nur 25.000 Parameter trainieren. Alle anderen Parameter der oberen konvolutionalen Filter sind vortrainiert. Das ist gut, da wir eine kleinere Anzahl von Parametern mit einer kleineren Anzahl von Beispielen feinabstimmen können.
Wir werden nun unser Netzwerk trainieren und sehen, wie gut wir werden können. Rechnen Sie mit einer ziemlich langen Laufzeit und machen Sie sich keine Sorgen, wenn die Ausführung für einige Zeit eingefroren zu sein scheint.
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
hist = model.fit(ds_train, validation_data=ds_test)
Es sieht so aus, als hätten wir einen ziemlich genauen Katzen-gegen-Hunde-Klassifikator erhalten!
Speichern und Laden des Modells
Sobald wir das Modell trainiert haben, können wir die Modellarchitektur und die trainierten Gewichte in einer Datei speichern, um sie später zu verwenden:
model.save('data/cats_dogs.tf')
Wir können das Modell jederzeit aus der Datei laden. Dies könnte nützlich sein, falls das nächste Experiment das Modell zerstört - Sie müssten nicht von vorne beginnen.
model = keras.models.load_model('data/cats_dogs.tf')
Feinabstimmung des Transfer-Lernens
Im vorherigen Abschnitt haben wir die finale Klassifikationsschicht trainiert, um Bilder in unserem eigenen Datensatz zu klassifizieren. Allerdings haben wir den Feature-Extraktor nicht neu trainiert, und unser Modell hat sich auf die Merkmale verlassen, die es aus den ImageNet-Daten gelernt hat. Wenn sich Ihre Objekte optisch stark von gewöhnlichen ImageNet-Bildern unterscheiden, könnte diese Kombination von Merkmalen nicht optimal funktionieren. Daher macht es Sinn, auch die Faltungsschichten zu trainieren.
Um dies zu tun, können wir die Parameter der Faltungsfilter, die wir zuvor eingefroren haben, wieder freigeben.
> Hinweis: Es ist wichtig, dass Sie die Parameter zuerst einfrieren und mehrere Trainings-Epochen durchführen, um die Gewichte in der Klassifikationsschicht zu stabilisieren. Wenn Sie direkt mit einem End-to-End-Netzwerk mit freigegebenen Parametern beginnen, können große Fehler die vortrainierten Gewichte in den Faltungsschichten zerstören.
Unser konvolutionales VGG-16-Modell befindet sich in der ersten Schicht und besteht selbst aus vielen Schichten. Wir können uns seine Struktur ansehen:
model.layers[0].summary()
Wir können alle Schichten der konvolutionalen Basis auftauen:
model.layers[0].trainable = True
Allerdings ist es keine gute Idee, alle auf einmal aufzutauen. Wir können zunächst nur einige der letzten Schichten von Convolutionen auftauen, da sie höherwertige Muster enthalten, die für unsere Bilder relevant sind. Zum Beispiel können wir zu Beginn alle Schichten außer den letzten 4 einfrieren:
for i in range(len(model.layers[0].layers)-4):
model.layers[0].layers[i].trainable = False
model.summary()
Beobachten Sie, dass die Anzahl der trainierbaren Parameter deutlich gestiegen ist, aber sie liegt immer noch bei etwa 50 % aller Parameter.
Nach dem Entsperren können wir ein paar weitere Trainings-Epochen durchführen (in unserem Beispiel machen wir nur eine). Sie können auch eine niedrigere Lernrate wählen, um den Einfluss auf die vortrainierten Gewichte zu minimieren. Allerdings können Sie selbst bei einer niedrigen Lernrate damit rechnen, dass die Genauigkeit zu Beginn des Trainings sinkt, bevor sie schließlich ein etwas höheres Niveau erreicht als im Fall von fixierten Gewichten.
> Hinweis: Dieses Training verläuft deutlich langsamer, da die Gradienten durch viele Schichten des Netzwerks zurückpropagiert werden müssen!
hist = model.fit(ds_train, validation_data=ds_test)
Wir werden wahrscheinlich eine höhere Trainingsgenauigkeit erreichen, da wir ein leistungsstärkeres Netzwerk mit mehr Parametern verwenden. Die Validierungsgenauigkeit wird jedoch nicht im gleichen Maße steigen.
Du kannst gerne ein paar weitere Schichten des Netzwerks freigeben und weiter trainieren, um zu sehen, ob du eine höhere Genauigkeit erzielen kannst!
Andere Modelle der Computer Vision
VGG-16 ist eine der einfachsten Architekturen für Computer Vision. Keras bietet viele weitere vortrainierte Netzwerke an. Die am häufigsten verwendeten darunter sind die ResNet-Architekturen, entwickelt von Microsoft, und Inception von Google. Zum Beispiel werfen wir einen Blick auf die Architektur des einfachsten ResNet-50-Modells (ResNet ist eine Familie von Modellen mit unterschiedlicher Tiefe. Sie können mit ResNet-152 experimentieren, wenn Sie sehen möchten, wie ein wirklich tiefes Modell aussieht):
resnet = keras.applications.ResNet50()
resnet.summary()
Wie Sie sehen können, enthält das Modell die gleichen vertrauten Bausteine: Convolutional Layers, Pooling Layers und einen abschließenden dichten Klassifikator. Wir können dieses Modell genau so verwenden, wie wir VGG-16 für Transfer Learning genutzt haben. Sie können mit dem obigen Code experimentieren, indem Sie verschiedene ResNet-Modelle als Basismodell verwenden und beobachten, wie sich die Genauigkeit verändert.
Batch-Normalisierung
Dieses Netzwerk enthält noch eine weitere Art von Schicht: Batch-Normalisierung. Die Idee der Batch-Normalisierung besteht darin, die Werte, die durch das neuronale Netzwerk fließen, in den richtigen Bereich zu bringen. Normalerweise funktionieren neuronale Netzwerke am besten, wenn alle Werte im Bereich von [-1,1] oder [0,1] liegen. Aus diesem Grund skalieren/normalisieren wir unsere Eingabedaten entsprechend. Während des Trainings eines tiefen Netzwerks kann es jedoch passieren, dass Werte signifikant außerhalb dieses Bereichs liegen, was das Training erschwert. Die Batch-Normalisierungsschicht berechnet den Durchschnitt und die Standardabweichung für alle Werte des aktuellen Minibatches und verwendet diese, um das Signal zu normalisieren, bevor es durch eine Schicht des neuronalen Netzwerks geleitet wird. Dies verbessert die Stabilität tiefer Netzwerke erheblich.
Fazit
Mit Transfer Learning konnten wir schnell einen Klassifikator für unsere benutzerdefinierte Objektklassifizierungsaufgabe erstellen und eine hohe Genauigkeit erreichen. Allerdings war dieses Beispiel nicht ganz fair, da das ursprüngliche VGG-16-Netzwerk bereits darauf trainiert war, Katzen und Hunde zu erkennen. Wir haben also lediglich die meisten Muster wiederverwendet, die bereits im Netzwerk vorhanden waren. Bei exotischeren, domänenspezifischen Objekten, wie Details einer Produktionslinie in einer Fabrik oder verschiedenen Baumblättern, können Sie mit einer geringeren Genauigkeit rechnen.
Sie können sehen, dass komplexere Aufgaben, die wir jetzt lösen, eine höhere Rechenleistung erfordern und nicht einfach auf der CPU gelöst werden können. In der nächsten Einheit werden wir versuchen, eine leichtere Implementierung zu verwenden, um dasselbe Modell mit geringeren Rechenressourcen zu trainieren, was nur zu einer leicht niedrigeren Genauigkeit führt.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Autoencoder
Beim Training von CNNs besteht eines der Probleme darin, dass wir eine große Menge an gelabelten Daten benötigen. Im Fall der Bildklassifikation müssen wir Bilder in verschiedene Klassen unterteilen, was mit manuellem Aufwand verbunden ist.
Wir könnten jedoch rohe (nicht gelabelte) Daten verwenden, um CNN-Feature-Extraktoren zu trainieren. Dies wird als selbstüberwachtes Lernen bezeichnet. Anstelle von Labels verwenden wir Trainingsbilder sowohl als Eingabe als auch als Ausgabe des Netzwerks. Die Hauptidee des Autoencoders ist, dass wir ein Encoder-Netzwerk haben, das das Eingabebild in einen latenten Raum umwandelt (normalerweise ist dies einfach ein Vektor mit kleinerer Größe), und ein Decoder-Netzwerk, dessen Ziel es ist, das ursprüngliche Bild zu rekonstruieren.
Da wir den Autoencoder darauf trainieren, so viele Informationen wie möglich aus dem ursprünglichen Bild zu erfassen, um eine genaue Rekonstruktion zu ermöglichen, versucht das Netzwerk, die beste Einbettung der Eingabebilder zu finden, um deren Bedeutung zu erfassen.

> Bild von Keras Blog
Lass uns den einfachsten Autoencoder für MNIST erstellen!
import torch
import torchvision
import matplotlib.pyplot as plt
from torchvision import transforms
from torch import nn
from torch import optim
from tqdm import tqdm
import numpy as np
import torch.nn.functional as F
torch.manual_seed(42)
np.random.seed(42)
Definieren Sie Trainingsparameter und überprüfen Sie, ob die GPU verfügbar ist:
device = 'cuda:0' if torch.cuda.is_available() else 'cpu'
train_size = 0.9
lr = 1e-3
eps = 1e-8
batch_size = 256
epochs = 30
Die folgende Funktion lädt den MNIST-Datensatz und wendet die angegebenen Transformationen darauf an. Sie wird ihn außerdem in Trainings- und Testdatensätze aufteilen.
def mnist(train_part, transform=None):
dataset = torchvision.datasets.MNIST('.', download=True, transform=transform)
train_part = int(train_part * len(dataset))
train_dataset, test_dataset = torch.utils.data.random_split(dataset, [train_part, len(dataset) - train_part])
return train_dataset, test_dataset
Lassen Sie uns nun den Datensatz laden und Dataloader für Training und Test definieren:
transform = transforms.Compose([transforms.ToTensor()])
train_dataset, test_dataset = mnist(train_size, transform)
train_dataloader = torch.utils.data.DataLoader(train_dataset, drop_last=True, batch_size=batch_size, shuffle=True)
test_dataloader = torch.utils.data.DataLoader(test_dataset, batch_size=1, shuffle=False)
dataloaders = (train_dataloader, test_dataloader)
def plotn(n, data, noisy=False, super_res=None):
fig, ax = plt.subplots(1, n)
for i, z in enumerate(data):
if i == n:
break
preprocess = z[0].reshape(1, 28, 28) if z[0].shape[1] == 28 else z[0].reshape(1, 14, 14) if z[0].shape[1] == 14 else z[0]
if super_res is not None:
_transform = transforms.Resize((int(preprocess.shape[1] / super_res), int(preprocess.shape[2] / super_res)))
preprocess = _transform(preprocess)
if noisy:
shapes = list(preprocess.shape)
preprocess += noisify(shapes)
ax[i].imshow(preprocess[0])
plt.show()
def noisify(shapes):
return np.random.normal(loc=0.5, scale=0.3, size=shapes)
plotn(5, train_dataset)
class Encoder(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 16, kernel_size=(3, 3), padding='same')
self.maxpool1 = nn.MaxPool2d(kernel_size=(2, 2))
self.conv2 = nn.Conv2d(16, 8, kernel_size=(3, 3), padding='same')
self.maxpool2 = nn.MaxPool2d(kernel_size=(2, 2))
self.conv3 = nn.Conv2d(8, 8, kernel_size=(3, 3), padding='same')
self.maxpool3 = nn.MaxPool2d(kernel_size=(2, 2), padding=(1, 1))
self.relu = nn.ReLU()
def forward(self, input):
hidden1 = self.maxpool1(self.relu(self.conv1(input)))
hidden2 = self.maxpool2(self.relu(self.conv2(hidden1)))
encoded = self.maxpool3(self.relu(self.conv3(hidden2)))
return encoded
class Decoder(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(8, 8, kernel_size=(3, 3), padding='same')
self.upsample1 = nn.Upsample(scale_factor=(2, 2))
self.conv2 = nn.Conv2d(8, 8, kernel_size=(3, 3), padding='same')
self.upsample2 = nn.Upsample(scale_factor=(2, 2))
self.conv3 = nn.Conv2d(8, 16, kernel_size=(3, 3))
self.upsample3 = nn.Upsample(scale_factor=(2, 2))
self.conv4 = nn.Conv2d(16, 1, kernel_size=(3, 3), padding='same')
self.relu = nn.ReLU()
self.sigmoid = nn.Sigmoid()
def forward(self, input):
hidden1 = self.upsample1(self.relu(self.conv1(input)))
hidden2 = self.upsample2(self.relu(self.conv2(hidden1)))
hidden3 = self.upsample3(self.relu(self.conv3(hidden2)))
decoded = self.sigmoid(self.conv4(hidden3))
return decoded
class AutoEncoder(nn.Module):
def __init__(self, super_resolution=False):
super().__init__()
if not super_resolution:
self.encoder = Encoder()
else:
self.encoder = SuperResolutionEncoder()
self.decoder = Decoder()
def forward(self, input):
encoded = self.encoder(input)
decoded = self.decoder(encoded)
return decoded
model = AutoEncoder().to(device)
optimizer = optim.Adam(model.parameters(), lr=lr, eps=eps)
loss_fn = nn.BCELoss()
def train(dataloaders, model, loss_fn, optimizer, epochs, device, noisy=None, super_res=None):
tqdm_iter = tqdm(range(epochs))
train_dataloader, test_dataloader = dataloaders[0], dataloaders[1]
for epoch in tqdm_iter:
model.train()
train_loss = 0.0
test_loss = 0.0
for batch in train_dataloader:
imgs, labels = batch
shapes = list(imgs.shape)
if super_res is not None:
shapes[2], shapes[3] = int(shapes[2] / super_res), int(shapes[3] / super_res)
_transform = transforms.Resize((shapes[2], shapes[3]))
imgs_transformed = _transform(imgs)
imgs_transformed = imgs_transformed.to(device)
imgs = imgs.to(device)
labels = labels.to(device)
if noisy is not None:
noisy_tensor = noisy[0]
else:
noisy_tensor = torch.zeros(tuple(shapes)).to(device)
if super_res is None:
imgs_noisy = imgs + noisy_tensor
else:
imgs_noisy = imgs_transformed + noisy_tensor
imgs_noisy = torch.clamp(imgs_noisy, 0., 1.)
preds = model(imgs_noisy)
loss = loss_fn(preds, imgs)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss += loss.item()
model.eval()
with torch.no_grad():
for batch in test_dataloader:
imgs, labels = batch
shapes = list(imgs.shape)
if super_res is not None:
shapes[2], shapes[3] = int(shapes[2] / super_res), int(shapes[3] / super_res)
_transform = transforms.Resize((shapes[2], shapes[3]))
imgs_transformed = _transform(imgs)
imgs_transformed = imgs_transformed.to(device)
imgs = imgs.to(device)
labels = labels.to(device)
if noisy is not None:
test_noisy_tensor = noisy[1]
else:
test_noisy_tensor = torch.zeros(tuple(shapes)).to(device)
if super_res is None:
imgs_noisy = imgs + test_noisy_tensor
else:
imgs_noisy = imgs_transformed + test_noisy_tensor
imgs_noisy = torch.clamp(imgs_noisy, 0., 1.)
preds = model(imgs_noisy)
loss = loss_fn(preds, imgs)
test_loss += loss.item()
train_loss /= len(train_dataloader)
test_loss /= len(test_dataloader)
tqdm_dct = {'train loss:': train_loss, 'test loss:': test_loss}
tqdm_iter.set_postfix(tqdm_dct, refresh=True)
tqdm_iter.refresh()
train(dataloaders, model, loss_fn, optimizer, epochs, device)
model.eval()
predictions = []
plots = 5
for i, data in enumerate(test_dataset):
if i == plots:
break
predictions.append(model(data[0].to(device).unsqueeze(0)).detach().cpu())
plotn(plots, test_dataset)
plotn(plots, predictions)
> Aufgabe 1: Versuche, einen Autoencoder mit einer sehr kleinen latenten Vektorgröße, z. B. 2, zu trainieren, und zeichne die Punkte, die den verschiedenen Ziffern entsprechen. Tipp: Verwende eine vollständig verbundene Dense-Schicht nach dem konvolutionalen Teil, um die Vektorgröße auf den gewünschten Wert zu reduzieren.
> Aufgabe 2: Beginne mit verschiedenen Ziffern, erhalte ihre Repräsentationen im latenten Raum und beobachte, welche Auswirkungen das Hinzufügen von etwas Rauschen zum latenten Raum auf die resultierenden Ziffern hat.
Rauschunterdrückung
Autoencoder können effektiv verwendet werden, um Rauschen aus Bildern zu entfernen. Um einen Rauschunterdrücker zu trainieren, beginnen wir mit rauschfreien Bildern und fügen ihnen künstliches Rauschen hinzu. Anschließend geben wir dem Autoencoder verrauschte Bilder als Eingabe und rauschfreie Bilder als Ausgabe.
Schauen wir uns an, wie das bei MNIST funktioniert:
plotn(5, train_dataset, noisy=True)
model = AutoEncoder().to(device)
optimizer = optim.Adam(model.parameters(), lr=lr, eps=eps)
loss_fn = nn.BCELoss()
noisy_tensor = torch.FloatTensor(noisify([256, 1, 28, 28])).to(device)
test_noisy_tensor = torch.FloatTensor(noisify([1, 1, 28, 28])).to(device)
noisy_tensors = (noisy_tensor, test_noisy_tensor)
train(dataloaders, model, loss_fn, optimizer, 100, device, noisy=noisy_tensors)
model.eval()
predictions = []
noise = []
plots = 5
for i, data in enumerate(test_dataset):
if i == plots:
break
shapes = data[0].shape
noisy_data = data[0] + test_noisy_tensor[0].detach().cpu()
noise.append(noisy_data)
predictions.append(model(noisy_data.to(device).unsqueeze(0)).detach().cpu())
plotn(plots, noise)
plotn(plots, predictions)
> Übung: Sehen Sie, wie der Denoiser, der auf MNIST-Ziffern trainiert wurde, mit verschiedenen Bildern funktioniert. Als Beispiel können Sie den Fashion MNIST-Datensatz verwenden, der die gleiche Bildgröße hat. Beachten Sie, dass der Denoiser nur bei demselben Bildtyp gut funktioniert, auf dem er trainiert wurde (d.h. für die gleiche Wahrscheinlichkeitsverteilung der Eingabedaten).
Super-Resolution
Ähnlich wie beim Denoiser können wir Autoencoder trainieren, um die Auflösung eines Bildes zu erhöhen. Um ein Super-Resolution-Netzwerk zu trainieren, beginnen wir mit hochauflösenden Bildern und skalieren diese automatisch herunter, um Eingaben für das Netzwerk zu erzeugen. Anschließend geben wir dem Autoencoder kleine Bilder als Eingaben und hochauflösende Bilder als Ausgaben.
Dazu skalieren wir das Bild während des Trainings auf 14x14 herunter.
super_res_koeff = 2.0
plotn(5, train_dataset, super_res=super_res_koeff)
class SuperResolutionEncoder(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 16, kernel_size=(3, 3), padding='same')
self.maxpool1 = nn.MaxPool2d(kernel_size=(2, 2))
self.conv2 = nn.Conv2d(16, 8, kernel_size=(3, 3), padding='same')
self.maxpool2 = nn.MaxPool2d(kernel_size=(2, 2), padding=(1, 1))
self.relu = nn.ReLU()
def forward(self, input):
hidden1 = self.maxpool1(self.relu(self.conv1(input)))
encoded = self.maxpool2(self.relu(self.conv2(hidden1)))
return encoded
model = AutoEncoder(super_resolution=True).to(device)
optimizer = optim.Adam(model.parameters(), lr=lr, eps=eps)
loss_fn = nn.BCELoss()
train(dataloaders, model, loss_fn, optimizer, epochs, device, super_res=2.0)
model.eval()
predictions = []
plots = 5
shapes = test_dataset[0][0].shape
for i, data in enumerate(test_dataset):
if i == plots:
break
_transform = transforms.Resize((int(shapes[1] / super_res_koeff), int(shapes[2] / super_res_koeff)))
predictions.append(model(_transform(data[0]).to(device).unsqueeze(0)).detach().cpu())
plotn(plots, test_dataset, super_res=super_res_koeff)
plotn(plots, predictions)
> Übung: Versuchen Sie, ein Super-Resolution-Netzwerk auf CIFAR-10 für 2x- und 4x-Hochskalierung zu trainieren. Verwenden Sie Rauschen als Eingabe für das 4x-Hochskalierungsmodell und beobachten Sie das Ergebnis.
Variational Auto-Encoders (VAE)
Traditionelle Autoencoder reduzieren die Dimension der Eingabedaten auf irgendeine Weise und identifizieren die wichtigen Merkmale von Eingabebildern. Allerdings ergeben latente Vektoren oft keinen Sinn. Mit anderen Worten: Wenn man beispielsweise den MNIST-Datensatz betrachtet, ist es nicht einfach herauszufinden, welche Ziffern den verschiedenen latenten Vektoren entsprechen, da nahe beieinanderliegende latente Vektoren nicht unbedingt denselben Ziffern entsprechen.
Andererseits ist es für das Training von generativen Modellen besser, ein gewisses Verständnis des latenten Raums zu haben. Diese Idee führt uns zu den variational auto-encoders (VAE).
VAE ist ein Autoencoder, der lernt, die statistische Verteilung der latenten Parameter, die sogenannte latente Verteilung, vorherzusagen. Zum Beispiel können wir annehmen, dass latente Vektoren als $N(\mathrm{z_mean},e^{\mathrm{z_log}})$ verteilt sind, wobei $\mathrm{z_mean}, \mathrm{z_log} \in\mathbb{R}^d$. Der Encoder im VAE lernt, diese Parameter vorherzusagen, und der Decoder nimmt dann einen zufälligen Vektor aus dieser Verteilung, um das Objekt zu rekonstruieren.
Zusammengefasst:
- Aus dem Eingabevektor sagen wir
z_meanundz_logvoraus (anstatt die Standardabweichung direkt vorherzusagen, sagen wir deren Logarithmus voraus) - Wir entnehmen einen Vektor
sample(z_val in code)aus der Verteilung $N(\mathrm{z_mean},e^{\mathrm{z_log_sigma}})$ - Der Decoder versucht, das ursprüngliche Bild mithilfe von
sampleals Eingabevektor zu dekodieren
<img src="images/vae.png" width="50%">
> Bild aus diesem Blogbeitrag von Isaak Dykeman
class VAEEncoder(nn.Module):
def __init__(self, device):
super().__init__()
self.intermediate_dim = 512
self.latent_dim = 2
self.linear = nn.Linear(784, self.intermediate_dim)
self.z_mean = nn.Linear(self.intermediate_dim, self.latent_dim)
self.z_log = nn.Linear(self.intermediate_dim, self.latent_dim)
self.relu = nn.ReLU()
self.device = device
def forward(self, input):
bs = input.shape[0]
hidden = self.relu(self.linear(input))
z_mean = self.z_mean(hidden)
z_log = self.z_log(hidden)
eps = torch.FloatTensor(np.random.normal(size=(bs, self.latent_dim))).to(device)
z_val = z_mean + torch.exp(z_log) * eps
return z_mean, z_log, z_val
class VAEDecoder(nn.Module):
def __init__(self):
super().__init__()
self.intermediate_dim = 512
self.latent_dim = 2
self.linear = nn.Linear(self.latent_dim, self.intermediate_dim)
self.output = nn.Linear(self.intermediate_dim, 784)
self.relu = nn.ReLU()
self.sigmoid = nn.Sigmoid()
def forward(self, input):
hidden = self.relu(self.linear(input))
decoded = self.sigmoid(self.output(hidden))
return decoded
class VAEAutoEncoder(nn.Module):
def __init__(self, device):
super().__init__()
self.encoder = VAEEncoder(device)
self.decoder = VAEDecoder()
self.z_vals = None
def forward(self, input):
bs, c, h, w = input.shape[0], input.shape[1], input.shape[2], input.shape[3]
input = input.view(bs, -1)
encoded = self.encoder(input)
self.z_vals = encoded
decoded = self.decoder(encoded[2])
return decoded
def get_zvals(self):
return self.z_vals
Variationale Autoencoder verwenden eine komplexe Verlustfunktion, die aus zwei Teilen besteht: * Rekonstruktionsverlust ist die Verlustfunktion, die zeigt, wie nah das rekonstruierte Bild am Zielbild ist (kann MSE sein). Es ist dieselbe Verlustfunktion wie bei normalen Autoencodern. * KL-Verlust, der sicherstellt, dass die Verteilung der latenten Variablen nahe an einer Normalverteilung bleibt. Er basiert auf dem Konzept der Kullback-Leibler-Divergenz – einem Maß zur Abschätzung, wie ähnlich zwei statistische Verteilungen sind.
def vae_loss(preds, targets, z_vals):
mse = nn.MSELoss()
reconstruction_loss = mse(preds, targets.view(targets.shape[0], -1)) * 784.0
temp = 1.0 + z_vals[1] - torch.square(z_vals[0]) - torch.exp(z_vals[1])
kl_loss = -0.5 * torch.sum(temp, axis=-1)
return torch.mean(reconstruction_loss + kl_loss)
model = VAEAutoEncoder(device).to(device)
optimizer = optim.RMSprop(model.parameters(), lr=lr, eps=eps)
def train_vae(dataloaders, model, optimizer, epochs, device):
tqdm_iter = tqdm(range(epochs))
train_dataloader, test_dataloader = dataloaders[0], dataloaders[1]
for epoch in tqdm_iter:
model.train()
train_loss = 0.0
test_loss = 0.0
for batch in train_dataloader:
imgs, labels = batch
imgs = imgs.to(device)
labels = labels.to(device)
preds = model(imgs)
z_vals = model.get_zvals()
loss = vae_loss(preds, imgs, z_vals)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss += loss.item()
model.eval()
with torch.no_grad():
for batch in test_dataloader:
imgs, labels = batch
imgs = imgs.to(device)
labels = labels.to(device)
preds = model(imgs)
z_vals = model.get_zvals()
loss = vae_loss(preds, imgs, z_vals)
test_loss += loss.item()
train_loss /= len(train_dataloader)
test_loss /= len(test_dataloader)
tqdm_dct = {'train loss:': train_loss, 'test loss:': test_loss}
tqdm_iter.set_postfix(tqdm_dct, refresh=True)
tqdm_iter.refresh()
train_vae(dataloaders, model, optimizer, epochs, device)
model.eval()
predictions = []
plots = 5
for i, data in enumerate(test_dataset):
if i == plots:
break
predictions.append(model(data[0].to(device).unsqueeze(0)).view(1, 28, 28).detach().cpu())
plotn(plots, test_dataset)
plotn(plots, predictions)
> Aufgabe: In unserem Beispiel haben wir ein vollständig verbundenes VAE trainiert. Nehmen Sie nun das CNN aus dem traditionellen Auto-Encoder oben und erstellen Sie ein CNN-basiertes VAE.
Adversarielle Auto-Encoder (AAE)
Adversarial Auto-Encoders sind eine Kombination aus Generativen Adversarial Networks und Variational Auto-Encoders.
Der Encoder fungiert als Generator, der Diskriminator lernt, die echten Bilder vom Encoder-Ausgang von den generierten zu unterscheiden. Der Encoder-Ausgang ist eine Verteilung, aus dieser Ausgabe wird der Decoder versuchen, das Bild zu dekodieren.
In diesem Ansatz haben wir drei Verlustfunktionen: Generator-Verlust, Diskriminator-Verlust aus GANs und Rekonstruktionsverlust aus VAEs.
<img src="images/aae.png" width="50%">
> Bild aus diesem Blogbeitrag von Felipe Ducau
class AAEEncoder(nn.Module):
def __init__(self, input_dim, inter_dim, latent_dim):
super().__init__()
self.linear1 = nn.Linear(input_dim, inter_dim)
self.linear2 = nn.Linear(inter_dim, inter_dim)
self.linear3 = nn.Linear(inter_dim, inter_dim)
self.linear4 = nn.Linear(inter_dim, latent_dim)
self.relu = nn.ReLU()
def forward(self, input):
hidden1 = self.relu(self.linear1(input))
hidden2 = self.relu(self.linear2(hidden1))
hidden3 = self.relu(self.linear3(hidden2))
encoded = self.linear4(hidden3)
return encoded
class AAEDecoder(nn.Module):
def __init__(self, latent_dim, inter_dim, output_dim):
super().__init__()
self.linear1 = nn.Linear(latent_dim, inter_dim)
self.linear2 = nn.Linear(inter_dim, inter_dim)
self.linear3 = nn.Linear(inter_dim, inter_dim)
self.linear4 = nn.Linear(inter_dim, output_dim)
self.relu = nn.ReLU()
self.sigmoid = nn.Sigmoid()
def forward(self, input):
hidden1 = self.relu(self.linear1(input))
hidden2 = self.relu(self.linear2(hidden1))
hidden3 = self.relu(self.linear3(hidden2))
decoded = self.sigmoid(self.linear4(hidden3))
return decoded
class AAEDiscriminator(nn.Module):
def __init__(self, latent_dim, inter_dim):
super().__init__()
self.latent_dim = latent_dim
self.inter_dim = inter_dim
self.linear1 = nn.Linear(latent_dim, inter_dim)
self.linear2 = nn.Linear(inter_dim, inter_dim)
self.linear3 = nn.Linear(inter_dim, inter_dim)
self.linear4 = nn.Linear(inter_dim, inter_dim)
self.linear5 = nn.Linear(inter_dim, 1)
self.relu = nn.ReLU()
self.sigmoid = nn.Sigmoid()
def forward(self, input):
hidden1 = self.relu(self.linear1(input))
hidden2 = self.relu(self.linear2(hidden1))
hidden3 = self.relu(self.linear3(hidden2))
hidden4 = self.relu(self.linear4(hidden3))
decoded = self.sigmoid(self.linear4(hidden4))
return decoded
def get_dims(self):
return self.latent_dim, self.inter_dim
input_dims = 784
inter_dims = 1000
latent_dims = 150
aae_encoder = AAEEncoder(input_dims, inter_dims, latent_dims).to(device)
aae_decoder = AAEDecoder(latent_dims, inter_dims, input_dims).to(device)
aae_discriminator = AAEDiscriminator(latent_dims, int(inter_dims / 2)).to(device)
lr = 1e-4
regularization_lr = 5e-5
optim_encoder = optim.Adam(aae_encoder.parameters(), lr=lr)
optim_encoder_regularization = optim.Adam(aae_encoder.parameters(), lr=regularization_lr)
optim_decoder = optim.Adam(aae_decoder.parameters(), lr=lr)
optim_discriminator = optim.Adam(aae_discriminator.parameters(), lr=regularization_lr)
def train_aae(dataloaders, models, optimizers, epochs, device):
tqdm_iter = tqdm(range(epochs))
train_dataloader, test_dataloader = dataloaders[0], dataloaders[1]
enc, dec, disc = models[0], models[1], models[2]
optim_enc, optim_enc_reg, optim_dec, optim_disc = optimizers[0], optimizers[1], optimizers[2], optimizers[3]
eps = 1e-9
for epoch in tqdm_iter:
enc.train()
dec.train()
disc.train()
train_reconst_loss = 0.0
train_disc_loss = 0.0
train_enc_loss = 0.0
test_reconst_loss = 0.0
test_disc_loss = 0.0
test_enc_loss = 0.0
for batch in train_dataloader:
imgs, labels = batch
imgs = imgs.view(imgs.shape[0], -1).to(device)
labels = labels.to(device)
enc.zero_grad()
dec.zero_grad()
disc.zero_grad()
encoded = enc(imgs)
decoded = dec(encoded)
reconstruction_loss = F.binary_cross_entropy(decoded, imgs)
reconstruction_loss.backward()
optim_enc.step()
optim_dec.step()
enc.eval()
latent_dim, disc_inter_dim = disc.get_dims()
real = torch.randn(imgs.shape[0], latent_dim).to(device)
disc_real = disc(real)
disc_fake = disc(enc(imgs))
disc_loss = -torch.mean(torch.log(disc_real + eps) + torch.log(1.0 - disc_fake + eps))
disc_loss.backward()
optim_dec.step()
enc.train()
disc_fake = disc(enc(imgs))
enc_loss = -torch.mean(torch.log(disc_fake + eps))
enc_loss.backward()
optim_enc_reg.step()
train_reconst_loss += reconstruction_loss.item()
train_disc_loss += disc_loss.item()
train_enc_loss += enc_loss.item()
enc.eval()
dec.eval()
disc.eval()
with torch.no_grad():
for batch in test_dataloader:
imgs, labels = batch
imgs = imgs.view(imgs.shape[0], -1).to(device)
labels = labels.to(device)
encoded = enc(imgs)
decoded = dec(encoded)
reconstruction_loss = F.binary_cross_entropy(decoded, imgs)
latent_dim, disc_inter_dim = disc.get_dims()
real = torch.randn(imgs.shape[0], latent_dim).to(device)
disc_real = disc(real)
disc_fake = disc(enc(imgs))
disc_loss = -torch.mean(torch.log(disc_real + eps) + torch.log(1.0 - disc_fake + eps))
disc_fake = disc(enc(imgs))
enc_loss = -torch.mean(torch.log(disc_fake + eps))
test_reconst_loss += reconstruction_loss.item()
test_disc_loss += disc_loss.item()
test_enc_loss += enc_loss.item()
train_reconst_loss /= len(train_dataloader)
train_disc_loss /= len(train_dataloader)
train_enc_loss /= len(train_dataloader)
test_reconst_loss /= len(test_dataloader)
test_disc_loss /= len(test_dataloader)
test_enc_loss /= len(test_dataloader)
tqdm_dct = {'train reconst loss:': train_reconst_loss, 'train disc loss:': train_disc_loss, 'train enc loss': train_enc_loss, \
'test reconst loss:': test_reconst_loss, 'test disc loss:': test_disc_loss, 'test enc loss': test_enc_loss}
tqdm_iter.set_postfix(tqdm_dct, refresh=True)
tqdm_iter.refresh()
models = (aae_encoder, aae_decoder, aae_discriminator)
optimizers = (optim_encoder, optim_encoder_regularization, optim_decoder, optim_discriminator)
train_aae(dataloaders, models, optimizers, epochs, device)
aae_encoder.eval()
aae_decoder.eval()
predictions = []
plots = 10
for i, data in enumerate(test_dataset):
if i == plots:
break
pred = aae_decoder(aae_encoder(data[0].to(device).unsqueeze(0).view(1, 784)))
predictions.append(pred.view(1, 28, 28).detach().cpu())
plotn(plots, test_dataset)
plotn(plots, predictions)
Zusätzliche Materialien
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Beim Training von CNNs besteht eines der Probleme darin, dass wir eine große Menge an gelabelten Daten benötigen. Im Fall der Bildklassifikation müssen wir Bilder in verschiedene Klassen unterteilen, was mit einem manuellen Aufwand verbunden ist.
Wir könnten jedoch rohe (nicht gelabelte) Daten verwenden, um CNN-Feature-Extraktoren zu trainieren, was als selbstüberwachtes Lernen bezeichnet wird. Anstelle von Labels verwenden wir Trainingsbilder sowohl als Eingabe als auch als Ausgabe des Netzwerks. Die Hauptidee des Autoencoders besteht darin, ein Encoder-Netzwerk zu haben, das das Eingabebild in einen latenten Raum umwandelt (normalerweise ist dies einfach ein Vektor mit einer kleineren Größe), und ein Decoder-Netzwerk, dessen Ziel es ist, das ursprüngliche Bild zu rekonstruieren.
Da wir den Autoencoder darauf trainieren, so viele Informationen wie möglich aus dem ursprünglichen Bild zu erfassen, um eine genaue Rekonstruktion zu ermöglichen, versucht das Netzwerk, die beste Einbettung der Eingabebilder zu finden, um deren Bedeutung zu erfassen.

Bild aus dem Keras-Blog
Die meisten der unten stehenden Beispiele sind von diesem Artikel inspiriert.
Lass uns den einfachsten Autoencoder für MNIST erstellen:
import tensorflow as tf
from tensorflow.keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt
(x_train, y_trainclass), (x_test, y_testclass) = mnist.load_data()
def plotn(n,x):
fig,ax = plt.subplots(1,n)
for i,z in enumerate(x[0:n]):
ax[i].imshow(z.reshape(28,28) if z.size==28*28 else z.reshape(14,14) if z.size==14*14 else z)
plt.show()
plotn(5,x_train)
from tensorflow.keras.layers import Input, Dense, Conv2D, MaxPooling2D, UpSampling2D, Lambda
from tensorflow.keras.models import Model
from tensorflow.keras.losses import binary_crossentropy,mse
input_img = Input(shape=(28, 28, 1))
x = Conv2D(16, (3, 3), activation='relu', padding='same')(input_img)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
encoded = MaxPooling2D((2, 2), padding='same')(x)
encoder = Model(input_img,encoded)
input_rep = Input(shape=(4,4,8))
x = Conv2D(8, (3, 3), activation='relu', padding='same')(input_rep)
x = UpSampling2D((2, 2))(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
x = Conv2D(16, (3, 3), activation='relu')(x)
x = UpSampling2D((2, 2))(x)
decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
decoder = Model(input_rep,decoded)
autoencoder = Model(input_img, decoder(encoder(input_img)))
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
autoencoder.fit(x_train, x_train,
epochs=25,
batch_size=128,
shuffle=True,
validation_data=(x_test, x_test))
y_test = autoencoder.predict(x_test[0:5])
plotn(5,x_test)
plotn(5,y_test)
encoder = Model(input_img, encoded)
encoded_imgs = encoder.predict(x_test[0:5])
plotn(5,encoded_imgs.reshape(5,-1,8))
print(encoded_imgs.max(),encoded_imgs.min())
res = decoder.predict(7*np.random.rand(7,4,4,8))
plotn(7,res)
> Aufgabe 1: Versuche, einen Autoencoder mit einer sehr kleinen latenten Vektorgröße, z. B. 2, zu trainieren und die Punkte zu plotten, die den verschiedenen Ziffern entsprechen. Tipp: Verwende eine vollständig verbundene Dense-Schicht nach dem konvolutionalen Teil, um die Vektorgröße auf den gewünschten Wert zu reduzieren.
> Aufgabe 2: Beginne mit verschiedenen Ziffern, erhalte ihre Repräsentationen im latenten Raum und untersuche, welche Auswirkungen das Hinzufügen von etwas Rauschen zum latenten Raum auf die resultierenden Ziffern hat.
Rauschunterdrückung
Autoencoder können effektiv verwendet werden, um Rauschen aus Bildern zu entfernen. Um einen Rauschunterdrücker zu trainieren, beginnen wir mit rauschfreien Bildern und fügen ihnen künstliches Rauschen hinzu. Anschließend geben wir dem Autoencoder verrauschte Bilder als Eingabe und rauschfreie Bilder als Ausgabe.
Schauen wir uns an, wie das bei MNIST funktioniert:
def noisify(data):
return np.clip(data+np.random.normal(loc=0.5,scale=0.5,size=data.shape),0.,1.)
x_train_noise = noisify(x_train)
x_test_noise = noisify(x_test)
plotn(5,x_train_noise)
autoencoder.fit(x_train_noise, x_train,
epochs=25,
batch_size=128,
shuffle=True,
validation_data=(x_test_noise, x_test))
y_test = autoencoder.predict(x_test_noise[0:5])
plotn(5,x_test_noise)
plotn(5,y_test)
> Übung: Sehen Sie, wie der auf MNIST-Ziffern trainierte Denoiser mit verschiedenen Bildern funktioniert. Als Beispiel können Sie den Fashion MNIST-Datensatz verwenden, der die gleiche Bildgröße hat. Beachten Sie, dass der Denoiser nur bei demselben Bildtyp gut funktioniert, auf dem er trainiert wurde (d. h. für die gleiche Wahrscheinlichkeitsverteilung der Eingabedaten).
Superauflösung
Ähnlich wie beim Rauschunterdrücker können wir Autoencoder trainieren, um die Auflösung eines Bildes zu erhöhen. Um ein Netzwerk für Superauflösung zu trainieren, beginnen wir mit hochauflösenden Bildern und skalieren diese automatisch herunter, um Eingaben für das Netzwerk zu erzeugen. Anschließend füttern wir den Autoencoder mit kleinen Bildern als Eingaben und hochauflösenden Bildern als Ausgaben.
Lassen Sie uns MNIST auf 14x14 herunterskalieren:
x_train_lr = tf.keras.layers.AveragePooling2D()(x_train).numpy()
x_test_lr = tf.keras.layers.AveragePooling2D()(x_test).numpy()
plotn(5,x_train_lr)
from tensorflow.keras.layers import Input, Dense, Conv2D, MaxPooling2D, UpSampling2D, Lambda
from tensorflow.keras.models import Model
from tensorflow.keras.losses import binary_crossentropy,mse
input_img = Input(shape=(14, 14, 1))
x = Conv2D(16, (3, 3), activation='relu', padding='same')(input_img)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
encoded = MaxPooling2D((2, 2), padding='same')(x)
encoder = Model(input_img,encoded)
input_rep = Input(shape=(4,4,8))
x = Conv2D(8, (3, 3), activation='relu', padding='same')(input_rep)
x = UpSampling2D((2, 2))(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
x = Conv2D(16, (3, 3), activation='relu')(x)
x = UpSampling2D((2, 2))(x)
decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
decoder = Model(input_rep,decoded)
autoencoder = Model(input_img, decoder(encoder(input_img)))
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
autoencoder.fit(x_train_lr, x_train,
epochs=25,
batch_size=128,
shuffle=True,
validation_data=(x_test_lr, x_test))
y_test_lr = autoencoder.predict(x_test_lr[0:5])
plotn(5,x_test_lr)
plotn(5,y_test_lr)
> Übung: Versuchen Sie, ein Super-Resolution-Netzwerk auf CIFAR-10 für 2x- und 4x-Skalierung zu trainieren. Verwenden Sie Rauschen als Eingabe für das 4x-Skalierungsmodell und beobachten Sie das Ergebnis.
Variational Auto-Encoders (VAE)
Traditionelle Autoencoder reduzieren die Dimension der Eingabedaten auf irgendeine Weise, indem sie die wichtigen Merkmale der Eingabebilder identifizieren. Allerdings ergeben latente Vektoren oft wenig Sinn. Mit anderen Worten: Wenn man beispielsweise den MNIST-Datensatz betrachtet, ist es nicht einfach herauszufinden, welche Ziffern zu welchen latenten Vektoren gehören, da nahe beieinanderliegende latente Vektoren nicht unbedingt denselben Ziffern entsprechen.
Andererseits ist es für das Training von generativen Modellen besser, ein gewisses Verständnis des latenten Raums zu haben. Diese Idee führt uns zum Variational Auto-Encoder (VAE).
Ein VAE ist ein Autoencoder, der lernt, die statistische Verteilung der latenten Parameter vorherzusagen, die sogenannte latente Verteilung. Zum Beispiel können wir annehmen, dass latente Vektoren gemäß $N(\mathrm{z_mean},e^{\mathrm{z_log_sigma}})$ verteilt sind, wobei $\mathrm{z_mean}, \mathrm{z_log_sigma} \in\mathbb{R}^d$. Der Encoder im VAE lernt, diese Parameter vorherzusagen, und der Decoder nimmt dann einen zufälligen Vektor aus dieser Verteilung, um das Objekt zu rekonstruieren.
Zusammengefasst:
- Aus dem Eingabevektor sagen wir
z_meanundz_log_sigmavoraus (anstatt die Standardabweichung direkt vorherzusagen, sagen wir deren Logarithmus voraus) - Wir ziehen einen Vektor
sampleaus der Verteilung $N(\mathrm{z_mean},e^{\mathrm{z_log_sigma}})$ - Der Decoder versucht, das ursprüngliche Bild mithilfe von
sampleals Eingabevektor zu decodieren
<img src="images/vae.png" width="50%">
intermediate_dim = 512
latent_dim = 2
batch_size = 128
tf.compat.v1.disable_eager_execution()
inputs = Input(shape=(784,))
h = Dense(intermediate_dim, activation='relu')(inputs)
z_mean = Dense(latent_dim)(h)
z_log_sigma = Dense(latent_dim)(h)
@tf.function
def sampling(args):
z_mean, z_log_sigma = args
bs = tf.shape(z_mean)[0]
epsilon = tf.random.normal(shape=(bs, latent_dim))
return z_mean + tf.exp(z_log_sigma) * epsilon
z = Lambda(sampling)([z_mean, z_log_sigma])
encoder = Model(inputs, [z_mean, z_log_sigma, z])
latent_inputs = Input(shape=(latent_dim,))
x = Dense(intermediate_dim, activation='relu')(latent_inputs)
outputs = Dense(784, activation='sigmoid')(x)
decoder = Model(latent_inputs, outputs)
outputs = decoder(encoder(inputs)[2])
vae = Model(inputs, outputs)
Variationale Autoencoder verwenden eine komplexe Verlustfunktion, die aus zwei Teilen besteht: * Rekonstruktionsverlust ist die Verlustfunktion, die zeigt, wie nah das rekonstruierte Bild am Ziel ist (kann MSE sein). Es ist dieselbe Verlustfunktion wie bei normalen Autoencodern. * KL-Verlust, der sicherstellt, dass die Verteilungen der latenten Variablen nahe an der Normalverteilung bleiben. Er basiert auf dem Konzept der Kullback-Leibler-Divergenz – einem Maß, um zu schätzen, wie ähnlich zwei statistische Verteilungen sind.
@tf.function
def vae_loss(x1,x2):
reconstruction_loss = mse(x1,x2)*784
tmp = 1 + z_log_sigma - tf.square(z_mean) - tf.exp(z_log_sigma)
kl_loss = -0.5*tf.reduce_sum(tmp, axis=-1)
return tf.convert_to_tensor(tf.reduce_mean(reconstruction_loss + kl_loss))
vae.compile(optimizer='rmsprop', loss=vae_loss)
x_train_flat = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test_flat = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))
vae.fit(x_train_flat, x_train_flat,
shuffle=True,
epochs=25,
batch_size=batch_size,
validation_data=(x_test_flat, x_test_flat))
y_test = vae.predict(x_test_flat[0:5])
plotn(5,x_test_flat)
plotn(5,y_test)
x_test_encoded = encoder.predict(x_test_flat)[0]
plt.figure(figsize=(6, 6))
plt.scatter(x_test_encoded[:, 0], x_test_encoded[:, 1], c=y_testclass)
plt.colorbar()
plt.show()
def plotsample(n):
dx = np.linspace(-1,1,n)
dy = np.linspace(-1,1,n)
fig,ax = plt.subplots(n,n)
for i,xi in enumerate(dx):
for j,xj in enumerate(dy):
res = decoder.predict(np.array([xi,xj]).reshape(-1,2))[0]
ax[i,j].imshow(res.reshape(28,28))
ax[i,j].axis('off')
plt.show()
plotsample(10)
> Aufgabe: In unserem Beispiel haben wir ein vollständig verbundenes VAE trainiert. Nehmen Sie nun das CNN aus dem traditionellen Auto-Encoder oben und erstellen Sie ein CNN-basiertes VAE.
Zusätzliche Materialien
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Autoencoder
Beim Training von CNNs besteht eines der Probleme darin, dass wir eine große Menge an gelabelten Daten benötigen. Im Fall der Bildklassifikation müssen wir Bilder in verschiedene Klassen unterteilen, was manuell erfolgen muss.
Quiz vor der Vorlesung
Es kann jedoch sinnvoll sein, rohe (nicht gelabelte) Daten für das Training von CNN-Feature-Extraktoren zu verwenden, was als selbstüberwachtes Lernen bezeichnet wird. Anstelle von Labels verwenden wir Trainingsbilder sowohl als Eingabe als auch als Ausgabe des Netzwerks. Die Hauptidee eines Autoencoders besteht darin, ein Encoder-Netzwerk zu haben, das das Eingabebild in einen latenten Raum (normalerweise ein Vektor mit kleinerer Größe) umwandelt, und ein Decoder-Netzwerk, dessen Ziel es ist, das ursprüngliche Bild zu rekonstruieren.
> ✅ Ein Autoencoder ist "eine Art künstliches neuronales Netzwerk, das effiziente Codierungen von nicht gelabelten Daten lernt."
Da wir einen Autoencoder trainieren, um so viele Informationen wie möglich aus dem ursprünglichen Bild zu erfassen, um eine genaue Rekonstruktion zu ermöglichen, versucht das Netzwerk, die beste Einbettung der Eingabebilder zu finden, um deren Bedeutung zu erfassen.

> Bild von Keras Blog
Szenarien für die Verwendung von Autoencodern
Obwohl die Rekonstruktion von Originalbildern an sich nicht besonders nützlich erscheint, gibt es einige Szenarien, in denen Autoencoder besonders hilfreich sind:
- Reduzierung der Dimension von Bildern zur Visualisierung oder Training von Bild-Einbettungen. Autoencoder liefern in der Regel bessere Ergebnisse als PCA, da sie die räumliche Natur von Bildern und hierarchische Merkmale berücksichtigen.
- Rauschunterdrückung, d. h. das Entfernen von Rauschen aus Bildern. Da Rauschen viele unnütze Informationen enthält, kann der Autoencoder nicht alles in den relativ kleinen latenten Raum einpassen und erfasst daher nur die wichtigen Teile des Bildes. Beim Training von Rauschunterdrückern beginnen wir mit Originalbildern und verwenden Bilder mit künstlich hinzugefügtem Rauschen als Eingabe für den Autoencoder.
- Superauflösung, d. h. die Erhöhung der Bildauflösung. Wir beginnen mit hochauflösenden Bildern und verwenden das Bild mit niedrigerer Auflösung als Eingabe für den Autoencoder.
- Generative Modelle. Sobald wir den Autoencoder trainiert haben, kann der Decoder-Teil verwendet werden, um neue Objekte aus zufälligen latenten Vektoren zu erstellen.
Variationale Autoencoder (VAE)
Traditionelle Autoencoder reduzieren die Dimension der Eingabedaten auf irgendeine Weise und identifizieren die wichtigen Merkmale der Eingabebilder. Allerdings machen latente Vektoren oft wenig Sinn. Mit anderen Worten: Wenn wir das MNIST-Dataset als Beispiel nehmen, ist es nicht einfach herauszufinden, welche Ziffern zu verschiedenen latenten Vektoren gehören, da nahegelegene latente Vektoren nicht unbedingt denselben Ziffern entsprechen.
Für das Training von generativen Modellen ist es jedoch besser, ein Verständnis des latenten Raums zu haben. Diese Idee führt uns zu variationalen Autoencodern (VAE).
Ein VAE ist ein Autoencoder, der lernt, die statistische Verteilung der latenten Parameter vorherzusagen, die sogenannte latente Verteilung. Zum Beispiel möchten wir vielleicht, dass latente Vektoren normal verteilt sind mit einem Mittelwert z<sub>mean</sub> und einer Standardabweichung z<sub>sigma</sub> (beide, Mittelwert und Standardabweichung, sind Vektoren einer bestimmten Dimension d). Der Encoder im VAE lernt, diese Parameter vorherzusagen, und der Decoder nimmt dann einen zufälligen Vektor aus dieser Verteilung, um das Objekt zu rekonstruieren.
Zusammengefasst:
- Aus dem Eingabevektor sagen wir
z_meanundz_log_sigmavoraus (anstatt die Standardabweichung direkt vorherzusagen, sagen wir deren Logarithmus voraus). - Wir entnehmen einen Vektor
sampleaus der Verteilung N(z<sub>mean</sub>,exp(z<sub>log_sigma</sub>)). - Der Decoder versucht, das ursprüngliche Bild mithilfe von
sampleals Eingabevektor zu dekodieren.
<img src="../../../../../translated_images/de/vae.464c465a5b6a9e25.webp" width="50%">
> Bild aus diesem Blogbeitrag von Isaak Dykeman
Variationale Autoencoder verwenden eine komplexe Verlustfunktion, die aus zwei Teilen besteht:
- Rekonstruktionsverlust ist die Verlustfunktion, die zeigt, wie nah ein rekonstruiertes Bild am Ziel ist (z. B. Mean Squared Error, MSE). Es ist dieselbe Verlustfunktion wie bei normalen Autoencodern.
- KL-Verlust, der sicherstellt, dass die Verteilung der latenten Variablen nahe an der Normalverteilung bleibt. Er basiert auf dem Konzept der Kullback-Leibler-Divergenz – einem Maß zur Schätzung der Ähnlichkeit zweier statistischer Verteilungen.
Ein wichtiger Vorteil von VAEs ist, dass sie es uns ermöglichen, relativ einfach neue Bilder zu generieren, da wir wissen, aus welcher Verteilung wir latente Vektoren entnehmen müssen. Wenn wir beispielsweise einen VAE mit einem 2D-latenten Vektor auf MNIST trainieren, können wir die Komponenten des latenten Vektors variieren, um verschiedene Ziffern zu erhalten:
<img alt="vaemnist" src="../../../../../translated_images/de/vaemnist.cab9e602dc08dc50.webp" width="50%"/>
> Bild von Dmitry Soshnikov
Beobachten Sie, wie Bilder ineinander übergehen, wenn wir beginnen, latente Vektoren aus verschiedenen Bereichen des latenten Parameterraums zu entnehmen. Wir können diesen Raum auch in 2D visualisieren:
<img alt="vaemnist cluster" src="../../../../../translated_images/de/vaemnist-diag.694315f775d5d666.webp" width="50%"/>
> Bild von Dmitry Soshnikov
✍️ Übungen: Autoencoder
Erfahren Sie mehr über Autoencoder in den entsprechenden Notebooks:
Eigenschaften von Autoencodern
- Daten-spezifisch - Sie funktionieren nur gut mit der Art von Bildern, auf denen sie trainiert wurden. Wenn wir beispielsweise ein Superauflösungsnetzwerk auf Blumen trainieren, funktioniert es nicht gut bei Porträts. Das liegt daran, dass das Netzwerk hochauflösende Bilder erzeugen kann, indem es feine Details aus den Merkmalen des Trainingsdatensatzes übernimmt.
- Verlustbehaftet - Das rekonstruierte Bild ist nicht identisch mit dem Originalbild. Die Art des Verlusts wird durch die während des Trainings verwendete Verlustfunktion definiert.
- Funktioniert mit nicht gelabelten Daten
Quiz nach der Vorlesung
Fazit
In dieser Lektion haben Sie die verschiedenen Arten von Autoencodern kennengelernt, die einem KI-Wissenschaftler zur Verfügung stehen. Sie haben gelernt, wie man sie erstellt und wie man sie verwendet, um Bilder zu rekonstruieren. Sie haben auch den VAE kennengelernt und erfahren, wie man ihn verwendet, um neue Bilder zu generieren.
🚀 Herausforderung
In dieser Lektion haben Sie gelernt, wie man Autoencoder für Bilder verwendet. Aber sie können auch für Musik verwendet werden! Schauen Sie sich das MusicVAE-Projekt des Magenta-Projekts an, das Autoencoder verwendet, um Musik zu rekonstruieren. Machen Sie einige Experimente mit dieser Bibliothek, um zu sehen, was Sie erstellen können.
Quiz nach der Vorlesung
Wiederholung & Selbststudium
Lesen Sie zur Referenz mehr über Autoencoder in diesen Ressourcen:
- Building Autoencoders in Keras
- Blogbeitrag auf NeuroHive
- Variational Autoencoders Explained
- Conditional Variational Autoencoders
Aufgabe
Am Ende dieses Notebooks mit TensorFlow finden Sie eine 'Aufgabe' – verwenden Sie diese als Ihre Hausaufgabe.
Generative Adversarial Networks
Das Hauptziel eines Generative Adversarial Network (GAN) ist es, Bilder zu erzeugen, die dem Trainingsdatensatz ähnlich (aber nicht identisch) sind.
Ein GAN besteht aus zwei neuronalen Netzwerken, die gegeneinander trainiert werden:
- Der Generator nimmt einen zufälligen Vektor und soll daraus ein Bild erzeugen.
- Der Diskriminator ist ein Netzwerk, das zwischen einem Originalbild (aus dem Trainingsdatensatz) und einem vom Generator erzeugten Bild unterscheiden soll.
import torch
import torchvision
import matplotlib.pyplot as plt
from torchvision import transforms
from torch import nn
from torch import optim
from tqdm import tqdm
import numpy as np
import torch.nn.functional as F
torch.manual_seed(42)
np.random.seed(42)
device = 'cuda:0' if torch.cuda.is_available() else 'cpu'
train_size = 1.0
lr = 2e-4
weight_decay = 8e-9
beta1 = 0.5
beta2 = 0.999
batch_size = 256
epochs = 100
plot_every = 10
Generator
Die Aufgabe eines Generators besteht darin, einen zufälligen Vektor einer bestimmten Größe (ähnlich dem latenten Vektor in Autoencodern) zu nehmen und das Zielbild zu erzeugen. Er ähnelt stark der generativen Seite eines Autoencoders.
In unserem Beispiel verwenden wir lineare neuronale Netzwerke und den MNIST-Datensatz.
class Generator(nn.Module):
def __init__(self):
super().__init__()
self.linear1 = nn.Linear(100, 256)
self.bn1 = nn.BatchNorm1d(256, momentum=0.2)
self.linear2 = nn.Linear(256, 512)
self.bn2 = nn.BatchNorm1d(512, momentum=0.2)
self.linear3 = nn.Linear(512, 1024)
self.bn3 = nn.BatchNorm1d(1024, momentum=0.2)
self.linear4 = nn.Linear(1024, 784)
self.tanh = nn.Tanh()
self.leaky_relu = nn.LeakyReLU(0.2)
def forward(self, input):
hidden1 = self.leaky_relu(self.bn1(self.linear1(input)))
hidden2 = self.leaky_relu(self.bn2(self.linear2(hidden1)))
hidden3 = self.leaky_relu(self.bn3(self.linear3(hidden2)))
generated = self.tanh(self.linear4(hidden3)).view(input.shape[0], 1, 28, 28)
return generated
Einige Tricks, die im Generator verwendet werden: * Anstelle von ReLU verwenden wir LeakyReLU, d.h. ein ReLU, das für negative $x$ nicht exakt 0 ist, sondern eine andere lineare Funktion mit einer sehr kleinen Steigung. * Wir verwenden BatchNorm1D, um das Training zu stabilisieren. * Die Aktivierungsfunktion in der letzten Schicht ist Tanh, sodass die Ausgabe im Bereich [-1,1] liegt.
Diskriminator
Der Diskriminator ist ein klassisches Bildklassifikationsnetzwerk. In unserem ersten Beispiel werden wir ebenfalls einen linearen Klassifikator verwenden.
class Discriminator(nn.Module):
def __init__(self):
super().__init__()
self.linear1 = nn.Linear(784, 512)
self.linear2 = nn.Linear(512, 256)
self.linear3 = nn.Linear(256, 1)
self.leaky_relu = nn.LeakyReLU(0.2)
self.sigmoid = nn.Sigmoid()
def forward(self, input):
input = input.view(input.shape[0], -1)
hidden1 = self.leaky_relu(self.linear1(input))
hidden2 = self.leaky_relu(self.linear2(hidden1))
classififed = self.sigmoid(self.linear3(hidden2))
return classififed
Laden des Datensatzes
Wir verwenden den MNIST-Datensatz.
def mnist(train_part, transform=None):
dataset = torchvision.datasets.MNIST('.', download=True, transform=transform)
train_part = int(train_part * len(dataset))
train_dataset, test_dataset = torch.utils.data.random_split(dataset, [train_part, len(dataset) - train_part])
return train_dataset, test_dataset
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=0.5, std=0.5)
])
train_dataset, test_dataset = mnist(train_size, transform)
train_dataloader = torch.utils.data.DataLoader(train_dataset, drop_last=True, batch_size=batch_size, shuffle=True)
dataloaders = (train_dataloader, )
Netzwerktraining
Bei jedem Schritt des Trainings gibt es zwei Phasen:
-
Generator-Training. Wir erzeugen einige zufällige Vektoren Rauschen (das Training erfolgt in Minibatches, daher verwenden wir jeweils 100 Vektoren), generieren wahre Labels (Vektor mit der Form (bs, 1) mit Werten von 1.0), berechnen den Generatorverlust zwischen der Ausgabe des eingefrorenen Diskriminators mit Rauschen als Eingabe und den wahren Labels.
-
Diskriminator-Training. Wir berechnen den Diskriminatorverlust aus zwei Teilen. Der erste Teil ist der Verlust zwischen der Ausgabe des Diskriminators mit Rauschen als Eingabe und falschen Labels (Vektor mit der Form (bs, 1) mit Werten von 0.0). Der zweite Teil ist der Verlust zwischen der Ausgabe des Diskriminators mit echten Bildern als Eingabe und den wahren Labels (Vektor mit der Form (bs, 1) mit Werten von 1.0). Der resultierende Verlust ist (erster_Teil_Verlust + zweiter_Teil_Verlust) / 2.
def plotn(n, generator, device):
generator.eval()
noise = torch.FloatTensor(np.random.normal(0, 1, (n, 100))).to(device)
imgs = generator(noise).detach().cpu()
fig, ax = plt.subplots(1, n)
for i, im in enumerate(imgs):
ax[i].imshow(im[0])
plt.show()
def train_gan(dataloaders, models, optimizers, loss_fn, epochs, plot_every, device):
tqdm_iter = tqdm(range(epochs))
train_dataloader = dataloaders[0]
gen, disc = models[0], models[1]
optim_gen, optim_disc = optimizers[0], optimizers[1]
for epoch in tqdm_iter:
gen.train()
disc.train()
train_gen_loss = 0.0
train_disc_loss = 0.0
test_gen_loss = 0.0
test_disc_loss = 0.0
for batch in train_dataloader:
imgs, _ = batch
imgs = imgs.to(device)
disc.eval()
gen.zero_grad()
noise = torch.FloatTensor(np.random.normal(0.0, 1.0, (imgs.shape[0], 100))).to(device)
real_labels = torch.ones((imgs.shape[0], 1)).to(device)
fake_labels = torch.zeros((imgs.shape[0], 1)).to(device)
generated = gen(noise)
disc_preds = disc(generated)
g_loss = loss_fn(disc_preds, real_labels)
g_loss.backward()
optim_gen.step()
disc.train()
disc.zero_grad()
disc_real = disc(imgs)
disc_real_loss = loss_fn(disc_real, real_labels)
disc_fake = disc(generated.detach())
disc_fake_loss = loss_fn(disc_fake, fake_labels)
d_loss = (disc_real_loss + disc_fake_loss) / 2.0
d_loss.backward()
optim_disc.step()
train_gen_loss += g_loss.item()
train_disc_loss += d_loss.item()
train_gen_loss /= len(train_dataloader)
train_disc_loss /= len(train_dataloader)
if epoch % plot_every == 0 or epoch == epochs - 1:
plotn(5, gen, device)
tqdm_dct = {'generator loss:': train_gen_loss, 'discriminator loss:': train_disc_loss}
tqdm_iter.set_postfix(tqdm_dct, refresh=True)
tqdm_iter.refresh()
generator = Generator().to(device)
discriminator = Discriminator().to(device)
optimizer_generator = optim.Adam(generator.parameters(), lr=lr, weight_decay=weight_decay, betas=(beta1, beta2))
optimizer_discriminator = optim.Adam(discriminator.parameters(), lr=lr, weight_decay=weight_decay, betas=(beta1, beta2))
loss_fn = nn.BCELoss()
models = (generator, discriminator)
optimizers = (optimizer_generator, optimizer_discriminator)
train_gan(dataloaders, models, optimizers, loss_fn, epochs, plot_every, device)
DCGAN
Deep Convolutional GAN ist die naheliegende Idee, Faltungsschichten für den Generator und den Diskriminator zu verwenden. Der Hauptunterschied hier ist die Verwendung der Conv2DTranspose-Schicht im Generator.
> Bild aus diesem Tutorial
class DCGenerator(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.ConvTranspose2d(100, 256, kernel_size=(3, 3), stride=(2, 2), bias=False)
self.bn1 = nn.BatchNorm2d(256)
self.conv2 = nn.ConvTranspose2d(256, 128, kernel_size=(3, 3), stride=(2, 2), bias=False)
self.bn2 = nn.BatchNorm2d(128)
self.conv3 = nn.ConvTranspose2d(128, 64, kernel_size=(3, 3), stride=(2, 2), bias=False)
self.bn3 = nn.BatchNorm2d(64)
self.conv4 = nn.ConvTranspose2d(64, 1, kernel_size=(3, 3), stride=(2, 2), padding=(2, 2), output_padding=(1, 1), bias=False)
self.tanh = nn.Tanh()
self.relu = nn.ReLU()
def forward(self, input):
hidden1 = self.relu(self.bn1(self.conv1(input)))
hidden2 = self.relu(self.bn2(self.conv2(hidden1)))
hidden3 = self.relu(self.bn3(self.conv3(hidden2)))
generated = self.tanh(self.conv4(hidden3)).view(input.shape[0], 1, 28, 28)
return generated
class DCDiscriminator(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
self.conv2 = nn.Conv2d(64, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
self.bn2 = nn.BatchNorm2d(128)
self.conv3 = nn.Conv2d(128, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
self.bn3 = nn.BatchNorm2d(256)
self.conv4 = nn.Conv2d(256, 1, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
self.leaky_relu = nn.LeakyReLU(0.2)
self.sigmoid = nn.Sigmoid()
def forward(self, input):
hidden1 = self.leaky_relu(self.conv1(input))
hidden2 = self.leaky_relu(self.bn2(self.conv2(hidden1)))
hidden3 = self.leaky_relu(self.bn3(self.conv3(hidden2)))
classified = self.sigmoid(self.conv4(hidden3)).view(input.shape[0], -1)
return classified
Gewichtsinitialisierung aus dem DCGAN-Papier.
def weights_init(model):
classname = model.__class__.__name__
if classname.find('Conv') != -1:
nn.init.normal_(model.weight.data, 0.0, 0.02)
elif classname.find('BatchNorm') != -1:
nn.init.normal_(model.weight.data, 1.0, 0.02)
nn.init.constant_(model.bias.data, 0)
transform = transforms.Compose([
transforms.ToTensor(),
])
train_dataset, test_dataset = mnist(train_size, transform)
train_dataloader = torch.utils.data.DataLoader(train_dataset, drop_last=True, batch_size=batch_size, shuffle=True)
dataloaders = (train_dataloader, )
generator = DCGenerator().to(device)
generator.apply(weights_init)
discriminator = DCDiscriminator().to(device)
discriminator.apply(weights_init)
optimizer_generator = optim.Adam(generator.parameters(), lr=lr, weight_decay=weight_decay, betas=(beta1, beta2))
optimizer_discriminator = optim.Adam(discriminator.parameters(), lr=lr, weight_decay=weight_decay, betas=(beta1, beta2))
loss_fn = nn.BCELoss()
models = (generator, discriminator)
optimizers = (optimizer_generator, optimizer_discriminator)
def dcplotn(n, generator, device):
generator.eval()
noise = torch.FloatTensor(np.random.normal(0, 1, (n, 100, 1, 1))).to(device)
imgs = generator(noise).detach().cpu()
fig, ax = plt.subplots(1, n)
for i, im in enumerate(imgs):
ax[i].imshow(im[0])
plt.show()
def train_dcgan(dataloaders, models, optimizers, loss_fn, epochs, plot_every, device):
tqdm_iter = tqdm(range(epochs))
train_dataloader = dataloaders[0]
gen, disc = models[0], models[1]
optim_gen, optim_disc = optimizers[0], optimizers[1]
gen.train()
disc.train()
for epoch in tqdm_iter:
train_gen_loss = 0.0
train_disc_loss = 0.0
test_gen_loss = 0.0
test_disc_loss = 0.0
for batch in train_dataloader:
imgs, _ = batch
imgs = imgs.to(device)
imgs = 2.0 * imgs - 1.0
gen.zero_grad()
noise = torch.FloatTensor(np.random.normal(0.0, 1.0, (imgs.shape[0], 100, 1, 1))).to(device)
real_labels = torch.ones((imgs.shape[0], 1)).to(device)
fake_labels = torch.zeros((imgs.shape[0], 1)).to(device)
generated = gen(noise)
disc_preds = disc(generated)
g_loss = loss_fn(disc_preds, real_labels)
g_loss.backward()
optim_gen.step()
disc.zero_grad()
disc_real = disc(imgs)
disc_real_loss = loss_fn(disc_real, real_labels)
disc_fake = disc(generated.detach())
disc_fake_loss = loss_fn(disc_fake, fake_labels)
d_loss = (disc_real_loss + disc_fake_loss) / 2.0
d_loss.backward()
optim_disc.step()
train_gen_loss += g_loss.item()
train_disc_loss += d_loss.item()
train_gen_loss /= len(train_dataloader)
train_disc_loss /= len(train_dataloader)
if epoch % plot_every == 0 or epoch == epochs - 1:
dcplotn(5, gen, device)
tqdm_dct = {'generator loss:': train_gen_loss, 'discriminator loss:': train_disc_loss}
tqdm_iter.set_postfix(tqdm_dct, refresh=True)
tqdm_iter.refresh()
train_dcgan(dataloaders, models, optimizers, loss_fn, epochs // 2, plot_every // 2, device)
generator.eval()
dcplotn(5, generator, device)
> Aufgabe: Versuchen Sie, komplexere Farbbilder mit DCGAN zu generieren – zum Beispiel eine Klasse aus dem CIFAR-10-Datensatz.
Training mit Gemälden
Eine der guten Optionen für das Training von GANs sind Gemälde, die von menschlichen Künstlern geschaffen wurden.

(Foto aus der Sammlung Art of Artificial)
Referenzen
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Generative Adversarial Networks
Das Hauptziel eines Generative Adversarial Network (GAN) ist es, Bilder zu erzeugen, die dem Trainingsdatensatz ähnlich sind (aber nicht identisch).
GAN besteht aus zwei neuronalen Netzwerken, die gegeneinander trainiert werden:
- Generator nimmt einen zufälligen Vektor und soll daraus ein Bild erzeugen.
- Discriminator ist ein Netzwerk, das zwischen einem Originalbild (aus dem Trainingsdatensatz) und dem vom Generator erzeugten Bild unterscheiden soll.
import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import *
import matplotlib.pyplot as plt
import numpy as np
Generator
Die Aufgabe eines Generators besteht darin, einen zufälligen Vektor einer bestimmten Größe (ähnlich dem latenten Vektor in Autoencodern) zu nehmen und das Zielbild zu erzeugen. Er ähnelt stark der generativen Seite eines Autoencoders.
In unserem Beispiel verwenden wir dichte neuronale Netzwerke und den MNIST-Datensatz.
generator = Sequential()
generator.add(Dense(256, input_shape=(100,)))
generator.add(LeakyReLU(alpha=0.2))
generator.add(BatchNormalization(momentum=0.8))
generator.add(Dense(512))
generator.add(LeakyReLU(alpha=0.2))
generator.add(BatchNormalization(momentum=0.8))
generator.add(Dense(1024))
generator.add(LeakyReLU(alpha=0.2))
generator.add(BatchNormalization(momentum=0.8))
generator.add(Dense(784, activation='tanh'))
generator.add(Reshape((28,28)))
optimizer = keras.optimizers.Adam(lr=0.0002, decay=8e-9)
generator.compile(loss='binary_crossentropy',optimizer=optimizer,metrics=['accuracy'])
Einige Tricks, die im Generator verwendet werden:
* Anstelle von ReLU verwenden wir Leaky ReLU, d.h. ein ReLU, das für negative $x$ nicht genau 0 ist, sondern eine andere lineare Funktion mit sehr kleiner Steigung. Das ist wichtig, da es dem Gradientenabstieg ermöglicht, Werte auch dann zu propagieren, wenn wir uns auf der negativen Seite von ReLU befinden (wo die Werte 0 sind).
* Wir verwenden Batch-Normalisierung, um das Training zu stabilisieren.
* Die Aktivierungsfunktion in der letzten Schicht ist tanh, sodass die Ausgabe im Bereich [-1,1] liegt.
Diskriminator
Der Diskriminator ist ein klassisches Bildklassifikationsnetzwerk. In unserem ersten Beispiel werden wir auch einen dichten Klassifikator verwenden.
discriminator = Sequential()
discriminator.add(Flatten(input_shape=(28,28)))
discriminator.add(Dense(784))
discriminator.add(LeakyReLU(alpha=0.2))
discriminator.add(Dense(784//2))
discriminator.add(LeakyReLU(alpha=0.2))
discriminator.add(Dense(1, activation='sigmoid'))
discriminator.compile(loss='binary_crossentropy',optimizer=optimizer,metrics=['accuracy'])
Wir werden auch ein adversariales Netzwerk definieren, das aus einem Generator gefolgt von einem Diskriminator besteht. Dieses Netzwerk beginnt mit einem Rauschvektor und liefert ein binäres Ergebnis zurück.
discriminator.trainable = False
adversarial = Sequential()
adversarial.add(generator)
adversarial.add(discriminator)
adversarial.compile(loss='binary_crossentropy', optimizer=optimizer)
Laden des Datensatzes
Wir verwenden den MNIST-Datensatz, der in Keras integriert ist:
(X_train, _), (_, _) = keras.datasets.mnist.load_data()
X_train = (X_train.astype(np.float32) - 127.5) / 127.5
Netzwerktraining
Bei jedem Schritt des Trainings gibt es zwei Phasen:
- Training des Diskriminators:
- Wir generieren einige zufällige Vektoren
noise. Das Training erfolgt in Minibatches, daher verwenden wirbatch//2Vektoren, umbatch//2generierte Bilder zu erzeugen. - Ziehen Sie
batch//2zufällige Bilder aus dem Datensatz. - Trainieren Sie den Diskriminator mit 50 % echten und 50 % generierten Bildern, wobei die entsprechenden Labels (0 oder 1) bereitgestellt werden.
- Trainieren Sie den Generator, indem Sie das kombinierte adversarielle Modell verwenden, zufällige Vektoren als Eingabe übergeben und 1er als Ausgabe erwarten (was echten Bildern entspricht).
def plotn(n):
noise = np.random.normal(0, 1, (n,100))
imgs = generator.predict(noise)
fig,ax = plt.subplots(1,n)
for i,im in enumerate(imgs):
ax[i].imshow(im.reshape(28,28))
plt.show()
batch=32
for cnt in range(3000):
## train discriminator
random_index = np.random.randint(0, len(X_train) - batch//2)
legit_images = X_train[random_index : random_index + batch//2].reshape(batch//2, 28, 28)
gen_noise = np.random.normal(0, 1, (batch//2,100))
syntetic_images = generator.predict(gen_noise)
x_combined_batch = np.concatenate((legit_images, syntetic_images))
y_combined_batch = np.concatenate((np.ones((batch//2, 1)), np.zeros((batch//2, 1))))
d_loss = discriminator.train_on_batch(x_combined_batch, y_combined_batch)
# train generator
noise = np.random.normal(0, 1, (batch,100))
y_mislabled = np.ones((batch, 1))
g_loss = adversarial.train_on_batch(noise, y_mislabled)
if cnt%500==0:
print ('epoch: %d, [Discriminator :: d_loss: %f], [ Generator :: loss: %f]' % (cnt, d_loss[0], g_loss))
plotn(5)
> Aufgabe: Sie können dieses GAN mit dem gesamten MNIST-Datensatz trainieren und sehen, wie gut es werden kann
DCGAN
Im vorherigen Beispiel haben wir dichte Netzwerke sowohl für den Generator als auch für den Diskriminator verwendet, aber wir wissen, dass CNNs eine bessere Leistung bei der Verarbeitung von Bildern bieten. Deep Convolutional GAN ist ähnlich wie die oben beschriebene Architektur, verwendet jedoch Faltungsschichten für den Generator und den Diskriminator.
Die Hauptschwierigkeit besteht hier darin, eine Architektur für den Generator zu erstellen, da dieser eine umgekehrte Aufgabe im Vergleich zu traditionellen CNNs ausführen muss – er muss ein Bild aus einem Merkmalsvektor erzeugen. In gewisser Weise ähnelt dies dem Decoder-Teil von Autoencodern. Deshalb werden wir Conv2DTranspose-Schichten im Generator verwenden.
(X_train, _), (_, _) = keras.datasets.mnist.load_data()
X_train = (X_train.astype(np.float32)-127.5) / 127.5
print(X_train.min(),X_train.max())
generator = Sequential()
generator.add(Dense(128 * 7 * 7, activation="relu", input_dim=100))
generator.add(Reshape((7, 7, 128)))
generator.add(UpSampling2D())
generator.add(Conv2DTranspose(128, kernel_size=3, padding="same"))
generator.add(BatchNormalization(momentum=0.8))
generator.add(Activation("relu"))
generator.add(UpSampling2D())
generator.add(Conv2DTranspose(64, kernel_size=3, padding="same"))
generator.add(BatchNormalization(momentum=0.8))
generator.add(Activation("relu"))
generator.add(Conv2DTranspose(1, kernel_size=3, padding="same"))
generator.add(Activation("tanh"))
optimizer = keras.optimizers.Adam(0.0001) #, 0.5)
generator.compile(loss='binary_crossentropy',optimizer=optimizer,metrics=['accuracy'])
generator.summary()
discriminator = Sequential()
discriminator.add(Conv2D(32, kernel_size=3, strides=2, input_shape=(28,28,1), padding="same"))
discriminator.add(LeakyReLU(alpha=0.2))
discriminator.add(Dropout(0.25))
discriminator.add(Conv2D(64, kernel_size=3, strides=2, padding="same"))
discriminator.add(ZeroPadding2D(padding=((0,1),(0,1))))
discriminator.add(BatchNormalization(momentum=0.8))
discriminator.add(LeakyReLU(alpha=0.2))
discriminator.add(Dropout(0.25))
discriminator.add(Conv2D(128, kernel_size=3, strides=2, padding="same"))
discriminator.add(BatchNormalization(momentum=0.8))
discriminator.add(LeakyReLU(alpha=0.2))
discriminator.add(Dropout(0.25))
discriminator.add(Conv2D(256, kernel_size=3, strides=1, padding="same"))
discriminator.add(BatchNormalization(momentum=0.8))
discriminator.add(LeakyReLU(alpha=0.2))
discriminator.add(Dropout(0.25))
discriminator.add(Flatten())
discriminator.add(Dense(1, activation='sigmoid'))
discriminator.compile(loss='binary_crossentropy',optimizer=optimizer)
discriminator.trainable = False
adversarial = Sequential()
adversarial.add(generator)
adversarial.add(discriminator)
adversarial.compile(loss='binary_crossentropy', optimizer=optimizer)
batch=32
y_labeled = np.ones((batch, 1))
y_mislabeled = np.zeros((batch, 1))
for cnt in range(1000):
## train discriminator
random_index = np.random.randint(0, len(X_train) - batch)
legit_images = X_train[random_index : random_index + batch].reshape(batch, 28, 28, 1)
gen_noise = np.random.normal(0, 1, (batch,100))
syntetic_images = generator.predict(gen_noise)
d_loss_1 = discriminator.train_on_batch(legit_images, y_labeled)
d_loss_2 = discriminator.train_on_batch(syntetic_images, y_mislabeled)
d_loss = 0.5*np.add(d_loss_1,d_loss_2)
# train generator
g_loss = adversarial.train_on_batch(gen_noise, y_labeled)
if cnt%100==0:
print ('epoch: %d, [Discriminator :: d_loss: %f], [ Generator :: loss: %f]' % (cnt, d_loss, g_loss))
plotn(5)
> Aufgabe: Versuchen Sie, komplexere Farbbilder mit DCGAN zu generieren - zum Beispiel eine Klasse aus dem CIFAR-10 Datensatz.
Training mit Gemälden
Eine der besten Optionen für das Training von GANs sind Gemälde, die von menschlichen Künstlern geschaffen wurden. Unten ist ein Beispielbild zu sehen, das von einem DCGAN generiert wurde, der auf einem Datensatz von WikiArt trainiert wurde. Die KeraGAN-Bibliothek wurde verwendet, um dieses Bild mit Azure Machine Learning zu erstellen.

(Foto aus der Sammlung Art of Artificial)
Referenzen
- Keras-Implementierung verschiedener einfacher GAN-Architekturen
- KeraGAN-Bibliothek
- Blogbeitrag über die Erstellung von GANs auf Azure ML
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Generative Adversarial Networks
Im vorherigen Abschnitt haben wir über generative Modelle gelernt: Modelle, die neue Bilder erzeugen können, die den Bildern im Trainingsdatensatz ähneln. VAE war ein gutes Beispiel für ein generatives Modell.
Quiz vor der Vorlesung
Wenn wir jedoch versuchen, etwas wirklich Bedeutungsvolles zu erzeugen, wie ein Gemälde in angemessener Auflösung, werden wir feststellen, dass das Training mit VAE nicht gut konvergiert. Für diesen Anwendungsfall sollten wir eine andere Architektur kennenlernen, die speziell auf generative Modelle ausgerichtet ist - Generative Adversarial Networks, oder GANs.
Die Hauptidee eines GANs besteht darin, zwei neuronale Netzwerke zu haben, die gegeneinander trainiert werden:
<img src="../../../../../translated_images/de/gan_architecture.8f3a5ab62b8d5d69.webp" width="70%"/>
> Bild von Dmitry Soshnikov
> ✅ Ein bisschen Vokabular: > * Generator ist ein Netzwerk, das einen zufälligen Vektor nimmt und daraus ein Bild erzeugt. > * Diskriminator ist ein Netzwerk, das ein Bild nimmt und entscheiden soll, ob es ein echtes Bild (aus dem Trainingsdatensatz) oder ein vom Generator erzeugtes Bild ist. Es ist im Wesentlichen ein Bildklassifikator.
Diskriminator
Die Architektur des Diskriminators unterscheidet sich nicht von einem gewöhnlichen Bildklassifikationsnetzwerk. Im einfachsten Fall kann es ein vollständig verbundenes Klassifikationsnetzwerk sein, aber höchstwahrscheinlich wird es ein Convolutional Network sein.
> ✅ Ein GAN, das auf Convolutional Networks basiert, wird als DCGAN bezeichnet.
Ein CNN-Diskriminator besteht aus den folgenden Schichten: mehreren Convolutions+Poolings (mit abnehmender räumlicher Größe) und einer oder mehreren vollständig verbundenen Schichten, um einen "Feature-Vektor" zu erhalten, sowie einem abschließenden binären Klassifikator.
> ✅ Ein 'Pooling' in diesem Kontext ist eine Technik, die die Größe des Bildes reduziert. "Pooling-Schichten reduzieren die Dimensionen der Daten, indem sie die Ausgaben von Neuronenclustern in einer Schicht zu einem einzigen Neuron in der nächsten Schicht kombinieren." - Quelle
Generator
Ein Generator ist etwas komplizierter. Man kann ihn als umgekehrten Diskriminator betrachten. Ausgehend von einem latenten Vektor (anstelle eines Feature-Vektors) hat er eine vollständig verbundene Schicht, um ihn in die erforderliche Größe/Form umzuwandeln, gefolgt von Deconvolutions+Upscaling. Dies ähnelt dem Decoder-Teil eines Autoencoders.
> ✅ Da die Convolution-Schicht als linearer Filter implementiert ist, der das Bild durchläuft, ist Deconvolution im Wesentlichen ähnlich wie Convolution und kann mit derselben Schichtlogik implementiert werden.
<img src="../../../../../translated_images/de/gan_arch_detail.46b95fd366f8e543.webp" width="70%"/>
> Bild von Dmitry Soshnikov
Training des GANs
GANs werden adversarial genannt, weil es einen ständigen Wettbewerb zwischen dem Generator und dem Diskriminator gibt. Während dieses Wettbewerbs verbessern sich sowohl der Generator als auch der Diskriminator, sodass das Netzwerk lernt, immer bessere Bilder zu erzeugen.
Das Training erfolgt in zwei Phasen:
- Training des Diskriminators. Diese Aufgabe ist ziemlich einfach: Wir erzeugen eine Batch von Bildern mit dem Generator, die mit 0 gekennzeichnet werden, was für ein gefälschtes Bild steht, und nehmen eine Batch von Bildern aus dem Eingabedatensatz (mit Label 1, echtes Bild). Wir erhalten einen Diskriminatorverlust und führen Backpropagation durch.
- Training des Generators. Dies ist etwas komplizierter, da wir den erwarteten Output für den Generator nicht direkt kennen. Wir nehmen das gesamte GAN-Netzwerk, bestehend aus einem Generator, gefolgt von einem Diskriminator, füttern es mit zufälligen Vektoren und erwarten, dass das Ergebnis 1 ist (entsprechend echten Bildern). Wir frieren dann die Parameter des Diskriminators ein (wir wollen ihn in diesem Schritt nicht trainieren) und führen Backpropagation durch.
Während dieses Prozesses sinken die Verluste des Generators und des Diskriminators nicht signifikant. Im Idealfall sollten sie oszillieren, was darauf hinweist, dass beide Netzwerke ihre Leistung verbessern.
✍️ Übungen: GANs
Probleme beim GAN-Training
GANs sind dafür bekannt, besonders schwierig zu trainieren zu sein. Hier sind einige Probleme:
- Mode Collapse. Damit ist gemeint, dass der Generator lernt, ein erfolgreiches Bild zu erzeugen, das den Diskriminator täuscht, und nicht eine Vielzahl unterschiedlicher Bilder.
- Empfindlichkeit gegenüber Hyperparametern. Oft kann man sehen, dass ein GAN überhaupt nicht konvergiert und dann plötzlich durch eine Verringerung der Lernrate zur Konvergenz führt.
- Das Gleichgewicht zwischen Generator und Diskriminator halten. In vielen Fällen kann der Diskriminatorverlust relativ schnell auf null sinken, was dazu führt, dass der Generator nicht weiter trainieren kann. Um dies zu überwinden, können wir versuchen, unterschiedliche Lernraten für Generator und Diskriminator festzulegen oder das Training des Diskriminators zu überspringen, wenn der Verlust bereits zu niedrig ist.
- Training für hohe Auflösung. Dieses Problem spiegelt dasselbe Problem wie bei Autoencodern wider und tritt auf, weil das Rekonstruieren zu vieler Schichten eines Convolutional Networks zu Artefakten führt. Dieses Problem wird typischerweise durch sogenanntes progressives Wachstum gelöst, bei dem zunächst einige Schichten mit niedrig aufgelösten Bildern trainiert werden und dann Schichten "freigeschaltet" oder hinzugefügt werden. Eine andere Lösung wäre, zusätzliche Verbindungen zwischen den Schichten hinzuzufügen und mehrere Auflösungen gleichzeitig zu trainieren - siehe dieses Multi-Scale Gradient GANs Paper für Details.
Style Transfer
GANs sind eine großartige Möglichkeit, künstlerische Bilder zu erzeugen. Eine andere interessante Technik ist der sogenannte Style Transfer, bei dem ein Inhaltsbild genommen und in einem anderen Stil neu gezeichnet wird, indem Filter aus einem Stilbild angewendet werden.
So funktioniert es: * Wir beginnen mit einem zufälligen Rauschbild (oder mit einem Inhaltsbild, aber der Einfachheit halber ist es leichter, mit zufälligem Rauschen zu beginnen). * Unser Ziel ist es, ein Bild zu erstellen, das sowohl dem Inhaltsbild als auch dem Stilbild nahekommt. Dies wird durch zwei Verlustfunktionen bestimmt: - Content Loss wird basierend auf den von der CNN extrahierten Features an einigen Schichten aus dem aktuellen Bild und dem Inhaltsbild berechnet. - Style Loss wird zwischen dem aktuellen Bild und dem Stilbild auf clevere Weise unter Verwendung von Gram-Matrizen berechnet (mehr Details im Beispiel-Notebook). * Um das Bild glatter zu machen und Rauschen zu entfernen, führen wir auch Variation Loss ein, der den durchschnittlichen Abstand zwischen benachbarten Pixeln berechnet. * Die Hauptoptimierungsschleife passt das aktuelle Bild mithilfe von Gradient Descent (oder einem anderen Optimierungsalgorithmus) an, um den Gesamten Verlust zu minimieren, der eine gewichtete Summe aller drei Verluste ist.
✍️ Beispiel: Style Transfer
Quiz nach der Vorlesung
Fazit
In dieser Lektion haben Sie etwas über GANs und deren Training gelernt. Sie haben auch die besonderen Herausforderungen kennengelernt, denen diese Art von neuronalen Netzwerken begegnen kann, und einige Strategien, um diese zu überwinden.
🚀 Herausforderung
Führen Sie das Style Transfer Notebook mit Ihren eigenen Bildern durch.
Überprüfung & Selbststudium
Lesen Sie zur Referenz mehr über GANs in diesen Ressourcen:
- Marco Pasini, 10 Lessons I Learned Training GANs for one Year
- StyleGAN, eine de facto GAN-Architektur, die man in Betracht ziehen sollte
- Creating Generative Art using GANs on Azure ML
Aufgabe
Besuchen Sie eines der beiden Notebooks, die mit dieser Lektion verbunden sind, und trainieren Sie das GAN mit Ihren eigenen Bildern neu. Was können Sie erstellen?
Ein Beispiel unten ist inspiriert von einem originalen Tutorial zu TensorFlow sowie von diesem Blogbeitrag. Ein weiteres gutes Beispiel für Style Transfer mit dem CNTK-Framework findet sich hier. Hier ist das originale Paper zu Artistic Style Transfer.
Die Hauptideen hinter Style Transfer sind folgende:
- Ausgehend von weißem Rauschen versuchen wir, das aktuelle Bild $x$ zu optimieren, um eine Verlustfunktion zu minimieren.
- Die Verlustfunktion besteht aus drei Komponenten $\mathcal{L(x)} = \alpha\mathcal{L}_c(x,i) + \beta\mathcal{L}_s(x,s)+\gamma\mathcal{L}_t(x)$
- $\mathcal{L}_c$ - Inhaltsverlust - zeigt, wie nah das aktuelle Bild $x$ am Originalbild $i$ ist
- $\mathcal{L}_s$ - Stilverlust - zeigt, wie nah das aktuelle Bild $x$ am Stilbild $s$ ist
- $\mathcal{L}_t$ - Verlust der totalen Variation (wir werden ihn in unserem Beispiel nicht berücksichtigen) - stellt sicher, dass das resultierende Bild glatt ist, d.h. es zeigt den mittleren quadratischen Fehler der benachbarten Pixel des Bildes $x$
Diese Verlustfunktionen müssen auf clevere Weise gestaltet werden, sodass beispielsweise der Stilverlust den Stil der Bilder miteinander vergleicht und nicht den tatsächlichen Inhalt. Dafür werden wir einige tiefere Feature-Schichten eines CNN vergleichen, das das Bild analysiert.
Lassen Sie uns damit beginnen, ein paar Bilder zu laden:
!mkdir -p images
!curl https://cdn.pixabay.com/photo/2016/05/18/00/27/franz-marc-1399594_960_720.jpg > images/style.jpg
!curl https://upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Golden_tabby_and_white_kitten_n01.jpg/1280px-Golden_tabby_and_white_kitten_n01.jpg > images/image.jpg
import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import tensorflow as tf
from tensorflow.keras.applications.vgg16 import preprocess_input
import IPython.display as display
img_size = 256
def load_image(fn):
x = cv2.imread(fn)
return cv2.cvtColor(x, cv2.COLOR_BGR2RGB)
img_style = load_image('images/style.jpg')
img_content = load_image('images/image.jpg')
img_content = img_content[:,200:200+857,:]
img_content = cv2.resize(img_content,(img_size,img_size))
img_style = img_style[:,200:200+671,:]
img_style = cv2.resize(img_style,(img_size,img_size))
img_result = np.random.uniform(size=(img_size,img_size,3))
matplotlib.rcParams['figure.figsize'] = (12, 12)
matplotlib.rcParams['axes.grid'] = False
fig,ax = plt.subplots(1,3)
ax[0].imshow(img_content)
ax[1].imshow(img_style)
ax[2].imshow((255*img_result).astype(int))
plt.show()
Um den Stilverlust und den Inhaltsverlust zu berechnen, müssen wir im Merkmalsraum arbeiten, der von einem CNN extrahiert wird. Wir können verschiedene CNN-Architekturen verwenden, aber der Einfachheit halber wählen wir in unserem Fall VGG-19, vortrainiert auf ImageNet.
vgg = tf.keras.applications.VGG16(include_top=False, weights='imagenet')
vgg.trainable = False
Lassen Sie uns einen Blick auf die Modellarchitektur werfen:
vgg.summary()
Lass uns eine Funktion definieren, die es uns ermöglicht, Zwischenmerkmale aus dem VGG-Netzwerk zu extrahieren:
def layer_extractor(layers):
outputs = [vgg.get_layer(x).output for x in layers]
model = tf.keras.Model([vgg.input],outputs)
return model
Inhaltsverlust
Inhaltsverlust zeigt, wie nah unser aktuelles Bild $x$ am Originalbild ist. Er betrachtet die Zwischenmerkmale in den Schichten des CNN und berechnet den quadratischen Fehler. Der Inhaltsverlust in Schicht $l$ wird definiert als $$ \mathcal{L}c = {1\over2}\sum{i,j} (F_{ij}^{(l)}-P_{ij}^{(l)})^2 $$ wobei $F^{(l)}$ und $P^{(l)}$ die Merkmale in Schicht $l$ sind.
content_layers = ['block4_conv2']
content_extractor = layer_extractor(content_layers)
content_target = content_extractor(preprocess_input(tf.expand_dims(img_content,axis=0)))
def content_loss(img):
z = content_extractor(preprocess_input(tf.expand_dims(255*img,axis=0)))
return 0.5*tf.reduce_sum((z-content_target)**2)
Jetzt werden wir den Haupttrick des Stiltransfers umsetzen - Optimierung. Wir beginnen mit einem zufälligen Bild und verwenden dann den TensorFlow-Optimizer, um dieses Bild so anzupassen, dass der Inhaltsverlust minimiert wird.
Wichtig: In unserem Fall werden alle Berechnungen mit dem GPU-fähigen TensorFlow-Framework durchgeführt, was es ermöglicht, diesen Code wesentlich effizienter auf der GPU auszuführen.
img = tf.Variable(img_result)
opt = tf.optimizers.Adam(learning_rate=0.002, beta_1=0.99, epsilon=1e-1)
clip = lambda x : tf.clip_by_value(x,clip_value_min=0,clip_value_max=1)
def optimize(img,loss_fn):
with tf.GradientTape() as tape:
loss = loss_fn(img)
grad = tape.gradient(loss,img)
opt.apply_gradients([(grad,img)])
#img.assign(tf.clip_by_value(img,clip_value_min=0,clip_value_max=1))
def train(img,loss_fn,epochs=10,steps_per_epoch=100):
for _ in range(epochs):
display.clear_output(wait=True)
plt.imshow((255*clip(img)).numpy().astype(int))
plt.show()
for _ in range(steps_per_epoch):
optimize(img,loss_fn=loss_fn)
train(img,content_loss)
> Übung: Experimentiere mit verschiedenen Schichten im Netzwerk und beobachte, was passiert. Du kannst auch versuchen, mehrere Schichten gleichzeitig zu optimieren, aber dafür müsstest du den Code für content_loss ein wenig anpassen.
Stilverlust
Der Stilverlust ist die Hauptidee hinter dem Stiltransfer. Dabei vergleichen wir nicht die eigentlichen Merkmale, sondern ihre Gram-Matrizen, die definiert sind als $$G=A\times A^T$$
Die Gram-Matrix ist ähnlich wie eine Korrelationsmatrix und zeigt, wie einige Filter von anderen abhängen. Der Stilverlust wird als Summe der Verluste aus verschiedenen Schichten berechnet, die oft mit gewichteten Koeffizienten berücksichtigt werden.
Die Gesamtverlustfunktion für den Stiltransfer ist eine Summe aus content loss und style loss.
def gram_matrix(x):
result = tf.linalg.einsum('bijc,bijd->bcd', x, x)
input_shape = tf.shape(x)
num_locations = tf.cast(input_shape[1]*input_shape[2], tf.float32)
return result/(num_locations)
style_layers = ['block1_conv1','block2_conv1','block3_conv1','block4_conv1']
def style_extractor(img):
return [gram_matrix(x) for x in layer_extractor(style_layers)(img)]
style_target = style_extractor(preprocess_input(tf.expand_dims(img_style,axis=0)))
def style_loss(img):
z = style_extractor(preprocess_input(tf.expand_dims(255*img,axis=0)))
loss = tf.add_n([tf.reduce_mean((x-target)**2)
for x,target in zip(z,style_target)])
return loss / len(style_layers)
Alles zusammenfügen
Wir werden die Funktion total_loss definieren, die den kombinierten Verlust berechnet, und die Optimierung durchführen:
def total_loss(img):
return 2*content_loss(img)+style_loss(img)
img.assign(img_result)
train(img,loss_fn=total_loss)
Der untenstehende Code führt die eigentliche Optimierung des Verlusts durch. Beachten Sie, dass die Optimierung selbst mit GPU eine beträchtliche Zeit in Anspruch nimmt. Sie können die Zelle unten mehrmals ausführen, um das Ergebnis zu verbessern.
Variationsverlust hinzufügen
Variationsverlust hilft dabei, das Bild weniger rauschhaft zu machen, indem die Unterschiede zwischen benachbarten Pixeln minimiert werden.
Wir beginnen die Optimierung außerdem mit dem ursprünglichen Inhaltsbild. Dadurch können wir mehr Inhaltsdetails im Bild beibehalten, ohne die Inhaltsverlustfunktion zu verkomplizieren. Ein wenig Rauschen werden wir jedoch hinzufügen.
def variation_loss(img):
img = tf.cast(img,tf.float32)
x_var = img[ :, 1:, :] - img[ :, :-1, :]
y_var = img[ 1:, :, :] - img[ :-1, :, :]
return tf.reduce_sum(tf.abs(x_var)) + tf.reduce_sum(tf.abs(y_var))
def total_loss_var(img):
return content_loss(img)+150*style_loss(img)+30*variation_loss(img)
img.assign(clip(np.random.normal(-0.3,0.3,size=img_content.shape)+img_content/255.0))
train(img,loss_fn=total_loss_var)
cv2.imwrite('result.jpg',(img.numpy()[:,:,::-1]*255))
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Ein Beispiel unten ist inspiriert von diesem Blogbeitrag, und ein Großteil des Codes wurde von dort übernommen. Ein weiteres gutes Beispiel für Style Transfer mit dem CNTK-Framework findet sich hier. Hier ist das Originalpapier über Artistic Style Transfer.
Die Hauptideen hinter dem Style Transfer sind folgende:
- Ausgehend von weißem Rauschen versuchen wir, das aktuelle Bild $x$ zu optimieren, um eine Verlustfunktion zu minimieren.
- Die Verlustfunktion besteht aus drei Komponenten $\mathcal{L(x)} = \alpha\mathcal{L}_c(x,i) + \beta\mathcal{L}_s(x,s)+\gamma\mathcal{L}_t(x)$
- $\mathcal{L}_c$ - Inhaltsverlust - zeigt, wie nah das aktuelle Bild $x$ am Originalbild $i$ ist
- $\mathcal{L}_s$ - Stilverlust - zeigt, wie nah das aktuelle Bild $x$ am Stilbild $s$ ist
- $\mathcal{L}_t$ - Verlust der totalen Variation (wir werden ihn in unserem Beispiel nicht berücksichtigen) - stellt sicher, dass das resultierende Bild glatt ist, d.h. es zeigt den mittleren quadratischen Fehler der benachbarten Pixel des Bildes $x$
Diese Verlustfunktionen müssen auf clevere Weise gestaltet werden, sodass beispielsweise der Stilverlust den Stil der Bilder miteinander vergleicht und nicht den tatsächlichen Inhalt. Dafür werden wir einige tiefere Feature-Schichten eines CNN vergleichen, das das Bild analysiert.
Lassen Sie uns mit dem Laden einiger Bilder beginnen:
!curl https://cdn.pixabay.com/photo/2016/05/18/00/27/franz-marc-1399594_960_720.jpg > images/style.jpg
!curl https://upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Golden_tabby_and_white_kitten_n01.jpg/1280px-Golden_tabby_and_white_kitten_n01.jpg > images/image.jpg
import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fmin_l_bfgs_b
img_size = 256
def load_image(fn):
x = cv2.imread(fn)
return cv2.cvtColor(x, cv2.COLOR_BGR2RGB)
img_style = load_image('images/style.jpg')
img_content = load_image('images/image.jpg')
img_content = img_content[:,200:200+857,:]
img_content = cv2.resize(img_content,(img_size,img_size))
img_style = img_style[:,200:200+671,:]
img_style = cv2.resize(img_style,(img_size,img_size))
img_result = np.random.randint(256,size=(img_size,img_size,3)).astype(np.float64)
fig,ax = plt.subplots(1,3)
ax[0].imshow(img_content)
ax[1].imshow(img_style)
ax[2].imshow(img_result.astype(np.int))
plt.show()
import tensorflow as tf
from tf.keras import backend as K
from tf.keras.applications.vgg16 import preprocess_input
from tf.keras.applications import VGG16
from tf.keras.preprocessing.image import load_img, img_to_array
tf_session = K.get_session()
img_content_var = K.variable(preprocess_input(np.expand_dims(img_content, axis=0)), dtype='float32')
img_style_var = K.variable(preprocess_input(np.expand_dims(img_style, axis=0)), dtype='float32')
img_result_1 = preprocess_input(np.expand_dims(img_result, axis=0))
img_result_holder = K.placeholder(shape=(1, img_size, img_size, 3))
Um den Stilverlust und den Inhaltsverlust zu berechnen, müssen wir im Merkmalsraum arbeiten, der von einem CNN extrahiert wird. Wir können verschiedene CNN-Architekturen verwenden, aber der Einfachheit halber werden wir in unserem Fall VGG-16 wählen, vortrainiert auf ImageNet.
cModel = VGG16(include_top=False, weights='imagenet', input_tensor=img_content_var)
sModel = VGG16(include_top=False, weights='imagenet', input_tensor=img_style_var)
gModel = VGG16(include_top=False, weights='imagenet', input_tensor=img_result_holder)
Lass uns einen Blick auf die Modellarchitektur werfen:
gModel.summary()
Inhaltsverlust
Inhaltsverlust zeigt, wie nah unser aktuelles Bild $x$ am Originalbild ist. Er betrachtet die Zwischenebenen der Merkmale im CNN und berechnet den quadratischen Fehler. Der Inhaltsverlust auf Ebene $l$ wird definiert als $$ \mathcal{L}c = {1\over2}\sum{i,j} (F_{ij}^{(l)}-P_{ij}^{(l)})^2 $$ wobei $F^{(l)}$ und $P^{(l)}$ -- Merkmale auf Ebene $l$ sind.
def get_feature_reps(x, layer_names, model):
featMatrices = []
for ln in layer_names:
selectedLayer = model.get_layer(ln)
featRaw = selectedLayer.output
featRawShape = K.shape(featRaw).eval(session=tf_session)
N_l = featRawShape[-1]
M_l = featRawShape[1]*featRawShape[2]
featMatrix = K.reshape(featRaw, (M_l, N_l))
featMatrix = K.transpose(featMatrix)
featMatrices.append(featMatrix)
return featMatrices
def get_content_loss(F, P):
cLoss = 0.5*K.sum(K.square(F - P))
return cLoss
Lassen Sie uns untersuchen, wie sich die Merkmale auf verschiedenen Ebenen auf das Bild auswirken. Dazu werden wir versuchen, den Inhaltsverlust nur für eine Ebene zu minimieren. Wir verwenden die Funktion fmin_l_bfgs_b aus SciPy, die die zu minimierende Funktion und deren Gradienten übernimmt (in unserem Fall gibt die Funktion help_loss sowohl die Verlustfunktion als auch den Gradienten zurück).
Wichtig: In unserem Fall werden alle Berechnungen mit dem GPU-fähigen TensorFlow-Framework durchgeführt. Die Funktion helper_loss gibt einen Berechnungsgraphen zurück, der verwendet werden kann, um den Verlust für ein gegebenes Bild zu berechnen, und sie nutzt K.gradients, um die Gradienten automatisch zu berechnen.
layer='block4_conv2'
P = get_feature_reps(x=img_content_var, layer_names=[layer], model=cModel)[0]
x = img_result.flatten()
def helper_loss(img):
R = get_feature_reps(img,[layer],gModel)[0]
return get_content_loss(R,P)
def help_loss(x):
if x.shape != (1, img_size, img_size, 3):
x = x.reshape((1,img_size, img_size, 3))
keras_fcn = K.function([gModel.input], [helper_loss(gModel.input)])
keras_grad = K.function([gModel.input], K.gradients(helper_loss(gModel.input),[gModel.input]))
return keras_fcn([x])[0].astype('float64'),keras_grad([x])[0].flatten().astype('float64')
x, _, _ = fmin_l_bfgs_b(help_loss, x, maxiter=30, disp=True)
def postprocess_array(x):
# Zero-center by mean pixel
if x.shape != (img_size, img_size, 3):
x = x.reshape((img_size, img_size, 3))
x[..., 0] += 103.939
x[..., 1] += 116.779
x[..., 2] += 123.68
# 'BGR'->'RGB'
x = x[..., ::-1]
x = np.clip(x, 0, 255)
x = x.astype('uint8')
return x
plt.imshow(postprocess_array(x.copy()))
plt.show()
layer='block3_conv2'
P = get_feature_reps(x=img_content_var, layer_names=[layer], model=cModel)[0]
x = img_result.flatten()
x, _, _ = fmin_l_bfgs_b(help_loss, x, maxiter=30, disp=True)
plt.imshow(postprocess_array(x.copy()))
plt.show()
layer='block5_conv1'
P = get_feature_reps(x=img_content_var, layer_names=[layer], model=cModel)[0]
x = img_result.flatten()
x, _, _ = fmin_l_bfgs_b(help_loss, x, maxiter=30, disp=True)
plt.imshow(postprocess_array(x.copy()))
plt.show()
Stilverlust
Einführung
Stilverlust tritt auf, wenn ein Modell bei der Generierung von Inhalten die charakteristischen Merkmale des ursprünglichen Stils nicht beibehält. Dies kann zu Ergebnissen führen, die unnatürlich oder unpassend wirken.
Häufige Ursachen für Stilverlust
- Ungenügende Trainingsdaten: Wenn das Modell nicht mit ausreichend Beispielen eines bestimmten Stils trainiert wurde, kann es Schwierigkeiten haben, diesen Stil zu reproduzieren.
- Übermäßige Generalisierung: Modelle, die zu stark generalisieren, neigen dazu, stilistische Feinheiten zu verlieren.
- Unklare Anweisungen: Wenn die Eingabeaufforderung nicht klar genug ist, kann das Modell den gewünschten Stil nicht korrekt interpretieren.
Wie man Stilverlust minimiert
- Verwendung hochwertiger Daten: Stellen Sie sicher, dass die Trainingsdaten vielfältig und repräsentativ für den gewünschten Stil sind.
- Feinabstimmung des Modells: Passen Sie das Modell gezielt an, um es auf einen bestimmten Stil zu optimieren.
- Präzise Eingabeaufforderungen: Geben Sie klare und spezifische Anweisungen, um den gewünschten Stil zu definieren.
Beispiele für Stilverlust
Beispiel 1: Formeller Stil
Eingabe: Schreiben Sie einen formellen Brief.
Ausgabe mit Stilverlust: Hey, wie geht's? Ich wollte nur mal kurz Bescheid geben...
Erwartete Ausgabe: Sehr geehrte Damen und Herren, ich möchte Sie hiermit informieren...
Beispiel 2: Kreativer Stil
Eingabe: Erzählen Sie eine fantasievolle Geschichte.
Ausgabe mit Stilverlust: Es war einmal ein Hund. Er lief durch den Park. Ende.
Erwartete Ausgabe: Vor langer Zeit, in einem magischen Wald, lebte ein Hund, der sprechen konnte und Abenteuer suchte...
Fazit
Stilverlust kann die Qualität und Wirkung der generierten Inhalte erheblich beeinträchtigen. Durch sorgfältige Datenvorbereitung, Modellanpassung und klare Anweisungen kann dieses Problem jedoch minimiert werden.
Stilverlust ist die Hauptidee hinter dem Stiltransfer. Wir vergleichen nicht die tatsächlichen Merkmale, sondern ihre Gram-Matrizen, die definiert sind als $$G=A\times A^T$$
Die Gram-Matrix ist ähnlich wie eine Korrelationsmatrix und zeigt, wie einige Filter von anderen abhängen. Der Stilverlust wird als Summe der Verluste aus verschiedenen Schichten berechnet, die oft mit gewichteten Koeffizienten berücksichtigt werden.
Die Gesamtverlustfunktion für den Stiltransfer ist eine Summe aus Inhaltsverlust und Stilverlust.
def get_Gram_matrix(F):
G = K.dot(F, K.transpose(F))
return G
def get_style_loss(ws, Gs, As):
sLoss = K.variable(0.)
for w, G, A in zip(ws, Gs, As):
M_l = K.int_shape(G)[1]
N_l = K.int_shape(G)[0]
G_gram = get_Gram_matrix(G)
A_gram = get_Gram_matrix(A)
sLoss+= w*0.25*K.sum(K.square(G_gram - A_gram))/ (N_l**2 * M_l**2)
return sLoss
def get_total_loss(gImPlaceholder, alpha=1.0, beta=30.0):
F = get_feature_reps(gImPlaceholder, layer_names=[content_layer_name], model=gModel)[0]
Gs = get_feature_reps(gImPlaceholder, layer_names=style_layer_names, model=gModel)
contentLoss = get_content_loss(F, P)
styleLoss = get_style_loss(ws, Gs, As)
totalLoss = alpha*contentLoss + beta*styleLoss
return totalLoss
Alles zusammenfügen
Hier berechnet die Funktion calualate_loss den Gesamtschaden:
def calculate_loss(gImArr):
"""
Calculate total loss using K.function
"""
if gImArr.shape != (1, img_size, img_size, 3):
gImArr = gImArr.reshape((1,img_size, img_size, 3))
loss_fcn = K.function([gModel.input], [get_total_loss(gModel.input)])
grad_fcn = K.function([gModel.input],
K.gradients(get_total_loss(gModel.input), [gModel.input]))
return loss_fcn([gImArr])[0].astype('float64'),grad_fcn([gImArr])[0].flatten().astype('float64')
content_layer_name = 'block4_conv2'
style_layer_names = ['block1_conv1','block2_conv1','block3_conv1','block4_conv1']
P = get_feature_reps(x=img_content_var, layer_names=[content_layer_name], model=cModel)[0]
As = get_feature_reps(x=img_style_var, layer_names=style_layer_names, model=sModel)
ws = np.ones(len(style_layer_names))/float(len(style_layer_names))
img_result = np.random.randint(256,size=(img_size,img_size,3)).astype(np.float64)
img_result_1 = preprocess_input(np.expand_dims(img_result, axis=0))
iterations = 10
x_opt = img_result_1.flatten()
Der untenstehende Code führt die eigentliche Optimierung des Verlusts durch. Beachten Sie, dass die Optimierung selbst mit GPU eine beträchtliche Zeit in Anspruch nimmt. Sie können die Zelle unten mehrmals ausführen, um das Ergebnis zu verbessern.
xopt, f_val, info= fmin_l_bfgs_b(calculate_loss, x_opt, maxiter=iterations, disp=True)
plt.imshow(postprocess_array(xopt.copy()))
plt.show()
iterations = 20
xopt, f_val, info= fmin_l_bfgs_b(calculate_loss, xopt, fprime=get_grad,
maxiter=iterations, disp=True)
plt.imshow(postprocess_array(xopt.copy()))
plt.show()
Variationsverlust hinzufügen
Variationsverlust ermöglicht es uns, das Bild weniger rauschend zu machen, indem die Unterschiede zwischen benachbarten Pixeln minimiert werden.
def total_variation_loss(x):
a = K.square(x[:,:img_size-1,:img_size-1,:] - x[:, 1:, :img_size-1,:])
b = K.square(x[:,:img_size-1,:img_size-1,:] - x[:, :img_size-1, 1:,:])
return K.sum(K.pow(a + b, 1.25))
def get_total_loss(gImPlaceholder, alpha=1.0, beta=30.0):
F = get_feature_reps(gImPlaceholder, layer_names=[content_layer_name], model=gModel)[0]
Gs = get_feature_reps(gImPlaceholder, layer_names=style_layer_names, model=gModel)
contentLoss = get_content_loss(F, P)
styleLoss = get_style_loss(ws, Gs, As)
variationLoss = total_variation_loss(gImPlaceholder)
totalLoss = alpha*contentLoss + beta*styleLoss + variationLoss
return totalLoss
img_result = np.random.randint(256,size=(img_size,img_size,3)).astype(np.float64)
img_result_1 = preprocess_input(np.expand_dims(img_result, axis=0))
iterations = 10
x_opt = img_result_1.flatten()
xopt, f_val, info= fmin_l_bfgs_b(calculate_loss, x_opt, maxiter=iterations, disp=True)
plt.imshow(postprocess_array(xopt.copy()))
plt.show()
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Kopferkennung mit dem Hollywood Heads Dataset
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
Das Zählen der Anzahl von Personen in einem Videoüberwachungsstream ist eine wichtige Aufgabe, die es uns ermöglicht, die Anzahl der Besucher in Geschäften, Stoßzeiten in Restaurants usw. zu schätzen. Um diese Aufgabe zu lösen, müssen wir in der Lage sein, menschliche Köpfe aus verschiedenen Blickwinkeln zu erkennen. Um ein Objekterkennungsmodell zu trainieren, das menschliche Köpfe erkennt, können wir das Hollywood Heads Dataset verwenden.
Das Dataset
Das Hollywood Heads Dataset enthält 369.846 menschliche Köpfe, die in 224.740 Filmframes aus Hollywood-Filmen annotiert sind. Es wird im https://host.robots.ox.ac.uk/pascal/VOC/-Format bereitgestellt, bei dem es zu jedem Bild auch eine XML-Beschreibungsdatei gibt, die so aussieht:
<annotation>
<folder>HollywoodHeads</folder>
<filename>mov_021_149390.jpeg</filename>
<source>
<database>HollywoodHeads 2015 Database</database>
<annotation>HollywoodHeads 2015</annotation>
<image>WILLOW</image>
</source>
<size>
<width>608</width>
<height>320</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>head</name>
<bndbox>
<xmin>201</xmin>
<ymin>1</ymin>
<xmax>480</xmax>
<ymax>263</ymax>
</bndbox>
<difficult>0</difficult>
</object>
<object>
<name>head</name>
<bndbox>
<xmin>3</xmin>
<ymin>4</ymin>
<xmax>241</xmax>
<ymax>285</ymax>
</bndbox>
<difficult>0</difficult>
</object>
</annotation>
In diesem Datensatz gibt es nur eine Objektklasse head, und für jeden Kopf erhält man die Koordinaten des Begrenzungsrahmens. Sie können XML mit Python-Bibliotheken analysieren oder diese Bibliothek verwenden, um direkt mit dem PASCAL VOC-Format zu arbeiten.
Training der Objekterkennung
Sie können ein Objekterkennungsmodell auf eine der folgenden Arten trainieren:
- Mit Azure Custom Vision und dessen Python-API, um das Modell programmgesteuert in der Cloud zu trainieren. Custom Vision kann jedoch nicht mehr als ein paar hundert Bilder für das Training des Modells verwenden, sodass Sie den Datensatz möglicherweise begrenzen müssen.
- Mit dem Beispiel aus dem Keras-Tutorial, um ein RetunaNet-Modell zu trainieren.
- Mit dem torchvision.models.detection.RetinaNet-Modul, das in torchvision integriert ist.
Fazit
Die Objekterkennung ist eine Aufgabe, die in der Industrie häufig benötigt wird. Während es einige Dienste gibt, die zur Durchführung der Objekterkennung verwendet werden können (wie z. B. Azure Custom Vision), ist es wichtig zu verstehen, wie Objekterkennung funktioniert, und in der Lage zu sein, eigene Modelle zu trainieren.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Objekterkennung
Dies ist ein Notebook aus dem AI for Beginners Curriculum

Naiver Ansatz zur Objekterkennung
- Bild in Kacheln unterteilen
- CNN-Bildklassifikator für jede Kachel ausführen
- Kacheln mit Aktivierung über dem Schwellenwert auswählen
import cv2
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
import os
Lassen Sie uns ein Beispielbild lesen, mit dem wir spielen können, und es auf quadratische Dimensionen auffüllen:
img = cv2.imread('images/1200px-Girl_and_cat.jpg')
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
img = np.pad(img,((158,158),(0,0),(0,0)),mode='edge')
plt.imshow(img)
Wir werden vortrainiertes VGG-16 CNN verwenden:
vgg = keras.applications.vgg16.VGG16(weights='imagenet')
Lass uns eine Funktion definieren, die die Wahrscheinlichkeit einer Katze auf dem Bild vorhersagt. Da ImageNet eine Anzahl von Klassen für Katzen enthält, die von 281 bis 294 indexiert sind, werden wir einfach die Wahrscheinlichkeiten für diese Klassen addieren, um die gesamte 'Katze'-Wahrscheinlichkeit zu erhalten:
def predict(img):
im = cv2.resize(img,(224,224))
im = keras.applications.vgg16.preprocess_input(im)
pr = vgg.predict(np.expand_dims(im,axis=0))[0]
return np.sum(pr[281:294]) # we know that VGG classes for cats are from 281 to 294
predict(img)
Die nächste Funktion erstellt eine Heatmap der Wahrscheinlichkeiten, indem sie das Bild in $n\times n$ Quadrate unterteilt:
def predict_map(img,n):
dx = img.shape[0] // n
res = np.zeros((n,n),dtype=np.float32)
for i in range(n):
for j in range(n):
im = img[dx*i:dx*(i+1),dx*j:dx*(j+1)]
r = predict(im)
res[i,j] = r
return res
fig,ax = plt.subplots(1,2,figsize=(15,5))
ax[1].imshow(img)
ax[0].imshow(predict_map(img,10))
Erkennung einfacher Objekte
Um den Standort einer Begrenzungsbox genauer zu bestimmen, müssen wir ein Regressionsmodell ausführen, um die Koordinaten der Begrenzungsbox vorherzusagen. Beginnen wir mit einem einfachen Beispiel: schwarze Rechtecke in 32x32-Bildern, die wir erkennen möchten. Die Idee und ein Teil des Codes stammen aus diesem Blogbeitrag.
Die folgende Funktion erzeugt eine Reihe von Beispielbildern:
def generate_images(num_imgs, img_size=8, min_object_size = 1, max_object_size = 4):
bboxes = np.zeros((num_imgs, 4))
imgs = np.zeros((num_imgs, img_size, img_size)) # set background to 0
for i_img in range(num_imgs):
w, h = np.random.randint(min_object_size, max_object_size, size=2)
x = np.random.randint(0, img_size - w)
y = np.random.randint(0, img_size - h)
imgs[i_img, x:x+w, y:y+h] = 1. # set rectangle to 1
bboxes[i_img] = [x, y, w, h]
return imgs, bboxes
imgs, bboxes = generate_images(100000)
print(f"Images shape = {imgs.shape}")
print(f"BBoxes shape = {bboxes.shape}")
Um die Ausgaben des Netzwerks im Bereich [0;1] zu halten, werden wir bboxes durch die Bildgröße teilen:
bb = bboxes/8.0
bb[0]
In unserem einfachen Beispiel werden wir ein dichtes neuronales Netzwerk verwenden. Im echten Leben, wenn Objekte eine komplexere Form haben, macht es definitiv Sinn, CNNs für eine Aufgabe wie diese zu verwenden. Wir werden den stochastischen Gradientenabstiegs-Optimierer und den mittleren quadratischen Fehler (MSE) als Metriken verwenden, da unsere Aufgabe Regression ist.
model = keras.Sequential([
keras.layers.Flatten(input_shape=(8,8)),
keras.layers.Dense(200, activation='relu'),
keras.layers.Dropout(0.2),
keras.layers.Dense(4)
])
model.compile('sgd','mse')
model.summary()
imgs_norm = (imgs-np.mean(imgs))/np.std(imgs)
model.fit(imgs_norm,bb,epochs=30)
Wir scheinen einen relativ guten Verlust zu haben, lassen Sie uns sehen, wie sich dies in greifbarere Metriken wie mAP übersetzt. Zunächst definieren wir die IOU-Metrik zwischen zwei Begrenzungsrahmen:
def IOU(bbox1, bbox2):
'''Calculate overlap between two bounding boxes [x, y, w, h] as the area of intersection over the area of unity'''
x1, y1, w1, h1 = bbox1[0], bbox1[1], bbox1[2], bbox1[3]
x2, y2, w2, h2 = bbox2[0], bbox2[1], bbox2[2], bbox2[3]
w_I = min(x1 + w1, x2 + w2) - max(x1, x2)
h_I = min(y1 + h1, y2 + h2) - max(y1, y2)
if w_I <= 0 or h_I <= 0: # no overlap
return 0.
I = w_I * h_I
U = w1 * h1 + w2 * h2 - I
return I / U
Wir werden nun 500 Testbilder generieren und die ersten 5 davon plotten, um zu visualisieren, wie genau wir sind. Wir werden auch die IOU-Metrik ausgeben.
import matplotlib
test_imgs, test_bboxes = generate_images(500)
bb_res = model.predict((test_imgs-np.mean(imgs))/np.std(imgs))*8
plt.figure(figsize=(15,5))
for i in range(5):
print(f"pred={bb_res[i]},act={test_bboxes[i]}, IOU={IOU(bb_res[i],test_bboxes[i])}")
plt.subplot(1,5,i+1)
plt.imshow(test_imgs[i])
plt.gca().add_patch(matplotlib.patches.Rectangle((bb_res[i,1],bb_res[i,0]),bb_res[i,3],bb_res[i,2],ec='r'))
#plt.annotate('IOU: {:.2f}'.format(IOU(bb_res[i],test_bboxes[i])),(bb_res[i,1],bb_res[i,0]+bb_res[i,3]),color='y')
Um die durchschnittliche Genauigkeit über alle Fälle zu berechnen, müssen wir nur alle unsere Testproben durchgehen, IoU berechnen und den Durchschnitt berechnen:
np.array([IOU(a,b) for a,b in zip(test_bboxes,bb_res)]).mean()
Echtzeit-Objekterkennung
Echte Objekterkennungsalgorithmen sind komplexer. Wir empfehlen dir, dem Keras-Tutorial zur Objekterkennung mit RetinaNet zu folgen, wenn du die Details der RetinaNet-Implementierung verstehen möchtest, oder die Keras RetinaNet Library zu nutzen, wenn du einfach ein Modell zur Objekterkennung trainieren möchtest.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Objekterkennung
Die Bildklassifizierungsmodelle, die wir bisher behandelt haben, nahmen ein Bild und lieferten ein kategorisches Ergebnis, wie beispielsweise die Klasse "Zahl" in einem MNIST-Problem. In vielen Fällen möchten wir jedoch nicht nur wissen, dass ein Bild Objekte darstellt – wir möchten auch deren genaue Position bestimmen können. Genau darum geht es bei der Objekterkennung.
Quiz vor der Vorlesung

> Bild von der YOLO v2 Webseite
Ein naiver Ansatz zur Objekterkennung
Angenommen, wir wollten eine Katze auf einem Bild finden, dann wäre ein sehr naiver Ansatz zur Objekterkennung folgender:
- Zerlege das Bild in eine Anzahl von Kacheln.
- Führe eine Bildklassifikation auf jeder Kachel durch.
- Die Kacheln, die eine ausreichend hohe Aktivierung zeigen, können als die Kacheln betrachtet werden, die das gesuchte Objekt enthalten.

> Bild aus dem Übungsnotebook
Dieser Ansatz ist jedoch alles andere als ideal, da er es dem Algorithmus nur erlaubt, die Begrenzungsbox des Objekts sehr ungenau zu lokalisieren. Für eine präzisere Lokalisierung müssen wir eine Art Regression durchführen, um die Koordinaten der Begrenzungsboxen vorherzusagen – und dafür benötigen wir spezielle Datensätze.
Regression für Objekterkennung
Dieser Blogbeitrag bietet eine großartige Einführung in die Erkennung von Formen.
Datensätze für Objekterkennung
Für diese Aufgabe könnten Sie auf die folgenden Datensätze stoßen:
- PASCAL VOC – 20 Klassen
- COCO – Common Objects in Context. 80 Klassen, Begrenzungsboxen und Segmentierungsmasken

Metriken für Objekterkennung
Intersection over Union
Während es bei der Bildklassifikation einfach ist, die Leistung des Algorithmus zu messen, müssen wir bei der Objekterkennung sowohl die Richtigkeit der Klasse als auch die Genauigkeit der vorhergesagten Position der Begrenzungsbox messen. Für Letzteres verwenden wir die sogenannte Intersection over Union (IoU), die misst, wie gut sich zwei Boxen (oder zwei beliebige Bereiche) überlappen.

> Abbildung 2 aus diesem ausgezeichneten Blogbeitrag über IoU
Die Idee ist einfach – wir teilen die Fläche der Überschneidung zwischen zwei Figuren durch die Fläche ihrer Vereinigung. Für zwei identische Flächen wäre IoU gleich 1, während für vollständig getrennte Flächen IoU gleich 0 ist. Ansonsten variiert der Wert zwischen 0 und 1. Wir betrachten typischerweise nur die Begrenzungsboxen, bei denen IoU über einem bestimmten Wert liegt.
Durchschnittliche Präzision
Angenommen, wir möchten messen, wie gut eine bestimmte Objektklasse $C$ erkannt wird. Um dies zu messen, verwenden wir die Durchschnittliche Präzision (Average Precision, AP), die wie folgt berechnet wird:
- Betrachten Sie die Precision-Recall-Kurve, die die Genauigkeit in Abhängigkeit von einem Erkennungsschwellenwert (von 0 bis 1) zeigt.
- Abhängig vom Schwellenwert werden mehr oder weniger Objekte im Bild erkannt, und es ergeben sich unterschiedliche Werte für Präzision und Recall.
- Die Kurve sieht wie folgt aus:
<img src="https://github.com/shwars/NeuroWorkshop/raw/master/images/ObjDetectionPrecisionRecall.png"/>
> Bild aus NeuroWorkshop
Die durchschnittliche Präzision für eine gegebene Klasse $C$ ist die Fläche unter dieser Kurve. Genauer gesagt wird die Recall-Achse typischerweise in 10 Teile unterteilt, und die Präzision wird über alle diese Punkte gemittelt:
$$ AP = {1\over11}\sum_{i=0}^{10}\mbox{Precision}(\mbox{Recall}={i\over10}) $$
AP und IoU
Wir betrachten nur die Erkennungen, bei denen IoU über einem bestimmten Wert liegt. Beispielsweise wird im PASCAL VOC-Datensatz typischerweise $\mbox{IoU Threshold} = 0.5$ angenommen, während im COCO-Datensatz AP für verschiedene Werte von $\mbox{IoU Threshold}$ gemessen wird.
<img src="https://github.com/shwars/NeuroWorkshop/raw/master/images/ObjDetectionPrecisionRecallIoU.png"/>
> Bild aus NeuroWorkshop
Mittlere Durchschnittliche Präzision – mAP
Die Hauptmetrik für die Objekterkennung wird Mittlere Durchschnittliche Präzision (Mean Average Precision, mAP) genannt. Sie ist der Wert der Durchschnittlichen Präzision, gemittelt über alle Objektklassen und manchmal auch über $\mbox{IoU Threshold}$. Der Prozess zur Berechnung von mAP wird ausführlich in diesem Blogbeitrag beschrieben, sowie hier mit Codebeispielen.
Verschiedene Ansätze zur Objekterkennung
Es gibt zwei Hauptklassen von Objekterkennungsalgorithmen:
- Region Proposal Networks (R-CNN, Fast R-CNN, Faster R-CNN). Die Hauptidee ist, Regions of Interest (ROI) zu generieren und CNN darüber laufen zu lassen, um maximale Aktivierung zu finden. Dies ähnelt dem naiven Ansatz, mit der Ausnahme, dass ROIs auf eine intelligentere Weise generiert werden. Ein Hauptnachteil solcher Methoden ist, dass sie langsam sind, da viele Durchläufe des CNN-Klassifikators über das Bild erforderlich sind.
- One-pass (YOLO, SSD, RetinaNet) Methoden. In diesen Architekturen wird das Netzwerk so gestaltet, dass es sowohl Klassen als auch ROIs in einem Durchgang vorhersagt.
R-CNN: Region-Based CNN
R-CNN verwendet Selective Search, um eine hierarchische Struktur von ROI-Regionen zu generieren, die dann durch CNN-Feature-Extraktoren und SVM-Klassifikatoren geleitet werden, um die Objektklasse zu bestimmen, sowie durch lineare Regression, um die Koordinaten der Begrenzungsbox zu bestimmen. Offizielles Paper

> Bild von van de Sande et al. ICCV’11

> Bilder aus diesem Blog
F-RCNN – Fast R-CNN
Dieser Ansatz ähnelt R-CNN, aber die Regionen werden definiert, nachdem die Convolution-Schichten angewendet wurden.

> Bild aus dem offiziellen Paper, arXiv, 2015
Faster R-CNN
Die Hauptidee dieses Ansatzes ist die Verwendung eines neuronalen Netzwerks zur Vorhersage von ROIs – des sogenannten Region Proposal Network. Paper, 2016

> Bild aus dem offiziellen Paper
R-FCN: Region-Based Fully Convolutional Network
Dieser Algorithmus ist sogar schneller als Faster R-CNN. Die Hauptidee ist folgende:
- Wir extrahieren Features mit ResNet-101.
- Die Features werden durch Position-Sensitive Score Map verarbeitet. Jedes Objekt aus $C$ Klassen wird in $k\times k$ Regionen unterteilt, und wir trainieren, um Teile von Objekten vorherzusagen.
- Für jeden Teil aus den $k\times k$ Regionen stimmen alle Netzwerke für Objektklassen ab, und die Objektklasse mit der maximalen Stimmenanzahl wird ausgewählt.

> Bild aus dem offiziellen Paper
YOLO – You Only Look Once
YOLO ist ein Echtzeit-One-Pass-Algorithmus. Die Hauptidee ist folgende:
- Das Bild wird in $S\times S$ Regionen unterteilt.
- Für jede Region sagt CNN $n$ mögliche Objekte, Koordinaten der Begrenzungsbox und Confidence=Wahrscheinlichkeit * IoU voraus.

> Bild aus dem offiziellen Paper
Andere Algorithmen
- RetinaNet: Offizielles Paper
- PyTorch-Implementierung in Torchvision
- Keras-Implementierung
- Objekterkennung mit RetinaNet in Keras-Beispielen
- SSD (Single Shot Detector): Offizielles Paper
✍️ Übungen: Objekterkennung
Setzen Sie Ihr Lernen im folgenden Notebook fort:
Fazit
In dieser Lektion haben Sie einen Überblick über die verschiedenen Möglichkeiten zur Objekterkennung erhalten!
🚀 Herausforderung
Lesen Sie diese Artikel und Notebooks über YOLO und probieren Sie sie selbst aus:
- Guter Blogbeitrag über YOLO
- Offizielle Seite
- Yolo: Keras-Implementierung, Schritt-für-Schritt-Notebook
- Yolo v2: Keras-Implementierung, Schritt-für-Schritt-Notebook
Quiz nach der Vorlesung
Überprüfung & Selbststudium
- Objekterkennung von Nikhil Sardana
- Ein guter Vergleich von Objekterkennungsalgorithmen
- Überblick über Deep-Learning-Algorithmen für die Objekterkennung
- Eine Schritt-für-Schritt-Einführung in die grundlegenden Objekterkennungsalgorithmen
- Implementierung von Faster R-CNN in Python für die Objekterkennung
Aufgabe: Objekterkennung
Körpersegmentierung
Laboraufgabe aus dem AI for Beginners Curriculum.
In der Videoproduktion, zum Beispiel bei Wettervorhersagen, müssen wir oft ein menschliches Bild aus der Kamera ausschneiden und es über anderes Filmmaterial legen. Dies wird typischerweise mit Chroma-Key-Techniken durchgeführt, bei denen eine Person vor einem einfarbigen Hintergrund gefilmt wird, der anschließend entfernt wird. In diesem Labor werden wir ein neuronales Netzwerk trainieren, um die Silhouette eines Menschen auszuschneiden.
Wir verwenden das Segmentation Full Body MADS Dataset von Kaggle. Laden Sie das Dataset manuell von Kaggle herunter und entpacken Sie es im aktuellen Verzeichnis.
dataset_path = 'segmentation_full_body_mads_dataset_1192_img'
import os
import matplotlib.pyplot as plt
Lass uns sehen, wie die Bilder im Datensatz aussehen:
img_path = os.path.join(dataset_path,'images')
mask_path = os.path.join(dataset_path,'masks')
fnames = os.listdir(img_path)
def load_image(img_name):
img = plt.imread(os.path.join(img_path,img_name))
mask = plt.imread(os.path.join(mask_path,img_name))
return img,mask
img, mask = load_image(fnames[5])
fig,ax = plt.subplots(1,2,figsize=(10,5))
ax[0].imshow(img)
ax[1].imshow(mask)
ax[0].axis('off')
ax[1].axis('off')
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Segmentierung des menschlichen Körpers
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
In der Videoproduktion, beispielsweise bei Wettervorhersagen, müssen wir oft ein menschliches Bild aus der Kamera ausschneiden und es über anderes Filmmaterial legen. Dies wird typischerweise mit Chroma-Key-Techniken durchgeführt, bei denen eine Person vor einem einfarbigen Hintergrund gefilmt wird, der anschließend entfernt wird. In diesem Labor werden wir ein neuronales Netzwerk trainieren, um die Silhouette eines Menschen auszuschneiden.
Der Datensatz
Wir verwenden den Segmentation Full Body MADS Dataset von Kaggle. Laden Sie den Datensatz manuell von Kaggle herunter.
Start-Notebook
Beginnen Sie das Labor, indem Sie BodySegmentation.ipynb öffnen.
Erkenntnis
Die Segmentierung des Körpers ist nur eine der gängigen Aufgaben, die wir mit Bildern von Menschen durchführen können. Weitere wichtige Aufgaben umfassen Skelett-Erkennung und Pose-Erkennung. Schauen Sie sich die OpenPose-Bibliothek an, um zu sehen, wie diese Aufgaben umgesetzt werden können.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Segmentierung
Wir haben zuvor über Objekterkennung gelernt, die es uns ermöglicht, Objekte im Bild zu lokalisieren, indem ihre begrenzenden Boxen vorhergesagt werden. Für einige Aufgaben benötigen wir jedoch nicht nur begrenzende Boxen, sondern auch eine präzisere Objektlokalisierung. Diese Aufgabe nennt man Segmentierung.
Quiz vor der Vorlesung
Segmentierung kann als Pixelklassifikation betrachtet werden, wobei für jedes Pixel des Bildes seine Klasse vorhergesagt werden muss (Hintergrund ist eine der Klassen). Es gibt zwei Hauptarten von Segmentierungsalgorithmen:
- Semantische Segmentierung gibt nur die Pixelklasse an und unterscheidet nicht zwischen verschiedenen Objekten derselben Klasse.
- Instanzsegmentierung teilt Klassen in verschiedene Instanzen auf.
Bei der Instanzsegmentierung sind diese Schafe unterschiedliche Objekte, aber bei der semantischen Segmentierung werden alle Schafe durch eine Klasse repräsentiert.
<img src="../../../../../translated_images/de/instance_vs_semantic.eee9812bebf8cd45.webp" width="50%">
> Bild aus diesem Blogbeitrag
Es gibt verschiedene neuronale Architekturen für die Segmentierung, aber sie haben alle die gleiche Struktur. In gewisser Weise ähnelt sie dem Autoencoder, den Sie zuvor kennengelernt haben, aber anstatt das ursprüngliche Bild zu rekonstruieren, ist unser Ziel, eine Maske zu rekonstruieren. Daher hat ein Segmentierungsnetzwerk die folgenden Teile:
- Encoder extrahiert Merkmale aus dem Eingabebild.
- Decoder transformiert diese Merkmale in das Maskenbild, mit derselben Größe und einer Anzahl von Kanälen, die der Anzahl der Klassen entspricht.
<img src="../../../../../translated_images/de/segm.92442f2cb42ff4fa.webp" width="80%">
> Bild aus dieser Publikation
Besonders erwähnenswert ist die Verlustfunktion, die für die Segmentierung verwendet wird. Bei klassischen Autoencodern müssen wir die Ähnlichkeit zwischen zwei Bildern messen, und dafür können wir den mittleren quadratischen Fehler (MSE) verwenden. Bei der Segmentierung repräsentiert jedes Pixel im Zielmaskenbild die Klassennummer (one-hot-encoded entlang der dritten Dimension), sodass wir Verlustfunktionen verwenden müssen, die speziell für Klassifikationen geeignet sind - Kreuzentropieverlust, gemittelt über alle Pixel. Wenn die Maske binär ist, wird binärer Kreuzentropieverlust (BCE) verwendet.
> ✅ One-hot-Encoding ist eine Methode, um eine Klassenbezeichnung in einen Vektor mit einer Länge zu kodieren, die der Anzahl der Klassen entspricht. Schauen Sie sich diesen Artikel zu dieser Technik an.
Segmentierung in der medizinischen Bildgebung
In dieser Lektion werden wir die Segmentierung in Aktion sehen, indem wir ein Netzwerk trainieren, um menschliche Nävi (auch bekannt als Muttermale) auf medizinischen Bildern zu erkennen. Wir verwenden die <a href="https://www.fc.up.pt/addi/ph2%20database.html">PH<sup>2</sup>-Datenbank</a> für Dermoskopiebilder als Bildquelle. Dieses Datenset enthält 200 Bilder von drei Klassen: typischer Nävus, atypischer Nävus und Melanom. Alle Bilder enthalten auch eine entsprechende Maske, die den Nävus umreißt.
> ✅ Diese Technik ist besonders geeignet für diese Art der medizinischen Bildgebung, aber welche anderen Anwendungen in der realen Welt könnten Sie sich vorstellen?
<img alt="navi" src="../../../../../translated_images/de/navi.2f20b727910110ea.webp"/>
> Bild aus der PH<sup>2</sup>-Datenbank
Wir werden ein Modell trainieren, um jeden Nävus vom Hintergrund zu segmentieren.
✍️ Übungen: Semantische Segmentierung
Öffnen Sie die untenstehenden Notebooks, um mehr über verschiedene semantische Segmentierungsarchitekturen zu erfahren, mit ihnen zu arbeiten und sie in Aktion zu sehen.
Quiz nach der Vorlesung
Fazit
Segmentierung ist eine sehr leistungsstarke Technik für die Bildklassifikation, die über begrenzende Boxen hinausgeht und eine Klassifikation auf Pixelebene ermöglicht. Sie wird unter anderem in der medizinischen Bildgebung eingesetzt.
🚀 Herausforderung
Die Segmentierung des Körpers ist nur eine der häufigen Aufgaben, die wir mit Bildern von Menschen durchführen können. Andere wichtige Aufgaben umfassen Skelett-Erkennung und Pose-Erkennung. Probieren Sie die OpenPose-Bibliothek aus, um zu sehen, wie Pose-Erkennung verwendet werden kann.
Überprüfung & Selbststudium
Dieser Wikipedia-Artikel bietet einen guten Überblick über die verschiedenen Anwendungen dieser Technik. Erfahren Sie mehr über die Unterbereiche der Instanzsegmentierung und Panoptischen Segmentierung in diesem Forschungsfeld.
Aufgabe
In diesem Labor versuchen Sie die Segmentierung des menschlichen Körpers mit dem Segmentation Full Body MADS Dataset von Kaggle.
Segmentierung
Wir haben bereits über Objekterkennung gelernt, die es uns ermöglicht, Objekte in einem Bild zu lokalisieren, indem ihre begrenzenden Boxen vorhergesagt werden. Für einige Aufgaben benötigen wir jedoch nicht nur begrenzende Boxen, sondern auch eine präzisere Objektlokalisierung. Diese Aufgabe nennt man Segmentierung.
Segmentierung kann als Pixelklassifikation betrachtet werden, wobei für jedes Pixel des Bildes seine Klasse vorhergesagt werden muss (Hintergrund ist eine der Klassen). Es gibt zwei Hauptalgorithmen für die Segmentierung:
- Semantische Segmentierung gibt nur die Pixelklasse an und unterscheidet nicht zwischen verschiedenen Objekten derselben Klasse.
- Instanzsegmentierung teilt Klassen in verschiedene Instanzen auf.
Bei der Instanzsegmentierung sind 10 Schafe unterschiedliche Objekte, bei der semantischen Segmentierung werden alle Schafe durch eine Klasse repräsentiert.
<img src="images/instance_vs_semantic.jpeg" width="50%">
> Bild aus diesem Blogbeitrag
Es gibt verschiedene neuronale Architekturen für die Segmentierung, aber sie haben alle die gleiche Struktur:
- Encoder extrahiert Merkmale aus dem Eingabebild.
- Decoder transformiert diese Merkmale in das Maskenbild, mit derselben Größe und einer Anzahl von Kanälen, die der Anzahl der Klassen entspricht.
<img src="images/segm.png" width="80%">
> Bild aus dieser Publikation
Voraussetzungen
Zunächst importieren wir die benötigten Bibliotheken und überprüfen, ob eine GPU für das Training verfügbar ist.
import torch
import torchvision
import matplotlib.pyplot as plt
from torchvision import transforms
from torch import nn
from torch import optim
from tqdm import tqdm
import numpy as np
import torch.nn.functional as F
from skimage.io import imread
from skimage.transform import resize
import os
torch.manual_seed(42)
np.random.seed(42)
device = 'cuda:0' if torch.cuda.is_available() else 'cpu'
train_size = 0.9
lr = 1e-3
weight_decay = 1e-6
batch_size = 32
epochs = 30
Der Datensatz
Wir verwenden Dermoskopie-Bilder von menschlichen Nävi. Dieser Datensatz enthält 200 Bilder, die in drei Klassen unterteilt sind: typischer Nävus, atypischer Nävus und Melanom. Alle Bilder enthalten außerdem entsprechende Masken, die den Nävus umreißen.
Der folgende Code lädt den Datensatz von der Originalquelle herunter und entpackt ihn. Damit dieser Code funktioniert, muss das unrar-Tool installiert sein. Sie können es unter Linux mit sudo apt-get install unrar installieren oder die Kommandozeilen-Version für Windows hier herunterladen.
#!apt-get install rar
!wget https://www.dropbox.com/s/k88qukc20ljnbuo/PH2Dataset.rar
!unrar x -Y PH2Dataset.rar
Nun werden wir den Code definieren, um den Datensatz zu laden. Wir werden alle Bilder in die Größe 256x256 umwandeln und den Datensatz in einen Trainings- und einen Testteil aufteilen. Diese Funktion gibt Trainings- und Testdatensätze zurück, die jeweils die Originalbilder und Masken enthalten, die das Muttermal umreißen.
def load_dataset(train_part, root='PH2Dataset'):
images = []
masks = []
for root, dirs, files in os.walk(os.path.join(root, 'PH2 Dataset images')):
if root.endswith('_Dermoscopic_Image'):
images.append(imread(os.path.join(root, files[0])))
if root.endswith('_lesion'):
masks.append(imread(os.path.join(root, files[0])))
size = (256, 256)
images = torch.permute(torch.FloatTensor(np.array([resize(image, size, mode='constant', anti_aliasing=True,) for image in images])), (0, 3, 1, 2))
masks = torch.FloatTensor(np.array([resize(mask, size, mode='constant', anti_aliasing=False) > 0.5 for mask in masks])).unsqueeze(1)
indices = np.random.permutation(range(len(images)))
train_part = int(train_part * len(images))
train_ind = indices[:train_part]
test_ind = indices[train_part:]
train_dataset = (images[train_ind, :, :, :], masks[train_ind, :, :, :])
test_dataset = (images[test_ind, :, :, :], masks[test_ind, :, :, :])
return train_dataset, test_dataset
train_dataset, test_dataset = load_dataset(train_size)
Lassen Sie uns nun einige der Bilder aus dem Datensatz plotten, um zu sehen, wie sie aussehen:
def plotn(n, data, only_mask=False):
images, masks = data[0], data[1]
fig, ax = plt.subplots(1, n)
fig1, ax1 = plt.subplots(1, n)
for i, (img, mask) in enumerate(zip(images, masks)):
if i == n:
break
if not only_mask:
ax[i].imshow(torch.permute(img, (1, 2, 0)))
else:
ax[i].imshow(img[0])
ax1[i].imshow(mask[0])
ax[i].axis('off')
ax1[i].axis('off')
plt.show()
plotn(5, train_dataset)
Wir werden auch Dataloader benötigen, um die Daten in unser neuronales Netzwerk einzuspeisen.
train_dataloader = torch.utils.data.DataLoader(list(zip(train_dataset[0], train_dataset[1])), batch_size=batch_size, shuffle=True)
test_dataloader = torch.utils.data.DataLoader(list(zip(test_dataset[0], test_dataset[1])), batch_size=1, shuffle=False)
dataloaders = (train_dataloader, test_dataloader)
SegNet
Die einfachste Encoder-Decoder-Architektur wird SegNet genannt. Sie verwendet ein standardmäßiges CNN mit Convolutions und Poolings im Encoder sowie ein Deconvolution-CNN, das Convolutions und Upsamplings im Decoder umfasst. Außerdem setzt sie auf Batch-Normalisierung, um ein erfolgreiches Training des mehrschichtigen Netzwerks zu ermöglichen.
<img src="images/segnet.png" width="80%">
> Bild aus diesem Paper: Badrinarayanan, V., Kendall, A., & Cipolla, R. (2015). SegNet: A deep convolutional encoder-decoder architecture for image segmentation
class SegNet(nn.Module):
def __init__(self):
super().__init__()
self.enc_conv0 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=(3,3), padding=1)
self.act0 = nn.ReLU()
self.bn0 = nn.BatchNorm2d(16)
self.pool0 = nn.MaxPool2d(kernel_size=(2,2))
self.enc_conv1 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=(3,3), padding=1)
self.act1 = nn.ReLU()
self.bn1 = nn.BatchNorm2d(32)
self.pool1 = nn.MaxPool2d(kernel_size=(2,2))
self.enc_conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=(3,3), padding=1)
self.act2 = nn.ReLU()
self.bn2 = nn.BatchNorm2d(64)
self.pool2 = nn.MaxPool2d(kernel_size=(2,2))
self.enc_conv3 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=(3,3), padding=1)
self.act3 = nn.ReLU()
self.bn3 = nn.BatchNorm2d(128)
self.pool3 = nn.MaxPool2d(kernel_size=(2,2))
self.bottleneck_conv = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=(3,3), padding=1)
self.upsample0 = nn.UpsamplingBilinear2d(scale_factor=2)
self.dec_conv0 = nn.Conv2d(in_channels=256, out_channels=128, kernel_size=(3,3), padding=1)
self.dec_act0 = nn.ReLU()
self.dec_bn0 = nn.BatchNorm2d(128)
self.upsample1 = nn.UpsamplingBilinear2d(scale_factor=2)
self.dec_conv1 = nn.Conv2d(in_channels=128, out_channels=64, kernel_size=(3,3), padding=1)
self.dec_act1 = nn.ReLU()
self.dec_bn1 = nn.BatchNorm2d(64)
self.upsample2 = nn.UpsamplingBilinear2d(scale_factor=2)
self.dec_conv2 = nn.Conv2d(in_channels=64, out_channels=32, kernel_size=(3,3), padding=1)
self.dec_act2 = nn.ReLU()
self.dec_bn2 = nn.BatchNorm2d(32)
self.upsample3 = nn.UpsamplingBilinear2d(scale_factor=2)
self.dec_conv3 = nn.Conv2d(in_channels=32, out_channels=1, kernel_size=(1,1))
self.sigmoid = nn.Sigmoid()
def forward(self, x):
e0 = self.pool0(self.bn0(self.act0(self.enc_conv0(x))))
e1 = self.pool1(self.bn1(self.act1(self.enc_conv1(e0))))
e2 = self.pool2(self.bn2(self.act2(self.enc_conv2(e1))))
e3 = self.pool3(self.bn3(self.act3(self.enc_conv3(e2))))
b = self.bottleneck_conv(e3)
d0 = self.dec_bn0(self.dec_act0(self.dec_conv0(self.upsample0(b))))
d1 = self.dec_bn1(self.dec_act1(self.dec_conv1(self.upsample1(d0))))
d2 = self.dec_bn2(self.dec_act2(self.dec_conv2(self.upsample2(d1))))
d3 = self.sigmoid(self.dec_conv3(self.upsample3(d2)))
return d3
Wir sollten insbesondere die Verlustfunktion erwähnen, die für die Segmentierung verwendet wird. In klassischen Autoencodern müssen wir die Ähnlichkeit zwischen zwei Bildern messen, und dafür können wir den mittleren quadratischen Fehler verwenden. Bei der Segmentierung repräsentiert jedes Pixel im Zielmaskenbild die Klassennummer (one-hot-codiert entlang der dritten Dimension), daher müssen wir verlustspezifische Funktionen für die Klassifikation verwenden - Kreuzentropieverlust, gemittelt über alle Pixel. Wenn die Maske binär ist (wie in unserem Beispiel) - verwenden wir den binären Kreuzentropieverlust (BCE).
model = SegNet().to(device)
optimizer = optim.Adam(model.parameters(), lr=lr, weight_decay=weight_decay)
loss_fn = nn.BCEWithLogitsLoss()
Der Trainingsloop wird auf die übliche Weise definiert:
def train(dataloaders, model, loss_fn, optimizer, epochs, device):
tqdm_iter = tqdm(range(epochs))
train_dataloader, test_dataloader = dataloaders[0], dataloaders[1]
for epoch in tqdm_iter:
model.train()
train_loss = 0.0
test_loss = 0.0
for batch in train_dataloader:
imgs, labels = batch
imgs = imgs.to(device)
labels = labels.to(device)
preds = model(imgs)
loss = loss_fn(preds, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss += loss.item()
model.eval()
with torch.no_grad():
for batch in test_dataloader:
imgs, labels = batch
imgs = imgs.to(device)
labels = labels.to(device)
preds = model(imgs)
loss = loss_fn(preds, labels)
test_loss += loss.item()
train_loss /= len(train_dataloader)
test_loss /= len(test_dataloader)
tqdm_dct = {'train loss:': train_loss, 'test loss:': test_loss}
tqdm_iter.set_postfix(tqdm_dct, refresh=True)
tqdm_iter.refresh()
train(dataloaders, model, loss_fn, optimizer, epochs, device)
Um unser Modell zu bewerten, werden wir einfach Zielmasken und vorhergesagte Masken für eine Anzahl von Bildern plotten:
model.eval()
predictions = []
image_mask = []
plots = 5
images, masks = test_dataset[0], test_dataset[1]
for i, (img, mask) in enumerate(zip(images, masks)):
if i == plots:
break
img = img.to(device).unsqueeze(0)
predictions.append((model(img).detach().cpu()[0] > 0.5).float())
image_mask.append(mask)
plotn(plots, (predictions, image_mask), only_mask=True)
Es gibt auch einige formale Metriken zur Bewertung der Leistung, über die Sie hier lesen können. Die einfachste zu verstehende ist die Pixelgenauigkeit - ein Prozentsatz der korrekt klassifizierten Pixel.
U-Net
Die SegNet-Architektur ist sehr intuitiv, aber nicht die genaueste. Tatsächlich wenden wir zunächst eine pyramidale CNN-Architektur auf das Originalbild an, was die räumliche Genauigkeit der Bildmerkmale verringert. Wenn wir dann das Bild rekonstruieren, können wir die Pixelpositionen nicht korrekt wiederherstellen.
Dies führt uns zur Idee der Skip-Verbindungen zwischen den Convolution-Schichten im Encoder und Decoder. Diese Architektur ist sehr verbreitet in der semantischen Segmentierung und wird als U-Net bezeichnet. Skip-Verbindungen auf jeder Convolution-Ebene helfen dem Netzwerk, keine Informationen über Merkmale aus dem ursprünglichen Input auf dieser Ebene zu verlieren.
Wir werden hier eine recht einfache CNN-Architektur verwenden, aber U-Net kann auch komplexere Encoder für die Merkmalsextraktion nutzen, wie zum Beispiel ResNet-50.
<img src="images/unet.png" width="70%">
> Bild aus der Publikation: Ronneberger, Olaf, Philipp Fischer und Thomas Brox. U-Net: Convolutional networks for biomedical image segmentation.
class UNet(nn.Module):
def __init__(self):
super().__init__()
self.enc_conv0 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=(3,3), padding=1)
self.act0 = nn.ReLU()
self.bn0 = nn.BatchNorm2d(16)
self.pool0 = nn.MaxPool2d(kernel_size=(2,2))
self.enc_conv1 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=(3,3), padding=1)
self.act1 = nn.ReLU()
self.bn1 = nn.BatchNorm2d(32)
self.pool1 = nn.MaxPool2d(kernel_size=(2,2))
self.enc_conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=(3,3), padding=1)
self.act2 = nn.ReLU()
self.bn2 = nn.BatchNorm2d(64)
self.pool2 = nn.MaxPool2d(kernel_size=(2,2))
self.enc_conv3 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=(3,3), padding=1)
self.act3 = nn.ReLU()
self.bn3 = nn.BatchNorm2d(128)
self.pool3 = nn.MaxPool2d(kernel_size=(2,2))
self.bottleneck_conv = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=(3,3), padding=1)
self.upsample0 = nn.UpsamplingBilinear2d(scale_factor=2)
self.dec_conv0 = nn.Conv2d(in_channels=384, out_channels=128, kernel_size=(3,3), padding=1)
self.dec_act0 = nn.ReLU()
self.dec_bn0 = nn.BatchNorm2d(128)
self.upsample1 = nn.UpsamplingBilinear2d(scale_factor=2)
self.dec_conv1 = nn.Conv2d(in_channels=192, out_channels=64, kernel_size=(3,3), padding=1)
self.dec_act1 = nn.ReLU()
self.dec_bn1 = nn.BatchNorm2d(64)
self.upsample2 = nn.UpsamplingBilinear2d(scale_factor=2)
self.dec_conv2 = nn.Conv2d(in_channels=96, out_channels=32, kernel_size=(3,3), padding=1)
self.dec_act2 = nn.ReLU()
self.dec_bn2 = nn.BatchNorm2d(32)
self.upsample3 = nn.UpsamplingBilinear2d(scale_factor=2)
self.dec_conv3 = nn.Conv2d(in_channels=48, out_channels=1, kernel_size=(1,1))
self.sigmoid = nn.Sigmoid()
def forward(self, x):
e0 = self.pool0(self.bn0(self.act0(self.enc_conv0(x))))
e1 = self.pool1(self.bn1(self.act1(self.enc_conv1(e0))))
e2 = self.pool2(self.bn2(self.act2(self.enc_conv2(e1))))
e3 = self.pool3(self.bn3(self.act3(self.enc_conv3(e2))))
cat0 = self.bn0(self.act0(self.enc_conv0(x)))
cat1 = self.bn1(self.act1(self.enc_conv1(e0)))
cat2 = self.bn2(self.act2(self.enc_conv2(e1)))
cat3 = self.bn3(self.act3(self.enc_conv3(e2)))
b = self.bottleneck_conv(e3)
d0 = self.dec_bn0(self.dec_act0(self.dec_conv0(torch.cat((self.upsample0(b), cat3), dim=1))))
d1 = self.dec_bn1(self.dec_act1(self.dec_conv1(torch.cat((self.upsample1(d0), cat2), dim=1))))
d2 = self.dec_bn2(self.dec_act2(self.dec_conv2(torch.cat((self.upsample2(d1), cat1), dim=1))))
d3 = self.sigmoid(self.dec_conv3(torch.cat((self.upsample3(d2), cat0), dim=1)))
return d3
model = UNet().to(device)
optimizer = optim.Adam(model.parameters(), lr=lr, weight_decay=weight_decay)
loss_fn = nn.BCEWithLogitsLoss()
train(dataloaders, model, loss_fn, optimizer, epochs, device)
model.eval()
predictions = []
image_mask = []
plots = 5
images, masks = test_dataset[0], test_dataset[1]
for i, (img, mask) in enumerate(zip(images, masks)):
if i == plots:
break
img = img.to(device).unsqueeze(0)
predictions.append((model(img).detach().cpu()[0] > 0.5).float())
image_mask.append(mask)
plotn(plots, (predictions, image_mask), only_mask=True)
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Semantische Segmentierung
Segmentierung ist eine der Hauptaufgaben der Computer Vision. Für jedes Pixel eines Bildes muss eine Klasse (einschließlich Hintergrund) angegeben werden. Die semantische Segmentierung gibt nur die Klasse eines Pixels an, während die Instanzsegmentierung Klassen in verschiedene Instanzen unterteilt.
Bei der Instanzsegmentierung sind zehn Autos unterschiedliche Objekte, bei der semantischen Segmentierung gehören alle Autos zu einer Klasse.
<img src="images/instance_vs_semantic.jpeg" width="50%">
> Bild aus diesem Blogbeitrag
Fast alle Architekturen haben denselben Aufbau. Der erste Teil ist der Encoder, der Merkmale aus dem Eingabebild extrahiert. Der zweite Teil ist der Decoder, der diese Merkmale in ein Bild mit derselben Höhe und Breite sowie einer bestimmten Anzahl von Kanälen umwandelt, die möglicherweise der Anzahl der Klassen entspricht.
<img src="images/segm.png" width="80%">
> Bild aus dieser Publikation
import tensorflow as tf
import tensorflow.keras.layers as keras
import matplotlib.pyplot as plt
from tqdm import tqdm
import numpy as np
from skimage.io import imread
from skimage.transform import resize
import os
import tensorflow.keras.optimizers as optimizers
import tensorflow.keras.losses as losses
from tensorflow.keras.preprocessing.image import ImageDataGenerator
tf.random.set_seed(42)
np.random.seed(42)
train_size = 0.8
lr = 3e-4
weight_decay = 8e-9
batch_size = 64
epochs = 100
Datensatz
!apt-get install rar
!wget https://www.dropbox.com/s/k88qukc20ljnbuo/PH2Dataset.rar
!unrar x -Y PH2Dataset.rar
def load_dataset(train_part, root='PH2Dataset'):
images = []
masks = []
for root, dirs, files in os.walk(os.path.join(root, 'PH2 Dataset images')):
if root.endswith('_Dermoscopic_Image'):
images.append(imread(os.path.join(root, files[0])))
if root.endswith('_lesion'):
masks.append(imread(os.path.join(root, files[0])))
size = (256, 256)
images = np.array([resize(image, size, mode='constant', anti_aliasing=True,) for image in images])
masks = np.expand_dims(np.array([resize(mask, size, mode='constant', anti_aliasing=False) > 0.5 for mask in masks]), axis=3)
indices = np.random.permutation(range(len(images)))
train_part = int(train_part * len(images))
train_ind = indices[:train_part]
test_ind = indices[train_part:]
X_train = tf.cast(images[train_ind, :, :, :], tf.float32)
y_train = tf.cast(masks[train_ind, :, :, :], tf.float32)
X_test = tf.cast(images[test_ind, :, :, :], tf.float32)
y_test = tf.cast(masks[test_ind, :, :, :], tf.float32)
return (X_train, y_train), (X_test, y_test)
(X_train, y_train), (X_test, y_test) = load_dataset(train_size)
def plotn(n, data):
images, masks = data[0], data[1]
fig, ax = plt.subplots(1, n)
fig1, ax1 = plt.subplots(1, n)
for i, (img, mask) in enumerate(zip(images, masks)):
if i == n:
break
ax[i].imshow(img)
ax1[i].imshow(mask[:, :, 0])
plt.show()
Lass uns einige Bilder mit den entsprechenden Masken darstellen.
plotn(5, (X_train, y_train))
SegNet
Einfache Encoder-Decoder-Architektur mit Faltungen, Poolings im Encoder und Faltungen, Hochskalierungen im Decoder.
<img src="images/segnet.png" width="80%">
- Badrinarayanan, V., Kendall, A., & Cipolla, R. (2015). SegNet: Eine tiefgehende Faltungs-Encoder-Decoder-Architektur für die Bildsegmentierung
class SegNet(tf.keras.Model):
def __init__(self):
super().__init__()
self.enc_conv0 = keras.Conv2D(16, kernel_size=3, padding='same')
self.bn0 = keras.BatchNormalization()
self.relu0 = keras.Activation('relu')
self.pool0 = keras.MaxPool2D()
self.enc_conv1 = keras.Conv2D(32, kernel_size=3, padding='same')
self.relu1 = keras.Activation('relu')
self.bn1 = keras.BatchNormalization()
self.pool1 = keras.MaxPool2D()
self.enc_conv2 = keras.Conv2D(64, kernel_size=3, padding='same')
self.relu2 = keras.Activation('relu')
self.bn2 = keras.BatchNormalization()
self.pool2 = keras.MaxPool2D()
self.enc_conv3 = keras.Conv2D(128, kernel_size=3, padding='same')
self.relu3 = keras.Activation('relu')
self.bn3 = keras.BatchNormalization()
self.pool3 = keras.MaxPool2D()
self.bottleneck_conv = keras.Conv2D(256, kernel_size=(3, 3), padding='same')
self.upsample0 = keras.UpSampling2D(interpolation='bilinear')
self.dec_conv0 = keras.Conv2D(128, kernel_size=3, padding='same')
self.dec_relu0 = keras.Activation('relu')
self.dec_bn0 = keras.BatchNormalization()
self.upsample1 = keras.UpSampling2D(interpolation='bilinear')
self.dec_conv1 = keras.Conv2D(64, kernel_size=3, padding='same')
self.dec_relu1 = keras.Activation('relu')
self.dec_bn1 = keras.BatchNormalization()
self.upsample2 = keras.UpSampling2D(interpolation='bilinear')
self.dec_conv2 = keras.Conv2D(32, kernel_size=3, padding='same')
self.dec_relu2 = keras.Activation('relu')
self.dec_bn2 = keras.BatchNormalization()
self.upsample3 = keras.UpSampling2D(interpolation='bilinear')
self.dec_conv3 = keras.Conv2D(1, kernel_size=1)
def call(self, input):
e0 = self.pool0(self.relu0(self.bn0(self.enc_conv0(input))))
e1 = self.pool1(self.relu1(self.bn1(self.enc_conv1(e0))))
e2 = self.pool2(self.relu2(self.bn2(self.enc_conv2(e1))))
e3 = self.pool3(self.relu3(self.bn3(self.enc_conv3(e2))))
b = self.bottleneck_conv(e3)
d0 = self.dec_relu0(self.dec_bn0(self.upsample0(self.dec_conv0(b))))
d1 = self.dec_relu1(self.dec_bn1(self.upsample1(self.dec_conv1(d0))))
d2 = self.dec_relu2(self.dec_bn2(self.upsample2(self.dec_conv2(d1))))
d3 = self.dec_conv3(self.upsample3(d2))
return d3
model = SegNet()
optimizer = optimizers.Adam(learning_rate=lr, decay=weight_decay)
loss_fn = losses.BinaryCrossentropy(from_logits=True)
model.compile(loss=loss_fn, optimizer=optimizer)
def train(datasets, model, epochs, batch_size):
train_dataset, test_dataset = datasets[0], datasets[1]
model.fit(train_dataset[0], train_dataset[1],
epochs=epochs,
batch_size=batch_size,
shuffle=True,
validation_data=(test_dataset[0], test_dataset[1]))
train(((X_train, y_train), (X_test, y_test)), model, epochs, batch_size)
predictions = []
image_mask = []
plots = 5
for i, (img, mask) in enumerate(zip(X_test, y_test)):
if i == plots:
break
img = tf.expand_dims(img, 0)
pred = np.array(model.predict(img))
predictions.append(pred[0, :, :, 0] > 0.5)
image_mask.append(mask)
plotn(plots, (predictions, image_mask))
U-Net
Sehr einfache Architektur, die Skip-Verbindungen verwendet. Skip-Verbindungen auf jeder Konvolutionsebene helfen dem Netzwerk, keine Informationen über Merkmale des ursprünglichen Eingangs auf dieser Ebene zu verlieren.
U-Net hat normalerweise einen Standard-Encoder zur Merkmalsextraktion, zum Beispiel resnet50.
<img src="images/unet.png" width="70%">
- Ronneberger, Olaf, Philipp Fischer und Thomas Brox. U-Net: Convolutional networks for biomedical image segmentation.
class UNet(tf.keras.Model):
def __init__(self):
super().__init__()
self.enc_conv0 = keras.Conv2D(16, kernel_size=3, padding='same')
self.bn0 = keras.BatchNormalization()
self.relu0 = keras.Activation('relu')
self.pool0 = keras.MaxPool2D()
self.enc_conv1 = keras.Conv2D(32, kernel_size=3, padding='same')
self.relu1 = keras.Activation('relu')
self.bn1 = keras.BatchNormalization()
self.pool1 = keras.MaxPool2D()
self.enc_conv2 = keras.Conv2D(64, kernel_size=3, padding='same')
self.relu2 = keras.Activation('relu')
self.bn2 = keras.BatchNormalization()
self.pool2 = keras.MaxPool2D()
self.enc_conv3 = keras.Conv2D(128, kernel_size=3, padding='same')
self.relu3 = keras.Activation('relu')
self.bn3 = keras.BatchNormalization()
self.pool3 = keras.MaxPool2D()
self.bottleneck_conv = keras.Conv2D(256, kernel_size=(3, 3), padding='same')
self.upsample0 = keras.UpSampling2D(interpolation='bilinear')
self.dec_conv0 = keras.Conv2D(128, kernel_size=3, padding='same', input_shape=[None, 384, None, None])
self.dec_relu0 = keras.Activation('relu')
self.dec_bn0 = keras.BatchNormalization()
self.upsample1 = keras.UpSampling2D(interpolation='bilinear')
self.dec_conv1 = keras.Conv2D(64, kernel_size=3, padding='same', input_shape=[None, 192, None, None])
self.dec_relu1 = keras.Activation('relu')
self.dec_bn1 = keras.BatchNormalization()
self.upsample2 = keras.UpSampling2D(interpolation='bilinear')
self.dec_conv2 = keras.Conv2D(32, kernel_size=3, padding='same', input_shape=[None, 96, None, None])
self.dec_relu2 = keras.Activation('relu')
self.dec_bn2 = keras.BatchNormalization()
self.upsample3 = keras.UpSampling2D(interpolation='bilinear')
self.dec_conv3 = keras.Conv2D(1, kernel_size=1, input_shape=[None, 48, None, None])
self.cat0 = keras.Concatenate(axis=3)
self.cat1 = keras.Concatenate(axis=3)
self.cat2 = keras.Concatenate(axis=3)
self.cat3 = keras.Concatenate(axis=3)
def call(self, input):
e0 = self.pool0(self.relu0(self.bn0(self.enc_conv0(input))))
e1 = self.pool1(self.relu1(self.bn1(self.enc_conv1(e0))))
e2 = self.pool2(self.relu2(self.bn2(self.enc_conv2(e1))))
e3 = self.pool3(self.relu3(self.bn3(self.enc_conv3(e2))))
cat0 = self.relu0(self.bn0(self.enc_conv0(input)))
cat1 = self.relu1(self.bn1(self.enc_conv1(e0)))
cat2 = self.relu2(self.bn2(self.enc_conv2(e1)))
cat3 = self.relu3(self.bn3(self.enc_conv3(e2)))
b = self.bottleneck_conv(e3)
cat_tens0 = self.cat0([self.upsample0(b), cat3])
d0 = self.dec_relu0(self.dec_bn0(self.dec_conv0(cat_tens0)))
cat_tens1 = self.cat1([self.upsample1(d0), cat2])
d1 = self.dec_relu1(self.dec_bn1(self.dec_conv1(cat_tens1)))
cat_tens2 = self.cat2([self.upsample2(d1), cat1])
d2 = self.dec_relu2(self.dec_bn2(self.dec_conv2(cat_tens2)))
cat_tens3 = self.cat3([self.upsample3(d2), cat0])
d3 = self.dec_conv3(cat_tens3)
return d3
model = UNet()
optimizer = optimizers.Adam(learning_rate=lr, decay=weight_decay)
loss_fn = losses.BinaryCrossentropy(from_logits=True)
model.compile(loss=loss_fn, optimizer=optimizer)
train(((X_train, y_train), (X_test, y_test)), model, epochs, batch_size)
predictions = []
image_mask = []
plots = 5
for i, (img, mask) in enumerate(zip(X_test, y_test)):
if i == plots:
break
img = tf.expand_dims(img, 0)
pred = np.array(model.predict(img))
predictions.append(pred[0, :, :, 0] > 0.5)
image_mask.append(mask)
plotn(plots, (predictions, image_mask))
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Computer Vision

In diesem Abschnitt lernen wir über:
- Einführung in Computer Vision und OpenCV
- Convolutional Neural Networks
- Vortrainierte Netzwerke und Transfer Learning
- Autoencoder
- Generative Adversarial Networks
- Objekterkennung
- Semantische Segmentierung
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Aufgabe: Notebooks
Verwenden Sie die Notebooks, die zu dieser Lektion gehören (entweder die PyTorch- oder die TensorFlow-Version), und führen Sie sie mit Ihrem eigenen Datensatz aus, möglicherweise einem von Kaggle, unter Angabe der Quelle. Überarbeiten Sie das Notebook, um Ihre eigenen Erkenntnisse hervorzuheben. Probieren Sie einige innovative Datensätze aus, die überraschend sein könnten, wie zum Beispiel diesen über UFO-Sichtungen von NUFORC.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Darstellung von Text als Tensoren
Quiz vor der Vorlesung
Textklassifikation
Im ersten Teil dieses Abschnitts konzentrieren wir uns auf die Aufgabe der Textklassifikation. Wir verwenden das AG News-Dataset, das Nachrichtenartikel wie die folgenden enthält:
- Kategorie: Wissenschaft/Technik
- Titel: Ky. Unternehmen erhält Zuschuss zur Erforschung von Peptiden (AP)
- Text: AP - Ein Unternehmen, das von einem Chemieforscher der Universität von Louisville gegründet wurde, erhielt einen Zuschuss zur Entwicklung...
Unser Ziel wird es sein, den Nachrichtenartikel basierend auf dem Text einer der Kategorien zuzuordnen.
Darstellung von Text
Um Aufgaben der natürlichen Sprachverarbeitung (NLP) mit neuronalen Netzwerken zu lösen, benötigen wir eine Methode, um Text als Tensoren darzustellen. Computer repräsentieren Textzeichen bereits als Zahlen, die mit Codierungen wie ASCII oder UTF-8 auf die Schriftarten auf Ihrem Bildschirm abgebildet werden.
<img alt="Bild zeigt ein Diagramm, das ein Zeichen mit einer ASCII- und Binärdarstellung verknüpft" src="../../../../../translated_images/de/ascii-character-map.18ed6aa7f3b0a7ff.webp" width="50%"/>
Als Menschen verstehen wir, was jeder Buchstabe darstellt und wie alle Zeichen zusammenkommen, um die Wörter eines Satzes zu bilden. Computer hingegen haben von sich aus kein solches Verständnis, und ein neuronales Netzwerk muss die Bedeutung während des Trainings lernen.
Daher können wir verschiedene Ansätze verwenden, um Text darzustellen:
- Zeichenbasierte Darstellung, bei der wir Text darstellen, indem wir jedes Zeichen als Zahl behandeln. Angenommen, wir haben C verschiedene Zeichen in unserem Textkorpus, dann würde das Wort Hello durch einen 5xC-Tensor dargestellt. Jeder Buchstabe würde einer Spalte des Tensors in One-Hot-Codierung entsprechen.
- Wortbasierte Darstellung, bei der wir ein Vokabular aller Wörter in unserem Text erstellen und dann Wörter mit One-Hot-Codierung darstellen. Dieser Ansatz ist in gewisser Weise besser, da jeder Buchstabe für sich genommen nicht viel Bedeutung hat. Durch die Verwendung höherer semantischer Konzepte – Wörter – vereinfachen wir die Aufgabe für das neuronale Netzwerk. Allerdings müssen wir aufgrund der großen Wörterbuchgröße mit hochdimensionalen, spärlichen Tensoren umgehen.
Unabhängig von der Darstellung müssen wir den Text zunächst in eine Sequenz von Tokens umwandeln, wobei ein Token entweder ein Zeichen, ein Wort oder manchmal sogar ein Teil eines Wortes sein kann. Anschließend konvertieren wir das Token in eine Zahl, typischerweise mithilfe eines Vokabulars, und diese Zahl kann mithilfe von One-Hot-Codierung in ein neuronales Netzwerk eingespeist werden.
N-Gramme
In der natürlichen Sprache kann die genaue Bedeutung von Wörtern nur im Kontext bestimmt werden. Zum Beispiel haben neuronales Netzwerk und Fischernetz völlig unterschiedliche Bedeutungen. Eine Möglichkeit, dies zu berücksichtigen, besteht darin, unser Modell auf Wortpaaren aufzubauen und Wortpaare als separate Vokabular-Tokens zu betrachten. Auf diese Weise wird der Satz Ich gehe gerne angeln durch die folgende Sequenz von Tokens dargestellt: Ich gehe, gehe gerne, gerne angeln. Das Problem bei diesem Ansatz ist, dass die Wörterbuchgröße erheblich wächst und Kombinationen wie gerne angeln und gerne einkaufen durch unterschiedliche Tokens dargestellt werden, die trotz des gleichen Verbs keine semantische Ähnlichkeit teilen.
In einigen Fällen können wir auch die Verwendung von Tri-Grammen – Kombinationen aus drei Wörtern – in Betracht ziehen. Daher wird dieser Ansatz oft als n-Gramme bezeichnet. Es macht auch Sinn, n-Gramme mit zeichenbasierter Darstellung zu verwenden, wobei n-Gramme ungefähr verschiedenen Silben entsprechen.
Bag-of-Words und TF/IDF
Bei Aufgaben wie der Textklassifikation müssen wir in der Lage sein, Text durch einen festen Vektor darzustellen, den wir als Eingabe für den abschließenden dichten Klassifikator verwenden. Eine der einfachsten Möglichkeiten, dies zu tun, besteht darin, alle individuellen Wortdarstellungen zu kombinieren, z. B. durch Addition. Wenn wir die One-Hot-Codierungen jedes Wortes addieren, erhalten wir einen Frequenzvektor, der zeigt, wie oft jedes Wort im Text vorkommt. Eine solche Darstellung von Text wird als Bag-of-Words (BoW) bezeichnet.
<img src="../../../../../translated_images/de/bow.3811869cff59368d.webp" width="90%"/>
> Bild vom Autor
Ein BoW zeigt im Wesentlichen, welche Wörter im Text vorkommen und in welchen Mengen, was tatsächlich ein guter Hinweis darauf sein kann, worum es im Text geht. Beispielsweise enthält ein Nachrichtenartikel über Politik wahrscheinlich Wörter wie Präsident und Land, während eine wissenschaftliche Veröffentlichung Begriffe wie Collider, entdeckt usw. enthalten könnte. Daher können Wortfrequenzen in vielen Fällen ein guter Indikator für den Textinhalt sein.
Das Problem bei BoW ist, dass bestimmte häufig vorkommende Wörter wie und, ist usw. in den meisten Texten erscheinen und die höchsten Frequenzen haben, wodurch die wirklich wichtigen Wörter überdeckt werden. Wir können die Bedeutung dieser Wörter verringern, indem wir die Häufigkeit berücksichtigen, mit der Wörter in der gesamten Dokumentensammlung vorkommen. Dies ist die Hauptidee hinter dem TF/IDF-Ansatz, der in den zu dieser Lektion beigefügten Notebooks ausführlicher behandelt wird.
Keiner dieser Ansätze kann jedoch die Semantik des Textes vollständig berücksichtigen. Um dies zu erreichen, benötigen wir leistungsstärkere Modelle für neuronale Netzwerke, die wir später in diesem Abschnitt besprechen werden.
✍️ Übungen: Textdarstellung
Setzen Sie Ihr Lernen in den folgenden Notebooks fort:
Fazit
Bisher haben wir Techniken untersucht, die Frequenzgewichtungen für verschiedene Wörter hinzufügen können. Sie sind jedoch nicht in der Lage, Bedeutung oder Reihenfolge darzustellen. Wie der berühmte Linguist J. R. Firth 1935 sagte: "Die vollständige Bedeutung eines Wortes ist immer kontextuell, und keine Untersuchung der Bedeutung außerhalb des Kontexts kann ernst genommen werden." Später im Kurs werden wir lernen, wie man kontextuelle Informationen aus Text mithilfe von Sprachmodellen erfasst.
🚀 Herausforderung
Probieren Sie einige andere Übungen mit Bag-of-Words und verschiedenen Datenmodellen aus. Lassen Sie sich vielleicht von diesem Wettbewerb auf Kaggle inspirieren.
Quiz nach der Vorlesung
Überprüfung & Selbststudium
Üben Sie Ihre Fähigkeiten mit Text-Einbettungen und Bag-of-Words-Techniken auf Microsoft Learn
Aufgabe: Notebooks
Textklassifizierungsaufgabe
Wie bereits erwähnt, konzentrieren wir uns auf eine einfache Textklassifizierungsaufgabe basierend auf dem AG_NEWS-Datensatz. Ziel ist es, Nachrichtenüberschriften in eine von vier Kategorien einzuordnen: Welt, Sport, Wirtschaft und Wissenschaft/Technik.
Der Datensatz
Dieser Datensatz ist im torchtext-Modul integriert, sodass wir leicht darauf zugreifen können.
import torch
import torchtext
import os
import collections
os.makedirs('./data',exist_ok=True)
train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')
classes = ['World', 'Sports', 'Business', 'Sci/Tech']
Hier enthalten train_dataset und test_dataset Sammlungen, die jeweils Paare aus Label (Nummer der Klasse) und Text zurückgeben, zum Beispiel:
list(train_dataset)[0]
Also, drucken wir die ersten 10 neuen Schlagzeilen aus unserem Datensatz aus:
for i,x in zip(range(5),train_dataset):
print(f"**{classes[x[0]]}** -> {x[1]}")
Da Datensätze Iteratoren sind, müssen wir sie in eine Liste umwandeln, wenn wir die Daten mehrmals verwenden möchten:
train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')
train_dataset = list(train_dataset)
test_dataset = list(test_dataset)
Tokenisierung
Nun müssen wir Text in Zahlen umwandeln, die als Tensoren dargestellt werden können. Wenn wir eine Wortebene-Darstellung möchten, müssen wir zwei Dinge tun: * einen Tokenizer verwenden, um den Text in Tokens zu zerlegen * ein Vokabular dieser Tokens erstellen.
tokenizer = torchtext.data.utils.get_tokenizer('basic_english')
tokenizer('He said: hello')
counter = collections.Counter()
for (label, line) in train_dataset:
counter.update(tokenizer(line))
vocab = torchtext.vocab.vocab(counter, min_freq=1)
Mit Vokabular können wir unsere tokenisierte Zeichenkette leicht in eine Zahlenmenge kodieren:
vocab_size = len(vocab)
print(f"Vocab size if {vocab_size}")
stoi = vocab.get_stoi() # dict to convert tokens to indices
def encode(x):
return [stoi[s] for s in tokenizer(x)]
encode('I love to play with my words')
Bag-of-Words Textdarstellung
Da Wörter Bedeutung repräsentieren, können wir manchmal die Bedeutung eines Textes allein durch die Betrachtung der einzelnen Wörter herausfinden, unabhängig von ihrer Reihenfolge im Satz. Zum Beispiel, wenn wir Nachrichten klassifizieren, deuten Wörter wie Wetter, Schnee wahrscheinlich auf eine Wettervorhersage hin, während Wörter wie Aktien, Dollar eher auf Finanznachrichten hinweisen.
Die Bag-of-Words (BoW)-Vektordarstellung ist die am häufigsten verwendete traditionelle Vektordarstellung. Jedes Wort ist einem Vektorindex zugeordnet, und das Vektorelement enthält die Anzahl der Vorkommen eines Wortes in einem bestimmten Dokument.
> Hinweis: Sie können BoW auch als die Summe aller One-Hot-encodierten Vektoren für einzelne Wörter im Text betrachten.
Im Folgenden finden Sie ein Beispiel, wie man eine Bag-of-Words-Darstellung mit der Scikit Learn Python-Bibliothek erzeugt:
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer()
corpus = [
'I like hot dogs.',
'The dog ran fast.',
'Its hot outside.',
]
vectorizer.fit_transform(corpus)
vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()
Um den Bag-of-Words-Vektor aus der Vektordarstellung unseres AG_NEWS-Datensatzes zu berechnen, können wir die folgende Funktion verwenden:
vocab_size = len(vocab)
def to_bow(text,bow_vocab_size=vocab_size):
res = torch.zeros(bow_vocab_size,dtype=torch.float32)
for i in encode(text):
if i<bow_vocab_size:
res[i] += 1
return res
print(to_bow(train_dataset[0][1]))
> Hinweis: Hier verwenden wir die globale Variable vocab_size, um die Standardgröße des Vokabulars festzulegen. Da die Vokabulargröße oft ziemlich groß ist, können wir die Größe des Vokabulars auf die häufigsten Wörter begrenzen. Versuchen Sie, den Wert von vocab_size zu verringern und den untenstehenden Code auszuführen, und beobachten Sie, wie sich dies auf die Genauigkeit auswirkt. Sie sollten einen gewissen Rückgang der Genauigkeit erwarten, aber keinen dramatischen, zugunsten einer höheren Leistung.
Training eines BoW-Klassifikators
Jetzt, da wir gelernt haben, wie man eine Bag-of-Words-Darstellung unseres Textes erstellt, lassen Sie uns einen Klassifikator darauf trainieren. Zunächst müssen wir unser Dataset für das Training so umwandeln, dass alle Positionsvektordarstellungen in Bag-of-Words-Darstellungen konvertiert werden. Dies kann erreicht werden, indem die Funktion bowify als Parameter collate_fn an den standardmäßigen torch DataLoader übergeben wird:
from torch.utils.data import DataLoader
import numpy as np
# this collate function gets list of batch_size tuples, and needs to
# return a pair of label-feature tensors for the whole minibatch
def bowify(b):
return (
torch.LongTensor([t[0]-1 for t in b]),
torch.stack([to_bow(t[1]) for t in b])
)
train_loader = DataLoader(train_dataset, batch_size=16, collate_fn=bowify, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=16, collate_fn=bowify, shuffle=True)
Lassen Sie uns nun ein einfaches Klassifikator-Neuronales Netzwerk definieren, das eine lineare Schicht enthält. Die Größe des Eingabevektors entspricht vocab_size, und die Ausgabengröße entspricht der Anzahl der Klassen (4). Da wir eine Klassifikationsaufgabe lösen, ist die endgültige Aktivierungsfunktion LogSoftmax().
net = torch.nn.Sequential(torch.nn.Linear(vocab_size,4),torch.nn.LogSoftmax(dim=1))
Jetzt definieren wir die standardmäßige PyTorch-Trainingsschleife. Da unser Datensatz ziemlich groß ist, werden wir für unsere Lehrzwecke nur für eine Epoche trainieren und manchmal sogar weniger als eine Epoche (die Angabe des Parameters epoch_size ermöglicht es uns, das Training zu begrenzen). Wir würden auch die akkumulierte Trainingsgenauigkeit während des Trainings berichten; die Häufigkeit der Berichterstattung wird mit dem Parameter report_freq angegeben.
def train_epoch(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.NLLLoss(),epoch_size=None, report_freq=200):
optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)
net.train()
total_loss,acc,count,i = 0,0,0,0
for labels,features in dataloader:
optimizer.zero_grad()
out = net(features)
loss = loss_fn(out,labels) #cross_entropy(out,labels)
loss.backward()
optimizer.step()
total_loss+=loss
_,predicted = torch.max(out,1)
acc+=(predicted==labels).sum()
count+=len(labels)
i+=1
if i%report_freq==0:
print(f"{count}: acc={acc.item()/count}")
if epoch_size and count>epoch_size:
break
return total_loss.item()/count, acc.item()/count
train_epoch(net,train_loader,epoch_size=15000)
BiGrams, TriGrams und N-Grams
Eine Einschränkung des Bag-of-Words-Ansatzes ist, dass einige Wörter Teil von mehrwortigen Ausdrücken sind. Zum Beispiel hat das Wort 'Hot Dog' eine völlig andere Bedeutung als die Wörter 'hot' und 'dog' in anderen Kontexten. Wenn wir die Wörter 'hot' und 'dog' immer durch die gleichen Vektoren darstellen, kann das unser Modell verwirren.
Um dies zu lösen, werden N-Gram-Darstellungen häufig in Methoden der Dokumentklassifikation verwendet, bei denen die Häufigkeit jedes Wortes, Zwei-Wort- oder Drei-Wort-Ausdrucks ein nützliches Merkmal für das Training von Klassifikatoren ist. In der Bigram-Darstellung fügen wir beispielsweise alle Wortpaare zusätzlich zu den ursprünglichen Wörtern dem Vokabular hinzu.
Unten ist ein Beispiel, wie man eine Bigram-Bag-of-Words-Darstellung mit Scikit Learn generiert:
bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), token_pattern=r'\b\w+\b', min_df=1)
corpus = [
'I like hot dogs.',
'The dog ran fast.',
'Its hot outside.',
]
bigram_vectorizer.fit_transform(corpus)
print("Vocabulary:\n",bigram_vectorizer.vocabulary_)
bigram_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()
Der Hauptnachteil des N-Gramm-Ansatzes ist, dass die Größe des Vokabulars extrem schnell wächst. In der Praxis müssen wir die N-Gramm-Darstellung mit einigen Techniken zur Dimensionsreduktion kombinieren, wie zum Beispiel Embeddings, die wir in der nächsten Einheit besprechen werden.
Um die N-Gramm-Darstellung in unserem AG News-Datensatz zu verwenden, müssen wir ein spezielles N-Gramm-Vokabular erstellen:
counter = collections.Counter()
for (label, line) in train_dataset:
l = tokenizer(line)
counter.update(torchtext.data.utils.ngrams_iterator(l,ngrams=2))
bi_vocab = torchtext.vocab.vocab(counter, min_freq=1)
print("Bigram vocabulary length = ",len(bi_vocab))
Wir könnten denselben Code wie oben verwenden, um den Klassifikator zu trainieren, allerdings wäre das sehr speicherineffizient. In der nächsten Einheit werden wir einen Bigramm-Klassifikator mithilfe von Embeddings trainieren.
> Hinweis: Du kannst nur die N-Gramme beibehalten, die im Text häufiger als eine bestimmte Anzahl vorkommen. Das stellt sicher, dass seltene Bigramme ausgelassen werden und die Dimensionalität erheblich reduziert wird. Um dies zu erreichen, setze den Parameter min_freq auf einen höheren Wert und beobachte, wie sich die Länge des Vokabulars verändert.
Termfrequenz-Inverse Dokumentfrequenz TF-IDF
In der BoW-Darstellung werden Wortvorkommen gleichmäßig gewichtet, unabhängig vom Wort selbst. Es ist jedoch offensichtlich, dass häufige Wörter wie ein, in usw. für die Klassifikation viel weniger wichtig sind als spezialisierte Begriffe. Tatsächlich sind bei den meisten NLP-Aufgaben einige Wörter relevanter als andere.
TF-IDF steht für Termfrequenz–Inverse Dokumentfrequenz. Es ist eine Variation des Bag-of-Words-Modells, bei der anstelle eines binären 0/1-Wertes, der das Auftreten eines Wortes in einem Dokument anzeigt, ein Gleitkommawert verwendet wird, der mit der Häufigkeit des Wortvorkommens im Korpus zusammenhängt.
Formal wird das Gewicht $w_{ij}$ eines Wortes $i$ im Dokument $j$ wie folgt definiert: $$ w_{ij} = tf_{ij}\times\log({N\over df_i}) $$ wobei * $tf_{ij}$ die Anzahl der Vorkommen von $i$ in $j$ ist, also der BoW-Wert, den wir zuvor gesehen haben * $N$ die Anzahl der Dokumente in der Sammlung ist * $df_i$ die Anzahl der Dokumente ist, die das Wort $i$ in der gesamten Sammlung enthalten
Der TF-IDF-Wert $w_{ij}$ steigt proportional zur Häufigkeit, mit der ein Wort in einem Dokument erscheint, und wird durch die Anzahl der Dokumente im Korpus, die das Wort enthalten, ausgeglichen. Dies hilft, den Umstand zu berücksichtigen, dass einige Wörter häufiger vorkommen als andere. Wenn beispielsweise ein Wort in jedem Dokument der Sammlung vorkommt, gilt $df_i=N$, und $w_{ij}=0$, und diese Begriffe würden vollständig ignoriert.
Mit Scikit Learn können Sie ganz einfach eine TF-IDF-Vektorisierung von Text erstellen:
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(ngram_range=(1,2))
vectorizer.fit_transform(corpus)
vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()
Fazit
Auch wenn TF-IDF-Darstellungen Wörtern unterschiedliche Gewichtungen basierend auf ihrer Häufigkeit zuweisen, sind sie nicht in der Lage, Bedeutung oder Reihenfolge darzustellen. Wie der berühmte Linguist J. R. Firth 1935 sagte: „Die vollständige Bedeutung eines Wortes ist immer kontextabhängig, und keine Untersuchung der Bedeutung ohne Kontext kann ernst genommen werden.“ Später im Kurs werden wir lernen, wie man kontextuelle Informationen aus Texten mithilfe von Sprachmodellen erfasst.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Textklassifizierungsaufgabe
In diesem Modul beginnen wir mit einer einfachen Textklassifizierungsaufgabe basierend auf dem AG_NEWS-Datensatz: Wir werden Nachrichtenüberschriften in eine von vier Kategorien einordnen: Welt, Sport, Wirtschaft und Wissenschaft/Technik.
Der Datensatz
Um den Datensatz zu laden, verwenden wir die TensorFlow Datasets-API.
import tensorflow as tf
from tensorflow import keras
import tensorflow_datasets as tfds
# In this tutorial, we will be training a lot of models. In order to use GPU memory cautiously,
# we will set tensorflow option to grow GPU memory allocation when required.
physical_devices = tf.config.list_physical_devices('GPU')
if len(physical_devices)>0:
tf.config.experimental.set_memory_growth(physical_devices[0], True)
dataset = tfds.load('ag_news_subset')
Wir können nun auf die Trainings- und Testteile des Datensatzes zugreifen, indem wir dataset['train'] und dataset['test'] verwenden:
ds_train = dataset['train']
ds_test = dataset['test']
print(f"Length of train dataset = {len(ds_train)}")
print(f"Length of test dataset = {len(ds_test)}")
Lassen Sie uns die ersten 10 neuen Schlagzeilen aus unserem Datensatz ausdrucken:
classes = ['World', 'Sports', 'Business', 'Sci/Tech']
for i,x in zip(range(5),ds_train):
print(f"{x['label']} ({classes[x['label']]}) -> {x['title']} {x['description']}")
Textvektorisierung
Nun müssen wir Text in Zahlen umwandeln, die als Tensoren dargestellt werden können. Wenn wir eine Wortebene-Darstellung möchten, müssen wir zwei Dinge tun:
- Einen Tokenizer verwenden, um den Text in Token zu zerlegen.
- Ein Vokabular dieser Token erstellen.
Begrenzung der Vokabulargröße
Im Beispiel des AG News-Datensatzes ist die Vokabulargröße ziemlich groß, mehr als 100.000 Wörter. Allgemein gesprochen benötigen wir keine Wörter, die selten im Text vorkommen — nur wenige Sätze enthalten sie, und das Modell wird nicht von ihnen lernen. Daher ist es sinnvoll, die Vokabulargröße auf eine kleinere Anzahl zu begrenzen, indem ein Argument an den Vektorisierer-Konstruktor übergeben wird:
Beide dieser Schritte können mit der TextVectorization-Schicht durchgeführt werden. Lassen Sie uns das Vektorisierungsobjekt instanziieren und anschließend die adapt-Methode aufrufen, um den gesamten Text zu durchlaufen und ein Vokabular zu erstellen:
vocab_size = 50000
vectorizer = keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size)
vectorizer.adapt(ds_train.take(500).map(lambda x: x['title']+' '+x['description']))
> Hinweis: Wir verwenden nur einen Teil des gesamten Datensatzes, um ein Vokabular zu erstellen. Dies tun wir, um die Ausführungszeit zu verkürzen und Sie nicht warten zu lassen. Allerdings gehen wir das Risiko ein, dass einige Wörter aus dem gesamten Datensatz nicht in das Vokabular aufgenommen werden und während des Trainings ignoriert werden. Die Verwendung der gesamten Vokabulargröße und das Durchlaufen des gesamten Datensatzes während adapt sollte die endgültige Genauigkeit erhöhen, jedoch nicht signifikant.
Nun können wir auf das tatsächliche Vokabular zugreifen:
vocab = vectorizer.get_vocabulary()
vocab_size = len(vocab)
print(vocab[:10])
print(f"Length of vocabulary: {vocab_size}")
Mit dem Vektorisierer können wir problemlos jeden Text in eine Zahlenmenge kodieren:
vectorizer('I love to play with my words')
Bag-of-words Textdarstellung
Da Wörter Bedeutung vermitteln, können wir manchmal die Bedeutung eines Textes allein durch die Betrachtung der einzelnen Wörter erkennen, unabhängig von ihrer Reihenfolge im Satz. Zum Beispiel deuten beim Klassifizieren von Nachrichten Wörter wie Wetter und Schnee wahrscheinlich auf eine Wettervorhersage hin, während Wörter wie Aktien und Dollar eher auf Finanznachrichten hindeuten.
Die Bag-of-words (BoW)-Vektordarstellung ist die einfachste und am leichtesten verständliche traditionelle Vektordarstellung. Jedes Wort wird einem Vektorindex zugeordnet, und ein Vektorelement enthält die Anzahl der Vorkommen jedes Wortes in einem bestimmten Dokument.
> Note: Sie können sich BoW auch als die Summe aller One-Hot-encodierten Vektoren für die einzelnen Wörter im Text vorstellen.
Unten sehen Sie ein Beispiel, wie man mit der Scikit Learn Python-Bibliothek eine Bag-of-words-Darstellung erzeugen kann:
from sklearn.feature_extraction.text import CountVectorizer
sc_vectorizer = CountVectorizer()
corpus = [
'I like hot dogs.',
'The dog ran fast.',
'Its hot outside.',
]
sc_vectorizer.fit_transform(corpus)
sc_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()
Wir können auch den Keras-Vektorisierer verwenden, den wir oben definiert haben, indem wir jede Wortnummer in eine One-Hot-Codierung umwandeln und alle diese Vektoren addieren:
def to_bow(text):
return tf.reduce_sum(tf.one_hot(vectorizer(text),vocab_size),axis=0)
to_bow('My dog likes hot dogs on a hot day.').numpy()
> Hinweis: Es könnte Sie überraschen, dass das Ergebnis sich vom vorherigen Beispiel unterscheidet. Der Grund dafür ist, dass im Keras-Beispiel die Länge des Vektors der Größe des Vokabulars entspricht, das aus dem gesamten AG News-Datensatz erstellt wurde, während wir im Scikit-Learn-Beispiel das Vokabular spontan aus dem Beispieltext erstellt haben.
Training des BoW-Klassifikators
Jetzt, da wir gelernt haben, wie man die Bag-of-Words-Darstellung unseres Textes erstellt, können wir einen Klassifikator trainieren, der diese verwendet. Zuerst müssen wir unser Dataset in eine Bag-of-Words-Darstellung umwandeln. Dies kann mit der map-Funktion auf folgende Weise erreicht werden:
batch_size = 128
ds_train_bow = ds_train.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)
ds_test_bow = ds_test.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)
Lassen Sie uns nun ein einfaches Klassifikator-Neuronales Netzwerk definieren, das eine lineare Schicht enthält. Die Eingabegröße ist vocab_size, und die Ausgabengröße entspricht der Anzahl der Klassen (4). Da wir eine Klassifikationsaufgabe lösen, ist die endgültige Aktivierungsfunktion softmax:
model = keras.models.Sequential([
keras.layers.Dense(4,activation='softmax',input_shape=(vocab_size,))
])
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])
model.fit(ds_train_bow,validation_data=ds_test_bow)
Da wir 4 Klassen haben, ist eine Genauigkeit von über 80 % ein gutes Ergebnis.
Einen Klassifikator als ein Netzwerk trainieren
Da der Vektorisierer ebenfalls eine Keras-Schicht ist, können wir ein Netzwerk definieren, das ihn einschließt, und es vollständig trainieren. Auf diese Weise müssen wir den Datensatz nicht mit map vektorisieren, sondern können den ursprünglichen Datensatz direkt an den Eingang des Netzwerks übergeben.
> Hinweis: Wir müssten dennoch map auf unseren Datensatz anwenden, um Felder aus Wörterbüchern (wie title, description und label) in Tupel umzuwandeln. Wenn wir die Daten jedoch von der Festplatte laden, können wir von Anfang an einen Datensatz mit der erforderlichen Struktur erstellen.
def extract_text(x):
return x['title']+' '+x['description']
def tupelize(x):
return (extract_text(x),x['label'])
inp = keras.Input(shape=(1,),dtype=tf.string)
x = vectorizer(inp)
x = tf.reduce_sum(tf.one_hot(x,vocab_size),axis=1)
out = keras.layers.Dense(4,activation='softmax')(x)
model = keras.models.Model(inp,out)
model.summary()
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])
model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))
Bigramme, Trigramme und N-Gramme
Eine Einschränkung des Bag-of-Words-Ansatzes ist, dass einige Wörter Teil von mehrwortigen Ausdrücken sind. Zum Beispiel hat das Wort 'Hot Dog' eine völlig andere Bedeutung als die Wörter 'hot' und 'dog' in anderen Kontexten. Wenn wir die Wörter 'hot' und 'dog' immer mit denselben Vektoren darstellen, kann dies unser Modell verwirren.
Um dies zu lösen, werden häufig N-Gramm-Darstellungen in Methoden der Dokumentklassifikation verwendet, bei denen die Häufigkeit jedes Wortes, Zwei-Wort- oder Drei-Wort-Ausdrucks eine nützliche Eigenschaft für das Training von Klassifikatoren darstellt. In Bigramm-Darstellungen fügen wir beispielsweise alle Wortpaare zusätzlich zu den ursprünglichen Wörtern dem Vokabular hinzu.
Unten sehen Sie ein Beispiel, wie man eine Bigramm-Bag-of-Words-Darstellung mit Scikit Learn erzeugt:
bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), token_pattern=r'\b\w+\b', min_df=1)
corpus = [
'I like hot dogs.',
'The dog ran fast.',
'Its hot outside.',
]
bigram_vectorizer.fit_transform(corpus)
print("Vocabulary:\n",bigram_vectorizer.vocabulary_)
bigram_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()
Der Hauptnachteil des n-Gramm-Ansatzes ist, dass die Größe des Vokabulars extrem schnell wächst. In der Praxis müssen wir die n-Gramm-Repräsentation mit einer Technik zur Dimensionsreduktion kombinieren, wie zum Beispiel Embeddings, die wir in der nächsten Einheit besprechen werden.
Um eine n-Gramm-Repräsentation in unserem AG News-Datensatz zu verwenden, müssen wir den Parameter ngrams an den TextVectorization-Konstruktor übergeben. Die Länge eines Bigramm-Vokabulars ist deutlich größer, in unserem Fall sind es mehr als 1,3 Millionen Tokens! Daher ist es sinnvoll, auch die Bigramm-Tokens auf eine vernünftige Anzahl zu begrenzen.
Wir könnten denselben Code wie oben verwenden, um den Klassifikator zu trainieren, allerdings wäre das sehr speicherineffizient. In der nächsten Einheit werden wir den Bigramm-Klassifikator mithilfe von Embeddings trainieren. In der Zwischenzeit kannst du mit dem Training eines Bigramm-Klassifikators in diesem Notebook experimentieren und sehen, ob du eine höhere Genauigkeit erzielen kannst.
Automatisches Berechnen von BoW-Vektoren
Im obigen Beispiel haben wir BoW-Vektoren manuell berechnet, indem wir die One-Hot-Codierungen einzelner Wörter summiert haben. Die neueste Version von TensorFlow ermöglicht es uns jedoch, BoW-Vektoren automatisch zu berechnen, indem wir den Parameter output_mode='count' an den Konstruktor des Vektorisierers übergeben. Dies vereinfacht das Definieren und Trainieren unseres Modells erheblich:
model = keras.models.Sequential([
keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='count'),
keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')
])
print("Training vectorizer")
model.layers[0].adapt(ds_train.take(500).map(extract_text))
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])
model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))
Termfrequenz - inverse Dokumentfrequenz (TF-IDF)
In der BoW-Darstellung werden Wortvorkommen unabhängig vom Wort selbst mit derselben Technik gewichtet. Es ist jedoch offensichtlich, dass häufige Wörter wie a und in für die Klassifikation viel weniger wichtig sind als spezialisierte Begriffe. Bei den meisten NLP-Aufgaben sind einige Wörter relevanter als andere.
TF-IDF steht für Termfrequenz - inverse Dokumentfrequenz. Es handelt sich um eine Variation des Bag-of-Words-Modells, bei der anstelle eines binären 0/1-Wertes, der das Auftreten eines Wortes in einem Dokument angibt, ein Gleitkommawert verwendet wird, der mit der Häufigkeit des Wortvorkommens im Korpus zusammenhängt.
Formal wird das Gewicht $w_{ij}$ eines Wortes $i$ im Dokument $j$ wie folgt definiert: $$ w_{ij} = tf_{ij}\times\log({N\over df_i}) $$ wobei * $tf_{ij}$ die Anzahl der Vorkommen von $i$ in $j$ ist, also der BoW-Wert, den wir zuvor gesehen haben * $N$ die Anzahl der Dokumente in der Sammlung ist * $df_i$ die Anzahl der Dokumente ist, die das Wort $i$ in der gesamten Sammlung enthalten
Der TF-IDF-Wert $w_{ij}$ steigt proportional zur Häufigkeit, mit der ein Wort in einem Dokument erscheint, und wird durch die Anzahl der Dokumente im Korpus, die das Wort enthalten, ausgeglichen. Dies hilft, den Umstand zu berücksichtigen, dass einige Wörter häufiger vorkommen als andere. Wenn beispielsweise ein Wort in jedem Dokument der Sammlung vorkommt, gilt $df_i=N$, und $w_{ij}=0$, und diese Begriffe würden vollständig ignoriert.
Mit Scikit Learn können Sie ganz einfach eine TF-IDF-Vektorisierung von Text erstellen:
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(ngram_range=(1,2))
vectorizer.fit_transform(corpus)
vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()
In Keras kann die TextVectorization-Schicht automatisch TF-IDF-Frequenzen berechnen, indem der Parameter output_mode='tf-idf' übergeben wird. Lassen Sie uns den oben verwendeten Code wiederholen, um zu sehen, ob die Verwendung von TF-IDF die Genauigkeit erhöht:
model = keras.models.Sequential([
keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='tf-idf'),
keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')
])
print("Training vectorizer")
model.layers[0].adapt(ds_train.take(500).map(extract_text))
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])
model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))
Fazit
Auch wenn TF-IDF-Darstellungen Häufigkeitsgewichte für verschiedene Wörter bereitstellen, sind sie nicht in der Lage, Bedeutung oder Reihenfolge abzubilden. Wie der berühmte Linguist J. R. Firth 1935 sagte: "Die vollständige Bedeutung eines Wortes ist immer kontextabhängig, und keine Untersuchung der Bedeutung ohne Kontext kann ernst genommen werden." Später im Kurs werden wir lernen, wie man kontextuelle Informationen aus Texten mithilfe von Sprachmodellen erfasst.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Aufgabe: Notebooks
Verwenden Sie die Notebooks, die mit dieser Lektion verbunden sind (entweder die PyTorch- oder die TensorFlow-Version), und führen Sie sie mit Ihrem eigenen Datensatz erneut aus, vielleicht einem von Kaggle, der mit entsprechender Quellenangabe verwendet wird. Überarbeiten Sie das Notebook, um Ihre eigenen Erkenntnisse hervorzuheben. Probieren Sie eine andere Art von Datensatz aus und dokumentieren Sie Ihre Ergebnisse, indem Sie beispielsweise Texte wie diese Beatles-Songtexte verwenden.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Einbettungen
In unserem vorherigen Beispiel haben wir mit hochdimensionalen Bag-of-Words-Vektoren der Länge vocab_size gearbeitet und explizit von niedrigdimensionalen Positionsdarstellungsvektoren in spärliche One-Hot-Darstellungen umgewandelt. Diese One-Hot-Darstellung ist nicht speichereffizient. Außerdem wird jedes Wort unabhängig von den anderen behandelt, d.h. One-Hot-codierte Vektoren drücken keine semantische Ähnlichkeit zwischen Wörtern aus.
In dieser Einheit werden wir weiterhin den News AG-Datensatz untersuchen. Zu Beginn laden wir die Daten und holen einige Definitionen aus dem vorherigen Notebook.
import torch
import torchtext
import numpy as np
from torchnlp import *
train_dataset, test_dataset, classes, vocab = load_dataset()
vocab_size = len(vocab)
print("Vocab size = ",vocab_size)
Was ist ein Embedding?
Die Idee des Embeddings besteht darin, Wörter durch niedrigdimensionale, dichte Vektoren darzustellen, die in gewisser Weise die semantische Bedeutung eines Wortes widerspiegeln. Später werden wir besprechen, wie man sinnvolle Wort-Embeddings erstellt, aber vorerst betrachten wir Embeddings einfach als eine Methode, die Dimensionalität eines Wortvektors zu reduzieren.
Eine Embedding-Schicht nimmt also ein Wort als Eingabe und erzeugt einen Ausgabevektor mit der angegebenen embedding_size. In gewisser Weise ähnelt sie einer Linear-Schicht, aber anstatt einen One-Hot-codierten Vektor zu verwenden, kann sie eine Wortnummer als Eingabe akzeptieren.
Indem wir die Embedding-Schicht als erste Schicht in unserem Netzwerk verwenden, können wir vom Bag-of-Words-Modell zum Embedding-Bag-Modell wechseln. Dabei wird jedes Wort in unserem Text zunächst in das entsprechende Embedding umgewandelt, und anschließend wird eine Aggregationsfunktion wie sum, average oder max über alle diese Embeddings berechnet.

Unser neuronales Klassifikationsnetzwerk beginnt mit einer Embedding-Schicht, gefolgt von einer Aggregationsschicht und einem linearen Klassifikator darüber:
class EmbedClassifier(torch.nn.Module):
def __init__(self, vocab_size, embed_dim, num_class):
super().__init__()
self.embedding = torch.nn.Embedding(vocab_size, embed_dim)
self.fc = torch.nn.Linear(embed_dim, num_class)
def forward(self, x):
x = self.embedding(x)
x = torch.mean(x,dim=1)
return self.fc(x)
Umgang mit variabler Sequenzgröße
Aufgrund dieser Architektur müssen Minibatches für unser Netzwerk auf eine bestimmte Weise erstellt werden. In der vorherigen Einheit, bei der Verwendung von Bag-of-Words, hatten alle BoW-Tensoren in einem Minibatch die gleiche Größe vocab_size, unabhängig von der tatsächlichen Länge unserer Textsequenz. Sobald wir zu Wort-Embeddings wechseln, haben wir eine variable Anzahl von Wörtern in jeder Textprobe, und beim Kombinieren dieser Proben in Minibatches müssen wir eine Auffüllung (Padding) anwenden.
Dies kann durch die gleiche Technik erreicht werden, indem eine collate_fn-Funktion an die Datenquelle übergeben wird:
def padify(b):
# b is the list of tuples of length batch_size
# - first element of a tuple = label,
# - second = feature (text sequence)
# build vectorized sequence
v = [encode(x[1]) for x in b]
# first, compute max length of a sequence in this minibatch
l = max(map(len,v))
return ( # tuple of two tensors - labels and features
torch.LongTensor([t[0]-1 for t in b]),
torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v])
)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=padify, shuffle=True)
Training des Einbettungs-Klassifikators
Nun, da wir einen geeigneten Dataloader definiert haben, können wir das Modell mit der Trainingsfunktion trainieren, die wir in der vorherigen Einheit definiert haben:
net = EmbedClassifier(vocab_size,32,len(classes)).to(device)
train_epoch(net,train_loader, lr=1, epoch_size=25000)
> Hinweis: Wir trainieren hier nur mit 25.000 Datensätzen (weniger als eine vollständige Epoche) aus Zeitgründen, aber Sie können das Training fortsetzen, eine Funktion schreiben, um über mehrere Epochen zu trainieren, und mit dem Lernratenparameter experimentieren, um eine höhere Genauigkeit zu erreichen. Sie sollten in der Lage sein, eine Genauigkeit von etwa 90 % zu erreichen.
EmbeddingBag-Schicht und Darstellung von Sequenzen variabler Länge
In der vorherigen Architektur mussten wir alle Sequenzen auf die gleiche Länge auffüllen, um sie in ein Minibatch einzupassen. Dies ist jedoch nicht die effizienteste Methode, um Sequenzen variabler Länge darzustellen – ein alternativer Ansatz wäre die Verwendung eines Offset-Vektors, der die Offsets aller Sequenzen in einem großen Vektor speichert.

> Hinweis: Auf dem obigen Bild zeigen wir eine Zeichenfolge, aber in unserem Beispiel arbeiten wir mit Wortsequenzen. Das allgemeine Prinzip, Sequenzen mit einem Offset-Vektor darzustellen, bleibt jedoch dasselbe.
Um mit der Offset-Darstellung zu arbeiten, verwenden wir die EmbeddingBag-Schicht. Sie ähnelt der Embedding-Schicht, nimmt jedoch einen Inhaltsvektor und einen Offset-Vektor als Eingabe und enthält außerdem eine Aggregationsschicht, die mean, sum oder max sein kann.
Hier ist ein modifiziertes Netzwerk, das EmbeddingBag verwendet:
class EmbedClassifier(torch.nn.Module):
def __init__(self, vocab_size, embed_dim, num_class):
super().__init__()
self.embedding = torch.nn.EmbeddingBag(vocab_size, embed_dim)
self.fc = torch.nn.Linear(embed_dim, num_class)
def forward(self, text, off):
x = self.embedding(text, off)
return self.fc(x)
Um den Datensatz für das Training vorzubereiten, müssen wir eine Umrechnungsfunktion bereitstellen, die den Offset-Vektor vorbereitet:
def offsetify(b):
# first, compute data tensor from all sequences
x = [torch.tensor(encode(t[1])) for t in b]
# now, compute the offsets by accumulating the tensor of sequence lengths
o = [0] + [len(t) for t in x]
o = torch.tensor(o[:-1]).cumsum(dim=0)
return (
torch.LongTensor([t[0]-1 for t in b]), # labels
torch.cat(x), # text
o
)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=offsetify, shuffle=True)
Beachten Sie, dass unser Netzwerk im Gegensatz zu allen vorherigen Beispielen jetzt zwei Parameter akzeptiert: Datenvektor und Offsetvektor, die unterschiedliche Größen haben. Ebenso liefert uns unser Datenlader jetzt 3 Werte anstelle von 2: Sowohl Text- als auch Offsetvektoren werden als Features bereitgestellt. Daher müssen wir unsere Trainingsfunktion geringfügig anpassen, um dies zu berücksichtigen:
net = EmbedClassifier(vocab_size,32,len(classes)).to(device)
def train_epoch_emb(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.CrossEntropyLoss(),epoch_size=None, report_freq=200):
optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)
loss_fn = loss_fn.to(device)
net.train()
total_loss,acc,count,i = 0,0,0,0
for labels,text,off in dataloader:
optimizer.zero_grad()
labels,text,off = labels.to(device), text.to(device), off.to(device)
out = net(text, off)
loss = loss_fn(out,labels) #cross_entropy(out,labels)
loss.backward()
optimizer.step()
total_loss+=loss
_,predicted = torch.max(out,1)
acc+=(predicted==labels).sum()
count+=len(labels)
i+=1
if i%report_freq==0:
print(f"{count}: acc={acc.item()/count}")
if epoch_size and count>epoch_size:
break
return total_loss.item()/count, acc.item()/count
train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)
Semantische Einbettungen: Word2Vec
In unserem vorherigen Beispiel hat die Einbettungsschicht des Modells gelernt, Wörter in Vektorrepräsentationen umzuwandeln. Diese Repräsentationen hatten jedoch nicht viel semantische Bedeutung. Es wäre wünschenswert, solche Vektorrepräsentationen zu lernen, bei denen ähnliche Wörter oder Synonyme Vektoren entsprechen, die in Bezug auf eine bestimmte Vektordistanz (z. B. euklidische Distanz) nahe beieinander liegen.
Um dies zu erreichen, müssen wir unser Einbettungsmodell auf eine große Textsammlung in einer spezifischen Weise vortrainieren. Eine der ersten Methoden, um semantische Einbettungen zu trainieren, wird Word2Vec genannt. Sie basiert auf zwei Hauptarchitekturen, die verwendet werden, um eine verteilte Repräsentation von Wörtern zu erzeugen:
- Continuous Bag-of-Words (CBoW) — In dieser Architektur trainieren wir das Modell darauf, ein Wort aus dem umgebenden Kontext vorherzusagen. Gegeben das N-Gramm $(W_{-2},W_{-1},W_0,W_1,W_2)$, ist das Ziel des Modells, $W_0$ aus $(W_{-2},W_{-1},W_1,W_2)$ vorherzusagen.
- Continuous Skip-Gram ist das Gegenteil von CBoW. Das Modell verwendet das umgebende Fenster von Kontextwörtern, um das aktuelle Wort vorherzusagen.
CBoW ist schneller, während Skip-Gram langsamer ist, aber eine bessere Repräsentation für seltene Wörter liefert.

Um mit Word2Vec-Einbettungen zu experimentieren, die auf dem Google-News-Datensatz vortrainiert wurden, können wir die gensim-Bibliothek verwenden. Unten finden wir die Wörter, die 'neural' am ähnlichsten sind.
> Hinweis: Wenn Sie zum ersten Mal Wortvektoren erstellen, kann das Herunterladen einige Zeit in Anspruch nehmen!
import gensim.downloader as api
w2v = api.load('word2vec-google-news-300')
for w,p in w2v.most_similar('neural'):
print(f"{w} -> {p}")
Wir können auch Vektoreinbettungen aus dem Wort berechnen, die zur Schulung des Klassifikationsmodells verwendet werden (wir zeigen nur die ersten 20 Komponenten des Vektors zur besseren Übersicht):
w2v.word_vec('play')[:20]
Das Großartige an semantischen Einbettungen ist, dass man die Vektorkodierung manipulieren kann, um die Semantik zu ändern. Zum Beispiel können wir nach einem Wort suchen, dessen Vektorrepräsentation so nah wie möglich an den Wörtern König und Frau liegt und so weit wie möglich vom Wort Mann entfernt ist:
w2v.most_similar(positive=['king','woman'],negative=['man'])[0]
Sowohl CBoW als auch Skip-Grams sind „prädiktive“ Einbettungen, da sie nur lokale Kontexte berücksichtigen. Word2Vec nutzt den globalen Kontext nicht aus.
FastText baut auf Word2Vec auf, indem es Vektorrepräsentationen für jedes Wort und die Zeichen-n-Gramme innerhalb jedes Wortes lernt. Die Werte der Repräsentationen werden dann bei jedem Trainingsschritt zu einem Vektor gemittelt. Obwohl dies eine Menge zusätzlicher Berechnungen während des Pre-Trainings erfordert, ermöglicht es den Wort-Einbettungen, Subwort-Informationen zu kodieren.
Eine andere Methode, GloVe, nutzt die Idee der Ko-Vorkommensmatrix und verwendet neuronale Methoden, um die Ko-Vorkommensmatrix in ausdrucksstärkere und nicht-lineare Wortvektoren zu zerlegen.
Du kannst mit dem Beispiel experimentieren, indem du die Einbettungen auf FastText und GloVe änderst, da gensim mehrere verschiedene Modelle für Wort-Einbettungen unterstützt.
Verwendung vortrainierter Einbettungen in PyTorch
Wir können das obige Beispiel so anpassen, dass die Matrix in unserer Einbettungsschicht mit semantischen Einbettungen wie Word2Vec vorab gefüllt wird. Dabei müssen wir berücksichtigen, dass die Vokabulare der vortrainierten Einbettungen und unseres Textkorpus wahrscheinlich nicht übereinstimmen. Daher werden wir die Gewichte für die fehlenden Wörter mit Zufallswerten initialisieren:
embed_size = len(w2v.get_vector('hello'))
print(f'Embedding size: {embed_size}')
net = EmbedClassifier(vocab_size,embed_size,len(classes))
print('Populating matrix, this will take some time...',end='')
found, not_found = 0,0
for i,w in enumerate(vocab.get_itos()):
try:
net.embedding.weight[i].data = torch.tensor(w2v.get_vector(w))
found+=1
except:
net.embedding.weight[i].data = torch.normal(0.0,1.0,(embed_size,))
not_found+=1
print(f"Done, found {found} words, {not_found} words missing")
net = net.to(device)
Jetzt lassen Sie uns unser Modell trainieren. Beachten Sie, dass die Zeit, die zum Trainieren des Modells benötigt wird, aufgrund der größeren Größe der Einbettungsschicht und damit der deutlich höheren Anzahl von Parametern erheblich länger ist als im vorherigen Beispiel. Außerdem müssen wir möglicherweise unser Modell mit mehr Beispielen trainieren, wenn wir Überanpassung vermeiden wollen.
train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)
In unserem Fall sehen wir keinen großen Anstieg der Genauigkeit, was wahrscheinlich auf sehr unterschiedliche Vokabulare zurückzuführen ist.
Um das Problem der unterschiedlichen Vokabulare zu lösen, können wir eine der folgenden Lösungen verwenden:
Das Word2Vec-Modell mit unserem Vokabular neu trainieren
Unser Dataset mit dem Vokabular des vortrainierten Word2Vec-Modells laden. Das Vokabular, das zum Laden des Datasets verwendet wird, kann während des Ladens angegeben werden.
Der letztere Ansatz scheint einfacher zu sein, insbesondere weil das PyTorch-Framework torchtext integrierte Unterstützung für Embeddings bietet. Wir können beispielsweise ein GloVe-basiertes Vokabular auf folgende Weise instanziieren:
vocab = torchtext.vocab.GloVe(name='6B', dim=50)
Das geladene Vokabular bietet die folgenden grundlegenden Operationen:
* Das vocab.stoi-Wörterbuch ermöglicht es uns, ein Wort in seinen Index im Wörterbuch umzuwandeln.
* vocab.itos macht das Gegenteil – es wandelt eine Zahl in ein Wort um.
* vocab.vectors ist das Array der Einbettungsvektoren. Um die Einbettung eines Wortes s zu erhalten, müssen wir vocab.vectors[vocab.stoi[s]] verwenden.
Hier ist ein Beispiel für die Manipulation von Einbettungen, um die Gleichung kind-man+woman = queen zu demonstrieren (ich musste den Koeffizienten ein wenig anpassen, damit es funktioniert):
# get the vector corresponding to kind-man+woman
qvec = vocab.vectors[vocab.stoi['king']]-vocab.vectors[vocab.stoi['man']]+1.3*vocab.vectors[vocab.stoi['woman']]
# find the index of the closest embedding vector
d = torch.sum((vocab.vectors-qvec)**2,dim=1)
min_idx = torch.argmin(d)
# find the corresponding word
vocab.itos[min_idx]
Um den Klassifikator mit diesen Einbettungen zu trainieren, müssen wir zunächst unseren Datensatz mit dem GloVe-Vokabular codieren:
def offsetify(b):
# first, compute data tensor from all sequences
x = [torch.tensor(encode(t[1],voc=vocab)) for t in b] # pass the instance of vocab to encode function!
# now, compute the offsets by accumulating the tensor of sequence lengths
o = [0] + [len(t) for t in x]
o = torch.tensor(o[:-1]).cumsum(dim=0)
return (
torch.LongTensor([t[0]-1 for t in b]), # labels
torch.cat(x), # text
o
)
Wie wir oben gesehen haben, werden alle Vektoreinbettungen in der vocab.vectors-Matrix gespeichert. Dadurch wird es sehr einfach, diese Gewichte durch einfaches Kopieren in die Gewichte der Einbettungsschicht zu laden:
net = EmbedClassifier(len(vocab),len(vocab.vectors[0]),len(classes))
net.embedding.weight.data = vocab.vectors
net = net.to(device)
Lassen Sie uns nun unser Modell trainieren und sehen, ob wir bessere Ergebnisse erzielen:
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=offsetify, shuffle=True)
train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)
Einer der Gründe, warum wir keine signifikante Steigerung der Genauigkeit sehen, liegt darin, dass einige Wörter aus unserem Datensatz im vortrainierten GloVe-Vokabular fehlen und daher im Wesentlichen ignoriert werden. Um dies zu überwinden, können wir eigene Embeddings auf unserem Datensatz trainieren.
Kontextuelle Einbettungen
Eine zentrale Einschränkung traditioneller vortrainierter Einbettungsrepräsentationen wie Word2Vec ist das Problem der Bedeutungsunterscheidung von Wörtern. Während vortrainierte Einbettungen einen Teil der Bedeutung von Wörtern im Kontext erfassen können, wird jede mögliche Bedeutung eines Wortes in derselben Einbettung kodiert. Dies kann in nachgelagerten Modellen zu Problemen führen, da viele Wörter, wie das Wort „play“, je nach Kontext unterschiedliche Bedeutungen haben.
Zum Beispiel hat das Wort „play“ in den folgenden zwei Sätzen eine ganz unterschiedliche Bedeutung: - Ich war in einem Theaterstück. - John möchte mit seinen Freunden spielen.
Die oben genannten vortrainierten Einbettungen repräsentieren beide Bedeutungen des Wortes „play“ in derselben Einbettung. Um diese Einschränkung zu überwinden, müssen wir Einbettungen basierend auf dem Sprachmodell erstellen, das auf einem großen Textkorpus trainiert wurde und versteht, wie Wörter in unterschiedlichen Kontexten zusammengefügt werden können. Die Diskussion über kontextuelle Einbettungen liegt außerhalb des Umfangs dieses Tutorials, aber wir werden darauf zurückkommen, wenn wir in der nächsten Einheit über Sprachmodelle sprechen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einbettungen
In unserem vorherigen Beispiel haben wir mit hochdimensionalen Bag-of-Words-Vektoren der Länge vocab_size gearbeitet und die niedrigdimensionalen Positionsdarstellungsvektoren explizit in eine spärliche One-Hot-Darstellung umgewandelt. Diese One-Hot-Darstellung ist nicht speichereffizient. Außerdem wird jedes Wort unabhängig von den anderen behandelt, sodass One-Hot-codierte Vektoren keine semantischen Ähnlichkeiten zwischen Wörtern ausdrücken.
In dieser Einheit werden wir weiterhin den News AG-Datensatz untersuchen. Zu Beginn laden wir die Daten und holen einige Definitionen aus der vorherigen Einheit.
import tensorflow as tf
from tensorflow import keras
import tensorflow_datasets as tfds
import numpy as np
ds_train, ds_test = tfds.load('ag_news_subset').values()
Was ist ein Embedding?
Die Idee eines Embeddings besteht darin, Wörter mithilfe von niedrigdimensionalen, dichten Vektoren darzustellen, die die semantische Bedeutung des Wortes widerspiegeln. Später werden wir besprechen, wie man sinnvolle Wort-Embeddings erstellt, aber vorerst betrachten wir Embeddings einfach als eine Möglichkeit, die Dimensionalität eines Wortvektors zu reduzieren.
Eine Embedding-Schicht nimmt also ein Wort als Eingabe und erzeugt einen Ausgabevektor mit einer festgelegten embedding_size. In gewisser Weise ähnelt sie einer Dense-Schicht, aber anstatt einen One-Hot-codierten Vektor als Eingabe zu verwenden, kann sie eine Wortnummer verarbeiten.
Indem wir eine Embedding-Schicht als erste Schicht in unserem Netzwerk verwenden, können wir von einem Bag-of-Words-Modell zu einem Embedding-Bag-Modell wechseln. Dabei wird jedes Wort in unserem Text zunächst in das entsprechende Embedding umgewandelt, und anschließend wird eine Aggregationsfunktion über alle diese Embeddings berechnet, wie z. B. sum, average oder max.

Unser Klassifikator-Neuronales-Netzwerk besteht aus den folgenden Schichten:
TextVectorization-Schicht, die einen String als Eingabe nimmt und einen Tensor mit Token-Nummern erzeugt. Wir werden eine angemessene Vokabulargrößevocab_sizefestlegen und weniger häufig verwendete Wörter ignorieren. Die Eingabeform wird 1 sein, und die Ausgabeform wird $n$ sein, da wir $n$ Token als Ergebnis erhalten, von denen jedes Zahlen von 0 bisvocab_sizeenthält.Embedding-Schicht, die $n$ Zahlen nimmt und jede Zahl in einen dichten Vektor einer bestimmten Länge (in unserem Beispiel 100) reduziert. Der Eingabetensor der Form $n$ wird somit in einen $n\times 100$-Tensor umgewandelt.- Aggregationsschicht, die den Durchschnitt dieses Tensors entlang der ersten Achse berechnet, d. h. sie berechnet den Durchschnitt aller $n$ Eingabetensoren, die verschiedenen Wörtern entsprechen. Um diese Schicht zu implementieren, verwenden wir eine
Lambda-Schicht und übergeben ihr die Funktion zur Berechnung des Durchschnitts. Die Ausgabe wird die Form 100 haben und die numerische Darstellung der gesamten Eingabesequenz sein. - Abschließender
Dense-linearer Klassifikator.
vocab_size = 30000
batch_size = 128
vectorizer = keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,input_shape=(1,))
model = keras.models.Sequential([
vectorizer,
keras.layers.Embedding(vocab_size,100),
keras.layers.Lambda(lambda x: tf.reduce_mean(x,axis=1)),
keras.layers.Dense(4, activation='softmax')
])
model.summary()
Im summary-Ausdruck entspricht die erste Tensor-Dimension None in der output shape-Spalte der Minibatch-Größe, und die zweite entspricht der Länge der Token-Sequenz. Alle Token-Sequenzen im Minibatch haben unterschiedliche Längen. Wir werden im nächsten Abschnitt besprechen, wie man damit umgeht.
Jetzt lass uns das Netzwerk trainieren:
def extract_text(x):
return x['title']+' '+x['description']
def tupelize(x):
return (extract_text(x),x['label'])
print("Training vectorizer")
vectorizer.adapt(ds_train.take(500).map(extract_text))
model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'])
model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))
> Hinweis: Wir erstellen den Vektorisierer basierend auf einem Teil der Daten. Dies wird durchgeführt, um den Prozess zu beschleunigen, und es könnte dazu führen, dass nicht alle Token aus unserem Text im Vokabular enthalten sind. In diesem Fall würden diese Token ignoriert, was zu einer leicht geringeren Genauigkeit führen kann. Allerdings liefert ein Teil des Textes in der Praxis oft eine gute Schätzung des Vokabulars.
Umgang mit variablen Sequenzgrößen
Lassen Sie uns verstehen, wie das Training in Minibatches abläuft. Im obigen Beispiel hat der Eingabetensor die Dimension 1, und wir verwenden 128 lange Minibatches, sodass die tatsächliche Größe des Tensors $128 \times 1$ beträgt. Allerdings ist die Anzahl der Tokens in jedem Satz unterschiedlich. Wenn wir die TextVectorization-Schicht auf eine einzelne Eingabe anwenden, ist die Anzahl der zurückgegebenen Tokens unterschiedlich, abhängig davon, wie der Text tokenisiert wird:
print(vectorizer('Hello, world!'))
print(vectorizer('I am glad to meet you!'))
Wenn wir den Vektorisierer jedoch auf mehrere Sequenzen anwenden, muss er einen Tensor mit rechteckiger Form erzeugen, sodass er nicht verwendete Elemente mit dem PAD-Token (was in unserem Fall null ist) auffüllt:
vectorizer(['Hello, world!','I am glad to meet you!'])
Hier können wir die Einbettungen sehen:
model.layers[1](vectorizer(['Hello, world!','I am glad to meet you!'])).numpy()
> Hinweis: Um die Menge an Auffüllung zu minimieren, kann es in einigen Fällen sinnvoll sein, alle Sequenzen im Datensatz in der Reihenfolge zunehmender Länge (oder genauer gesagt, Anzahl der Token) zu sortieren. Dies stellt sicher, dass jede Minibatch Sequenzen ähnlicher Länge enthält.
Semantische Einbettungen: Word2Vec
In unserem vorherigen Beispiel hat die Einbettungsschicht gelernt, Wörter in Vektorrepräsentationen abzubilden, jedoch hatten diese Repräsentationen keine semantische Bedeutung. Es wäre wünschenswert, eine Vektorrepräsentation zu erlernen, bei der ähnliche Wörter oder Synonyme Vektoren entsprechen, die in Bezug auf eine Vektordistanz (zum Beispiel euklidische Distanz) nahe beieinander liegen.
Um dies zu erreichen, müssen wir unser Einbettungsmodell mit einer großen Textsammlung vortrainieren, indem wir eine Technik wie Word2Vec verwenden. Diese basiert auf zwei Hauptarchitekturen, die verwendet werden, um eine verteilte Repräsentation von Wörtern zu erzeugen:
- Continuous bag-of-words (CBoW), bei dem wir das Modell darauf trainieren, ein Wort aus dem umgebenden Kontext vorherzusagen. Gegeben ist das N-Gramm $(W_{-2},W_{-1},W_0,W_1,W_2)$, und das Ziel des Modells ist es, $W_0$ aus $(W_{-2},W_{-1},W_1,W_2)$ vorherzusagen.
- Continuous skip-gram ist das Gegenteil von CBoW. Das Modell verwendet das umgebende Fenster von Kontextwörtern, um das aktuelle Wort vorherzusagen.
CBoW ist schneller, während Skip-Gram zwar langsamer ist, aber eine bessere Repräsentation für seltene Wörter liefert.

Um mit der Word2Vec-Einbettung, die auf dem Google-News-Datensatz vortrainiert wurde, zu experimentieren, können wir die gensim-Bibliothek verwenden. Unten finden wir die Wörter, die 'neural' am ähnlichsten sind.
> Hinweis: Wenn Sie zum ersten Mal Wortvektoren erstellen, kann das Herunterladen einige Zeit in Anspruch nehmen!
import gensim.downloader as api
w2v = api.load('word2vec-google-news-300')
for w,p in w2v.most_similar('neural'):
print(f"{w} -> {p}")
Wir können auch die Vektoreinbettung aus dem Wort extrahieren, um sie beim Training des Klassifikationsmodells zu verwenden. Die Einbettung hat 300 Komponenten, aber hier zeigen wir aus Gründen der Klarheit nur die ersten 20 Komponenten des Vektors:
w2v['play'][:20]
Das Großartige an semantischen Einbettungen ist, dass man die Vektor-Codierung basierend auf Semantik manipulieren kann. Zum Beispiel können wir nach einem Wort suchen, dessen Vektorrepräsentation so nah wie möglich an den Wörtern König und Frau ist und so weit wie möglich vom Wort Mann entfernt ist:
w2v.most_similar(positive=['king','woman'],negative=['man'])[0]
Ein Beispiel oben verwendet einige interne GenSym-Magie, aber die zugrunde liegende Logik ist tatsächlich ziemlich einfach. Eine interessante Sache an Einbettungen ist, dass man normale Vektoroperationen auf Einbettungsvektoren durchführen kann, und das würde Operationen auf Wortbedeutungen widerspiegeln. Das obige Beispiel kann in Form von Vektoroperationen ausgedrückt werden: Wir berechnen den Vektor, der KÖNIG-MANN+FRAU entspricht (Operationen + und - werden auf Vektordarstellungen der entsprechenden Wörter durchgeführt), und finden dann das nächstgelegene Wort im Wörterbuch zu diesem Vektor:
# get the vector corresponding to kind-man+woman
qvec = w2v['king']-1.7*w2v['man']+1.7*w2v['woman']
# find the index of the closest embedding vector
d = np.sum((w2v.vectors-qvec)**2,axis=1)
min_idx = np.argmin(d)
# find the corresponding word
w2v.index_to_key[min_idx]
> NOTE: Wir mussten kleine Koeffizienten zu den man- und woman-Vektoren hinzufügen – versuchen Sie, diese zu entfernen, um zu sehen, was passiert.
Um den nächstgelegenen Vektor zu finden, verwenden wir TensorFlow-Mechanismen, um einen Vektor von Abständen zwischen unserem Vektor und allen Vektoren im Vokabular zu berechnen, und finden dann den Index des minimalen Wortes mit argmin.
Während Word2Vec eine großartige Möglichkeit zu sein scheint, die Semantik von Wörtern auszudrücken, hat es viele Nachteile, darunter die folgenden:
- Sowohl CBoW- als auch Skip-Gram-Modelle sind prädiktive Einbettungen und berücksichtigen nur den lokalen Kontext. Word2Vec nutzt den globalen Kontext nicht.
- Word2Vec berücksichtigt nicht die Morphologie von Wörtern, d. h. die Tatsache, dass die Bedeutung eines Wortes von verschiedenen Teilen des Wortes, wie z. B. dem Stamm, abhängen kann.
FastText versucht, die zweite Einschränkung zu überwinden, und baut auf Word2Vec auf, indem es Vektordarstellungen für jedes Wort und die Zeichen-n-Gramme innerhalb jedes Wortes lernt. Die Werte der Darstellungen werden dann bei jedem Trainingsschritt zu einem Vektor gemittelt. Obwohl dies eine Menge zusätzlicher Berechnungen beim Pretraining erfordert, ermöglicht es den Wort-Einbettungen, Subwort-Informationen zu kodieren.
Eine andere Methode, GloVe, verwendet einen anderen Ansatz für Wort-Einbettungen, der auf der Faktorisierung der Wort-Kontext-Matrix basiert. Zunächst wird eine große Matrix erstellt, die die Anzahl der Wortvorkommen in verschiedenen Kontexten zählt, und dann wird versucht, diese Matrix in niedrigeren Dimensionen so darzustellen, dass der Rekonstruktionsverlust minimiert wird.
Die gensim-Bibliothek unterstützt diese Wort-Einbettungen, und Sie können mit ihnen experimentieren, indem Sie den Modell-Ladecode oben ändern.
Verwendung vortrainierter Embeddings in Keras
Wir können das obige Beispiel anpassen, um die Matrix in unserer Embedding-Schicht mit semantischen Embeddings wie Word2Vec vorab zu füllen. Die Vokabulare des vortrainierten Embeddings und des Textkorpus werden wahrscheinlich nicht übereinstimmen, daher müssen wir eines auswählen. Hier untersuchen wir die beiden möglichen Optionen: die Verwendung des Tokenizer-Vokabulars und die Verwendung des Vokabulars aus den Word2Vec-Embeddings.
Verwendung des Tokenizer-Vokabulars
Bei der Verwendung des Tokenizer-Vokabulars haben einige Wörter aus dem Vokabular entsprechende Word2Vec-Embeddings, während andere fehlen. Angenommen, unsere Vokabulargröße ist vocab_size und die Länge des Word2Vec-Embedding-Vektors ist embed_size, wird die Embedding-Schicht durch eine Gewichtsmatrix der Form vocab_size$\times$embed_size dargestellt. Wir füllen diese Matrix, indem wir das Vokabular durchgehen:
embed_size = len(w2v.get_vector('hello'))
print(f'Embedding size: {embed_size}')
vocab = vectorizer.get_vocabulary()
W = np.zeros((vocab_size,embed_size))
print('Populating matrix, this will take some time...',end='')
found, not_found = 0,0
for i,w in enumerate(vocab):
try:
W[i] = w2v.get_vector(w)
found+=1
except:
# W[i] = np.random.normal(0.0,0.3,size=(embed_size,))
not_found+=1
print(f"Done, found {found} words, {not_found} words missing")
Für Wörter, die nicht im Word2Vec-Wortschatz vorhanden sind, können wir sie entweder als Nullen belassen oder einen zufälligen Vektor generieren.
Nun können wir eine Einbettungsschicht mit vortrainierten Gewichten definieren:
emb = keras.layers.Embedding(vocab_size,embed_size,weights=[W],trainable=False)
model = keras.models.Sequential([
vectorizer, emb,
keras.layers.Lambda(lambda x: tf.reduce_mean(x,axis=1)),
keras.layers.Dense(4, activation='softmax')
])
model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'])
model.fit(ds_train.map(tupelize).batch(batch_size),
validation_data=ds_test.map(tupelize).batch(batch_size))
> Hinweis: Beachten Sie, dass wir trainable=False setzen, wenn wir die Embedding erstellen. Das bedeutet, dass wir die Embedding-Schicht nicht neu trainieren. Dies kann dazu führen, dass die Genauigkeit etwas geringer ist, aber es beschleunigt das Training.
Verwendung des Embedding-Vokabulars
Ein Problem bei dem vorherigen Ansatz ist, dass die in der TextVectorization und Embedding verwendeten Vokabulare unterschiedlich sind. Um dieses Problem zu lösen, können wir eine der folgenden Lösungen verwenden: * Das Word2Vec-Modell mit unserem Vokabular neu trainieren. * Unser Dataset mit dem Vokabular aus dem vortrainierten Word2Vec-Modell laden. Die Vokabulare, die zum Laden des Datasets verwendet werden, können während des Ladens angegeben werden.
Der zweite Ansatz scheint einfacher zu sein, also setzen wir ihn um. Zunächst erstellen wir eine TextVectorization-Schicht mit dem angegebenen Vokabular, das aus den Word2Vec-Embeddings stammt:
vocab = list(w2v.vocab.keys())
vectorizer = keras.layers.experimental.preprocessing.TextVectorization(input_shape=(1,))
vectorizer.set_vocabulary(vocab)
Die Gensim-Wort-Einbettungsbibliothek enthält eine praktische Funktion, get_keras_embeddings, die automatisch die entsprechende Keras-Einbettungsschicht für Sie erstellt.
model = keras.models.Sequential([
vectorizer,
w2v.get_keras_embedding(train_embeddings=False),
keras.layers.Lambda(lambda x: tf.reduce_mean(x,axis=1)),
keras.layers.Dense(4, activation='softmax')
])
model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'])
model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128),epochs=5)
Einer der Gründe, warum wir keine höhere Genauigkeit sehen, ist, dass einige Wörter aus unserem Datensatz im vortrainierten GloVe-Vokabular fehlen und daher im Wesentlichen ignoriert werden. Um dies zu überwinden, können wir unsere eigenen Einbettungen basierend auf unserem Datensatz trainieren.
Kontextuelle Einbettungen
Eine zentrale Einschränkung traditioneller vortrainierter Einbettungsrepräsentationen wie Word2Vec ist die Tatsache, dass sie zwar eine gewisse Bedeutung eines Wortes erfassen können, aber nicht zwischen verschiedenen Bedeutungen unterscheiden können. Dies kann in nachgelagerten Modellen zu Problemen führen.
Zum Beispiel hat das Wort „play“ in diesen beiden Sätzen unterschiedliche Bedeutungen: - Ich war in einem Theaterstück im Theater. - John möchte mit seinen Freunden spielen.
Die vortrainierten Einbettungen, über die wir gesprochen haben, repräsentieren beide Bedeutungen des Wortes „play“ in derselben Einbettung. Um diese Einschränkung zu überwinden, müssen wir Einbettungen basierend auf dem Sprachmodell erstellen, das auf einem großen Textkorpus trainiert wurde und versteht, wie Wörter in unterschiedlichen Kontexten zusammengefügt werden können. Die Diskussion über kontextuelle Einbettungen liegt außerhalb des Umfangs dieses Tutorials, aber wir werden darauf zurückkommen, wenn wir im nächsten Abschnitt über Sprachmodelle sprechen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Einbettungen
Quiz vor der Vorlesung
Beim Training von Klassifikatoren basierend auf BoW oder TF/IDF haben wir mit hochdimensionalen Bag-of-Words-Vektoren gearbeitet, deren Länge vocab_size entspricht. Dabei haben wir explizit von niedrigdimensionalen Positionsdarstellungsvektoren in spärliche One-Hot-Darstellungen umgewandelt. Diese One-Hot-Darstellung ist jedoch nicht speichereffizient. Außerdem wird jedes Wort unabhängig von den anderen behandelt, d. h. One-Hot-codierte Vektoren drücken keine semantische Ähnlichkeit zwischen Wörtern aus.
Die Idee der Einbettung besteht darin, Wörter durch niedrigdimensionale dichte Vektoren darzustellen, die irgendwie die semantische Bedeutung eines Wortes widerspiegeln. Später werden wir besprechen, wie man sinnvolle Wort-Einbettungen erstellt, aber vorerst können wir Einbettungen als eine Methode betrachten, die Dimensionalität eines Wortvektors zu reduzieren.
Die Einbettungsschicht würde also ein Wort als Eingabe nehmen und einen Ausgabesektor mit einer festgelegten embedding_size erzeugen. In gewisser Weise ähnelt sie einer Linear-Schicht, aber anstatt einen One-Hot-codierten Vektor zu verwenden, kann sie eine Wortnummer als Eingabe akzeptieren, wodurch wir große One-Hot-codierte Vektoren vermeiden können.
Durch die Verwendung einer Einbettungsschicht als erste Schicht in unserem Klassifikator-Netzwerk können wir von einem Bag-of-Words-Modell zu einem Embedding-Bag-Modell wechseln, bei dem wir zunächst jedes Wort in unserem Text in die entsprechende Einbettung umwandeln und dann eine Aggregatfunktion über alle diese Einbettungen berechnen, wie z. B. sum, average oder max.

> Bild vom Autor
✍️ Übungen: Einbettungen
Setze dein Lernen in den folgenden Notebooks fort: * Einbettungen mit PyTorch * Einbettungen mit TensorFlow
Semantische Einbettungen: Word2Vec
Während die Einbettungsschicht gelernt hat, Wörter in Vektordarstellungen zu überführen, hat diese Darstellung jedoch nicht unbedingt eine semantische Bedeutung. Es wäre wünschenswert, eine Vektordarstellung zu lernen, bei der ähnliche Wörter oder Synonyme Vektoren entsprechen, die in Bezug auf eine Vektordistanz (z. B. euklidische Distanz) nahe beieinander liegen.
Um dies zu erreichen, müssen wir unser Einbettungsmodell auf einer großen Textsammlung in einer spezifischen Weise vortrainieren. Eine Methode, semantische Einbettungen zu trainieren, nennt sich Word2Vec. Es basiert auf zwei Hauptarchitekturen, die verwendet werden, um eine verteilte Darstellung von Wörtern zu erzeugen:
- Continuous Bag-of-Words (CBoW) — In dieser Architektur trainieren wir das Modell darauf, ein Wort aus dem umgebenden Kontext vorherzusagen. Gegeben das Ngram $(W_{-2},W_{-1},W_0,W_1,W_2)$, ist das Ziel des Modells, $W_0$ aus $(W_{-2},W_{-1},W_1,W_2)$ vorherzusagen.
- Continuous Skip-Gram ist das Gegenteil von CBoW. Das Modell verwendet das umgebende Fenster von Kontextwörtern, um das aktuelle Wort vorherzusagen.
CBoW ist schneller, während Skip-Gram langsamer ist, aber eine bessere Darstellung von seltenen Wörtern liefert.

> Bild aus diesem Paper
Word2Vec vortrainierte Einbettungen (sowie andere ähnliche Modelle wie GloVe) können auch anstelle der Einbettungsschicht in neuronalen Netzwerken verwendet werden. Allerdings müssen wir uns mit Vokabularen auseinandersetzen, da das Vokabular, das zum Vortrainieren von Word2Vec/GloVe verwendet wurde, wahrscheinlich von dem Vokabular in unserem Textkorpus abweicht. Schau dir die oben genannten Notebooks an, um zu sehen, wie dieses Problem gelöst werden kann.
Kontextuelle Einbettungen
Eine zentrale Einschränkung traditioneller vortrainierter Einbettungsdarstellungen wie Word2Vec ist das Problem der Mehrdeutigkeit von Wortbedeutungen. Während vortrainierte Einbettungen einige Bedeutungen von Wörtern im Kontext erfassen können, wird jede mögliche Bedeutung eines Wortes in derselben Einbettung kodiert. Dies kann Probleme in nachgelagerten Modellen verursachen, da viele Wörter, wie das Wort 'play', je nach Kontext unterschiedliche Bedeutungen haben.
Zum Beispiel hat das Wort 'play' in diesen beiden Sätzen ganz unterschiedliche Bedeutungen:
- Ich war in einem Theaterstück.
- John möchte mit seinen Freunden spielen.
Die oben genannten vortrainierten Einbettungen repräsentieren beide Bedeutungen des Wortes 'play' in derselben Einbettung. Um diese Einschränkung zu überwinden, müssen wir Einbettungen basierend auf dem Sprachmodell erstellen, das auf einem großen Textkorpus trainiert wurde und weiß, wie Wörter in verschiedenen Kontexten zusammengefügt werden können. Die Diskussion über kontextuelle Einbettungen liegt außerhalb des Umfangs dieses Tutorials, aber wir werden später im Kurs darauf zurückkommen, wenn wir über Sprachmodelle sprechen.
Fazit
In dieser Lektion hast du gelernt, wie man Einbettungsschichten in TensorFlow und PyTorch erstellt und verwendet, um die semantische Bedeutung von Wörtern besser widerzuspiegeln.
🚀 Herausforderung
Word2Vec wurde für einige interessante Anwendungen verwendet, einschließlich der Generierung von Songtexten und Gedichten. Schau dir diesen Artikel an, der erklärt, wie der Autor Word2Vec verwendet hat, um Gedichte zu generieren. Sieh dir auch dieses Video von Dan Shiffmann an, um eine andere Erklärung dieser Technik zu entdecken. Versuche dann, diese Techniken auf deinen eigenen Textkorpus anzuwenden, vielleicht aus Kaggle.
Quiz nach der Vorlesung
Überprüfung & Selbststudium
Lies dieses Paper über Word2Vec: Efficient Estimation of Word Representations in Vector Space
Aufgabe: Notebooks
Training CBoW-Modell
Dieses Notebook ist Teil des AI for Beginners Curriculum
In diesem Beispiel werden wir ein CBoW-Sprachmodell trainieren, um unseren eigenen Word2Vec-Einbettungsraum zu erstellen. Als Textquelle verwenden wir den AG News-Datensatz.
import torch
import torchtext
import os
import collections
import builtins
import random
import numpy as np
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
Zuerst laden wir unser Dataset und definieren Tokenizer und Vokabular. Wir setzen vocab_size auf 5000, um die Berechnungen etwas zu begrenzen.
def load_dataset(ngrams = 1, min_freq = 1, vocab_size = 5000 , lines_cnt = 500):
tokenizer = torchtext.data.utils.get_tokenizer('basic_english')
print("Loading dataset...")
test_dataset, train_dataset = torchtext.datasets.AG_NEWS(root='./data')
train_dataset = list(train_dataset)
test_dataset = list(test_dataset)
classes = ['World', 'Sports', 'Business', 'Sci/Tech']
print('Building vocab...')
counter = collections.Counter()
for i, (_, line) in enumerate(train_dataset):
counter.update(torchtext.data.utils.ngrams_iterator(tokenizer(line),ngrams=ngrams))
if i == lines_cnt:
break
vocab = torchtext.vocab.Vocab(collections.Counter(dict(counter.most_common(vocab_size))), min_freq=min_freq)
return train_dataset, test_dataset, classes, vocab, tokenizer
train_dataset, test_dataset, _, vocab, tokenizer = load_dataset()
def encode(x, vocabulary, tokenizer = tokenizer):
return [vocabulary[s] for s in tokenizer(x)]
CBoW-Modell
CBoW lernt, ein Wort basierend auf den $2N$ benachbarten Wörtern vorherzusagen. Zum Beispiel, wenn $N=1$, erhalten wir die folgenden Paare aus dem Satz I like to train networks: (like,I), (I, like), (to, like), (like,to), (train,to), (to, train), (networks, train), (train,networks). Hier ist das erste Wort das benachbarte Wort, das als Eingabe verwendet wird, und das zweite Wort ist das, das wir vorhersagen.
Um ein Netzwerk zu erstellen, das das nächste Wort vorhersagt, müssen wir das benachbarte Wort als Eingabe bereitstellen und die Wortnummer als Ausgabe erhalten. Die Architektur des CBoW-Netzwerks sieht wie folgt aus:
- Das Eingabewort wird durch die Embedding-Schicht geleitet. Diese Embedding-Schicht wird unser Word2Vec-Embedding sein, daher definieren wir sie separat als die Variable
embedder. In diesem Beispiel verwenden wir eine Embedding-Größe von 30, obwohl Sie möglicherweise mit höheren Dimensionen experimentieren möchten (echtes Word2Vec hat 300). - Der Embedding-Vektor wird dann an eine lineare Schicht weitergegeben, die das Ausgabewort vorhersagt. Daher hat sie
vocab_sizeNeuronen.
Für die Ausgabe: Wenn wir CrossEntropyLoss als Verlustfunktion verwenden, müssen wir auch nur die Wortnummern als erwartete Ergebnisse bereitstellen, ohne One-Hot-Encoding.
vocab_size = len(vocab)
embedder = torch.nn.Embedding(num_embeddings = vocab_size, embedding_dim = 30)
model = torch.nn.Sequential(
embedder,
torch.nn.Linear(in_features = 30, out_features = vocab_size),
)
print(model)
Vorbereitung der Trainingsdaten
Nun programmieren wir die Hauptfunktion, die CBoW-Wortpaare aus Text berechnet. Diese Funktion ermöglicht es uns, die Fenstergröße festzulegen und gibt ein Set von Paaren zurück – Eingabe- und Ausgabewort. Beachten Sie, dass diese Funktion sowohl auf Wörter als auch auf Vektoren/Tensoren angewendet werden kann – was es uns ermöglicht, den Text zu kodieren, bevor er an die Funktion to_cbow übergeben wird.
def to_cbow(sent,window_size=2):
res = []
for i,x in enumerate(sent):
for j in range(max(0,i-window_size),min(i+window_size+1,len(sent))):
if i!=j:
res.append([sent[j],x])
return res
print(to_cbow(['I','like','to','train','networks']))
print(to_cbow(encode('I like to train networks', vocab)))
Lass uns den Trainingsdatensatz vorbereiten. Wir werden alle Nachrichten durchgehen, to_cbow aufrufen, um die Liste der Wortpaare zu erhalten, und diese Paare zu X und Y hinzufügen. Aus Zeitgründen werden wir nur die ersten 10.000 Nachrichten berücksichtigen - du kannst die Einschränkung leicht entfernen, falls du mehr Zeit hast und bessere Einbettungen erhalten möchtest :)
X = []
Y = []
for i, x in zip(range(10000), train_dataset):
for w1, w2 in to_cbow(encode(x[1], vocab), window_size = 5):
X.append(w1)
Y.append(w2)
X = torch.tensor(X)
Y = torch.tensor(Y)
Wir werden diese Daten auch in einen Datensatz umwandeln und einen Datenlader erstellen:
class SimpleIterableDataset(torch.utils.data.IterableDataset):
def __init__(self, X, Y):
super(SimpleIterableDataset).__init__()
self.data = []
for i in range(len(X)):
self.data.append( (Y[i], X[i]) )
random.shuffle(self.data)
def __iter__(self):
return iter(self.data)
Wir werden diese Daten auch in einen Datensatz umwandeln und einen Datenlader erstellen:
ds = SimpleIterableDataset(X, Y)
dl = torch.utils.data.DataLoader(ds, batch_size = 256)
Jetzt beginnen wir mit dem eigentlichen Training. Wir verwenden den SGD-Optimierer mit einer ziemlich hohen Lernrate. Du kannst auch andere Optimierer ausprobieren, wie zum Beispiel Adam. Wir werden zunächst für 10 Epochen trainieren – und du kannst diese Zelle erneut ausführen, wenn du einen noch geringeren Verlust erzielen möchtest.
def train_epoch(net, dataloader, lr = 0.01, optimizer = None, loss_fn = torch.nn.CrossEntropyLoss(), epochs = None, report_freq = 1):
optimizer = optimizer or torch.optim.Adam(net.parameters(), lr = lr)
loss_fn = loss_fn.to(device)
net.train()
for i in range(epochs):
total_loss, j = 0, 0,
for labels, features in dataloader:
optimizer.zero_grad()
features, labels = features.to(device), labels.to(device)
out = net(features)
loss = loss_fn(out, labels)
loss.backward()
optimizer.step()
total_loss += loss
j += 1
if i % report_freq == 0:
print(f"Epoch: {i+1}: loss={total_loss.item()/j}")
return total_loss.item()/j
train_epoch(net = model, dataloader = dl, optimizer = torch.optim.SGD(model.parameters(), lr = 0.1), loss_fn = torch.nn.CrossEntropyLoss(), epochs = 10)
Ausprobieren von Word2Vec
Um Word2Vec zu verwenden, extrahieren wir die Vektoren, die den Wörtern in unserem Vokabular entsprechen:
vectors = torch.stack([embedder(torch.tensor(vocab[s])) for s in vocab.itos], 0)
Lass uns sehen, wie das Wort Paris beispielsweise in einen Vektor codiert wird:
paris_vec = embedder(torch.tensor(vocab['paris']))
print(paris_vec)
Es ist interessant, Word2Vec zu verwenden, um nach Synonymen zu suchen. Die folgende Funktion gibt die n nächsten Wörter zu einer gegebenen Eingabe zurück. Um sie zu finden, berechnen wir die Norm von $|w_i - v|$, wobei $v$ der Vektor ist, der unserem Eingabewort entspricht, und $w_i$ die Kodierung des $i$-ten Wortes im Vokabular ist. Anschließend sortieren wir das Array und geben die entsprechenden Indizes mit argsort zurück, wobei wir die ersten n Elemente der Liste nehmen, die die Positionen der nächsten Wörter im Vokabular kodieren.
def close_words(x, n = 5):
vec = embedder(torch.tensor(vocab[x]))
top5 = np.linalg.norm(vectors.detach().numpy() - vec.detach().numpy(), axis = 1).argsort()[:n]
return [ vocab.itos[x] for x in top5 ]
close_words('microsoft')
close_words('basketball')
close_words('funds')
Erkenntnis
Mit cleveren Techniken wie CBoW können wir ein Word2Vec-Modell trainieren. Du kannst auch versuchen, ein Skip-Gram-Modell zu trainieren, das darauf ausgelegt ist, das benachbarte Wort basierend auf dem zentralen Wort vorherzusagen, und sehen, wie gut es funktioniert.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Training eines CBoW-Modells
Dieses Notebook ist Teil des AI for Beginners Curriculum
In diesem Beispiel werden wir ein CBoW-Sprachmodell trainieren, um unseren eigenen Word2Vec-Embedding-Raum zu erstellen. Wir verwenden das AG News-Dataset als Textquelle.
from tensorflow import keras
import tensorflow as tf
import tensorflow_datasets as tfds
import numpy as np
Wir beginnen mit dem Laden des Datensatzes:
ds_train, ds_test = tfds.load('ag_news_subset').values()
CBoW-Modell
CBoW lernt, ein Wort basierend auf den $2N$ benachbarten Wörtern vorherzusagen. Zum Beispiel, wenn $N=1$, erhalten wir die folgenden Paare aus dem Satz I like to train networks: (like,I), (I, like), (to, like), (like,to), (train,to), (to, train), (networks, train), (train,networks). Hier ist das erste Wort das benachbarte Wort, das als Eingabe verwendet wird, und das zweite Wort ist das, das wir vorhersagen.
Um ein Netzwerk zu erstellen, das das nächste Wort vorhersagt, müssen wir das benachbarte Wort als Eingabe bereitstellen und die Wortnummer als Ausgabe erhalten. Die Architektur des CBoW-Netzwerks sieht wie folgt aus:
- Das Eingabewort wird durch die Embedding-Schicht geleitet. Diese Embedding-Schicht wird unser Word2Vec-Embedding sein, daher definieren wir sie separat als
embedder-Variable. In diesem Beispiel verwenden wir eine Embedding-Größe von 30, obwohl Sie möglicherweise mit höheren Dimensionen experimentieren möchten (echtes Word2Vec hat 300). - Der Embedding-Vektor wird dann an eine Dense-Schicht weitergegeben, die das Ausgabewort vorhersagt. Daher hat sie
vocab_sizeNeuronen.
Die Embedding-Schicht in Keras weiß automatisch, wie sie numerische Eingaben in One-Hot-Encoding umwandelt, sodass wir das Eingabewort nicht separat One-Hot-Encoden müssen. Wir geben input_length=1 an, um anzuzeigen, dass wir nur ein Wort in der Eingabesequenz möchten – normalerweise ist die Embedding-Schicht für längere Sequenzen ausgelegt.
Für die Ausgabe, wenn wir sparse_categorical_crossentropy als Verlustfunktion verwenden, müssen wir auch nur Wortnummern als erwartete Ergebnisse bereitstellen, ohne One-Hot-Encoding.
Wir setzen vocab_size auf 5000, um die Berechnungen etwas zu begrenzen. Außerdem definieren wir einen Vektorisierer, den wir später verwenden werden.
vocab_size = 5000
vectorizer = keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,input_shape=(1,))
embedder = keras.layers.Embedding(vocab_size,30,input_length=1)
model = keras.Sequential([
embedder,
keras.layers.Dense(vocab_size,activation='softmax')
])
model.summary()
Lassen Sie uns den Vektorisierer initialisieren und das Vokabular herausnehmen:
def extract_text(x):
return x['title']+' '+x['description']
vectorizer.adapt(ds_train.take(500).map(extract_text))
vocab = vectorizer.get_vocabulary()
Vorbereitung der Trainingsdaten
Nun programmieren wir die Hauptfunktion, die CBoW-Wortpaare aus Text berechnet. Diese Funktion ermöglicht es uns, die Fenstergröße festzulegen und gibt ein Set von Paaren zurück – Eingabe- und Ausgabewort. Beachten Sie, dass diese Funktion sowohl auf Wörter als auch auf Vektoren/Tensoren angewendet werden kann – was es uns ermöglicht, den Text zu kodieren, bevor er an die Funktion to_cbow übergeben wird.
def to_cbow(sent,window_size=2):
res = []
for i,x in enumerate(sent):
for j in range(max(0,i-window_size),min(i+window_size+1,len(sent))):
if i!=j:
res.append([sent[j],x])
return res
print(to_cbow(['I','like','to','train','networks']))
print(to_cbow(vectorizer('I like to train networks')))
Lass uns den Trainingsdatensatz vorbereiten. Wir werden alle Nachrichten durchgehen, to_cbow aufrufen, um die Liste der Wortpaare zu erhalten, und diese Paare zu X und Y hinzufügen. Aus Zeitgründen werden wir nur die ersten 10.000 Nachrichten berücksichtigen - du kannst die Einschränkung leicht entfernen, falls du mehr Zeit hast und bessere Einbettungen erhalten möchtest :)
X = []
Y = []
for i,x in zip(range(10000),ds_train.map(extract_text).as_numpy_iterator()):
for w1, w2 in to_cbow(vectorizer(x),window_size=1):
X.append(tf.expand_dims(w1,0))
Y.append(tf.expand_dims(w2,0))
Wir werden diese Daten auch in einen Datensatz umwandeln und für das Training stapeln:
ds = tf.data.Dataset.from_tensor_slices((X,Y)).batch(256)
Jetzt beginnen wir mit dem eigentlichen Training. Wir verwenden den SGD-Optimierer mit einer ziemlich hohen Lernrate. Du kannst auch andere Optimierer ausprobieren, wie zum Beispiel Adam. Wir werden zunächst für 200 Epochen trainieren – und du kannst diese Zelle erneut ausführen, wenn du einen noch geringeren Verlust erzielen möchtest.
model.compile(optimizer=keras.optimizers.SGD(lr=0.1),loss='sparse_categorical_crossentropy')
model.fit(ds,epochs=200)
Ausprobieren von Word2Vec
Um Word2Vec zu verwenden, extrahieren wir Vektoren, die den Wörtern in unserem Vokabular entsprechen:
vectors = embedder(vectorizer(vocab))
vectors = tf.reshape(vectors,(-1,30)) # we need reshape to get rid of extra dimension
Lass uns sehen, wie das Wort Paris beispielsweise in einen Vektor kodiert wird:
paris_vec = embedder(vectorizer('paris'))[0]
print(paris_vec)
Es ist interessant, Word2Vec zu verwenden, um nach Synonymen zu suchen. Die folgende Funktion gibt die n nächsten Wörter zu einem gegebenen Eingabewort zurück. Um sie zu finden, berechnen wir die Norm von $|w_i - v|$, wobei $v$ der Vektor ist, der unserem Eingabewort entspricht, und $w_i$ die Kodierung des $i$-ten Wortes im Vokabular ist. Anschließend sortieren wir das Array und geben die entsprechenden Indizes mit argsort zurück, wobei wir die ersten n Elemente der Liste nehmen, die die Positionen der nächsten Wörter im Vokabular kodieren.
def close_words(x,n=5):
vec = embedder(vectorizer(x))[0]
top5 = np.linalg.norm(vectors-vec,axis=1).argsort()[:n]
return [ vocab[x] for x in top5 ]
close_words('paris')
close_words('china')
close_words('official')
Erkenntnis
Mit cleveren Techniken wie CBoW können wir ein Word2Vec-Modell trainieren. Sie können auch versuchen, ein Skip-Gram-Modell zu trainieren, das darauf ausgelegt ist, das benachbarte Wort basierend auf dem zentralen Wort vorherzusagen, und sehen, wie gut es funktioniert.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Training eines Skip-Gram-Modells
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
In diesem Labor fordern wir Sie heraus, ein Word2Vec-Modell mit der Skip-Gram-Technik zu trainieren. Trainieren Sie ein Netzwerk mit Embedding, um benachbarte Wörter in einem $N$-Tokens-breiten Skip-Gram-Fenster vorherzusagen. Sie können den Code aus dieser Lektion verwenden und leicht anpassen.
Der Datensatz
Sie können jedes beliebige Buch verwenden. Viele kostenlose Texte finden Sie bei Project Gutenberg, zum Beispiel gibt es hier einen direkten Link zu Alice's Adventures in Wonderland) von Lewis Carroll. Alternativ können Sie auch die Stücke von Shakespeare verwenden, die Sie mit folgendem Code abrufen können:
path_to_file = tf.keras.utils.get_file(
'shakespeare.txt',
'https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt')
text = open(path_to_file, 'rb').read().decode(encoding='utf-8')
Erkunden Sie!
Wenn Sie Zeit haben und tiefer in das Thema eintauchen möchten, versuchen Sie, mehrere Dinge zu erforschen:
- Wie beeinflusst die Größe des Embeddings die Ergebnisse?
- Wie beeinflussen unterschiedliche Textstile das Ergebnis?
- Nehmen Sie mehrere sehr unterschiedliche Worttypen und deren Synonyme, erhalten Sie deren Vektorrepräsentationen, wenden Sie PCA an, um die Dimensionen auf 2 zu reduzieren, und plotten Sie sie im 2D-Raum. Erkennen Sie irgendwelche Muster?
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Sprachmodellierung
Semantische Einbettungen wie Word2Vec und GloVe sind tatsächlich ein erster Schritt in Richtung Sprachmodellierung – Modelle zu erstellen, die irgendwie die Natur der Sprache verstehen (oder repräsentieren).
Quiz vor der Vorlesung
Die Hauptidee hinter der Sprachmodellierung besteht darin, Modelle auf nicht gekennzeichneten Datensätzen in einer unüberwachten Weise zu trainieren. Das ist wichtig, da wir riesige Mengen an unbeschriftetem Text zur Verfügung haben, während die Menge an beschriftetem Text immer durch den Aufwand begrenzt wäre, den wir für die Beschriftung aufbringen können. Meistens können wir Sprachmodelle erstellen, die fehlende Wörter im Text vorhersagen, da es einfach ist, ein zufälliges Wort im Text auszublenden und es als Trainingsbeispiel zu verwenden.
Training von Einbettungen
In unseren vorherigen Beispielen haben wir vortrainierte semantische Einbettungen verwendet, aber es ist interessant zu sehen, wie diese Einbettungen trainiert werden können. Es gibt mehrere mögliche Ansätze, die verwendet werden können:
- N-Gramm-Sprachmodellierung, bei der wir ein Token vorhersagen, indem wir auf die N vorherigen Tokens schauen (N-Gramm).
- Continuous Bag-of-Words (CBoW), bei der wir das mittlere Token $W_0$ in einer Token-Sequenz $W_{-N}$, ..., $W_N$ vorhersagen.
- Skip-Gramm, bei dem wir eine Menge benachbarter Tokens {$W_{-N},\dots, W_{-1}, W_1,\dots, W_N$} aus dem mittleren Token $W_0$ vorhersagen.

> Bild aus dieser Arbeit
✍️ Beispiel-Notebooks: Training eines CBoW-Modells
Setze dein Lernen mit den folgenden Notebooks fort:
Fazit
In der vorherigen Lektion haben wir gesehen, dass Wort-Einbettungen wie Magie funktionieren! Jetzt wissen wir, dass das Training von Wort-Einbettungen keine sehr komplexe Aufgabe ist, und wir sollten in der Lage sein, unsere eigenen Wort-Einbettungen für domänenspezifische Texte zu trainieren, falls erforderlich.
Quiz nach der Vorlesung
Wiederholung & Selbststudium
- Offizielles PyTorch-Tutorial zur Sprachmodellierung.
- Offizielles TensorFlow-Tutorial zum Training eines Word2Vec-Modells.
- Die Verwendung des gensim-Frameworks, um die am häufigsten verwendeten Einbettungen mit wenigen Codezeilen zu trainieren, wird in dieser Dokumentation beschrieben.
🚀 Aufgabe: Skip-Gramm-Modell trainieren
Im Labor fordern wir dich heraus, den Code aus dieser Lektion zu ändern, um ein Skip-Gramm-Modell anstelle von CBoW zu trainieren. Lies die Details
Aufgabe: Notebooks
Verwenden Sie die Notebooks, die mit dieser Lektion verbunden sind (entweder die PyTorch- oder die TensorFlow-Version), und führen Sie sie mit Ihrem eigenen Datensatz erneut aus, möglicherweise einem von Kaggle, unter Angabe der Quelle. Überarbeiten Sie das Notebook, um Ihre eigenen Erkenntnisse hervorzuheben. Probieren Sie eine andere Art von Datensatz aus und dokumentieren Sie Ihre Ergebnisse, beispielsweise mit Text wie diesem Kaggle-Wettbewerbsdatensatz über Wetter-Tweets.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Rekurrente Neuronale Netze
Quiz vor der Vorlesung
In den vorherigen Abschnitten haben wir reichhaltige semantische Repräsentationen von Text und einen einfachen linearen Klassifikator auf den Einbettungen verwendet. Diese Architektur erfasst die aggregierte Bedeutung der Wörter in einem Satz, berücksichtigt jedoch nicht die Reihenfolge der Wörter, da die Aggregationsoperation auf den Einbettungen diese Information aus dem ursprünglichen Text entfernt. Da diese Modelle die Wortreihenfolge nicht modellieren können, sind sie nicht in der Lage, komplexere oder mehrdeutige Aufgaben wie Textgenerierung oder Fragebeantwortung zu lösen.
Um die Bedeutung einer Textsequenz zu erfassen, müssen wir eine andere Architektur für neuronale Netze verwenden, die als rekurrentes neuronales Netz oder RNN bezeichnet wird. Im RNN geben wir unseren Satz ein Symbol nach dem anderen durch das Netzwerk, und das Netzwerk erzeugt einen Zustand, den wir dann mit dem nächsten Symbol erneut in das Netzwerk einspeisen.

> Bild vom Autor
Angenommen, wir haben eine Eingabesequenz von Token X<sub>0</sub>,...,X<sub>n</sub>, erstellt das RNN eine Sequenz von neuronalen Netzwerkblöcken und trainiert diese Sequenz end-to-end mittels Backpropagation. Jeder Netzwerkblock nimmt ein Paar (X<sub>i</sub>,S<sub>i</sub>) als Eingabe und erzeugt S<sub>i+1</sub> als Ergebnis. Der finale Zustand S<sub>n</sub> oder (Ausgabe Y<sub>n</sub>) wird in einen linearen Klassifikator eingespeist, um das Ergebnis zu erzeugen. Alle Netzwerkblöcke teilen sich die gleichen Gewichte und werden end-to-end mit einem Backpropagation-Durchgang trainiert.
Da die Zustandsvektoren S<sub>0</sub>,...,S<sub>n</sub> durch das Netzwerk weitergegeben werden, kann es die sequentiellen Abhängigkeiten zwischen Wörtern lernen. Zum Beispiel, wenn das Wort nicht irgendwo in der Sequenz erscheint, kann es lernen, bestimmte Elemente innerhalb des Zustandsvektors zu negieren, was zu einer Verneinung führt.
> ✅ Da die Gewichte aller RNN-Blöcke im obigen Bild geteilt werden, kann dasselbe Bild als ein Block (rechts) mit einer rekurrenten Rückkopplungsschleife dargestellt werden, die den Ausgabestatus des Netzwerks wieder an die Eingabe weitergibt.
Anatomie einer RNN-Zelle
Schauen wir uns an, wie eine einfache RNN-Zelle organisiert ist. Sie akzeptiert den vorherigen Zustand S<sub>i-1</sub> und das aktuelle Symbol X<sub>i</sub> als Eingaben und muss den Ausgabestatus S<sub>i</sub> erzeugen (und manchmal sind wir auch an einer anderen Ausgabe Y<sub>i</sub> interessiert, wie im Fall von generativen Netzwerken).
Eine einfache RNN-Zelle hat zwei Gewichtsmatrizen: eine transformiert ein Eingabesymbol (wir nennen sie W), und eine andere transformiert einen Eingabezustand (H). In diesem Fall wird die Ausgabe des Netzwerks als σ(W×X<sub>i</sub>+H×S<sub>i-1</sub>+b) berechnet, wobei σ die Aktivierungsfunktion und b ein zusätzlicher Bias ist.
<img alt="Anatomie einer RNN-Zelle" src="../../../../../translated_images/de/rnn-anatomy.79ee3f3920b3294b.webp" width="50%"/>
> Bild vom Autor
In vielen Fällen werden Eingabetoken vor dem Eintritt in das RNN durch die Einbettungsschicht geleitet, um die Dimensionalität zu reduzieren. In diesem Fall, wenn die Dimension der Eingabevektoren emb_size ist und der Zustandsvektor hid_size ist - beträgt die Größe von W emb_size×hid_size, und die Größe von H ist hid_size×hid_size.
Long Short Term Memory (LSTM)
Eines der Hauptprobleme klassischer RNNs ist das sogenannte Problem der verschwindenden Gradienten. Da RNNs end-to-end in einem Backpropagation-Durchgang trainiert werden, haben sie Schwierigkeiten, Fehler zu den ersten Schichten des Netzwerks zu propagieren, und können daher keine Beziehungen zwischen weit entfernten Token lernen. Eine Möglichkeit, dieses Problem zu vermeiden, besteht darin, explizites Zustandsmanagement durch sogenannte Gates einzuführen. Es gibt zwei bekannte Architekturen dieser Art: Long Short Term Memory (LSTM) und Gated Relay Unit (GRU).
> Bildquelle TBD
Das LSTM-Netzwerk ist ähnlich wie ein RNN organisiert, aber es gibt zwei Zustände, die von Schicht zu Schicht weitergegeben werden: der eigentliche Zustand C und der versteckte Vektor H. In jeder Einheit wird der versteckte Vektor H<sub>i</sub> mit der Eingabe X<sub>i</sub> verkettet, und sie steuern, was mit dem Zustand C über Gates geschieht. Jedes Gate ist ein neuronales Netzwerk mit Sigmoid-Aktivierung (Ausgabe im Bereich [0,1]), das als bitweises Maskieren betrachtet werden kann, wenn es mit dem Zustandsvektor multipliziert wird. Es gibt die folgenden Gates (von links nach rechts im obigen Bild):
- Das Vergessens-Gate nimmt einen versteckten Vektor und bestimmt, welche Komponenten des Vektors C wir vergessen und welche wir durchlassen müssen.
- Das Eingabe-Gate nimmt einige Informationen aus den Eingabe- und versteckten Vektoren und fügt sie in den Zustand ein.
- Das Ausgabe-Gate transformiert den Zustand über eine lineare Schicht mit tanh-Aktivierung und wählt dann einige seiner Komponenten mithilfe eines versteckten Vektors H<sub>i</sub> aus, um einen neuen Zustand C<sub>i+1</sub> zu erzeugen.
Komponenten des Zustands C können als Flags betrachtet werden, die ein- und ausgeschaltet werden können. Zum Beispiel, wenn wir in der Sequenz den Namen Alice begegnen, könnten wir annehmen, dass er sich auf eine weibliche Figur bezieht, und das Flag im Zustand setzen, dass wir ein weibliches Substantiv im Satz haben. Wenn wir später die Phrase und Tom begegnen, setzen wir das Flag, dass wir ein Plural-Substantiv haben. Durch die Manipulation des Zustands können wir also angeblich die grammatikalischen Eigenschaften von Satzteilen verfolgen.
> ✅ Eine ausgezeichnete Ressource, um die Interna von LSTM zu verstehen, ist dieser großartige Artikel Understanding LSTM Networks von Christopher Olah.
Bidirektionale und mehrschichtige RNNs
Wir haben rekurrente Netzwerke besprochen, die in eine Richtung arbeiten, vom Anfang einer Sequenz bis zum Ende. Das erscheint natürlich, da es der Art und Weise ähnelt, wie wir lesen und Sprache hören. Da wir jedoch in vielen praktischen Fällen zufälligen Zugriff auf die Eingabesequenz haben, könnte es sinnvoll sein, die rekurrente Berechnung in beide Richtungen auszuführen. Solche Netzwerke werden als bidirektionale RNNs bezeichnet. Bei einem bidirektionalen Netzwerk benötigen wir zwei versteckte Zustandsvektoren, einen für jede Richtung.
Ein rekurrentes Netzwerk, sei es eindirektional oder bidirektional, erfasst bestimmte Muster innerhalb einer Sequenz und kann sie in einem Zustandsvektor speichern oder in die Ausgabe weitergeben. Wie bei konvolutionalen Netzwerken können wir eine weitere rekurrente Schicht auf die erste aufbauen, um höherstufige Muster zu erfassen und aus den niedrigstufigen Mustern zu bauen, die von der ersten Schicht extrahiert wurden. Dies führt uns zum Konzept eines mehrschichtigen RNN, das aus zwei oder mehr rekurrenten Netzwerken besteht, wobei die Ausgabe der vorherigen Schicht als Eingabe an die nächste Schicht weitergegeben wird.

Bild aus diesem wunderbaren Beitrag von Fernando López
✍️ Übungen: Einbettungen
Setzen Sie Ihr Lernen in den folgenden Notebooks fort:
Fazit
In dieser Einheit haben wir gesehen, dass RNNs für die Sequenzklassifikation verwendet werden können, aber tatsächlich können sie viele weitere Aufgaben bewältigen, wie Textgenerierung, maschinelle Übersetzung und mehr. Diese Aufgaben werden wir in der nächsten Einheit betrachten.
🚀 Herausforderung
Lesen Sie einige Literatur über LSTMs und denken Sie über deren Anwendungen nach:
- Grid Long Short-Term Memory
- Show, Attend and Tell: Neural Image Caption Generation with Visual Attention
Quiz nach der Vorlesung
Überprüfung & Selbststudium
- Understanding LSTM Networks von Christopher Olah.
Aufgabe: Notebooks
Rekurrente neuronale Netze
Im vorherigen Modul haben wir reichhaltige semantische Repräsentationen von Text verwendet und einen einfachen linearen Klassifikator auf den Einbettungen aufgebaut. Diese Architektur erfasst die aggregierte Bedeutung der Wörter in einem Satz, berücksichtigt jedoch nicht die Reihenfolge der Wörter, da die Aggregationsoperation auf den Einbettungen diese Information aus dem ursprünglichen Text entfernt hat. Da diese Modelle die Wortreihenfolge nicht modellieren können, sind sie nicht in der Lage, komplexere oder mehrdeutige Aufgaben wie Textgenerierung oder Fragebeantwortung zu lösen.
Um die Bedeutung einer Textsequenz zu erfassen, müssen wir eine andere Architektur neuronaler Netze verwenden, die als rekurrentes neuronales Netz oder RNN bezeichnet wird. In einem RNN führen wir unseren Satz nacheinander Symbol für Symbol durch das Netzwerk, und das Netzwerk erzeugt einen Zustand, den wir dann zusammen mit dem nächsten Symbol erneut in das Netzwerk einspeisen.
Gegeben die Eingabesequenz von Tokens $X_0,\dots,X_n$, erstellt das RNN eine Sequenz von neuronalen Netzwerkblöcken und trainiert diese Sequenz end-to-end mittels Backpropagation. Jeder Netzwerkblock nimmt ein Paar $(X_i,S_i)$ als Eingabe und erzeugt $S_{i+1}$ als Ergebnis. Der finale Zustand $S_n$ oder die Ausgabe $X_n$ wird in einen linearen Klassifikator eingespeist, um das Ergebnis zu erzeugen. Alle Netzwerkblöcke teilen sich die gleichen Gewichte und werden in einem einzigen Backpropagation-Durchlauf end-to-end trainiert.
Da die Zustandsvektoren $S_0,\dots,S_n$ durch das Netzwerk weitergegeben werden, kann es die sequentiellen Abhängigkeiten zwischen Wörtern lernen. Zum Beispiel, wenn das Wort nicht irgendwo in der Sequenz erscheint, kann es lernen, bestimmte Elemente innerhalb des Zustandsvektors zu negieren, was zu einer Verneinung führt.
> Da die Gewichte aller RNN-Blöcke im Bild geteilt werden, kann dasselbe Bild als ein Block (rechts) mit einer rekurrenten Rückkopplungsschleife dargestellt werden, die den Ausgabestatus des Netzwerks zurück an den Eingang weitergibt.
Schauen wir uns an, wie rekurrente neuronale Netze uns dabei helfen können, unser Nachrichten-Dataset zu klassifizieren.
import torch
import torchtext
from torchnlp import *
train_dataset, test_dataset, classes, vocab = load_dataset()
vocab_size = len(vocab)
Einfacher RNN-Klassifikator
Im Fall eines einfachen RNN ist jede rekurrente Einheit ein einfaches lineares Netzwerk, das einen zusammengefügten Eingabevektor und Zustandsvektor aufnimmt und einen neuen Zustandsvektor erzeugt. PyTorch repräsentiert diese Einheit mit der Klasse RNNCell, und ein Netzwerk solcher Zellen als RNN-Schicht.
Um einen RNN-Klassifikator zu definieren, wenden wir zunächst eine Embedding-Schicht an, um die Dimensionalität des Eingabevokabulars zu reduzieren, und fügen dann eine RNN-Schicht darüber hinzu:
class RNNClassifier(torch.nn.Module):
def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):
super().__init__()
self.hidden_dim = hidden_dim
self.embedding = torch.nn.Embedding(vocab_size, embed_dim)
self.rnn = torch.nn.RNN(embed_dim,hidden_dim,batch_first=True)
self.fc = torch.nn.Linear(hidden_dim, num_class)
def forward(self, x):
batch_size = x.size(0)
x = self.embedding(x)
x,h = self.rnn(x)
return self.fc(x.mean(dim=1))
> Hinweis: Wir verwenden hier eine untrainierte Einbettungsschicht zur Vereinfachung, aber für noch bessere Ergebnisse können wir eine vortrainierte Einbettungsschicht mit Word2Vec- oder GloVe-Einbettungen verwenden, wie in der vorherigen Einheit beschrieben. Für ein besseres Verständnis könnten Sie den Code anpassen, um mit vortrainierten Einbettungen zu arbeiten.
In unserem Fall verwenden wir einen gepolsterten Datenlader, sodass jede Charge eine Anzahl gepolsterter Sequenzen gleicher Länge enthält. Die RNN-Schicht nimmt die Sequenz von Einbettungstensoren und erzeugt zwei Ausgaben: * $x$ ist eine Sequenz von RNN-Zellenausgaben bei jedem Schritt * $h$ ist der finale versteckte Zustand für das letzte Element der Sequenz
Anschließend wenden wir einen vollständig verbundenen linearen Klassifikator an, um die Anzahl der Klassen zu bestimmen.
> Hinweis: RNNs sind recht schwierig zu trainieren, da die Anzahl der Schichten, die bei der Rückwärtsausbreitung beteiligt sind, ziemlich groß wird, sobald die RNN-Zellen entlang der Sequenzlänge entrollt werden. Daher müssen wir eine kleine Lernrate wählen und das Netzwerk auf einem größeren Datensatz trainieren, um gute Ergebnisse zu erzielen. Dies kann ziemlich lange dauern, daher wird die Verwendung einer GPU bevorzugt.
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=padify, shuffle=True)
net = RNNClassifier(vocab_size,64,32,len(classes)).to(device)
train_epoch(net,train_loader, lr=0.001)
Langzeit-Kurzzeitgedächtnis (LSTM)
Eines der Hauptprobleme klassischer RNNs ist das sogenannte Problem der verschwindenden Gradienten. Da RNNs in einem einzigen Backpropagation-Durchlauf Ende-zu-Ende trainiert werden, fällt es ihnen schwer, den Fehler bis zu den ersten Schichten des Netzwerks weiterzuleiten. Dadurch kann das Netzwerk keine Beziehungen zwischen weit entfernten Tokens lernen. Eine Möglichkeit, dieses Problem zu umgehen, besteht darin, eine explizite Zustandsverwaltung durch den Einsatz sogenannter Gates einzuführen. Zwei der bekanntesten Architekturen dieser Art sind: Langzeit-Kurzzeitgedächtnis (LSTM) und Gated Relay Unit (GRU).
Ein LSTM-Netzwerk ist ähnlich wie ein RNN organisiert, aber es gibt zwei Zustände, die von Schicht zu Schicht weitergegeben werden: der aktuelle Zustand $c$ und der versteckte Vektor $h$. In jeder Einheit wird der versteckte Vektor $h_i$ mit der Eingabe $x_i$ verknüpft, und sie steuern über Gates, was mit dem Zustand $c$ geschieht. Jedes Gate ist ein neuronales Netzwerk mit einer Sigmoid-Aktivierung (Ausgabe im Bereich $[0,1]$), das als bitweises Maskieren betrachtet werden kann, wenn es mit dem Zustandsvektor multipliziert wird. Es gibt folgende Gates (von links nach rechts im obigen Bild): * Vergessens-Gate: Es nimmt den versteckten Vektor und bestimmt, welche Komponenten des Vektors $c$ wir vergessen und welche wir durchlassen müssen. * Eingabe-Gate: Es nimmt Informationen aus der Eingabe und dem versteckten Vektor und fügt sie dem Zustand hinzu. * Ausgabe-Gate: Es transformiert den Zustand über eine lineare Schicht mit $\tanh$-Aktivierung und wählt dann einige seiner Komponenten mithilfe des versteckten Vektors $h_i$ aus, um den neuen Zustand $c_{i+1}$ zu erzeugen.
Die Komponenten des Zustands $c$ können als Flags betrachtet werden, die ein- und ausgeschaltet werden können. Zum Beispiel, wenn wir im Sequenzkontext den Namen Alice begegnen, könnten wir annehmen, dass es sich um eine weibliche Figur handelt, und das Flag im Zustand setzen, dass wir ein weibliches Substantiv im Satz haben. Wenn wir später auf die Phrase und Tom stoßen, setzen wir das Flag, dass wir ein Plural-Substantiv haben. Durch die Manipulation des Zustands können wir also theoretisch grammatikalische Eigenschaften von Satzteilen verfolgen.
> Hinweis: Eine großartige Ressource, um die Interna von LSTMs zu verstehen, ist der Artikel Understanding LSTM Networks von Christopher Olah.
Obwohl die interne Struktur einer LSTM-Zelle komplex erscheinen mag, verbirgt PyTorch diese Implementierung in der LSTMCell-Klasse und stellt das LSTM-Objekt bereit, um die gesamte LSTM-Schicht darzustellen. Daher wird die Implementierung eines LSTM-Klassifikators der eines einfachen RNNs, das wir oben gesehen haben, ziemlich ähnlich sein:
class LSTMClassifier(torch.nn.Module):
def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):
super().__init__()
self.hidden_dim = hidden_dim
self.embedding = torch.nn.Embedding(vocab_size, embed_dim)
self.embedding.weight.data = torch.randn_like(self.embedding.weight.data)-0.5
self.rnn = torch.nn.LSTM(embed_dim,hidden_dim,batch_first=True)
self.fc = torch.nn.Linear(hidden_dim, num_class)
def forward(self, x):
batch_size = x.size(0)
x = self.embedding(x)
x,(h,c) = self.rnn(x)
return self.fc(h[-1])
net = LSTMClassifier(vocab_size,64,32,len(classes)).to(device)
train_epoch(net,train_loader, lr=0.001)
Gepackte Sequenzen
In unserem Beispiel mussten wir alle Sequenzen im Minibatch mit Nullvektoren auffüllen. Dies führt zwar zu einem gewissen Speicherverbrauch, aber bei RNNs ist es noch kritischer, dass zusätzliche RNN-Zellen für die aufgefüllten Eingabeelemente erstellt werden. Diese nehmen am Training teil, tragen jedoch keine wichtigen Eingabeinformationen. Es wäre viel besser, das RNN nur bis zur tatsächlichen Sequenzlänge zu trainieren.
Um dies zu erreichen, wurde in PyTorch ein spezielles Format zur Speicherung gepolsterter Sequenzen eingeführt. Angenommen, wir haben ein gepolstertes Eingabe-Minigruppenbatch, das so aussieht:
[[1,2,3,4,5],
[6,7,8,0,0],
[9,0,0,0,0]]
Hierbei repräsentiert 0 die gepolsterten Werte, und der tatsächliche Längenvektor der Eingabesequenzen ist [5,3,1].
Um ein RNN effektiv mit gepolsterten Sequenzen zu trainieren, möchten wir die erste Gruppe von RNN-Zellen mit einem großen Minibatch ([1,6,9]) starten, dann jedoch die Verarbeitung der dritten Sequenz beenden und mit verkleinerten Minibatches ([2,7], [3,8]) weitermachen, und so weiter. Eine gepackte Sequenz wird daher als ein einziger Vektor dargestellt – in unserem Fall [1,6,9,2,7,3,8,4,5] – und einem Längenvektor ([5,3,1]), aus dem wir das ursprüngliche gepolsterte Minibatch leicht rekonstruieren können.
Um eine gepackte Sequenz zu erzeugen, können wir die Funktion torch.nn.utils.rnn.pack_padded_sequence verwenden. Alle rekurrenten Schichten, einschließlich RNN, LSTM und GRU, unterstützen gepackte Sequenzen als Eingabe und erzeugen gepackte Ausgaben, die mit torch.nn.utils.rnn.pad_packed_sequence dekodiert werden können.
Um eine gepackte Sequenz erzeugen zu können, müssen wir den Längenvektor an das Netzwerk übergeben. Daher benötigen wir eine andere Funktion, um Minibatches vorzubereiten:
def pad_length(b):
# build vectorized sequence
v = [encode(x[1]) for x in b]
# compute max length of a sequence in this minibatch and length sequence itself
len_seq = list(map(len,v))
l = max(len_seq)
return ( # tuple of three tensors - labels, padded features, length sequence
torch.LongTensor([t[0]-1 for t in b]),
torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v]),
torch.tensor(len_seq)
)
train_loader_len = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=pad_length, shuffle=True)
Das tatsächliche Netzwerk wäre dem oben genannten LSTMClassifier sehr ähnlich, aber der forward-Durchlauf erhält sowohl das gepolsterte Minibatch als auch den Vektor der Sequenzlängen. Nach der Berechnung des Embeddings erstellen wir eine gepackte Sequenz, geben sie an die LSTM-Schicht weiter und entpacken anschließend das Ergebnis.
> Hinweis: Tatsächlich verwenden wir das entpackte Ergebnis x nicht, da wir die Ausgabe aus den versteckten Schichten für die folgenden Berechnungen nutzen. Daher könnten wir das Entpacken in diesem Code vollständig entfernen. Der Grund, warum wir es hier belassen, ist, dass Sie diesen Code bei Bedarf leicht anpassen können, falls Sie die Netzwerkausgabe in weiteren Berechnungen verwenden möchten.
class LSTMPackClassifier(torch.nn.Module):
def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):
super().__init__()
self.hidden_dim = hidden_dim
self.embedding = torch.nn.Embedding(vocab_size, embed_dim)
self.embedding.weight.data = torch.randn_like(self.embedding.weight.data)-0.5
self.rnn = torch.nn.LSTM(embed_dim,hidden_dim,batch_first=True)
self.fc = torch.nn.Linear(hidden_dim, num_class)
def forward(self, x, lengths):
batch_size = x.size(0)
x = self.embedding(x)
pad_x = torch.nn.utils.rnn.pack_padded_sequence(x,lengths,batch_first=True,enforce_sorted=False)
pad_x,(h,c) = self.rnn(pad_x)
x, _ = torch.nn.utils.rnn.pad_packed_sequence(pad_x,batch_first=True)
return self.fc(h[-1])
net = LSTMPackClassifier(vocab_size,64,32,len(classes)).to(device)
train_epoch_emb(net,train_loader_len, lr=0.001,use_pack_sequence=True)
> Hinweis: Sie haben möglicherweise den Parameter use_pack_sequence bemerkt, den wir an die Trainingsfunktion übergeben. Derzeit erfordert die Funktion pack_padded_sequence, dass der Längensequenz-Tensor auf dem CPU-Gerät ist, und daher muss die Trainingsfunktion vermeiden, die Längensequenz-Daten während des Trainings auf die GPU zu verschieben. Sie können die Implementierung der Funktion train_emb in der Datei torchnlp.py einsehen.
Bidirektionale und mehrschichtige RNNs
In unseren Beispielen haben alle rekurrenten Netzwerke in eine Richtung gearbeitet, von Anfang bis Ende einer Sequenz. Das erscheint natürlich, da es der Art und Weise ähnelt, wie wir lesen und Sprache hören. Allerdings haben wir in vielen praktischen Fällen zufälligen Zugriff auf die Eingabesequenz, weshalb es sinnvoll sein könnte, die rekurrente Berechnung in beide Richtungen auszuführen. Solche Netzwerke werden als bidirektionale RNNs bezeichnet, und sie können erstellt werden, indem man den Parameter bidirectional=True an den Konstruktor von RNN/LSTM/GRU übergibt.
Bei der Arbeit mit einem bidirektionalen Netzwerk benötigen wir zwei Zustandsvektoren, einen für jede Richtung. PyTorch kodiert diese Vektoren als einen Vektor mit doppelter Größe, was sehr praktisch ist, da man den resultierenden Zustandsvektor normalerweise an eine vollständig verbundene lineare Schicht übergibt. Man muss lediglich diese Größenänderung berücksichtigen, wenn man die Schicht erstellt.
Ein rekurrentes Netzwerk, sei es eindirektional oder bidirektional, erfasst bestimmte Muster innerhalb einer Sequenz und kann diese entweder im Zustandsvektor speichern oder in die Ausgabe weitergeben. Ähnlich wie bei konvolutionalen Netzwerken können wir eine weitere rekurrente Schicht auf die erste aufbauen, um Muster höherer Ordnung zu erfassen, die aus den von der ersten Schicht extrahierten Mustern niedriger Ordnung bestehen. Dies führt uns zum Konzept des mehrschichtigen RNN, das aus zwei oder mehr rekurrenten Netzwerken besteht, wobei die Ausgabe der vorherigen Schicht als Eingabe an die nächste Schicht weitergegeben wird.

Bild aus diesem großartigen Beitrag von Fernando López
PyTorch macht die Konstruktion solcher Netzwerke einfach, da man lediglich den Parameter num_layers an den RNN/LSTM/GRU-Konstruktor übergeben muss, um mehrere rekurrente Schichten automatisch zu erstellen. Das bedeutet auch, dass die Größe des Zustandsvektors proportional zunimmt, und man muss dies berücksichtigen, wenn man die Ausgabe der rekurrenten Schichten verarbeitet.
RNNs für andere Aufgaben
In dieser Einheit haben wir gesehen, dass RNNs für die Sequenzklassifikation verwendet werden können. Tatsächlich können sie jedoch viele weitere Aufgaben bewältigen, wie Textgenerierung, maschinelle Übersetzung und mehr. Diese Aufgaben werden wir in der nächsten Einheit betrachten.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Rekurrente neuronale Netze
Im vorherigen Modul haben wir uns mit reichhaltigen semantischen Repräsentationen von Texten beschäftigt. Die Architektur, die wir verwendet haben, erfasst die aggregierte Bedeutung der Wörter in einem Satz, berücksichtigt jedoch nicht die Reihenfolge der Wörter, da die Aggregationsoperation, die den Einbettungen folgt, diese Information aus dem ursprünglichen Text entfernt. Da diese Modelle die Wortreihenfolge nicht darstellen können, sind sie nicht in der Lage, komplexere oder mehrdeutige Aufgaben wie Textgenerierung oder Beantwortung von Fragen zu lösen.
Um die Bedeutung einer Textsequenz zu erfassen, verwenden wir eine neuronale Netzwerkarchitektur namens rekurrentes neuronales Netz (RNN). Bei der Verwendung eines RNN führen wir unseren Satz Token für Token durch das Netzwerk, und das Netzwerk erzeugt einen Zustand, den wir dann mit dem nächsten Token erneut in das Netzwerk einspeisen.

Angenommen, wir haben eine Eingabesequenz von Tokens $X_0,\dots,X_n$, dann erstellt das RNN eine Sequenz von neuronalen Netzwerkblöcken und trainiert diese Sequenz end-to-end mithilfe von Backpropagation. Jeder Netzwerkblock nimmt ein Paar $(X_i,S_i)$ als Eingabe und erzeugt $S_{i+1}$ als Ergebnis. Der finale Zustand $S_n$ oder die Ausgabe $Y_n$ wird in einen linearen Klassifikator eingespeist, um das Ergebnis zu erzeugen. Alle Netzwerkblöcke teilen sich die gleichen Gewichte und werden in einem einzigen Backpropagation-Durchlauf end-to-end trainiert.
> Die obige Abbildung zeigt ein rekurrentes neuronales Netz in entfalteter Form (links) und in kompakter rekurrenter Darstellung (rechts). Es ist wichtig zu verstehen, dass alle RNN-Zellen die gleichen teilbaren Gewichte haben.
Da Zustandsvektoren $S_0,\dots,S_n$ durch das Netzwerk weitergegeben werden, kann das RNN sequentielle Abhängigkeiten zwischen Wörtern lernen. Zum Beispiel kann es, wenn das Wort nicht irgendwo in der Sequenz erscheint, lernen, bestimmte Elemente innerhalb des Zustandsvektors zu negieren.
Innerhalb jeder RNN-Zelle befinden sich zwei Gewichtsmatrizen: $W_H$ und $W_I$, sowie ein Bias $b$. Bei jedem RNN-Schritt wird der Ausgabestatus wie folgt berechnet: $S_{i+1} = f(W_H\times S_i + W_I\times X_i+b)$, wobei $f$ eine Aktivierungsfunktion ist (oft $\tanh$).
> Bei Problemen wie der Textgenerierung (die wir im nächsten Abschnitt behandeln werden) oder der maschinellen Übersetzung möchten wir auch bei jedem RNN-Schritt einen Ausgabewert erhalten. In diesem Fall gibt es eine weitere Matrix $W_O$, und die Ausgabe wird berechnet als $Y_i=f(W_O\times S_i+b_O)$.
Schauen wir uns an, wie rekurrente neuronale Netze uns dabei helfen können, unser Nachrichten-Dataset zu klassifizieren.
> Für die Sandbox-Umgebung müssen wir die folgende Zelle ausführen, um sicherzustellen, dass die erforderliche Bibliothek installiert ist und die Daten vorab geladen werden. Wenn Sie lokal arbeiten, können Sie die folgende Zelle überspringen.
import sys
!{sys.executable} -m pip install --quiet tensorflow_datasets==4.4.0
!cd ~ && wget -q -O - https://mslearntensorflowlp.blob.core.windows.net/data/tfds-ag-news.tgz | tar xz
import tensorflow as tf
from tensorflow import keras
import tensorflow_datasets as tfds
import numpy as np
# We are going to be training pretty large models. In order not to face errors, we need
# to set tensorflow option to grow GPU memory allocation when required
physical_devices = tf.config.list_physical_devices('GPU')
if len(physical_devices)>0:
tf.config.experimental.set_memory_growth(physical_devices[0], True)
ds_train, ds_test = tfds.load('ag_news_subset').values()
Beim Training großer Modelle kann die Zuweisung von GPU-Speicher problematisch werden. Außerdem müssen wir möglicherweise mit verschiedenen Minibatch-Größen experimentieren, damit die Daten in den GPU-Speicher passen und das Training dennoch schnell genug ist. Wenn Sie diesen Code auf Ihrer eigenen GPU-Maschine ausführen, können Sie mit der Anpassung der Minibatch-Größe experimentieren, um das Training zu beschleunigen.
> Hinweis: Es ist bekannt, dass bestimmte Versionen von NVidia-Treibern den Speicher nach dem Training des Modells nicht freigeben. In diesem Notebook führen wir mehrere Beispiele aus, was dazu führen kann, dass der Speicher in bestimmten Konfigurationen erschöpft wird, insbesondere wenn Sie eigene Experimente im selben Notebook durchführen. Wenn Sie auf seltsame Fehler stoßen, wenn Sie mit dem Training des Modells beginnen, sollten Sie den Notebook-Kernel neu starten.
batch_size = 16
embed_size = 64
Einfacher RNN-Klassifikator
Bei einem einfachen RNN ist jede rekurrente Einheit ein einfaches lineares Netzwerk, das einen Eingabevektor und einen Zustandsvektor aufnimmt und einen neuen Zustandsvektor erzeugt. In Keras kann dies durch die SimpleRNN-Schicht dargestellt werden.
Obwohl wir der RNN-Schicht direkt one-hot-codierte Tokens übergeben könnten, ist dies aufgrund ihrer hohen Dimensionalität keine gute Idee. Daher verwenden wir eine Embedding-Schicht, um die Dimensionalität der Wortvektoren zu reduzieren, gefolgt von einer RNN-Schicht und schließlich einem Dense-Klassifikator.
> Hinweis: In Fällen, in denen die Dimensionalität nicht so hoch ist, wie beispielsweise bei der Tokenisierung auf Zeichenebene, könnte es sinnvoll sein, one-hot-codierte Tokens direkt in die RNN-Zelle einzuspeisen.
vocab_size = 20000
vectorizer = keras.layers.experimental.preprocessing.TextVectorization(
max_tokens=vocab_size,
input_shape=(1,))
model = keras.models.Sequential([
vectorizer,
keras.layers.Embedding(vocab_size, embed_size),
keras.layers.SimpleRNN(16),
keras.layers.Dense(4,activation='softmax')
])
model.summary()
> Hinweis: Hier verwenden wir eine untrainierte Einbettungsschicht zur Vereinfachung, aber für bessere Ergebnisse können wir eine vortrainierte Einbettungsschicht mit Word2Vec verwenden, wie im vorherigen Abschnitt beschrieben. Es wäre eine gute Übung für dich, diesen Code so anzupassen, dass er mit vortrainierten Einbettungen funktioniert.
Nun lassen wir unser RNN trainieren. RNNs sind im Allgemeinen recht schwierig zu trainieren, da die Anzahl der Schichten, die bei der Rückpropagation beteiligt sind, sehr groß wird, sobald die RNN-Zellen entlang der Sequenzlänge entfaltet werden. Daher müssen wir eine kleinere Lernrate wählen und das Netzwerk auf einem größeren Datensatz trainieren, um gute Ergebnisse zu erzielen. Dies kann ziemlich lange dauern, daher wird die Verwendung einer GPU empfohlen.
Um den Prozess zu beschleunigen, werden wir das RNN-Modell nur mit Nachrichtentiteln trainieren und die Beschreibung weglassen. Du kannst versuchen, mit der Beschreibung zu trainieren und sehen, ob du das Modell zum Laufen bringen kannst.
def extract_title(x):
return x['title']
def tupelize_title(x):
return (extract_title(x),x['label'])
print('Training vectorizer')
vectorizer.adapt(ds_train.take(2000).map(extract_title))
model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')
model.fit(ds_train.map(tupelize_title).batch(batch_size),validation_data=ds_test.map(tupelize_title).batch(batch_size))
> Hinweis: Die Genauigkeit ist hier wahrscheinlich geringer, da wir nur mit Nachrichtentiteln trainieren.
Überprüfung von variablen Sequenzen
Denken Sie daran, dass die TextVectorization-Schicht automatisch Sequenzen mit variabler Länge in einem Minibatch mit Pad-Tokens auffüllt. Es stellt sich heraus, dass diese Tokens auch am Training teilnehmen und die Konvergenz des Modells erschweren können.
Es gibt mehrere Ansätze, die wir verfolgen können, um die Menge an Padding zu minimieren. Einer davon ist, den Datensatz nach Sequenzlänge neu zu ordnen und alle Sequenzen nach Größe zu gruppieren. Dies kann mit der Funktion tf.data.experimental.bucket_by_sequence_length durchgeführt werden (siehe Dokumentation).
Ein weiterer Ansatz ist die Verwendung von Maskierung. In Keras unterstützen einige Schichten zusätzliche Eingaben, die zeigen, welche Tokens beim Training berücksichtigt werden sollen. Um Maskierung in unser Modell zu integrieren, können wir entweder eine separate Masking-Schicht einfügen (Dokumentation) oder den Parameter mask_zero=True in unserer Embedding-Schicht angeben.
> Note: Dieses Training wird etwa 5 Minuten dauern, um eine Epoche auf dem gesamten Datensatz abzuschließen. Sie können das Training jederzeit unterbrechen, wenn Sie die Geduld verlieren. Alternativ können Sie die Menge der für das Training verwendeten Daten begrenzen, indem Sie nach den Datensätzen ds_train und ds_test eine .take(...)-Klausel hinzufügen.
def extract_text(x):
return x['title']+' '+x['description']
def tupelize(x):
return (extract_text(x),x['label'])
model = keras.models.Sequential([
vectorizer,
keras.layers.Embedding(vocab_size,embed_size,mask_zero=True),
keras.layers.SimpleRNN(16),
keras.layers.Dense(4,activation='softmax')
])
model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')
model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))
Jetzt, da wir Maskierung verwenden, können wir das Modell mit dem gesamten Datensatz aus Titeln und Beschreibungen trainieren.
> Hinweis: Ist Ihnen aufgefallen, dass wir einen Vektorisierer verwenden, der auf den Nachrichtentiteln trainiert wurde, und nicht auf dem gesamten Artikeltext? Das könnte dazu führen, dass einige Tokens ignoriert werden. Es wäre daher besser, den Vektorisierer neu zu trainieren. Allerdings könnte der Effekt nur sehr gering sein, daher bleiben wir der Einfachheit halber beim vorher trainierten Vektorisierer.
LSTM: Langzeit-Kurzzeitspeicher
Eines der Hauptprobleme von RNNs sind verschwindende Gradienten. RNNs können ziemlich lang sein und haben möglicherweise Schwierigkeiten, die Gradienten während der Rückwärtspropagation bis zur ersten Schicht des Netzwerks zurückzuführen. Wenn dies passiert, kann das Netzwerk keine Beziehungen zwischen weit entfernten Tokens lernen. Eine Möglichkeit, dieses Problem zu vermeiden, besteht darin, explizites Zustandsmanagement durch den Einsatz von Gates einzuführen. Die beiden gängigsten Architekturen, die Gates verwenden, sind Langzeit-Kurzzeitspeicher (LSTM) und Gated Relay Unit (GRU). Hier werden wir uns mit LSTMs beschäftigen.
Ein LSTM-Netzwerk ist ähnlich wie ein RNN organisiert, aber es gibt zwei Zustände, die von Schicht zu Schicht weitergegeben werden: den tatsächlichen Zustand $c$ und den versteckten Vektor $h$. In jeder Einheit wird der versteckte Vektor $h_{t-1}$ mit der Eingabe $x_t$ kombiniert, und zusammen steuern sie, was mit dem Zustand $c_t$ und der Ausgabe $h_{t}$ durch Gates geschieht. Jedes Gate hat eine Sigmoid-Aktivierung (Ausgabe im Bereich $[0,1]$), die als bitweises Maskieren betrachtet werden kann, wenn sie mit dem Zustandsvektor multipliziert wird. LSTMs haben die folgenden Gates (von links nach rechts im obigen Bild): * Vergessens-Gate, das bestimmt, welche Komponenten des Vektors $c_{t-1}$ wir vergessen und welche wir durchlassen müssen. * Eingabe-Gate, das bestimmt, wie viele Informationen aus dem Eingabevektor und dem vorherigen versteckten Vektor in den Zustandsvektor aufgenommen werden sollen. * Ausgabe-Gate, das den neuen Zustandsvektor nimmt und entscheidet, welche seiner Komponenten verwendet werden, um den neuen versteckten Vektor $h_t$ zu erzeugen.
Die Komponenten des Zustands $c$ können als Flags betrachtet werden, die ein- und ausgeschaltet werden können. Zum Beispiel, wenn wir im Sequenzverlauf den Namen Alice sehen, vermuten wir, dass es sich um eine Frau handelt, und setzen das Flag im Zustand, das anzeigt, dass wir ein weibliches Substantiv im Satz haben. Wenn wir später die Wörter und Tom sehen, setzen wir das Flag, das anzeigt, dass wir ein Plural-Substantiv haben. Durch die Manipulation des Zustands können wir also die grammatikalischen Eigenschaften des Satzes verfolgen.
> Note: Hier ist eine großartige Ressource, um die Interna von LSTMs zu verstehen: Understanding LSTM Networks von Christopher Olah.
Obwohl die interne Struktur einer LSTM-Zelle komplex erscheinen mag, verbirgt Keras diese Implementierung in der LSTM-Schicht. Das Einzige, was wir im obigen Beispiel tun müssen, ist, die rekurrente Schicht zu ersetzen:
model = keras.models.Sequential([
vectorizer,
keras.layers.Embedding(vocab_size, embed_size),
keras.layers.LSTM(8),
keras.layers.Dense(4,activation='softmax')
])
model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')
model.fit(ds_train.map(tupelize).batch(8),validation_data=ds_test.map(tupelize).batch(8))
Bidirektionale und mehrschichtige RNNs
In unseren bisherigen Beispielen arbeiten die rekurrenten Netzwerke von Anfang bis Ende einer Sequenz. Das erscheint uns natürlich, da es der Richtung entspricht, in der wir lesen oder Sprache hören. Für Szenarien, die einen zufälligen Zugriff auf die Eingabesequenz erfordern, ist es jedoch sinnvoller, die rekurrente Berechnung in beide Richtungen auszuführen. RNNs, die Berechnungen in beide Richtungen ermöglichen, werden als bidirektionale RNNs bezeichnet, und sie können erstellt werden, indem die rekurrente Schicht mit einer speziellen Bidirectional-Schicht umwickelt wird.
> Note: Die Bidirectional-Schicht erstellt zwei Kopien der darin enthaltenen Schicht und setzt die Eigenschaft go_backwards einer dieser Kopien auf True, sodass sie in die entgegengesetzte Richtung entlang der Sequenz läuft.
Rekurrente Netzwerke, ob unidirektional oder bidirektional, erfassen Muster innerhalb einer Sequenz und speichern sie in Zustandsvektoren oder geben sie als Ausgabe zurück. Wie bei konvolutionalen Netzwerken können wir eine weitere rekurrente Schicht hinzufügen, die der ersten folgt, um höherwertige Muster zu erfassen, die aus niedrigeren Mustern bestehen, die von der ersten Schicht extrahiert wurden. Dies führt uns zum Konzept eines mehrschichtigen RNN, das aus zwei oder mehr rekurrenten Netzwerken besteht, wobei die Ausgabe der vorherigen Schicht als Eingabe an die nächste Schicht weitergegeben wird.

Bild aus diesem großartigen Beitrag von Fernando López.
Keras macht den Aufbau dieser Netzwerke zu einer einfachen Aufgabe, da Sie einfach weitere rekurrente Schichten zum Modell hinzufügen müssen. Für alle Schichten außer der letzten müssen wir den Parameter return_sequences=True angeben, da wir möchten, dass die Schicht alle Zwischenzustände zurückgibt und nicht nur den Endzustand der rekurrenten Berechnung.
Lassen Sie uns ein zweischichtiges bidirektionales LSTM für unser Klassifizierungsproblem erstellen.
> Note Dieser Code benötigt erneut ziemlich viel Zeit, um abgeschlossen zu werden, aber er liefert uns die höchste Genauigkeit, die wir bisher gesehen haben. Es könnte sich also lohnen, zu warten und das Ergebnis zu sehen.
model = keras.models.Sequential([
vectorizer,
keras.layers.Embedding(vocab_size, 128, mask_zero=True),
keras.layers.Bidirectional(keras.layers.LSTM(64,return_sequences=True)),
keras.layers.Bidirectional(keras.layers.LSTM(64)),
keras.layers.Dense(4,activation='softmax')
])
model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')
model.fit(ds_train.map(tupelize).batch(batch_size),
validation_data=ds_test.map(tupelize).batch(batch_size))
RNNs für andere Aufgaben
Bis jetzt haben wir uns darauf konzentriert, RNNs zur Klassifikation von Textsequenzen zu verwenden. Aber sie können noch viele weitere Aufgaben bewältigen, wie zum Beispiel Textgenerierung und maschinelle Übersetzung — diese Aufgaben werden wir in der nächsten Einheit betrachten.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Generative Netzwerke
Rekurrente neuronale Netzwerke (RNNs) und ihre Varianten mit gated Zellen wie Long Short Term Memory Cells (LSTMs) und Gated Recurrent Units (GRUs) bieten einen Mechanismus für Sprachmodellierung, d.h. sie können die Reihenfolge von Wörtern lernen und Vorhersagen für das nächste Wort in einer Sequenz treffen. Dies ermöglicht es uns, RNNs für generative Aufgaben zu nutzen, wie z.B. gewöhnliche Textgenerierung, maschinelle Übersetzung und sogar Bildbeschriftung.
In der RNN-Architektur, die wir in der vorherigen Einheit besprochen haben, produzierte jede RNN-Einheit den nächsten versteckten Zustand als Ausgabe. Wir können jedoch auch eine weitere Ausgabe zu jeder rekurrenten Einheit hinzufügen, die es uns ermöglicht, eine Sequenz auszugeben (die genauso lang ist wie die ursprüngliche Sequenz). Darüber hinaus können wir RNN-Einheiten verwenden, die bei jedem Schritt keine Eingabe akzeptieren, sondern lediglich einen Anfangszustandsvektor nehmen und dann eine Sequenz von Ausgaben erzeugen.
In diesem Notebook konzentrieren wir uns auf einfache generative Modelle, die uns helfen, Text zu generieren. Der Einfachheit halber bauen wir ein zeichenbasiertes Netzwerk, das Text Buchstabe für Buchstabe generiert. Während des Trainings müssen wir einen Textkorpus nehmen und ihn in Buchstabenfolgen aufteilen.
import torch
import torchtext
import numpy as np
from torchnlp import *
train_dataset,test_dataset,classes,vocab = load_dataset()
Aufbau eines Zeichen-Vokabulars
Um ein generatives Netzwerk auf Zeichenebene zu erstellen, müssen wir den Text in einzelne Zeichen statt in Wörter aufteilen. Dies kann durch die Definition eines anderen Tokenizers erfolgen:
def char_tokenizer(words):
return list(words) #[word for word in words]
counter = collections.Counter()
for (label, line) in train_dataset:
counter.update(char_tokenizer(line))
vocab = torchtext.vocab.vocab(counter)
vocab_size = len(vocab)
print(f"Vocabulary size = {vocab_size}")
print(f"Encoding of 'a' is {vocab.get_stoi()['a']}")
print(f"Character with code 13 is {vocab.get_itos()[13]}")
Lassen Sie uns das Beispiel sehen, wie wir den Text aus unserem Datensatz codieren können:
def enc(x):
return torch.LongTensor(encode(x,voc=vocab,tokenizer=char_tokenizer))
enc(train_dataset[0][1])
Training eines generativen RNN
So werden wir das RNN trainieren, um Text zu generieren: Bei jedem Schritt nehmen wir eine Zeichenfolge der Länge nchars und lassen das Netzwerk für jedes Eingabezeichen das nächste Ausgabesymbol vorhersagen:

Je nach Szenario möchten wir möglicherweise auch einige Sonderzeichen einbeziehen, wie zum Beispiel Ende-der-Sequenz <eos>. In unserem Fall möchten wir das Netzwerk jedoch für die endlose Textgenerierung trainieren. Daher legen wir die Größe jeder Sequenz auf nchars Tokens fest. Folglich besteht jedes Trainingsexemplar aus nchars Eingaben und nchars Ausgaben (die Eingabesequenz, um ein Symbol nach links verschoben). Ein Minibatch wird aus mehreren solcher Sequenzen bestehen.
Die Minibatches werden wir folgendermaßen generieren: Wir nehmen jeden Nachrichtentext der Länge l und erzeugen daraus alle möglichen Eingabe-Ausgabe-Kombinationen (es wird l-nchars solcher Kombinationen geben). Diese bilden ein Minibatch, und die Größe der Minibatches wird bei jedem Trainingsschritt unterschiedlich sein.
nchars = 100
def get_batch(s,nchars=nchars):
ins = torch.zeros(len(s)-nchars,nchars,dtype=torch.long,device=device)
outs = torch.zeros(len(s)-nchars,nchars,dtype=torch.long,device=device)
for i in range(len(s)-nchars):
ins[i] = enc(s[i:i+nchars])
outs[i] = enc(s[i+1:i+nchars+1])
return ins,outs
get_batch(train_dataset[0][1])
Nun definieren wir das Generatornetzwerk. Es kann auf jeder rekurrenten Zelle basieren, die wir in der vorherigen Einheit besprochen haben (einfach, LSTM oder GRU). In unserem Beispiel verwenden wir LSTM.
Da das Netzwerk Zeichen als Eingabe erhält und die Vokabulärgröße relativ klein ist, benötigen wir keine Embedding-Schicht. Die one-hot-codierte Eingabe kann direkt an die LSTM-Zelle übergeben werden. Da wir jedoch Zeichen als Zahlen übergeben, müssen wir diese vor der Übergabe an die LSTM-Zelle one-hot-codieren. Dies geschieht, indem die Funktion one_hot während des forward-Durchlaufs aufgerufen wird. Der Ausgabe-Encoder wäre eine lineare Schicht, die den versteckten Zustand in eine one-hot-codierte Ausgabe umwandelt.
class LSTMGenerator(torch.nn.Module):
def __init__(self, vocab_size, hidden_dim):
super().__init__()
self.rnn = torch.nn.LSTM(vocab_size,hidden_dim,batch_first=True)
self.fc = torch.nn.Linear(hidden_dim, vocab_size)
def forward(self, x, s=None):
x = torch.nn.functional.one_hot(x,vocab_size).to(torch.float32)
x,s = self.rnn(x,s)
return self.fc(x),s
Während des Trainings möchten wir in der Lage sein, generierten Text zu sampeln. Dazu definieren wir die Funktion generate, die eine Ausgabestring der Länge size erzeugt, beginnend mit dem Anfangsstring start.
So funktioniert es: Zuerst geben wir den gesamten Startstring durch das Netzwerk und erhalten den Ausgabestatus s und das nächste vorhergesagte Zeichen out. Da out one-hot codiert ist, verwenden wir argmax, um den Index des Zeichens nc im Vokabular zu erhalten, und nutzen itos, um das tatsächliche Zeichen zu ermitteln und es der resultierenden Zeichenliste chars hinzuzufügen. Dieser Prozess der Generierung eines Zeichens wird size-mal wiederholt, um die gewünschte Anzahl von Zeichen zu erzeugen.
def generate(net,size=100,start='today '):
chars = list(start)
out, s = net(enc(chars).view(1,-1).to(device))
for i in range(size):
nc = torch.argmax(out[0][-1])
chars.append(vocab.get_itos()[nc])
out, s = net(nc.view(1,-1),s)
return ''.join(chars)
Jetzt geht's ans Training! Die Trainingsschleife ist fast dieselbe wie in all unseren vorherigen Beispielen, aber anstelle der Genauigkeit geben wir alle 1000 Epochen einen Ausschnitt des generierten Textes aus.
Besondere Aufmerksamkeit sollte der Art und Weise gewidmet werden, wie wir den Verlust berechnen. Wir müssen den Verlust basierend auf der One-Hot-codierten Ausgabe out und dem erwarteten Text text_out berechnen, welcher die Liste der Zeichenindizes darstellt. Glücklicherweise erwartet die Funktion cross_entropy als erstes Argument die unnormalisierte Netzwerkausgabe und als zweites die Klassennummer – genau das, was wir haben. Sie führt außerdem eine automatische Mittelung über die Minibatch-Größe durch.
Wir begrenzen das Training außerdem auf samples_to_train Samples, um nicht zu lange warten zu müssen. Wir ermutigen euch, zu experimentieren und längeres Training auszuprobieren, möglicherweise über mehrere Epochen (in diesem Fall müsstet ihr eine weitere Schleife um diesen Code erstellen).
net = LSTMGenerator(vocab_size,64).to(device)
samples_to_train = 10000
optimizer = torch.optim.Adam(net.parameters(),0.01)
loss_fn = torch.nn.CrossEntropyLoss()
net.train()
for i,x in enumerate(train_dataset):
# x[0] is class label, x[1] is text
if len(x[1])-nchars<10:
continue
samples_to_train-=1
if not samples_to_train: break
text_in, text_out = get_batch(x[1])
optimizer.zero_grad()
out,s = net(text_in)
loss = torch.nn.functional.cross_entropy(out.view(-1,vocab_size),text_out.flatten()) #cross_entropy(out,labels)
loss.backward()
optimizer.step()
if i%1000==0:
print(f"Current loss = {loss.item()}")
print(generate(net))
Dieses Beispiel erzeugt bereits ziemlich guten Text, aber es gibt mehrere Möglichkeiten, ihn weiter zu verbessern:
-
Bessere Minibatch-Erstellung. Die Art und Weise, wie wir die Daten für das Training vorbereitet haben, bestand darin, ein Minibatch aus einer einzelnen Probe zu generieren. Das ist nicht ideal, da die Minibatches alle unterschiedliche Größen haben und einige von ihnen nicht einmal generiert werden können, weil der Text kleiner als
ncharsist. Außerdem nutzen kleine Minibatches die GPU nicht ausreichend aus. Es wäre klüger, einen großen Textabschnitt aus allen Proben zu nehmen, dann alle Eingabe-Ausgabe-Paare zu generieren, sie zu mischen und Minibatches gleicher Größe zu erstellen. -
Mehrschichtige LSTM. Es macht Sinn, 2 oder 3 Schichten von LSTM-Zellen auszuprobieren. Wie wir in der vorherigen Einheit erwähnt haben, extrahiert jede Schicht eines LSTM bestimmte Muster aus dem Text. Im Fall eines zeichenbasierten Generators können wir erwarten, dass die untere LSTM-Schicht für die Extraktion von Silben verantwortlich ist, während die höheren Schichten für Wörter und Wortkombinationen zuständig sind. Dies kann einfach implementiert werden, indem man den Parameter für die Anzahl der Schichten an den LSTM-Konstruktor übergibt.
-
Es könnte auch interessant sein, mit GRU-Einheiten zu experimentieren, um zu sehen, welche besser funktionieren, sowie mit unterschiedlichen Größen der versteckten Schichten. Eine zu große versteckte Schicht kann zu Overfitting führen (z. B. lernt das Netzwerk den exakten Text), während eine kleinere Größe möglicherweise keine guten Ergebnisse liefert.
Weiche Textgenerierung und Temperatur
In der vorherigen Definition von generate haben wir immer das Zeichen mit der höchsten Wahrscheinlichkeit als nächstes Zeichen im generierten Text ausgewählt. Dies führte oft dazu, dass sich der Text zwischen denselben Zeichenfolgen immer wieder "wiederholte", wie in diesem Beispiel:
today of the second the company and a second the company ...
Wenn wir uns jedoch die Wahrscheinlichkeitsverteilung für das nächste Zeichen ansehen, könnte es sein, dass der Unterschied zwischen den höchsten Wahrscheinlichkeiten nicht groß ist, z. B. kann ein Zeichen eine Wahrscheinlichkeit von 0,2 haben, ein anderes - 0,19 usw. Wenn wir beispielsweise das nächste Zeichen in der Sequenz 'play' suchen, könnte das nächste Zeichen genauso gut ein Leerzeichen oder e sein (wie im Wort player).
Das führt uns zu der Erkenntnis, dass es nicht immer "fair" ist, das Zeichen mit der höchsten Wahrscheinlichkeit auszuwählen, da die Wahl des zweitwahrscheinlichsten Zeichens dennoch zu sinnvollem Text führen könnte. Es ist klüger, Zeichen aus der Wahrscheinlichkeitsverteilung zu samplen, die durch die Netzwerkausgabe vorgegeben wird.
Dieses Sampling kann mit der Funktion multinomial durchgeführt werden, die die sogenannte multinomiale Verteilung implementiert. Eine Funktion, die diese weiche Textgenerierung umsetzt, ist unten definiert:
def generate_soft(net,size=100,start='today ',temperature=1.0):
chars = list(start)
out, s = net(enc(chars).view(1,-1).to(device))
for i in range(size):
#nc = torch.argmax(out[0][-1])
out_dist = out[0][-1].div(temperature).exp()
nc = torch.multinomial(out_dist,1)[0]
chars.append(vocab.get_itos()[nc])
out, s = net(nc.view(1,-1),s)
return ''.join(chars)
for i in [0.3,0.8,1.0,1.3,1.8]:
print(f"--- Temperature = {i}\n{generate_soft(net,size=300,start='Today ',temperature=i)}\n")
Wir haben einen weiteren Parameter namens Temperatur eingeführt, der angibt, wie strikt wir uns an die höchste Wahrscheinlichkeit halten sollten. Wenn die Temperatur 1,0 beträgt, führen wir eine faire multinomiale Stichprobe durch, und wenn die Temperatur gegen unendlich geht, werden alle Wahrscheinlichkeiten gleich, und wir wählen zufällig das nächste Zeichen aus. Im untenstehenden Beispiel können wir beobachten, dass der Text bedeutungslos wird, wenn wir die Temperatur zu stark erhöhen, und er ähnelt einem "zyklischen" hart generierten Text, wenn er sich näher an 0 bewegt.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Generative Netzwerke
Rekurrente neuronale Netzwerke (RNNs) und ihre Varianten mit gated Zellen wie Long Short Term Memory Cells (LSTMs) und Gated Recurrent Units (GRUs) bieten einen Mechanismus für Sprachmodellierung, d.h. sie können die Reihenfolge von Wörtern lernen und Vorhersagen für das nächste Wort in einer Sequenz treffen. Dies ermöglicht es uns, RNNs für generative Aufgaben zu nutzen, wie z.B. gewöhnliche Textgenerierung, maschinelle Übersetzung und sogar Bildbeschriftung.
In der RNN-Architektur, die wir in der vorherigen Einheit besprochen haben, hat jede RNN-Einheit den nächsten versteckten Zustand als Ausgabe erzeugt. Wir können jedoch auch eine weitere Ausgabe zu jeder rekurrenten Einheit hinzufügen, die es uns ermöglicht, eine Sequenz auszugeben (die genauso lang ist wie die ursprüngliche Sequenz). Darüber hinaus können wir RNN-Einheiten verwenden, die bei jedem Schritt keine Eingabe akzeptieren, sondern nur einen anfänglichen Zustandsvektor nehmen und dann eine Sequenz von Ausgaben erzeugen.
In diesem Notebook konzentrieren wir uns auf einfache generative Modelle, die uns helfen, Text zu generieren. Der Einfachheit halber bauen wir ein zeichenbasiertes Netzwerk, das Text Buchstabe für Buchstabe generiert. Während des Trainings müssen wir einen Textkorpus nehmen und ihn in Buchstabenfolgen aufteilen.
import tensorflow as tf
from tensorflow import keras
import tensorflow_datasets as tfds
import numpy as np
ds_train, ds_test = tfds.load('ag_news_subset').values()
Aufbau eines Zeichen-Vokabulars
Um ein generatives Netzwerk auf Zeichenebene zu erstellen, müssen wir den Text in einzelne Zeichen statt in Wörter aufteilen. Die TextVectorization-Schicht, die wir bisher verwendet haben, kann das nicht, daher haben wir zwei Möglichkeiten:
- Den Text manuell laden und die Tokenisierung "von Hand" durchführen, wie in diesem offiziellen Keras-Beispiel
- Die
Tokenizer-Klasse für die Tokenisierung auf Zeichenebene verwenden.
Wir entscheiden uns für die zweite Option. Mit Tokenizer kann man auch in Wörter tokenisieren, sodass man relativ einfach zwischen Tokenisierung auf Zeichen- und Wortebene wechseln kann.
Um eine Tokenisierung auf Zeichenebene durchzuführen, müssen wir den Parameter char_level=True übergeben:
def extract_text(x):
return x['title']+' '+x['description']
def tupelize(x):
return (extract_text(x),x['label'])
tokenizer = keras.preprocessing.text.Tokenizer(char_level=True,lower=False)
tokenizer.fit_on_texts([x['title'].numpy().decode('utf-8') for x in ds_train])
Wir möchten auch ein spezielles Token verwenden, um das Ende der Sequenz zu kennzeichnen, das wir <eos> nennen werden. Lassen Sie uns dieses manuell zum Vokabular hinzufügen:
eos_token = len(tokenizer.word_index)+1
tokenizer.word_index['<eos>'] = eos_token
vocab_size = eos_token + 1
Um Text in Zahlenfolgen zu kodieren, können wir verwenden:
tokenizer.texts_to_sequences(['Hello, world!'])
Training eines generativen RNN zur Erstellung von Titeln
Die Methode, mit der wir ein RNN trainieren, um Nachrichtentitel zu generieren, ist wie folgt: In jedem Schritt nehmen wir einen Titel, der in ein RNN eingespeist wird, und für jedes Eingabezeichen bitten wir das Netzwerk, das nächste Ausgabezeichen zu erzeugen:

Für das letzte Zeichen unserer Sequenz bitten wir das Netzwerk, das <eos>-Token zu generieren.
Der Hauptunterschied bei dem generativen RNN, das wir hier verwenden, besteht darin, dass wir die Ausgabe von jedem Schritt des RNN nehmen und nicht nur von der letzten Zelle. Dies kann erreicht werden, indem der Parameter return_sequences für die RNN-Zelle angegeben wird.
Während des Trainings wäre die Eingabe für das Netzwerk also eine Sequenz von codierten Zeichen einer bestimmten Länge, und die Ausgabe wäre eine Sequenz derselben Länge, jedoch um ein Element verschoben und mit <eos> abgeschlossen. Ein Minibatch besteht aus mehreren solchen Sequenzen, und wir müssen Padding verwenden, um alle Sequenzen auszurichten.
Lassen Sie uns Funktionen erstellen, die den Datensatz für uns transformieren. Da wir Sequenzen auf Minibatch-Ebene auffüllen möchten, werden wir den Datensatz zunächst durch Aufruf von .batch() gruppieren und ihn dann mit map transformieren. Die Transformationsfunktion nimmt also ein ganzes Minibatch als Parameter:
def title_batch(x):
x = [t.numpy().decode('utf-8') for t in x]
z = tokenizer.texts_to_sequences(x)
z = tf.keras.preprocessing.sequence.pad_sequences(z)
return tf.one_hot(z,vocab_size), tf.one_hot(tf.concat([z[:,1:],tf.constant(eos_token,shape=(len(z),1))],axis=1),vocab_size)
Einige wichtige Dinge, die wir hier tun:
Zuerst extrahieren wir den eigentlichen Text aus dem String-Tensor
text_to_sequences konvertiert die Liste von Strings in eine Liste von Integer-Tensoren
pad_sequences füllt diese Tensoren auf ihre maximale Länge auf
Schließlich führen wir eine One-Hot-Codierung aller Zeichen durch, verschieben sie und fügen <eos> hinzu. Wir werden bald sehen, warum wir One-Hot-codierte Zeichen benötigen
Diese Funktion ist jedoch Pythonic, d.h. sie kann nicht automatisch in ein Tensorflow-Berechnungsdiagramm übersetzt werden. Wir erhalten Fehler, wenn wir versuchen, diese Funktion direkt in der Dataset.map-Funktion zu verwenden. Wir müssen diesen Pythonic-Aufruf mit dem py_function-Wrapper umschließen:
def title_batch_fn(x):
x = x['title']
a,b = tf.py_function(title_batch,inp=[x],Tout=(tf.float32,tf.float32))
return a,b
> Hinweis: Der Unterschied zwischen Pythonischen und Tensorflow-Transformationsfunktionen mag etwas zu komplex erscheinen, und Sie fragen sich vielleicht, warum wir den Datensatz nicht mit Standard-Python-Funktionen transformieren, bevor wir ihn an fit übergeben. Obwohl dies definitiv möglich ist, hat die Verwendung von Dataset.map einen großen Vorteil, da die Datenverarbeitungspipeline mit dem Tensorflow-Berechnungsgraphen ausgeführt wird. Dieser nutzt GPU-Berechnungen und minimiert die Notwendigkeit, Daten zwischen CPU und GPU hin- und herzuschieben.
Nun können wir unser Generator-Netzwerk erstellen und mit dem Training beginnen. Es kann auf jeder rekurrenten Zelle basieren, die wir in der vorherigen Einheit besprochen haben (einfach, LSTM oder GRU). In unserem Beispiel verwenden wir LSTM.
Da das Netzwerk Zeichen als Eingabe erhält und die Vokabulargröße relativ klein ist, benötigen wir keine Embedding-Schicht. Die One-Hot-kodierte Eingabe kann direkt in die LSTM-Zelle eingehen. Die Ausgabeschicht wäre ein Dense-Klassifikator, der die LSTM-Ausgabe in One-Hot-kodierte Token-Nummern umwandelt.
Außerdem, da wir es mit Sequenzen variabler Länge zu tun haben, können wir die Masking-Schicht verwenden, um eine Maske zu erstellen, die den gepolsterten Teil der Zeichenkette ignoriert. Dies ist nicht unbedingt erforderlich, da wir uns nicht besonders für alles interessieren, was über das <eos>-Token hinausgeht. Aber wir werden es verwenden, um etwas Erfahrung mit diesem Schichttyp zu sammeln. input_shape wäre (None, vocab_size), wobei None die Sequenz variabler Länge angibt, und die Ausgabeschicht ist ebenfalls (None, vocab_size), wie Sie aus der summary sehen können:
model = keras.models.Sequential([
keras.layers.Masking(input_shape=(None,vocab_size)),
keras.layers.LSTM(128,return_sequences=True),
keras.layers.Dense(vocab_size,activation='softmax')
])
model.summary()
model.compile(loss='categorical_crossentropy')
model.fit(ds_train.batch(8).map(title_batch_fn))
Generieren von Ausgaben
Nachdem wir das Modell trainiert haben, möchten wir es verwenden, um einige Ausgaben zu erzeugen. Zunächst benötigen wir eine Möglichkeit, Text zu dekodieren, der durch eine Sequenz von Token-Nummern dargestellt wird. Dafür könnten wir die Funktion tokenizer.sequences_to_texts verwenden; allerdings funktioniert sie nicht gut mit einer Tokenisierung auf Zeichenebene. Daher nehmen wir ein Wörterbuch der Tokens aus dem Tokenizer (genannt word_index), erstellen eine umgekehrte Zuordnung und schreiben unsere eigene Dekodierungsfunktion:
reverse_map = {val:key for key, val in tokenizer.word_index.items()}
def decode(x):
return ''.join([reverse_map[t] for t in x])
Nun beginnen wir mit einer Zeichenkette start, kodieren sie in eine Sequenz inp, und rufen dann bei jedem Schritt unser Netzwerk auf, um das nächste Zeichen zu bestimmen.
Die Ausgabe des Netzwerks out ist ein Vektor mit vocab_size Elementen, der die Wahrscheinlichkeiten jedes Tokens darstellt. Mit argmax können wir die Nummer des wahrscheinlichsten Tokens finden. Dieses Zeichen fügen wir dann der generierten Liste von Tokens hinzu und setzen die Generierung fort. Dieser Prozess, bei dem ein Zeichen generiert wird, wird size-mal wiederholt, um die benötigte Anzahl von Zeichen zu erzeugen. Die Generierung wird vorzeitig beendet, wenn das eos_token erreicht wird.
def generate(model,size=100,start='Today '):
inp = tokenizer.texts_to_sequences([start])[0]
chars = inp
for i in range(size):
out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]
nc = tf.argmax(out)
if nc==eos_token:
break
chars.append(nc.numpy())
inp = inp+[nc]
return decode(chars)
generate(model)
Ausgabe während des Trainings sampeln
Da wir keine nützlichen Metriken wie Genauigkeit haben, ist die einzige Möglichkeit, zu überprüfen, ob unser Modell besser wird, das Sampeln von generierten Zeichenketten während des Trainings. Dafür verwenden wir Callbacks, also Funktionen, die wir an die fit-Funktion übergeben können und die während des Trainings regelmäßig aufgerufen werden.
sampling_callback = keras.callbacks.LambdaCallback(
on_epoch_end = lambda batch, logs: print(generate(model))
)
model.fit(ds_train.batch(8).map(title_batch_fn),callbacks=[sampling_callback],epochs=3)
Dieses Beispiel erzeugt bereits ziemlich guten Text, aber es gibt mehrere Möglichkeiten, ihn weiter zu verbessern:
-
Mehr Text. Wir haben nur Titel für unsere Aufgabe verwendet, aber es könnte sinnvoll sein, mit vollständigem Text zu experimentieren. Beachten Sie, dass RNNs nicht besonders gut mit langen Sequenzen umgehen können. Daher macht es Sinn, entweder die Texte in kürzere Sätze aufzuteilen oder immer mit einer festen Sequenzlänge eines vordefinierten Werts
num_chars(z. B. 256) zu trainieren. Sie könnten das obige Beispiel in eine solche Architektur umwandeln, indem Sie sich vom offiziellen Keras-Tutorial inspirieren lassen. -
Mehrschichtige LSTM. Es könnte sinnvoll sein, 2 oder 3 Schichten von LSTM-Zellen auszuprobieren. Wie wir in der vorherigen Einheit erwähnt haben, extrahiert jede Schicht eines LSTM bestimmte Muster aus dem Text. Bei einem zeichenbasierten Generator können wir erwarten, dass die unteren LSTM-Schichten für die Extraktion von Silben verantwortlich sind, während die höheren Schichten Wörter und Wortkombinationen erkennen. Dies kann einfach implementiert werden, indem ein Parameter für die Anzahl der Schichten an den LSTM-Konstruktor übergeben wird.
-
Sie könnten auch mit GRU-Einheiten experimentieren, um zu sehen, welche besser abschneiden, sowie mit unterschiedlichen Größen der versteckten Schichten. Eine zu große versteckte Schicht könnte zu Overfitting führen (z. B. lernt das Netzwerk den genauen Text auswendig), während eine kleinere Größe möglicherweise keine guten Ergebnisse liefert.
Weiche Textgenerierung und Temperatur
In der vorherigen Definition von generate haben wir immer das Zeichen mit der höchsten Wahrscheinlichkeit als nächstes Zeichen im generierten Text ausgewählt. Dies führte oft dazu, dass sich der Text zwischen denselben Zeichenfolgen immer wieder "wiederholte", wie in diesem Beispiel:
today of the second the company and a second the company ...
Wenn wir uns jedoch die Wahrscheinlichkeitsverteilung für das nächste Zeichen ansehen, könnte es sein, dass der Unterschied zwischen den höchsten Wahrscheinlichkeiten nicht groß ist, z. B. kann ein Zeichen eine Wahrscheinlichkeit von 0,2 haben, ein anderes - 0,19 usw. Wenn wir beispielsweise das nächste Zeichen in der Sequenz 'play' suchen, könnte das nächste Zeichen genauso gut ein Leerzeichen oder ein e sein (wie im Wort player).
Das führt uns zu der Erkenntnis, dass es nicht immer "fair" ist, das Zeichen mit der höchsten Wahrscheinlichkeit auszuwählen, da die Wahl des zweitwahrscheinlichsten Zeichens dennoch zu sinnvollem Text führen kann. Es ist klüger, Zeichen aus der Wahrscheinlichkeitsverteilung zu samplen, die durch die Netzwerkausgabe gegeben ist.
Dieses Sampling kann mit der Funktion np.multinomial durchgeführt werden, die die sogenannte multinomiale Verteilung implementiert. Eine Funktion, die diese weiche Textgenerierung umsetzt, ist unten definiert:
def generate_soft(model,size=100,start='Today ',temperature=1.0):
inp = tokenizer.texts_to_sequences([start])[0]
chars = inp
for i in range(size):
out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]
probs = tf.exp(tf.math.log(out)/temperature).numpy().astype(np.float64)
probs = probs/np.sum(probs)
nc = np.argmax(np.random.multinomial(1,probs,1))
if nc==eos_token:
break
chars.append(nc)
inp = inp+[nc]
return decode(chars)
words = ['Today ','On Sunday ','Moscow, ','President ','Little red riding hood ']
for i in [0.3,0.8,1.0,1.3,1.8]:
print(f"\n--- Temperature = {i}")
for j in range(5):
print(generate_soft(model,size=300,start=words[j],temperature=i))
Wir haben einen weiteren Parameter namens Temperatur eingeführt, der angibt, wie strikt wir uns an die höchste Wahrscheinlichkeit halten sollten. Wenn die Temperatur 1,0 beträgt, führen wir eine faire multinomiale Stichprobe durch, und wenn die Temperatur gegen unendlich geht, werden alle Wahrscheinlichkeiten gleich, und wir wählen zufällig das nächste Zeichen aus. Im untenstehenden Beispiel können wir beobachten, dass der Text bedeutungslos wird, wenn wir die Temperatur zu stark erhöhen, und er ähnelt einem "zyklischen" hart generierten Text, wenn er sich näher an 0 bewegt.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Wortbasierte Textgenerierung mit RNNs
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
In diesem Labor sollen Sie ein beliebiges Buch verwenden und es als Datensatz nutzen, um einen wortbasierten Textgenerator zu trainieren.
Der Datensatz
Sie können jedes beliebige Buch verwenden. Viele kostenlose Texte finden Sie bei Project Gutenberg, zum Beispiel gibt es hier einen direkten Link zu Alice's Adventures in Wonderland) von Lewis Carroll.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Generative Netzwerke
Quiz vor der Vorlesung
Recurrent Neural Networks (RNNs) und ihre Varianten mit gated Zellen wie Long Short Term Memory Cells (LSTMs) und Gated Recurrent Units (GRUs) bieten eine Möglichkeit zur Sprachmodellierung, da sie die Wortreihenfolge lernen und Vorhersagen für das nächste Wort in einer Sequenz treffen können. Dies ermöglicht es uns, RNNs für generative Aufgaben zu nutzen, wie z. B. gewöhnliche Textgenerierung, maschinelle Übersetzung und sogar Bildbeschriftung.
> ✅ Denke an all die Male, in denen du von generativen Aufgaben wie der Textvervollständigung beim Tippen profitiert hast. Recherchiere zu deinen Lieblingsanwendungen, um herauszufinden, ob sie RNNs verwendet haben.
In der RNN-Architektur, die wir in der vorherigen Einheit besprochen haben, erzeugte jede RNN-Einheit den nächsten versteckten Zustand als Ausgabe. Wir können jedoch auch eine weitere Ausgabe zu jeder rekurrenten Einheit hinzufügen, die es uns ermöglicht, eine Sequenz auszugeben (die genauso lang ist wie die ursprüngliche Sequenz). Darüber hinaus können wir RNN-Einheiten verwenden, die bei jedem Schritt keine Eingabe akzeptieren, sondern nur einen anfänglichen Zustandsvektor nehmen und dann eine Sequenz von Ausgaben erzeugen.
Dies ermöglicht verschiedene neuronale Architekturen, die im folgenden Bild dargestellt sind:

> Bild aus dem Blogpost Unreasonable Effectiveness of Recurrent Neural Networks von Andrej Karpaty
- One-to-one ist ein traditionelles neuronales Netzwerk mit einer Eingabe und einer Ausgabe.
- One-to-many ist eine generative Architektur, die einen Eingabewert akzeptiert und eine Sequenz von Ausgabewerten erzeugt. Zum Beispiel, wenn wir ein Bildbeschriftungsnetzwerk trainieren möchten, das eine textuelle Beschreibung eines Bildes erzeugt, können wir ein Bild als Eingabe nehmen, es durch ein CNN leiten, um seinen versteckten Zustand zu erhalten, und dann eine rekurrente Kette Wort für Wort die Beschriftung generieren lassen.
- Many-to-one entspricht den RNN-Architekturen, die wir in der vorherigen Einheit beschrieben haben, wie z. B. Textklassifikation.
- Many-to-many, oder sequence-to-sequence, entspricht Aufgaben wie maschineller Übersetzung, bei denen wir zuerst ein RNN alle Informationen aus der Eingabesequenz in den versteckten Zustand sammeln lassen und eine andere RNN-Kette diesen Zustand in die Ausgabesequenz entfaltet.
In dieser Einheit konzentrieren wir uns auf einfache generative Modelle, die uns helfen, Text zu generieren. Der Einfachheit halber verwenden wir eine Tokenisierung auf Zeichenebene.
Wir werden dieses RNN trainieren, um Text Schritt für Schritt zu generieren. Bei jedem Schritt nehmen wir eine Zeichenfolge der Länge nchars und bitten das Netzwerk, das nächste Ausgabesymbol für jedes Eingabesymbol zu generieren:

Bei der Textgenerierung (während der Inferenz) beginnen wir mit einem Prompt, der durch die RNN-Zellen geleitet wird, um seinen Zwischenzustand zu erzeugen, und dann beginnt die Generierung aus diesem Zustand. Wir generieren ein Zeichen nach dem anderen und übergeben den Zustand und das generierte Zeichen an eine andere RNN-Zelle, um das nächste zu generieren, bis wir genügend Zeichen erzeugt haben.
<img src="../../../../../translated_images/de/rnn-generate-inf.5168dc65e0370eea.webp" width="60%"/>
> Bild vom Autor
✍️ Übungen: Generative Netzwerke
Setze dein Lernen in den folgenden Notebooks fort:
Weiche Textgenerierung und Temperatur
Die Ausgabe jeder RNN-Zelle ist eine Wahrscheinlichkeitsverteilung von Zeichen. Wenn wir immer das Zeichen mit der höchsten Wahrscheinlichkeit als nächstes Zeichen im generierten Text nehmen, kann der Text oft "zyklisch" werden und sich zwischen denselben Zeichenfolgen wiederholen, wie in diesem Beispiel:
today of the second the company and a second the company ...
Wenn wir jedoch die Wahrscheinlichkeitsverteilung für das nächste Zeichen betrachten, könnte es sein, dass der Unterschied zwischen den höchsten Wahrscheinlichkeiten nicht groß ist, z. B. könnte ein Zeichen eine Wahrscheinlichkeit von 0,2 haben, ein anderes - 0,19 usw. Zum Beispiel könnte das nächste Zeichen in der Sequenz 'play' genauso gut ein Leerzeichen oder e sein (wie im Wort player).
Dies führt uns zu der Erkenntnis, dass es nicht immer "fair" ist, das Zeichen mit der höchsten Wahrscheinlichkeit auszuwählen, da die Wahl des zweitbesten Zeichens immer noch zu sinnvollem Text führen könnte. Es ist klüger, Zeichen aus der Wahrscheinlichkeitsverteilung zu samplen, die durch die Netzwerkausgabe gegeben wird. Wir können auch einen Parameter, Temperatur, verwenden, der die Wahrscheinlichkeitsverteilung abflacht, falls wir mehr Zufälligkeit hinzufügen möchten, oder sie steiler macht, wenn wir uns stärker an die Zeichen mit der höchsten Wahrscheinlichkeit halten möchten.
Erkunde, wie diese weiche Textgenerierung in den oben verlinkten Notebooks implementiert ist.
Fazit
Während die Textgenerierung an sich nützlich sein kann, liegen die Hauptvorteile in der Fähigkeit, Text mithilfe von RNNs aus einem anfänglichen Feature-Vektor zu generieren. Zum Beispiel wird die Textgenerierung als Teil der maschinellen Übersetzung verwendet (sequence-to-sequence, in diesem Fall wird der Zustandsvektor vom Encoder verwendet, um die übersetzte Nachricht zu generieren oder zu decodieren), oder um eine textuelle Beschreibung eines Bildes zu erzeugen (in diesem Fall würde der Feature-Vektor von einem CNN-Extraktor stammen).
🚀 Herausforderung
Nimm einige Lektionen auf Microsoft Learn zu diesem Thema:
- Textgenerierung mit PyTorch/TensorFlow
Quiz nach der Vorlesung
Rückblick & Selbststudium
Hier sind einige Artikel, um dein Wissen zu erweitern:
- Verschiedene Ansätze zur Textgenerierung mit Markov-Kette, LSTM und GPT-2: Blogpost
- Beispiel zur Textgenerierung in der Keras-Dokumentation
Aufgabe
Wir haben gesehen, wie man Text Zeichen für Zeichen generiert. Im Labor wirst du die Textgenerierung auf Wortebene erkunden.
Aufgabe: Transformers
Experimentiere mit Transformers auf HuggingFace! Probiere einige der Skripte aus, die sie bereitstellen, um mit den verschiedenen Modellen auf ihrer Website zu arbeiten: https://huggingface.co/docs/transformers/run_scripts. Teste eines ihrer Datensätze, importiere dann einen eigenen aus diesem Lehrplan oder von Kaggle und schau, ob du interessante Texte generieren kannst. Erstelle ein Notebook mit deinen Ergebnissen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Aufmerksamkeitsmechanismen und Transformer
Quiz vor der Vorlesung
Eines der wichtigsten Probleme im Bereich der NLP ist die maschinelle Übersetzung, eine zentrale Aufgabe, die Tools wie Google Translate zugrunde liegt. In diesem Abschnitt konzentrieren wir uns auf die maschinelle Übersetzung oder allgemeiner auf jede Sequence-to-Sequence-Aufgabe (auch Satztransduktion genannt).
Mit RNNs wird Sequence-to-Sequence durch zwei rekurrente Netzwerke implementiert, wobei ein Netzwerk, der Encoder, eine Eingabesequenz in einen versteckten Zustand zusammenfasst, während ein anderes Netzwerk, der Decoder, diesen versteckten Zustand in ein übersetztes Ergebnis entfaltet. Es gibt jedoch einige Probleme bei diesem Ansatz:
- Der Endzustand des Encoder-Netzwerks hat Schwierigkeiten, sich an den Anfang eines Satzes zu erinnern, was zu einer schlechten Modellqualität bei langen Sätzen führt.
- Alle Wörter in einer Sequenz haben den gleichen Einfluss auf das Ergebnis. In der Realität haben jedoch bestimmte Wörter in der Eingabesequenz oft mehr Einfluss auf die sequentiellen Ausgaben als andere.
Aufmerksamkeitsmechanismen bieten eine Möglichkeit, den kontextuellen Einfluss jedes Eingabevektors auf jede Ausgabewahrscheinlichkeit des RNN zu gewichten. Dies wird durch die Erstellung von Abkürzungen zwischen den Zwischenzuständen des Eingabe-RNN und des Ausgabe-RNN umgesetzt. Auf diese Weise berücksichtigen wir beim Generieren des Ausgabesymbols y<sub>t</sub> alle versteckten Eingabezustände h<sub>i</sub>, mit unterschiedlichen Gewichtungskoeffizienten α<sub>t,i</sub>.

> Das Encoder-Decoder-Modell mit additivem Aufmerksamkeitsmechanismus aus Bahdanau et al., 2015, zitiert aus diesem Blogbeitrag
Die Aufmerksamkeitsmatrix {α<sub>i,j</sub>} repräsentiert den Grad, in dem bestimmte Eingabewörter bei der Generierung eines bestimmten Wortes in der Ausgabesequenz eine Rolle spielen. Unten ist ein Beispiel für eine solche Matrix:

> Abbildung aus Bahdanau et al., 2015 (Fig.3)
Aufmerksamkeitsmechanismen sind verantwortlich für viele der aktuellen oder nahezu aktuellen Spitzenleistungen in der NLP. Das Hinzufügen von Aufmerksamkeit erhöht jedoch die Anzahl der Modellparameter erheblich, was zu Skalierungsproblemen bei RNNs führte. Eine zentrale Einschränkung bei der Skalierung von RNNs ist, dass die rekurrente Natur der Modelle es schwierig macht, das Training zu batchen und zu parallelisieren. In einem RNN muss jedes Element einer Sequenz in der Reihenfolge verarbeitet werden, was eine einfache Parallelisierung verhindert.

> Abbildung aus Googles Blog
Die Einführung von Aufmerksamkeitsmechanismen in Kombination mit dieser Einschränkung führte zur Entwicklung der heute bekannten und genutzten Transformer-Modelle, wie BERT und Open-GPT3.
Transformer-Modelle
Eine der Hauptideen hinter Transformern ist es, die sequentielle Natur von RNNs zu vermeiden und ein Modell zu schaffen, das während des Trainings parallelisierbar ist. Dies wird durch die Implementierung von zwei Ideen erreicht:
- Positionskodierung
- Verwendung des Self-Attention-Mechanismus, um Muster zu erfassen, anstelle von RNNs (oder CNNs) (deshalb heißt das Paper, das Transformer einführt, Attention is all you need).
Positionskodierung/Einbettung
Die Idee der Positionskodierung ist folgende:
1. Bei der Verwendung von RNNs wird die relative Position der Tokens durch die Anzahl der Schritte dargestellt und muss daher nicht explizit repräsentiert werden.
2. Sobald wir jedoch zu Aufmerksamkeit wechseln, müssen wir die relativen Positionen der Tokens innerhalb einer Sequenz kennen.
3. Um Positionskodierung zu erhalten, erweitern wir unsere Sequenz von Tokens mit einer Sequenz von Token-Positionen in der Sequenz (d.h. eine Sequenz von Zahlen 0,1, ...).
4. Wir mischen dann die Token-Position mit einem Token-Einbettungsvektor. Um die Position (Ganzzahl) in einen Vektor zu transformieren, können wir verschiedene Ansätze verwenden:
- Trainierbare Einbettung, ähnlich wie Token-Einbettung. Dies ist der Ansatz, den wir hier betrachten. Wir wenden Einbettungsschichten sowohl auf Tokens als auch auf ihre Positionen an, was zu Einbettungsvektoren mit denselben Dimensionen führt, die wir dann zusammen addieren.
- Feste Positionskodierungsfunktion, wie im ursprünglichen Paper vorgeschlagen.
<img src="../../../../../translated_images/de/pos-embedding.e41ce9b6cf6078af.webp" width="50%"/>
> Bild vom Autor
Das Ergebnis, das wir mit Positionskodierung erhalten, bettet sowohl das ursprüngliche Token als auch dessen Position innerhalb einer Sequenz ein.
Multi-Head Self-Attention
Als Nächstes müssen wir einige Muster innerhalb unserer Sequenz erfassen. Um dies zu tun, verwenden Transformer einen Self-Attention-Mechanismus, der im Wesentlichen Aufmerksamkeit ist, die auf dieselbe Sequenz als Eingabe und Ausgabe angewendet wird. Die Anwendung von Self-Attention ermöglicht es uns, den Kontext innerhalb des Satzes zu berücksichtigen und zu sehen, welche Wörter miteinander in Beziehung stehen. Zum Beispiel ermöglicht es uns zu sehen, auf welche Wörter durch Koreferenzen wie es verwiesen wird, und auch den Kontext zu berücksichtigen:

> Bild aus dem Google Blog
In Transformern verwenden wir Multi-Head Attention, um dem Netzwerk die Fähigkeit zu geben, verschiedene Arten von Abhängigkeiten zu erfassen, z. B. langfristige vs. kurzfristige Wortbeziehungen, Koreferenzen vs. etwas anderes usw.
TensorFlow Notebook enthält weitere Details zur Implementierung von Transformer-Schichten.
Encoder-Decoder-Aufmerksamkeit
In Transformern wird Aufmerksamkeit an zwei Stellen verwendet:
- Um Muster innerhalb des Eingabetextes mit Self-Attention zu erfassen
- Um Sequenzübersetzung durchzuführen – dies ist die Aufmerksamkeits-Schicht zwischen Encoder und Decoder.
Encoder-Decoder-Aufmerksamkeit ist der Aufmerksamkeitsmechanismus, der in RNNs verwendet wird, wie zu Beginn dieses Abschnitts beschrieben. Dieses animierte Diagramm erklärt die Rolle der Encoder-Decoder-Aufmerksamkeit.

Da jede Eingabeposition unabhängig von jeder Ausgabeposition abgebildet wird, können Transformer besser parallelisieren als RNNs, was viel größere und ausdrucksstärkere Sprachmodelle ermöglicht. Jeder Aufmerksamkeitskopf kann verwendet werden, um verschiedene Beziehungen zwischen Wörtern zu lernen, was die nachgelagerten Aufgaben der natürlichen Sprachverarbeitung verbessert.
BERT
BERT (Bidirectional Encoder Representations from Transformers) ist ein sehr großes mehrschichtiges Transformer-Netzwerk mit 12 Schichten für BERT-base und 24 für BERT-large. Das Modell wird zunächst auf einem großen Textkorpus (Wikipedia + Bücher) mit unüberwachtem Training (Vorhersage maskierter Wörter in einem Satz) vortrainiert. Während des Vortrainings nimmt das Modell ein erhebliches Maß an Sprachverständnis auf, das dann mit anderen Datensätzen durch Feintuning genutzt werden kann. Dieser Prozess wird als Transfer Learning bezeichnet.

> Bild Quelle
✍️ Übungen: Transformer
Setzen Sie Ihr Lernen in den folgenden Notebooks fort:
Fazit
In dieser Lektion haben Sie etwas über Transformer und Aufmerksamkeitsmechanismen gelernt, alles wesentliche Werkzeuge im NLP-Werkzeugkasten. Es gibt viele Variationen von Transformer-Architekturen, einschließlich BERT, DistilBERT, BigBird, OpenGPT3 und mehr, die fein abgestimmt werden können. Das HuggingFace-Paket bietet ein Repository für das Training vieler dieser Architekturen mit sowohl PyTorch als auch TensorFlow.
🚀 Herausforderung
Quiz nach der Vorlesung
Überprüfung & Selbststudium
- Blogbeitrag, der das klassische Attention is all you need-Paper über Transformer erklärt.
- Eine Serie von Blogbeiträgen über Transformer, die die Architektur im Detail erklären.
Aufgabe
Aufmerksamkeitsmechanismen und Transformer
Ein wesentlicher Nachteil von rekurrenten Netzwerken ist, dass alle Wörter in einer Sequenz den gleichen Einfluss auf das Ergebnis haben. Dies führt zu suboptimaler Leistung bei Standard-LSTM-Encoder-Decoder-Modellen für Sequenz-zu-Sequenz-Aufgaben wie der Erkennung benannter Entitäten (Named Entity Recognition) und maschineller Übersetzung. In der Realität haben bestimmte Wörter in der Eingabesequenz oft mehr Einfluss auf die sequentiellen Ausgaben als andere.
Betrachten wir ein Sequenz-zu-Sequenz-Modell, wie es bei der maschinellen Übersetzung verwendet wird. Es wird durch zwei rekurrente Netzwerke implementiert, wobei ein Netzwerk (Encoder) die Eingabesequenz in einen versteckten Zustand komprimiert und ein anderes Netzwerk (Decoder) diesen versteckten Zustand in das übersetzte Ergebnis entfaltet. Das Problem bei diesem Ansatz ist, dass der Endzustand des Netzwerks Schwierigkeiten hat, sich an den Anfang eines Satzes zu erinnern, was zu einer schlechten Modellqualität bei langen Sätzen führt.
Aufmerksamkeitsmechanismen bieten eine Möglichkeit, den kontextuellen Einfluss jedes Eingabevektors auf jede Ausgabewahrscheinlichkeit des RNN zu gewichten. Dies wird durch die Erstellung von Abkürzungen zwischen den Zwischenzuständen des Eingabe-RNN und des Ausgabe-RNN umgesetzt. Auf diese Weise berücksichtigen wir bei der Generierung des Ausgabesymbols $y_t$ alle versteckten Eingabezustände $h_i$, mit unterschiedlichen Gewichtungskoeffizienten $\alpha_{t,i}$.
Das Encoder-Decoder-Modell mit additivem Aufmerksamkeitsmechanismus aus Bahdanau et al., 2015, zitiert aus diesem Blogpost
Die Aufmerksamkeitsmatrix ${\alpha_{i,j}}$ repräsentiert den Grad, in dem bestimmte Eingabewörter bei der Generierung eines bestimmten Wortes in der Ausgabesequenz eine Rolle spielen. Unten ist ein Beispiel für eine solche Matrix dargestellt:

Abbildung aus Bahdanau et al., 2015 (Fig.3)
Aufmerksamkeitsmechanismen sind für einen Großteil des aktuellen oder nahezu aktuellen Stands der Technik in der Verarbeitung natürlicher Sprache verantwortlich. Das Hinzufügen von Aufmerksamkeit erhöht jedoch die Anzahl der Modellparameter erheblich, was zu Skalierungsproblemen bei RNNs führte. Eine zentrale Einschränkung bei der Skalierung von RNNs ist, dass die rekurrente Natur der Modelle es schwierig macht, das Training zu batchen und zu parallelisieren. In einem RNN muss jedes Element einer Sequenz in der Reihenfolge verarbeitet werden, was bedeutet, dass es nicht leicht parallelisiert werden kann.
Die Einführung von Aufmerksamkeitsmechanismen in Kombination mit dieser Einschränkung führte zur Entwicklung der heute bekannten und genutzten Transformer-Modelle, die den Stand der Technik darstellen, von BERT bis OpenGPT3.
Transformer-Modelle
Anstatt den Kontext jeder vorherigen Vorhersage in den nächsten Evaluierungsschritt weiterzuleiten, verwenden Transformer-Modelle Positionskodierungen und Aufmerksamkeit, um den Kontext einer gegebenen Eingabe innerhalb eines bereitgestellten Textfensters zu erfassen. Das folgende Bild zeigt, wie Positionskodierungen mit Aufmerksamkeit den Kontext innerhalb eines bestimmten Fensters erfassen können.

Da jede Eingabeposition unabhängig auf jede Ausgabeposition abgebildet wird, können Transformer besser parallelisiert werden als RNNs, was viel größere und ausdrucksstärkere Sprachmodelle ermöglicht. Jeder Aufmerksamkeitskopf kann verwendet werden, um unterschiedliche Beziehungen zwischen Wörtern zu lernen, was die nachgelagerten Aufgaben der Verarbeitung natürlicher Sprache verbessert.
BERT (Bidirectional Encoder Representations from Transformers) ist ein sehr großes mehrschichtiges Transformer-Netzwerk mit 12 Schichten für BERT-base und 24 für BERT-large. Das Modell wird zunächst auf einem großen Textkorpus (Wikipedia + Bücher) mit unüberwachtem Training (Vorhersage maskierter Wörter in einem Satz) vortrainiert. Während des Vortrainings erwirbt das Modell ein signifikantes Maß an Sprachverständnis, das dann mit anderen Datensätzen durch Feintuning genutzt werden kann. Dieser Prozess wird als Transferlernen bezeichnet.

Es gibt viele Variationen von Transformer-Architekturen, darunter BERT, DistilBERT, BigBird, OpenGPT3 und mehr, die feinabgestimmt werden können. Das HuggingFace-Paket bietet ein Repository für das Training vieler dieser Architekturen mit PyTorch.
Verwendung von BERT für Textklassifikation
Schauen wir uns an, wie wir ein vortrainiertes BERT-Modell verwenden können, um unsere traditionelle Aufgabe zu lösen: die Sequenzklassifikation. Wir werden unser ursprüngliches AG-News-Dataset klassifizieren.
Zuerst laden wir die HuggingFace-Bibliothek und unser Dataset:
import torch
import torchtext
from torchnlp import *
import transformers
train_dataset, test_dataset, classes, vocab = load_dataset()
vocab_len = len(vocab)
Da wir ein vortrainiertes BERT-Modell verwenden werden, benötigen wir einen spezifischen Tokenizer. Zunächst laden wir einen Tokenizer, der mit dem vortrainierten BERT-Modell verbunden ist.
Die HuggingFace-Bibliothek enthält ein Repository vortrainierter Modelle, die Sie einfach verwenden können, indem Sie ihre Namen als Argumente für die from_pretrained-Funktionen angeben. Alle erforderlichen Binärdateien für das Modell werden automatisch heruntergeladen.
Es gibt jedoch Situationen, in denen Sie Ihre eigenen Modelle laden müssen. In diesem Fall können Sie das Verzeichnis angeben, das alle relevanten Dateien enthält, einschließlich der Parameter für den Tokenizer, der config.json-Datei mit den Modellparametern, der Binärgewichte usw.
# To load the model from Internet repository using model name.
# Use this if you are running from your own copy of the notebooks
bert_model = 'bert-base-uncased'
# To load the model from the directory on disk. Use this for Microsoft Learn module, because we have
# prepared all required files for you.
bert_model = './bert'
tokenizer = transformers.BertTokenizer.from_pretrained(bert_model)
MAX_SEQ_LEN = 128
PAD_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)
UNK_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.unk_token)
Das tokenizer-Objekt enthält die encode-Funktion, die direkt verwendet werden kann, um Text zu kodieren:
tokenizer.encode('PyTorch is a great framework for NLP')
Dann erstellen wir Iteratoren, die wir während des Trainings verwenden, um auf die Daten zuzugreifen. Da BERT seine eigene Kodierungsfunktion verwendet, müssen wir eine Padding-Funktion ähnlich der zuvor definierten padify-Funktion definieren:
def pad_bert(b):
# b is the list of tuples of length batch_size
# - first element of a tuple = label,
# - second = feature (text sequence)
# build vectorized sequence
v = [tokenizer.encode(x[1]) for x in b]
# compute max length of a sequence in this minibatch
l = max(map(len,v))
return ( # tuple of two tensors - labels and features
torch.LongTensor([t[0] for t in b]),
torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v])
)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=8, collate_fn=pad_bert, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=8, collate_fn=pad_bert)
In unserem Fall werden wir ein vortrainiertes BERT-Modell namens bert-base-uncased verwenden. Laden wir das Modell mit dem Paket BertForSequenceClassification. Dies stellt sicher, dass unser Modell bereits über die erforderliche Architektur für die Klassifikation verfügt, einschließlich des finalen Klassifikators. Sie werden eine Warnmeldung sehen, die besagt, dass die Gewichte des finalen Klassifikators nicht initialisiert sind und das Modell ein Pre-Training erfordert – das ist völlig in Ordnung, denn genau das werden wir jetzt tun!
model = transformers.BertForSequenceClassification.from_pretrained(bert_model,num_labels=4).to(device)
Jetzt können wir mit dem Training beginnen! Da BERT bereits vortrainiert ist, möchten wir mit einer eher kleinen Lernrate starten, um die anfänglichen Gewichte nicht zu zerstören.
Die Hauptarbeit wird vom Modell BertForSequenceClassification erledigt. Wenn wir das Modell auf die Trainingsdaten anwenden, liefert es sowohl den Verlust als auch die Netzwerkausgabe für den Eingabe-Minibatch. Den Verlust verwenden wir für die Parameteroptimierung (loss.backward() führt den Backward-Pass aus), und out nutzen wir, um die Trainingsgenauigkeit zu berechnen, indem wir die erhaltenen Labels labs (berechnet mit argmax) mit den erwarteten labels vergleichen.
Um den Prozess zu kontrollieren, akkumulieren wir Verlust und Genauigkeit über mehrere Iterationen und geben sie alle report_freq Trainingszyklen aus.
Dieses Training wird wahrscheinlich ziemlich lange dauern, daher begrenzen wir die Anzahl der Iterationen.
optimizer = torch.optim.Adam(model.parameters(), lr=2e-5)
report_freq = 50
iterations = 500 # make this larger to train for longer time!
model.train()
i,c = 0,0
acc_loss = 0
acc_acc = 0
for labels,texts in train_loader:
labels = labels.to(device)-1 # get labels in the range 0-3
texts = texts.to(device)
loss, out = model(texts, labels=labels)[:2]
labs = out.argmax(dim=1)
acc = torch.mean((labs==labels).type(torch.float32))
optimizer.zero_grad()
loss.backward()
optimizer.step()
acc_loss += loss
acc_acc += acc
i+=1
c+=1
if i%report_freq==0:
print(f"Loss = {acc_loss.item()/c}, Accuracy = {acc_acc.item()/c}")
c = 0
acc_loss = 0
acc_acc = 0
iterations-=1
if not iterations:
break
Man kann sehen (besonders wenn man die Anzahl der Iterationen erhöht und lange genug wartet), dass die Klassifikation mit BERT uns eine ziemlich gute Genauigkeit liefert! Das liegt daran, dass BERT die Struktur der Sprache bereits sehr gut versteht und wir nur den finalen Klassifikator feinabstimmen müssen. Allerdings ist BERT ein großes Modell, weshalb der gesamte Trainingsprozess viel Zeit in Anspruch nimmt und erhebliche Rechenleistung erfordert! (GPU, und vorzugsweise mehr als eine).
> Hinweis: In unserem Beispiel haben wir eines der kleinsten vortrainierten BERT-Modelle verwendet. Es gibt größere Modelle, die wahrscheinlich bessere Ergebnisse liefern.
Bewertung der Modellleistung
Nun können wir die Leistung unseres Modells auf dem Testdatensatz bewerten. Die Evaluierungsschleife ähnelt stark der Trainingsschleife, aber wir dürfen nicht vergessen, das Modell in den Evaluierungsmodus zu versetzen, indem wir model.eval() aufrufen.
model.eval()
iterations = 100
acc = 0
i = 0
for labels,texts in test_loader:
labels = labels.to(device)-1
texts = texts.to(device)
_, out = model(texts, labels=labels)[:2]
labs = out.argmax(dim=1)
acc += torch.mean((labs==labels).type(torch.float32))
i+=1
if i>iterations: break
print(f"Final accuracy: {acc.item()/i}")
Wichtiges Fazit
In dieser Einheit haben wir gesehen, wie einfach es ist, ein vortrainiertes Sprachmodell aus der transformers-Bibliothek zu übernehmen und es an unsere Textklassifizierungsaufgabe anzupassen. Ebenso können BERT-Modelle für die Entitätsextraktion, das Beantworten von Fragen und andere NLP-Aufgaben verwendet werden.
Transformermodelle stellen den aktuellen Stand der Technik im Bereich NLP dar, und in den meisten Fällen sollten sie die erste Lösung sein, mit der Sie experimentieren, wenn Sie benutzerdefinierte NLP-Lösungen implementieren. Dennoch ist es äußerst wichtig, die grundlegenden Prinzipien von rekurrenten neuronalen Netzwerken, die in diesem Modul besprochen wurden, zu verstehen, wenn Sie fortgeschrittene neuronale Modelle entwickeln möchten.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Aufmerksamkeitsmechanismen und Transformer
Ein wesentlicher Nachteil von rekurrenten Netzwerken ist, dass alle Wörter in einer Sequenz den gleichen Einfluss auf das Ergebnis haben. Dies führt zu suboptimaler Leistung bei Standard-LSTM-Encoder-Decoder-Modellen für Sequenz-zu-Sequenz-Aufgaben wie der Erkennung benannter Entitäten (Named Entity Recognition) und maschineller Übersetzung. In der Realität haben bestimmte Wörter in der Eingabesequenz oft mehr Einfluss auf die sequentiellen Ausgaben als andere.
Betrachten wir ein Sequenz-zu-Sequenz-Modell, wie es bei der maschinellen Übersetzung verwendet wird. Es wird durch zwei rekurrente Netzwerke implementiert, wobei ein Netzwerk (Encoder) die Eingabesequenz in einen versteckten Zustand komprimiert und ein anderes Netzwerk (Decoder) diesen versteckten Zustand in das übersetzte Ergebnis entfaltet. Das Problem bei diesem Ansatz ist, dass der Endzustand des Netzwerks Schwierigkeiten hat, sich an den Anfang eines Satzes zu erinnern, was zu einer schlechten Modellqualität bei langen Sätzen führt.
Aufmerksamkeitsmechanismen bieten eine Möglichkeit, den kontextuellen Einfluss jedes Eingabevektors auf jede Ausgabewahrscheinlichkeit des RNN zu gewichten. Dies wird durch die Erstellung von Abkürzungen zwischen den Zwischenzuständen des Eingabe-RNN und des Ausgabe-RNN umgesetzt. Auf diese Weise berücksichtigen wir bei der Generierung des Ausgabesymbols $y_t$ alle versteckten Eingabezustände $h_i$, mit unterschiedlichen Gewichtungskoeffizienten $\alpha_{t,i}$.
Das Encoder-Decoder-Modell mit additivem Aufmerksamkeitsmechanismus aus Bahdanau et al., 2015, zitiert aus diesem Blogbeitrag
Die Aufmerksamkeitsmatrix ${\alpha_{i,j}}$ repräsentiert den Grad, in dem bestimmte Eingabewörter bei der Generierung eines bestimmten Wortes in der Ausgabesequenz eine Rolle spielen. Unten ist ein Beispiel für eine solche Matrix dargestellt:

Abbildung aus Bahdanau et al., 2015 (Abb. 3)
Aufmerksamkeitsmechanismen sind für einen Großteil des aktuellen oder nahezu aktuellen Stands der Technik in der Verarbeitung natürlicher Sprache verantwortlich. Das Hinzufügen von Aufmerksamkeit erhöht jedoch die Anzahl der Modellparameter erheblich, was zu Skalierungsproblemen bei RNNs führte. Eine zentrale Einschränkung bei der Skalierung von RNNs ist, dass die rekurrente Natur der Modelle es schwierig macht, das Training zu batchen und zu parallelisieren. In einem RNN muss jedes Element einer Sequenz in der Reihenfolge verarbeitet werden, was bedeutet, dass es nicht leicht parallelisiert werden kann.
Die Einführung von Aufmerksamkeitsmechanismen in Kombination mit dieser Einschränkung führte zur Entwicklung der heute bekannten und genutzten Transformer-Modelle, die den Stand der Technik darstellen, von BERT bis OpenGPT3.
Transformer-Modelle
Anstatt den Kontext jeder vorherigen Vorhersage in den nächsten Evaluierungsschritt weiterzuleiten, verwenden Transformer-Modelle Positionskodierungen und Aufmerksamkeit, um den Kontext einer gegebenen Eingabe innerhalb eines bereitgestellten Textfensters zu erfassen. Das folgende Bild zeigt, wie Positionskodierungen mit Aufmerksamkeit den Kontext innerhalb eines bestimmten Fensters erfassen können.

Da jede Eingabeposition unabhängig auf jede Ausgabeposition abgebildet wird, können Transformer besser parallelisieren als RNNs, was viel größere und ausdrucksstärkere Sprachmodelle ermöglicht. Jeder Aufmerksamkeitskopf kann verwendet werden, um unterschiedliche Beziehungen zwischen Wörtern zu lernen, was die nachgelagerten Aufgaben der Verarbeitung natürlicher Sprache verbessert.
Einfaches Transformer-Modell erstellen
Keras enthält keine eingebaute Transformer-Schicht, aber wir können unsere eigene erstellen. Wie zuvor konzentrieren wir uns auf die Textklassifikation des AG-News-Datensatzes, aber es ist erwähnenswert, dass Transformer-Modelle bei schwierigeren NLP-Aufgaben die besten Ergebnisse zeigen.
import tensorflow as tf
from tensorflow import keras
import tensorflow_datasets as tfds
import numpy as np
ds_train, ds_test = tfds.load('ag_news_subset').values()
def extract_text(x):
return x['title']+' '+x['description']
def tupelize(x):
return (extract_text(x),x['label'])
Neue Schichten in Keras sollten die Klasse Layer unterklassen und die Methode call implementieren. Beginnen wir mit der Positional Embedding-Schicht. Wir werden einige Code aus der offiziellen Keras-Dokumentation verwenden. Wir nehmen an, dass wir alle Eingabesequenzen auf die Länge maxlen auffüllen.
class TokenAndPositionEmbedding(keras.layers.Layer):
def __init__(self, maxlen, vocab_size, embed_dim):
super(TokenAndPositionEmbedding, self).__init__()
self.token_emb = keras.layers.Embedding(input_dim=vocab_size, output_dim=embed_dim)
self.pos_emb = keras.layers.Embedding(input_dim=maxlen, output_dim=embed_dim)
self.maxlen = maxlen
def call(self, x):
maxlen = self.maxlen
positions = tf.range(start=0, limit=maxlen, delta=1)
positions = self.pos_emb(positions)
x = self.token_emb(x)
return x+positions
Diese Schicht besteht aus zwei Embedding-Schichten: eine für das Einbetten von Tokens (wie wir es zuvor besprochen haben) und eine für die Positionen der Tokens. Die Positionen der Tokens werden als eine Sequenz natürlicher Zahlen von 0 bis maxlen mithilfe von tf.range erstellt und anschließend durch die Einbettungsschicht geleitet. Die beiden resultierenden Einbettungsvektoren werden dann addiert, wodurch eine positionsbezogene Einbettungsdarstellung der Eingabe mit der Form maxlen$\times$embed_dim entsteht.
Nun implementieren wir den Transformer-Block. Er wird die Ausgabe der zuvor definierten Einbettungsschicht übernehmen:
class TransformerBlock(keras.layers.Layer):
def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1):
super(TransformerBlock, self).__init__()
self.att = keras.layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, name='attn')
self.ffn = keras.Sequential(
[keras.layers.Dense(ff_dim, activation="relu"), keras.layers.Dense(embed_dim),]
)
self.layernorm1 = keras.layers.LayerNormalization(epsilon=1e-6)
self.layernorm2 = keras.layers.LayerNormalization(epsilon=1e-6)
self.dropout1 = keras.layers.Dropout(rate)
self.dropout2 = keras.layers.Dropout(rate)
def call(self, inputs, training):
attn_output = self.att(inputs, inputs)
attn_output = self.dropout1(attn_output, training=training)
out1 = self.layernorm1(inputs + attn_output)
ffn_output = self.ffn(out1)
ffn_output = self.dropout2(ffn_output, training=training)
return self.layernorm2(out1 + ffn_output)
Der Transformer wendet MultiHeadAttention auf die positionskodierte Eingabe an, um den Aufmerksamkeitsvektor mit der Dimension maxlen$\times$embed_dim zu erzeugen, der dann mit der Eingabe gemischt und mittels LayerNormalization normalisiert wird.
> Hinweis: LayerNormalization ähnelt der BatchNormalization, die im Abschnitt Computer Vision dieses Lernpfads behandelt wurde. Sie normalisiert die Ausgaben der vorherigen Schicht für jede Trainingsprobe unabhängig, um sie in den Bereich [-1..1] zu bringen.
Die Ausgabe dieser Schicht wird anschließend durch ein Dense Netzwerk geleitet (in unserem Fall ein zweischichtiger Perzeptron), und das Ergebnis wird zur endgültigen Ausgabe hinzugefügt (die erneut normalisiert wird).
embed_dim = 32 # Embedding size for each token
num_heads = 2 # Number of attention heads
ff_dim = 32 # Hidden layer size in feed forward network inside transformer
maxlen = 256
vocab_size = 20000
model = keras.models.Sequential([
keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_sequence_length=maxlen, input_shape=(1,)),
TokenAndPositionEmbedding(maxlen, vocab_size, embed_dim),
TransformerBlock(embed_dim, num_heads, ff_dim),
keras.layers.GlobalAveragePooling1D(),
keras.layers.Dropout(0.1),
keras.layers.Dense(20, activation="relu"),
keras.layers.Dropout(0.1),
keras.layers.Dense(4, activation="softmax")
])
model.summary()
print('Training tokenizer')
model.layers[0].adapt(ds_train.map(extract_text))
model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')
model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128))
BERT Transformer-Modelle
BERT (Bidirectional Encoder Representations from Transformers) ist ein sehr großes mehrschichtiges Transformer-Netzwerk mit 12 Schichten für BERT-base und 24 für BERT-large. Das Modell wird zunächst mit einem großen Textkorpus (Wikipedia + Bücher) mittels unüberwachtem Training vortrainiert (Vorhersage von maskierten Wörtern in einem Satz). Während des Vortrainings erlangt das Modell ein erhebliches Maß an Sprachverständnis, das anschließend mit anderen Datensätzen durch Feintuning genutzt werden kann. Dieser Prozess wird als Transferlernen bezeichnet.

Es gibt viele Varianten von Transformer-Architekturen, darunter BERT, DistilBERT, BigBird, OpenGPT3 und mehr, die fein abgestimmt werden können.
Schauen wir uns an, wie wir ein vortrainiertes BERT-Modell verwenden können, um unser traditionelles Problem der Sequenzklassifikation zu lösen. Wir werden die Idee und etwas Code aus der offiziellen Dokumentation übernehmen.
Um vortrainierte Modelle zu laden, verwenden wir Tensorflow hub. Zunächst laden wir den BERT-spezifischen Vektorisierer:
import tensorflow_text
import tensorflow_hub as hub
vectorizer = hub.KerasLayer('https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3')
vectorizer(['I love transformers'])
Es ist wichtig, dass Sie denselben Vektorisierer verwenden, mit dem das ursprüngliche Netzwerk trainiert wurde. Außerdem gibt der BERT-Vektorisierer drei Komponenten zurück:
* input_word_ids, eine Sequenz von Token-Nummern für den Eingabesatz
* input_mask, die zeigt, welcher Teil der Sequenz tatsächliche Eingaben enthält und welcher Teil Padding ist. Dies ist ähnlich der Maske, die von der Masking-Schicht erzeugt wird
* input_type_ids wird für Aufgaben im Bereich Sprachmodellierung verwendet und ermöglicht es, zwei Eingabesätze in einer Sequenz anzugeben.
Anschließend können wir den BERT-Feature-Extractor instanziieren:
bert = hub.KerasLayer('https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-128_A-2/1')
z = bert(vectorizer(['I love transformers']))
for i,x in z.items():
print(f"{i} -> { len(x) if isinstance(x, list) else x.shape }")
Die BERT-Schicht liefert eine Reihe nützlicher Ergebnisse:
* pooled_output ist das Ergebnis des Mittelwerts aller Tokens in der Sequenz. Sie können es als eine intelligente semantische Einbettung des gesamten Netzwerks betrachten. Es entspricht der Ausgabe der GlobalAveragePooling1D-Schicht in unserem vorherigen Modell.
* sequence_output ist die Ausgabe der letzten Transformer-Schicht (entspricht der Ausgabe von TransformerBlock in unserem obigen Modell).
* encoder_outputs sind die Ausgaben aller Transformer-Schichten. Da wir ein 4-Schichten-BERT-Modell geladen haben (wie Sie wahrscheinlich aus dem Namen schließen können, der 4_H enthält), gibt es 4 Tensoren. Der letzte davon ist identisch mit sequence_output.
Nun werden wir das End-to-End-Klassifikationsmodell definieren. Wir verwenden die funktionale Modelldefinition, bei der wir den Modelleingang definieren und dann eine Reihe von Ausdrücken angeben, um dessen Ausgabe zu berechnen. Außerdem werden wir die Gewichte des BERT-Modells nicht trainierbar machen und nur den finalen Klassifikator trainieren:
inp = keras.Input(shape=(),dtype=tf.string)
x = vectorizer(inp)
x = bert(x)
x = keras.layers.Dropout(0.1)(x['pooled_output'])
out = keras.layers.Dense(4,activation='softmax')(x)
model = keras.models.Model(inp,out)
bert.trainable = False
model.summary()
model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')
model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128))
Trotz der Tatsache, dass es nur wenige trainierbare Parameter gibt, ist der Prozess ziemlich langsam, da der BERT-Feature-Extractor rechnerisch sehr aufwendig ist. Es scheint, dass wir keine angemessene Genauigkeit erreichen konnten, entweder aufgrund mangelnden Trainings oder fehlender Modellparameter.
Lassen Sie uns versuchen, die BERT-Gewichte zu entsperren und ebenfalls zu trainieren. Dies erfordert eine sehr kleine Lernrate und eine sorgfältigere Trainingsstrategie mit Warmup, unter Verwendung des AdamW-Optimierers. Wir werden das tf-models-official-Paket verwenden, um den Optimierer zu erstellen:
from official.nlp import optimization
bert.trainable=True
model.summary()
epochs = 3
opt = optimization.create_optimizer(
init_lr=3e-5,
num_train_steps=epochs*len(ds_train),
num_warmup_steps=0.1*epochs*len(ds_train),
optimizer_type='adamw')
model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer=opt)
model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128))
Wie Sie sehen, verläuft das Training ziemlich langsam – aber Sie könnten experimentieren und das Modell für ein paar Epochen (5-10) trainieren, um zu sehen, ob Sie im Vergleich zu den zuvor verwendeten Ansätzen das beste Ergebnis erzielen können.
Huggingface Transformers-Bibliothek
Eine weitere sehr gängige (und etwas einfachere) Möglichkeit, Transformer-Modelle zu verwenden, ist das HuggingFace-Paket, das einfache Bausteine für verschiedene NLP-Aufgaben bereitstellt. Es ist sowohl für Tensorflow als auch für PyTorch verfügbar, ein weiteres sehr beliebtes Framework für neuronale Netze.
> Hinweis: Wenn Sie nicht daran interessiert sind, zu sehen, wie die Transformers-Bibliothek funktioniert, können Sie zum Ende dieses Notebooks springen, da Sie nichts wesentlich anderes sehen werden als das, was wir oben gemacht haben. Wir werden die gleichen Schritte des Trainings eines BERT-Modells mit einer anderen Bibliothek und einem wesentlich größeren Modell wiederholen. Der Prozess beinhaltet daher ein ziemlich langes Training, sodass Sie vielleicht nur den Code durchsehen möchten.
Schauen wir uns an, wie unser Problem mit Huggingface Transformers gelöst werden kann.
Das Erste, was wir tun müssen, ist, das Modell auszuwählen, das wir verwenden möchten. Neben einigen integrierten Modellen bietet Huggingface ein Online-Modell-Repository, in dem Sie viele weitere vortrainierte Modelle der Community finden können. All diese Modelle können geladen und verwendet werden, indem einfach der Modellname angegeben wird. Alle erforderlichen Binärdateien für das Modell werden automatisch heruntergeladen.
Manchmal müssen Sie Ihre eigenen Modelle laden. In diesem Fall können Sie das Verzeichnis angeben, das alle relevanten Dateien enthält, einschließlich der Parameter für den Tokenizer, der config.json-Datei mit den Modellparametern, der Binärgewichte usw.
Aus dem Modellnamen können wir sowohl das Modell als auch den Tokenizer instanziieren. Beginnen wir mit einem Tokenizer:
import transformers
# To load the model from Internet repository using model name.
# Use this if you are running from your own copy of the notebooks
bert_model = 'bert-base-uncased'
# To load the model from the directory on disk. Use this for Microsoft Learn module, because we have
# prepared all required files for you.
#bert_model = './bert'
tokenizer = transformers.BertTokenizer.from_pretrained(bert_model)
MAX_SEQ_LEN = 128
PAD_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)
UNK_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.unk_token)
Das tokenizer-Objekt enthält die encode-Funktion, die direkt verwendet werden kann, um Text zu kodieren:
tokenizer.encode('Tensorflow is a great framework for NLP')
Wir können auch den Tokenizer verwenden, um eine Sequenz auf eine Weise zu codieren, die für die Übergabe an das Modell geeignet ist, d. h. einschließlich der Felder token_ids, input_mask usw. Wir können auch angeben, dass wir Tensorflow-Tensoren möchten, indem wir das Argument return_tensors='tf' bereitstellen:
tokenizer(['Hello, there'],return_tensors='tf')
In unserem Fall verwenden wir ein vortrainiertes BERT-Modell namens bert-base-uncased. Uncased bedeutet, dass das Modell nicht zwischen Groß- und Kleinschreibung unterscheidet.
Beim Training des Modells müssen wir eine tokenisierte Sequenz als Eingabe bereitstellen, und daher werden wir eine Datenverarbeitungspipeline entwerfen. Da tokenizer.encode eine Python-Funktion ist, werden wir denselben Ansatz wie in der letzten Einheit verwenden, indem wir sie mit py_function aufrufen:
def process(x):
return tokenizer.encode(x.numpy().decode('utf-8'),return_tensors='tf',padding='max_length',max_length=MAX_SEQ_LEN,truncation=True)[0]
def process_fn(x):
s = x['title']+' '+x['description']
e = tf.py_function(process,inp=[s],Tout=(tf.int32))
e.set_shape(MAX_SEQ_LEN)
return e,x['label']
Jetzt können wir das eigentliche Modell mit dem Paket BertForSequenceClassification laden. Dies stellt sicher, dass unser Modell bereits über eine erforderliche Architektur für die Klassifikation verfügt, einschließlich des endgültigen Klassifikators. Sie werden eine Warnmeldung sehen, die besagt, dass die Gewichte des endgültigen Klassifikators nicht initialisiert sind und das Modell ein Pre-Training erfordert – das ist völlig in Ordnung, denn genau das werden wir jetzt tun!
model = transformers.TFBertForSequenceClassification.from_pretrained(bert_model,num_labels=4,output_attentions=False)
model.summary()
Wie Sie aus summary() sehen können, enthält das Modell fast 110 Millionen Parameter! Vermutlich möchten wir, wenn wir eine einfache Klassifikationsaufgabe auf einem relativ kleinen Datensatz durchführen wollen, die BERT-Basis-Schicht nicht trainieren:
model.layers[0].trainable = False
model.summary()
Jetzt können wir mit dem Training beginnen!
> Hinweis: Das Training eines vollständigen BERT-Modells kann sehr zeitaufwendig sein! Daher werden wir es nur für die ersten 32 Batches trainieren. Dies dient lediglich dazu, zu zeigen, wie das Modelltraining eingerichtet wird. Wenn Sie daran interessiert sind, ein vollständiges Training auszuprobieren, entfernen Sie einfach die Parameter steps_per_epoch und validation_steps und bereiten Sie sich darauf vor, zu warten!
model.compile('adam','sparse_categorical_crossentropy',['acc'])
tf.get_logger().setLevel('ERROR')
model.fit(ds_train.map(process_fn).batch(32),validation_data=ds_test.map(process_fn).batch(32),steps_per_epoch=32,validation_steps=2)
Wenn Sie die Anzahl der Iterationen erhöhen, lange genug warten und über mehrere Epochen trainieren, können Sie erwarten, dass die BERT-Klassifikation uns die beste Genauigkeit liefert! Das liegt daran, dass BERT die Struktur der Sprache bereits ziemlich gut versteht und wir nur den finalen Klassifikator feinabstimmen müssen. Allerdings ist BERT ein großes Modell, weshalb der gesamte Trainingsprozess viel Zeit in Anspruch nimmt und erhebliche Rechenleistung erfordert! (GPU, und vorzugsweise mehr als eine).
> Hinweis: In unserem Beispiel verwenden wir eines der kleinsten vortrainierten BERT-Modelle. Es gibt größere Modelle, die wahrscheinlich bessere Ergebnisse liefern.
Fazit
In dieser Einheit haben wir uns mit sehr aktuellen Modellarchitekturen basierend auf Transformers beschäftigt. Wir haben sie für unsere Textklassifizierungsaufgabe angewendet, aber ebenso können BERT-Modelle für die Extraktion von Entitäten, das Beantworten von Fragen und andere NLP-Aufgaben genutzt werden.
Transformermodelle stellen den aktuellen Stand der Technik im Bereich NLP dar, und in den meisten Fällen sollten sie die erste Lösung sein, mit der Sie experimentieren, wenn Sie maßgeschneiderte NLP-Lösungen implementieren. Dennoch ist es äußerst wichtig, die grundlegenden Prinzipien von rekurrenten neuronalen Netzen, die in diesem Modul behandelt wurden, zu verstehen, wenn Sie fortgeschrittene neuronale Modelle entwickeln möchten.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
NER
Laboraufgabe aus dem AI for Beginners Curriculum.
Aufgabe
In diesem Labor müssen Sie ein Modell zur Erkennung benannter Entitäten (NER) für medizinische Begriffe trainieren.
Der Datensatz
Um ein NER-Modell zu trainieren, benötigen wir einen korrekt gekennzeichneten Datensatz mit medizinischen Entitäten. Der BC5CDR-Datensatz enthält gekennzeichnete Krankheits- und Chemikalienentitäten aus mehr als 1500 wissenschaftlichen Artikeln. Sie können den Datensatz nach der Registrierung auf deren Website herunterladen.
Der BC5CDR-Datensatz sieht wie folgt aus:
6794356|t|Tricuspid valve regurgitation and lithium carbonate toxicity in a newborn infant.
6794356|a|A newborn with massive tricuspid regurgitation, atrial flutter, congestive heart failure, and a high serum lithium level is described. This is the first patient to initially manifest tricuspid regurgitation and atrial flutter, and the 11th described patient with cardiac disease among infants exposed to lithium compounds in the first trimester of pregnancy. Sixty-three percent of these infants had tricuspid valve involvement. Lithium carbonate may be a factor in the increasing incidence of congenital heart disease when taken during early pregnancy. It also causes neurologic depression, cyanosis, and cardiac arrhythmia when consumed prior to delivery.
6794356 0 29 Tricuspid valve regurgitation Disease D014262
6794356 34 51 lithium carbonate Chemical D016651
6794356 52 60 toxicity Disease D064420
...
In diesem Datensatz befinden sich der Titel und die Zusammenfassung des Artikels in den ersten beiden Zeilen, gefolgt von den einzelnen Entitäten mit Anfangs- und Endpositionen innerhalb des Titel+Zusammenfassungsblocks. Zusätzlich zur Entitätstyp erhalten Sie die Ontologie-ID dieser Entität innerhalb einer medizinischen Ontologie.
Sie müssen etwas Python-Code schreiben, um dies in BIO-Codierung umzuwandeln.
Das Netzwerk
Ein erster Versuch mit NER kann mit einem LSTM-Netzwerk durchgeführt werden, wie Sie es in unserem Beispiel während der Lektion gesehen haben. Allerdings zeigen bei NLP-Aufgaben die Transformer-Architektur und speziell BERT-Sprachmodelle deutlich bessere Ergebnisse. Vorgefertigte BERT-Modelle verstehen die allgemeine Struktur einer Sprache und können mit relativ kleinen Datensätzen und geringem Rechenaufwand für spezifische Aufgaben feinabgestimmt werden.
Da wir planen, NER in einem medizinischen Szenario anzuwenden, macht es Sinn, ein BERT-Modell zu verwenden, das auf medizinischen Texten trainiert wurde. Microsoft Research hat ein vortrainiertes Modell namens [PubMedBERT][PubMedBERT] ([Publikation][PubMedBERT-Pub]) veröffentlicht, das mit Texten aus dem PubMed Repository feinabgestimmt wurde.
Der de facto Standard für das Training von Transformer-Modellen ist die Hugging Face Transformers Bibliothek. Sie enthält auch ein Repository mit von der Community gepflegten vortrainierten Modellen, einschließlich PubMedBERT. Um dieses Modell zu laden und zu verwenden, benötigen wir nur ein paar Zeilen Code:
model_name = "microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract"
classes = ... # number of classes: 2*entities+1
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = BertForTokenClassification.from_pretrained(model_name, classes)
Dies liefert uns das model selbst, das für die Token-Klassifikationsaufgabe mit classes Anzahl von Klassen gebaut wurde, sowie das tokenizer-Objekt, das den Eingabetext in Tokens aufteilen kann. Sie müssen den Datensatz in BIO-Format umwandeln und dabei die Tokenisierung von PubMedBERT berücksichtigen. Sie können dieses Stück Python-Code als Inspiration verwenden.
Fazit
Diese Aufgabe ist der tatsächlichen Arbeit sehr nahe, die Sie wahrscheinlich durchführen werden, wenn Sie tiefere Einblicke in große Mengen an natürlichen Sprachtexten gewinnen möchten. In unserem Fall können wir unser trainiertes Modell auf den Datensatz von COVID-bezogenen Artikeln anwenden und sehen, welche Erkenntnisse wir daraus gewinnen können. Dieser Blogbeitrag und dieses Paper beschreiben die Forschung, die mit diesem Korpus von Artikeln unter Verwendung von NER durchgeführt werden kann.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Erkennung benannter Entitäten (NER)
Dieses Notebook stammt aus dem AI for Beginners Curriculum.
In diesem Beispiel lernen wir, wie man ein NER-Modell mit dem Annotated Corpus for Named Entity Recognition-Datensatz von Kaggle trainiert. Bevor Sie fortfahren, laden Sie bitte die Datei ner_dataset.csv in das aktuelle Verzeichnis herunter.
import pandas as pd
from tensorflow import keras
import numpy as np
Vorbereitung des Datensatzes
Wir beginnen damit, den Datensatz in ein DataFrame einzulesen. Wenn Sie mehr über die Verwendung von Pandas erfahren möchten, besuchen Sie eine Lektion zur Datenverarbeitung in unserem Data Science für Anfänger.
df = pd.read_csv('ner_dataset.csv',encoding='unicode-escape')
df.head()
Lass uns einzigartige Tags erhalten und Nachschlage-Dictionaries erstellen, die wir verwenden können, um Tags in Klassennummern umzuwandeln:
tags = df.Tag.unique()
tags
id2tag = dict(enumerate(tags))
tag2id = { v : k for k,v in id2tag.items() }
id2tag[0]
Jetzt müssen wir dasselbe mit dem Vokabular tun. Der Einfachheit halber werden wir ein Vokabular erstellen, ohne die Wortfrequenz zu berücksichtigen; im echten Leben möchten Sie möglicherweise den Keras-Vektorisierer verwenden und die Anzahl der Wörter begrenzen.
vocab = set(df['Word'].apply(lambda x: x.lower()))
id2word = { i+1 : v for i,v in enumerate(vocab) }
id2word[0] = '<UNK>'
vocab.add('<UNK>')
word2id = { v : k for k,v in id2word.items() }
Wir müssen einen Datensatz von Sätzen für das Training erstellen. Lassen Sie uns den ursprünglichen Datensatz durchlaufen und alle einzelnen Sätze in X (Listen von Wörtern) und Y (Listen von Token) trennen:
X,Y = [],[]
s,t = [],[]
for i,row in df[['Sentence #','Word','Tag']].iterrows():
if pd.isna(row['Sentence #']):
s.append(row['Word'])
t.append(row['Tag'])
else:
if len(s)>0:
X.append(s)
Y.append(t)
s,t = [row['Word']],[row['Tag']]
X.append(s)
Y.append(t)
def vectorize(seq):
return [word2id[x.lower()] for x in seq]
def tagify(seq):
return [tag2id[x] for x in seq]
Xv = list(map(vectorize,X))
Yv = list(map(tagify,Y))
Xv[0], Yv[0]
Zur Vereinfachung werden wir alle Sätze mit 0 Tokens auf die maximale Länge auffüllen. Im echten Leben könnten wir eine klügere Strategie verwenden und Sequenzen nur innerhalb eines Minibatches auffüllen.
X_data = keras.preprocessing.sequence.pad_sequences(Xv,padding='post')
Y_data = keras.preprocessing.sequence.pad_sequences(Yv,padding='post')
Definition des Token-Klassifikationsnetzwerks
Wir verwenden ein zweischichtiges bidirektionales LSTM-Netzwerk für die Token-Klassifikation. Um einen dichten Klassifikator auf jeden der Ausgaben der letzten LSTM-Schicht anzuwenden, nutzen wir die TimeDistributed-Konstruktion, die dieselbe dichte Schicht auf jede Ausgabe des LSTM bei jedem Schritt repliziert:
maxlen = X_data.shape[1]
vocab_size = len(vocab)
num_tags = len(tags)
model = keras.models.Sequential([
keras.layers.Embedding(vocab_size, 300, input_length=maxlen),
keras.layers.Bidirectional(keras.layers.LSTM(units=100, activation='tanh', return_sequences=True)),
keras.layers.Bidirectional(keras.layers.LSTM(units=100, activation='tanh', return_sequences=True)),
keras.layers.TimeDistributed(keras.layers.Dense(num_tags, activation='softmax'))
])
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])
model.summary()
Beachten Sie hier, dass wir maxlen explizit für unser Dataset angeben – falls wir möchten, dass das Netzwerk mit Sequenzen variabler Länge umgehen kann, müssen wir beim Definieren des Netzwerks etwas cleverer vorgehen.
Lassen Sie uns nun das Modell trainieren. Aus Zeitgründen werden wir nur für eine Epoche trainieren, aber Sie können versuchen, länger zu trainieren. Außerdem könnten Sie einen Teil des Datasets als Trainingsdatensatz abtrennen, um die Validierungsgenauigkeit zu beobachten.
model.fit(X_data,Y_data)
Testen des Ergebnisses
Schauen wir uns nun an, wie unser Modell zur Erkennung von Entitäten mit einem Beispielsatz funktioniert:
sent = 'John Smith went to Paris to attend a conference in cancer development institute'
words = sent.lower().split()
v = keras.preprocessing.sequence.pad_sequences([[word2id[x] for x in words]],padding='post',maxlen=maxlen)
res = model(v)[0]
r = np.argmax(res.numpy(),axis=1)
for i,w in zip(r,words):
print(f"{w} -> {id2tag[i]}")
Erkenntnis
Selbst ein einfaches LSTM-Modell liefert vernünftige Ergebnisse bei der NER. Um jedoch deutlich bessere Ergebnisse zu erzielen, sollten Sie große vortrainierte Sprachmodelle wie BERT verwenden. Die Schulung von BERT für NER mit der Huggingface Transformers-Bibliothek wird hier beschrieben.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Named Entity Recognition
Bis jetzt haben wir uns hauptsächlich auf eine NLP-Aufgabe konzentriert – die Klassifikation. Es gibt jedoch auch andere NLP-Aufgaben, die mit neuronalen Netzwerken gelöst werden können. Eine dieser Aufgaben ist Named Entity Recognition (NER), die sich mit der Erkennung spezifischer Entitäten im Text befasst, wie Orte, Personennamen, Zeitintervalle, chemische Formeln und vieles mehr.
Quiz vor der Vorlesung
Beispiel für die Verwendung von NER
Angenommen, Sie möchten einen natürlichen Sprach-Chatbot entwickeln, ähnlich wie Amazon Alexa oder Google Assistant. Intelligente Chatbots funktionieren, indem sie verstehen, was der Benutzer möchte, indem sie eine Textklassifikation auf den Eingabesatz anwenden. Das Ergebnis dieser Klassifikation ist die sogenannte Intent, die bestimmt, was der Chatbot tun soll.
<img alt="Bot NER" src="../../../../../translated_images/de/bot-ner.4b09235dbb0ad275.webp" width="50%"/>
> Bild vom Autor
Ein Benutzer könnte jedoch einige Parameter als Teil des Satzes angeben. Wenn er beispielsweise nach dem Wetter fragt, könnte er einen Ort oder ein Datum angeben. Ein Bot sollte in der Lage sein, diese Entitäten zu verstehen und die Parameter entsprechend auszufüllen, bevor er die Aktion ausführt. Genau hier kommt NER ins Spiel.
> ✅ Ein weiteres Beispiel wäre die Analyse wissenschaftlicher medizinischer Artikel. Eine der Hauptaufgaben besteht darin, spezifische medizinische Begriffe wie Krankheiten und medizinische Substanzen zu identifizieren. Während eine kleine Anzahl von Krankheiten wahrscheinlich durch Substring-Suche extrahiert werden kann, erfordern komplexere Entitäten wie chemische Verbindungen und Medikamentennamen einen komplexeren Ansatz.
NER als Token-Klassifikation
NER-Modelle sind im Wesentlichen Token-Klassifikationsmodelle, da wir für jedes der Eingabetokens entscheiden müssen, ob es zu einer Entität gehört oder nicht, und falls ja – zu welcher Entitätsklasse.
Betrachten Sie den folgenden Titel eines Artikels:
Trikuspidalklappeninsuffizienz und Lithiumcarbonat-Toxizität bei einem neugeborenen Säugling.
Die Entitäten hier sind:
- Trikuspidalklappeninsuffizienz ist eine Krankheit (
DIS) - Lithiumcarbonat ist eine chemische Substanz (
CHEM) - Toxizität ist ebenfalls eine Krankheit (
DIS)
Beachten Sie, dass eine Entität aus mehreren Tokens bestehen kann. Und wie in diesem Fall müssen wir zwischen zwei aufeinanderfolgenden Entitäten unterscheiden. Daher ist es üblich, zwei Klassen für jede Entität zu verwenden – eine, die das erste Token der Entität angibt (oft wird das Präfix B- für beginning verwendet), und eine andere für die Fortsetzung einer Entität (I-, für inner Token). Wir verwenden auch O als Klasse, um alle other Tokens darzustellen. Eine solche Token-Kennzeichnung wird BIO-Tagging (oder IOB) genannt. Nach der Kennzeichnung sieht unser Titel so aus:
| Token | Tag |
|---|---|
| Trikuspidalklappen | B-DIS |
| insuffizienz | I-DIS |
| und | O |
| Lithium | B-CHEM |
| carbonat | I-CHEM |
| Toxizität | B-DIS |
| bei | O |
| einem | O |
| neugeborenen | O |
| Säugling | O |
| . | O |
Da wir eine Eins-zu-Eins-Korrespondenz zwischen Tokens und Klassen herstellen müssen, können wir ein rechtsbasiertes Many-to-Many-Neuralnetzwerkmodell aus diesem Bild trainieren:

> Bild aus diesem Blogbeitrag von Andrej Karpathy. NER-Token-Klassifikationsmodelle entsprechen der rechtsbasierten Netzwerkarchitektur auf diesem Bild.
Training von NER-Modellen
Da ein NER-Modell im Wesentlichen ein Token-Klassifikationsmodell ist, können wir RNNs, die wir bereits kennen, für diese Aufgabe verwenden. In diesem Fall gibt jeder Block des rekurrenten Netzwerks die Token-ID zurück. Das folgende Beispiel-Notebook zeigt, wie man LSTM für die Token-Klassifikation trainiert.
✍️ Beispiel-Notebooks: NER
Setzen Sie Ihr Lernen mit dem folgenden Notebook fort:
Fazit
Ein NER-Modell ist ein Token-Klassifikationsmodell, was bedeutet, dass es zur Token-Klassifikation verwendet werden kann. Dies ist eine sehr häufige Aufgabe in der NLP, die hilft, spezifische Entitäten im Text zu erkennen, einschließlich Orte, Namen, Daten und mehr.
🚀 Herausforderung
Bearbeiten Sie die unten verlinkte Aufgabe, um ein Named Entity Recognition-Modell für medizinische Begriffe zu trainieren, und testen Sie es anschließend mit einem anderen Datensatz.
Quiz nach der Vorlesung
Überprüfung & Selbststudium
Lesen Sie den Blog The Unreasonable Effectiveness of Recurrent Neural Networks und folgen Sie dem Abschnitt "Weiterführende Literatur" in diesem Artikel, um Ihr Wissen zu vertiefen.
Aufgabe
In der Aufgabe zu dieser Lektion müssen Sie ein Modell zur Erkennung medizinischer Entitäten trainieren. Sie können mit dem Training eines LSTM-Modells beginnen, wie in dieser Lektion beschrieben, und anschließend das BERT-Transformer-Modell verwenden. Lesen Sie die Anweisungen, um alle Details zu erhalten.
Experimentieren mit OpenAI GPT
Dieses Notebook ist Teil des AI for Beginners Curriculum.
In diesem Notebook werden wir untersuchen, wie wir mit dem OpenAI-GPT-Modell mithilfe der transformers-Bibliothek von Hugging Face experimentieren können.
Ohne weitere Umschweife, lassen Sie uns eine Textgenerierungspipeline erstellen und mit der Generierung beginnen!
from transformers import pipeline
model_name = 'openai-gpt'
generator = pipeline('text-generation', model=model_name)
generator("Hello! I am a neural network, and I want to say that", max_length=100, num_return_sequences=5)
Prompt-Entwicklung
Bei einigen Problemen können Sie die openai-gpt-Generierung direkt nutzen, indem Sie passende Eingabeaufforderungen erstellen. Schauen Sie sich die folgenden Beispiele an:
generator("Synonyms of a word cat:", max_length=20, num_return_sequences=5)
generator("I love when you say this -> Positive\nI have myself -> Negative\nThis is awful for you to say this ->", max_length=40, num_return_sequences=5)
generator("Translate English to French: cat => chat, dog => chien, student => ", top_k=50, max_length=30, num_return_sequences=3)
generator("People who liked the movie The Matrix also liked ", max_length=40, num_return_sequences=5)
Text-Sampling-Strategien
Bisher haben wir eine einfache gierige Sampling-Strategie verwendet, bei der das nächste Wort basierend auf der höchsten Wahrscheinlichkeit ausgewählt wurde. So funktioniert es:
prompt = "It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw"
generator(prompt,max_length=100,num_return_sequences=5)
Beam Search ermöglicht es dem Generator, mehrere Richtungen (Beams) der Textgenerierung zu erkunden und diejenigen mit der höchsten Gesamtpunktzahl auszuwählen. Sie können Beam Search durchführen, indem Sie den Parameter num_beams angeben. Sie können auch no_repeat_ngram_size festlegen, um das Modell dafür zu bestrafen, n-Gramme einer bestimmten Größe zu wiederholen:
prompt = "It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw"
generator(prompt,max_length=100,num_return_sequences=5,num_beams=10,no_repeat_ngram_size=2)
Sampling wählt das nächste Wort nicht-deterministisch aus, basierend auf der vom Modell zurückgegebenen Wahrscheinlichkeitsverteilung. Sie aktivieren Sampling mit dem Parameter do_sample=True. Sie können auch die temperature festlegen, um das Modell mehr oder weniger deterministisch zu machen.
prompt = "It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw"
generator(prompt,max_length=100,do_sample=True,temperature=0.8)
Wir können auch zusätzliche Parameter für das Sampling bereitstellen:
* top_k gibt die Anzahl der Wortoptionen an, die beim Sampling berücksichtigt werden sollen. Dies minimiert die Wahrscheinlichkeit, seltsame (niedrig wahrscheinliche) Wörter in unserem Text zu erhalten.
* top_p ist ähnlich, aber hier wählen wir die kleinste Teilmenge der wahrscheinlichsten Wörter aus, deren Gesamtwahrscheinlichkeit größer als p ist.
Experimentiere gerne damit, diese Parameter hinzuzufügen.
Feinabstimmung Ihrer Modelle
Sie können Ihr Modell auch feinabstimmen mit Ihrem eigenen Datensatz. Dies ermöglicht es Ihnen, den Stil des Textes anzupassen, während der Hauptteil des Sprachmodells erhalten bleibt.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Vorgefertigte große Sprachmodelle
In all unseren bisherigen Aufgaben haben wir ein neuronales Netzwerk darauf trainiert, eine bestimmte Aufgabe mithilfe eines beschrifteten Datensatzes auszuführen. Bei großen Transformermodellen wie BERT verwenden wir Sprachmodellierung in selbstüberwachter Weise, um ein Sprachmodell zu erstellen, das anschließend durch weitere domänenspezifische Trainings für spezifische Downstream-Aufgaben spezialisiert wird. Es wurde jedoch gezeigt, dass große Sprachmodelle viele Aufgaben auch ohne jegliches domänenspezifisches Training lösen können. Eine Familie von Modellen, die dazu in der Lage ist, wird als GPT bezeichnet: Generative Pre-Trained Transformer.
Quiz vor der Vorlesung
Textgenerierung und Perplexität
Die Idee, dass ein neuronales Netzwerk allgemeine Aufgaben ohne Downstream-Training ausführen kann, wird im Paper Language Models are Unsupervised Multitask Learners vorgestellt. Der Hauptgedanke ist, dass viele andere Aufgaben mithilfe der Textgenerierung modelliert werden können, da das Verstehen von Text im Wesentlichen bedeutet, in der Lage zu sein, ihn zu produzieren. Da das Modell auf einer riesigen Menge an Text trainiert wird, die menschliches Wissen umfasst, wird es auch über eine Vielzahl von Themen informiert.
> Text zu verstehen und zu produzieren bedeutet auch, etwas über die Welt um uns herum zu wissen. Menschen lernen ebenfalls in großem Maße durch Lesen, und das GPT-Netzwerk ist in dieser Hinsicht ähnlich.
Textgenerierungsnetzwerke arbeiten, indem sie die Wahrscheinlichkeit des nächsten Wortes $$P(w_N)$$ vorhersagen. Die unbedingte Wahrscheinlichkeit des nächsten Wortes entspricht jedoch der Häufigkeit dieses Wortes im Textkorpus. GPT ist in der Lage, uns die bedingte Wahrscheinlichkeit des nächsten Wortes zu geben, basierend auf den vorherigen Wörtern: $$P(w_N | w_{n-1}, ..., w_0)$$
> Mehr über Wahrscheinlichkeiten kannst du in unserem Data Science for Beginners Curriculum nachlesen.
Die Qualität eines sprachgenerierenden Modells kann durch die Perplexität definiert werden. Dies ist eine intrinsische Metrik, die es uns ermöglicht, die Modellqualität ohne einen aufgabenspezifischen Datensatz zu messen. Sie basiert auf dem Konzept der Wahrscheinlichkeit eines Satzes – das Modell weist einem Satz, der wahrscheinlich real ist (d. h. das Modell ist nicht verwirrt davon), eine hohe Wahrscheinlichkeit zu und Sätzen, die weniger Sinn ergeben (z. B. Kann es was tun?), eine niedrige Wahrscheinlichkeit. Wenn wir unserem Modell Sätze aus einem echten Textkorpus geben, erwarten wir, dass diese eine hohe Wahrscheinlichkeit und eine niedrige Perplexität haben. Mathematisch wird sie als normalisierte inverse Wahrscheinlichkeit des Testdatensatzes definiert: $$ \mathrm{Perplexity}(W) = \sqrt[N]{1\over P(W_1,...,W_N)} $$
Du kannst mit der Textgenerierung experimentieren, indem du den GPT-basierten Texteditor von Hugging Face verwendest. In diesem Editor beginnst du mit dem Schreiben deines Textes, und durch Drücken von [TAB] werden dir mehrere Vervollständigungsoptionen angeboten. Wenn diese zu kurz sind oder du nicht zufrieden bist, drücke erneut [TAB], und du erhältst weitere Optionen, einschließlich längerer Textstücke.
GPT ist eine Familie
GPT ist kein einzelnes Modell, sondern eine Sammlung von Modellen, die von OpenAI entwickelt und trainiert wurden.
Zu den GPT-Modellen gehören:
| GPT-2 | GPT-3 | GPT-4 |
|---|---|---|
| Sprachmodell mit bis zu 1,5 Milliarden Parametern. | Sprachmodell mit bis zu 175 Milliarden Parametern. | 100T Parameter, akzeptiert sowohl Bild- als auch Texteingaben und gibt Text aus. |
Die Modelle GPT-3 und GPT-4 sind verfügbar als kognitive Dienste von Microsoft Azure und als OpenAI API.
Prompt Engineering
Da GPT auf großen Datenmengen trainiert wurde, um Sprache und Code zu verstehen, liefert es Ausgaben als Reaktion auf Eingaben (Prompts). Prompts sind Eingaben oder Abfragen für GPT, bei denen man den Modellen Anweisungen zu den Aufgaben gibt, die sie als Nächstes ausführen sollen. Um ein gewünschtes Ergebnis zu erzielen, benötigt man den effektivsten Prompt, was die Auswahl der richtigen Wörter, Formate, Phrasen oder sogar Symbole umfasst. Dieser Ansatz wird als Prompt Engineering bezeichnet.
Diese Dokumentation bietet dir weitere Informationen zum Prompt Engineering.
✍️ Beispiel-Notebook: Spielen mit OpenAI-GPT
Setze dein Lernen in den folgenden Notebooks fort:
Fazit
Neue vortrainierte allgemeine Sprachmodelle modellieren nicht nur die Sprachstruktur, sondern enthalten auch eine enorme Menge an natürlicher Sprache. Daher können sie effektiv eingesetzt werden, um einige NLP-Aufgaben in Zero-Shot- oder Few-Shot-Szenarien zu lösen.
Quiz nach der Vorlesung
Verarbeitung natürlicher Sprache

In diesem Abschnitt konzentrieren wir uns darauf, neuronale Netzwerke für Aufgaben im Bereich der Verarbeitung natürlicher Sprache (Natural Language Processing, NLP) einzusetzen. Es gibt viele NLP-Probleme, die wir möchten, dass Computer lösen können:
- Textklassifikation ist ein typisches Klassifikationsproblem, das sich auf Textsequenzen bezieht. Beispiele sind das Klassifizieren von E-Mails als Spam oder Nicht-Spam oder das Kategorisieren von Artikeln in Sport, Wirtschaft, Politik usw. Auch bei der Entwicklung von Chatbots müssen wir oft verstehen, was ein Benutzer sagen wollte – in diesem Fall handelt es sich um Intent-Klassifikation. Häufig müssen wir bei der Intent-Klassifikation mit vielen Kategorien umgehen.
- Sentiment-Analyse ist ein typisches Regressionsproblem, bei dem wir einer Zahl (einem Sentiment) zuordnen müssen, wie positiv/negativ die Bedeutung eines Satzes ist. Eine fortgeschrittenere Version der Sentiment-Analyse ist die aspektbasierte Sentiment-Analyse (ABSA), bei der wir das Sentiment nicht dem gesamten Satz, sondern verschiedenen Teilen davon (Aspekten) zuordnen, z. B. In diesem Restaurant mochte ich die Küche, aber die Atmosphäre war schrecklich.
- Erkennung benannter Entitäten (Named Entity Recognition, NER) bezieht sich auf das Problem, bestimmte Entitäten aus Text zu extrahieren. Zum Beispiel müssen wir verstehen, dass in der Phrase Ich muss morgen nach Paris fliegen das Wort morgen ein DATUM und Paris ein ORT ist.
- Schlüsselwortextraktion ist ähnlich wie NER, aber hier müssen wir automatisch Wörter extrahieren, die für die Bedeutung des Satzes wichtig sind, ohne vorheriges Training für spezifische Entitätstypen.
- Text-Clustering kann nützlich sein, wenn wir ähnliche Sätze gruppieren möchten, z. B. ähnliche Anfragen in technischen Supportgesprächen.
- Fragebeantwortung bezieht sich auf die Fähigkeit eines Modells, eine spezifische Frage zu beantworten. Das Modell erhält einen Textabschnitt und eine Frage als Eingaben und muss eine Stelle im Text angeben, an der die Antwort auf die Frage enthalten ist (oder manchmal die Antwort generieren).
- Textgenerierung ist die Fähigkeit eines Modells, neuen Text zu generieren. Dies kann als Klassifikationsaufgabe betrachtet werden, bei der der nächste Buchstabe/das nächste Wort basierend auf einem Textprompt vorhergesagt wird. Fortgeschrittene Textgenerierungsmodelle wie GPT-3 können andere NLP-Aufgaben wie Klassifikation mithilfe einer Technik namens Prompt Programming oder Prompt Engineering lösen.
- Textzusammenfassung ist eine Technik, bei der wir möchten, dass ein Computer einen langen Text "liest" und ihn in wenigen Sätzen zusammenfasst.
- Maschinelle Übersetzung kann als Kombination aus Textverständnis in einer Sprache und Textgenerierung in einer anderen betrachtet werden.
Anfangs wurden die meisten NLP-Aufgaben mit traditionellen Methoden wie Grammatiken gelöst. Zum Beispiel wurden in der maschinellen Übersetzung Parser verwendet, um einen Ausgangssatz in einen Syntaxbaum zu transformieren, dann wurden semantische Strukturen höherer Ebene extrahiert, um die Bedeutung des Satzes darzustellen, und basierend auf dieser Bedeutung und der Grammatik der Zielsprache wurde das Ergebnis generiert. Heutzutage werden viele NLP-Aufgaben effektiver mit neuronalen Netzwerken gelöst.
> Viele klassische NLP-Methoden sind in der Python-Bibliothek Natural Language Processing Toolkit (NLTK) implementiert. Es gibt ein großartiges NLTK-Buch, das online verfügbar ist und zeigt, wie verschiedene NLP-Aufgaben mit NLTK gelöst werden können.
In unserem Kurs konzentrieren wir uns hauptsächlich auf die Verwendung neuronaler Netzwerke für NLP und verwenden NLTK, wo es erforderlich ist.
Wir haben bereits gelernt, wie neuronale Netzwerke für tabellarische Daten und Bilder verwendet werden können. Der Hauptunterschied zwischen diesen Datentypen und Text besteht darin, dass Text eine Sequenz variabler Länge ist, während die Eingabegröße bei Bildern im Voraus bekannt ist. Während konvolutionale Netzwerke Muster aus Eingabedaten extrahieren können, sind Muster in Texten komplexer. Zum Beispiel kann eine Verneinung vom Subjekt durch viele Wörter getrennt sein (z. B. Ich mag keine Orangen vs. Ich mag diese großen bunten leckeren Orangen nicht), und das sollte dennoch als ein Muster interpretiert werden. Daher müssen wir zur Verarbeitung von Sprache neue Arten von neuronalen Netzwerken einführen, wie z. B. rekurrente Netzwerke und Transformers.
Bibliotheken installieren
Wenn Sie eine lokale Python-Installation verwenden, um diesen Kurs auszuführen, müssen Sie möglicherweise alle erforderlichen Bibliotheken für NLP mit den folgenden Befehlen installieren:
Für PyTorch
pip install -r requirements-torch.txt
Für TensorFlow
pip install -r requirements-tf.txt
> Sie können NLP mit TensorFlow auf Microsoft Learn ausprobieren.
GPU-Warnung
In diesem Abschnitt werden wir in einigen Beispielen recht große Modelle trainieren.
Verwenden Sie einen Computer mit GPU-Unterstützung: Es wird empfohlen, Ihre Notebooks auf einem Computer mit GPU-Unterstützung auszuführen, um die Wartezeiten beim Arbeiten mit großen Modellen zu reduzieren.
GPU-Speicherbeschränkungen: Das Ausführen auf einer GPU kann dazu führen, dass der GPU-Speicher ausgeht, insbesondere beim Training großer Modelle.
GPU-Speicherverbrauch: Die Menge des während des Trainings verbrauchten GPU-Speichers hängt von verschiedenen Faktoren ab, einschließlich der Minibatch-Größe.
Minimieren Sie die Minibatch-Größe: Wenn Sie auf GPU-Speicherprobleme stoßen, sollten Sie die Minibatch-Größe in Ihrem Code reduzieren.
TensorFlow GPU-Speicherfreigabe: Ältere Versionen von TensorFlow geben den GPU-Speicher möglicherweise nicht korrekt frei, wenn mehrere Modelle innerhalb eines Python-Kernels trainiert werden. Um den GPU-Speicher effektiv zu verwalten, können Sie TensorFlow so konfigurieren, dass GPU-Speicher nur bei Bedarf zugewiesen wird.
Code-Einbindung: Um TensorFlow so einzustellen, dass GPU-Speicher nur bei Bedarf wächst, fügen Sie den folgenden Code in Ihre Notebooks ein:
physical_devices = tf.config.list_physical_devices('GPU')
if len(physical_devices)>0:
tf.config.experimental.set_memory_growth(physical_devices[0], True)
Wenn Sie daran interessiert sind, NLP aus der Perspektive des klassischen maschinellen Lernens zu lernen, besuchen Sie diese Lektionenreihe.
In diesem Abschnitt
In diesem Abschnitt werden wir lernen:
- Text als Tensoren darstellen
- Wort-Embeddings
- Sprachmodellierung
- Rekurrente neuronale Netzwerke
- Generative Netzwerke
- Transformers
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
Aufgabe: Diophantische Gleichungen
> Diese Aufgabe ist Teil des AI for Beginners Curriculum und wurde von diesem Beitrag inspiriert.
Dein Ziel ist es, die sogenannte diophantische Gleichung zu lösen – eine Gleichung mit ganzzahligen Wurzeln und ganzzahligen Koeffizienten. Betrachte zum Beispiel die folgende Gleichung:
$$a+2b+3c+4d=30$$
Du musst ganzzahlige Wurzeln $a$,$b$,$c$,$d\in\mathbb{N}$ finden, die diese Gleichung erfüllen.
Hinweise: 1. Du kannst die Wurzeln im Intervall [0;30] betrachten. 1. Als Gen kannst du die Liste der Wurzelwerte verwenden.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Genetische Algorithmen
Dieses Notebook ist Teil des AI for Beginners Curriculum.
import random
import matplotlib.pyplot as plt
import numpy as np
import math
import time
Ein wenig Theorie
Genetische Algorithmen (GA) basieren auf einem evolutionären Ansatz der KI, bei dem Methoden der Populationsentwicklung verwendet werden, um eine optimale Lösung für ein gegebenes Problem zu finden. Sie wurden 1975 von John Henry Holland vorgeschlagen.
Genetische Algorithmen basieren auf den folgenden Ideen: * Gültige Lösungen für das Problem können als Gene dargestellt werden. * Crossover ermöglicht es, zwei Lösungen zu kombinieren, um eine neue gültige Lösung zu erhalten. * Selektion wird verwendet, um optimalere Lösungen mithilfe einer Fitnessfunktion auszuwählen. * Mutationen werden eingeführt, um die Optimierung zu destabilisieren und uns aus einem lokalen Minimum herauszuführen.
Wenn Sie einen genetischen Algorithmus implementieren möchten, benötigen Sie Folgendes:
- Eine Methode, um die Problemlösungen mithilfe von Genen $g\in\Gamma$ zu codieren.
- Auf der Menge der Gene $\Gamma$ müssen wir eine Fitnessfunktion $\mathrm{fit}: \Gamma\to\mathbb{R}$ definieren. Kleinere Funktionswerte entsprechen besseren Lösungen.
- Einen Crossover-Mechanismus, um zwei Gene zu kombinieren und eine neue gültige Lösung zu erhalten $\mathrm{crossover}: \Gamma^2\to\Gamma$.
- Einen Mutationsmechanismus $\mathrm{mutate}: \Gamma\to\Gamma$. In vielen Fällen sind Crossover und Mutation recht einfache Algorithmen, um Gene als numerische Sequenzen oder Bitvektoren zu manipulieren.
Die spezifische Implementierung eines genetischen Algorithmus kann je nach Fall variieren, aber die allgemeine Struktur ist wie folgt:
- Wählen Sie eine Anfangspopulation $G\subset\Gamma$.
- Wählen Sie zufällig eine der Operationen aus, die in diesem Schritt ausgeführt werden sollen: Crossover oder Mutation.
- Crossover: * Wählen Sie zufällig zwei Gene $g_1, g_2 \in G$. * Berechnen Sie das Crossover $g=\mathrm{crossover}(g_1,g_2)$. * Wenn $\mathrm{fit}(g)<\mathrm{fit}(g_1)$ oder $\mathrm{fit}(g)<\mathrm{fit}(g_2)$ - ersetzen Sie das entsprechende Gen in der Population durch $g$.
- Mutation - Wählen Sie ein zufälliges Gen $g\in G$ und ersetzen Sie es durch $\mathrm{mutate}(g)$.
- Wiederholen Sie ab Schritt 2, bis wir einen ausreichend kleinen Wert von $\mathrm{fit}$ erhalten oder bis das Limit der Anzahl der Schritte erreicht ist.
Typische Aufgaben, die durch GA gelöst werden: 1. Optimierung von Zeitplänen 1. Optimales Packen 1. Optimales Schneiden 1. Beschleunigung der erschöpfenden Suche
Problem 1: Gerechte Schatzaufteilung
Aufgabe:
Zwei Personen haben einen Schatz gefunden, der Diamanten unterschiedlicher Größen (und entsprechend unterschiedlicher Preise) enthält. Sie müssen den Schatz in zwei Teile aufteilen, sodass der Preisunterschied 0 (oder minimal) ist.
Formale Definition:
Wir haben eine Menge von Zahlen $S$. Wir müssen sie in zwei Teilmengen $S_1$ und $S_2$ aufteilen, sodass $$\left|\sum_{i\in S_1}i - \sum_{j\in S_2}j\right|\to\min$$ und $S_1\cup S_2=S$, $S_1\cap S_2=\emptyset$.
Zunächst definieren wir die Menge $S$:
N = 200
S = np.array([random.randint(1,10000) for _ in range(N)])
print(S)
Lassen Sie uns jede mögliche Lösung des Problems durch einen Binärvektor $B\in{0,1}^N$ kodieren, wobei die Zahl an der $i$-ten Position zeigt, zu welcher der Mengen ($S_1$ oder $S_2$) die $i$-te Zahl in der ursprünglichen Menge $S$ gehört. Die Funktion generate wird diese zufälligen Binärvektoren erzeugen.
def generate(S):
return np.array([random.randint(0,1) for _ in S])
b = generate(S)
print(b)
Lassen Sie uns nun die Funktion fit definieren, die die "Kosten" der Lösung berechnet. Es wird die Differenz zwischen der Summe der beiden Mengen $S_1$ und $S_2$ sein:
def fit(B,S=S):
c1 = (B*S).sum()
c2 = ((1-B)*S).sum()
return abs(c1-c2)
fit(b)
Nun müssen wir Funktionen für Mutation und Kreuzung definieren:
* Für die Mutation wählen wir ein zufälliges Bit aus und negieren es (ändern von 0 zu 1 und umgekehrt).
* Für die Kreuzung nehmen wir einige Bits aus einem Vektor und einige Bits aus einem anderen. Wir verwenden die gleiche generate-Funktion, um zufällig auszuwählen, welche Bits aus welchen der Eingabemasken übernommen werden.
def mutate(b):
x = b.copy()
i = random.randint(0,len(b)-1)
x[i] = 1-x[i]
return x
def xover(b1,b2):
x = generate(b1)
return b1*x+b2*(1-x)
Lass uns eine Anfangspopulation der Lösungen $P$ der Größe pop_size erstellen:
pop_size = 30
P = [generate(S) for _ in range(pop_size)]
Nun, die Hauptfunktion zur Durchführung der Evolution. n ist die Anzahl der Evolutionsschritte, die durchgeführt werden sollen. In jedem Schritt:
* Mit einer Wahrscheinlichkeit von 30 % führen wir eine Mutation durch und ersetzen das Element mit der schlechtesten fit-Funktion durch das mutierte Element.
* Mit einer Wahrscheinlichkeit von 70 % führen wir ein Crossover durch.
Die Funktion gibt die beste Lösung (Gen, das der besten Lösung entspricht) und die Historie der minimalen fit-Funktion in der Population bei jeder Iteration zurück.
def evolve(P,S=S,n=2000):
res = []
for _ in range(n):
f = min([fit(b) for b in P])
res.append(f)
if f==0:
break
if random.randint(1,10)<3:
i = random.randint(0,len(P)-1)
b = mutate(P[i])
i = np.argmax([fit(z) for z in P])
P[i] = b
else:
i = random.randint(0,len(P)-1)
j = random.randint(0,len(P)-1)
b = xover(P[i],P[j])
if fit(b)<fit(P[i]):
P[i]=b
elif fit(b)<fit(P[j]):
P[j]=b
else:
pass
i = np.argmin([fit(b) for b in P])
return (P[i],res)
(s,hist) = evolve(P)
print(s,fit(s))
Man kann sehen, dass es uns gelungen ist, die fit-Funktion erheblich zu minimieren! Hier ist der Graph, der zeigt, wie sich die fit-Funktion für die gesamte Population während des Prozesses verhält.
plt.plot(hist)
plt.show()
Problem 2: N-Damen-Problem
Aufgabe:
Du musst $N$ Damen auf einem Schachbrett der Größe $N\times N$ so platzieren, dass sie sich gegenseitig nicht angreifen.
Zunächst lösen wir das Problem ohne genetische Algorithmen, indem wir eine vollständige Suche durchführen. Wir können den Zustand des Schachbretts durch die Liste $L$ darstellen, wobei die $i$-te Zahl in der Liste die horizontale Position der Dame in der $i$-ten Reihe angibt. Es ist ziemlich offensichtlich, dass jede Lösung nur eine Dame pro Reihe haben wird und jede Reihe eine Dame enthalten muss.
Unser Ziel ist es, die erste Lösung für das Problem zu finden, nach der wir die Suche beenden. Du kannst diese Funktion leicht erweitern, um alle möglichen Positionen für die Damen zu generieren.
N = 8
def checkbeats(i_new,j_new,l):
for i,j in enumerate(l,start=1):
if j==j_new:
return False
else:
if abs(j-j_new) == i_new-i:
return False
return True
def nqueens(l,N=8,disp=True):
if len(l)==N:
if disp: print(l)
return True
else:
for j in range(1,N+1):
if checkbeats(len(l)+1,j,l):
l.append(j)
if nqueens(l,N,disp): return True
else: l.pop()
return False
nqueens([],8)
Lassen Sie uns nun messen, wie lange es dauert, eine Lösung für das 20-Damen-Problem zu finden:
%timeit nqueens([],20,False)
Lassen Sie uns dasselbe Problem mit einem genetischen Algorithmus lösen. Diese Lösung ist inspiriert von diesem Blogbeitrag.
Wir werden jede Lösung durch dieselbe Liste der Länge $N$ darstellen, und als fit-Funktion nehmen wir die Anzahl der Damen, die sich gegenseitig angreifen:
def fit(L):
x=0
for i1,j1 in enumerate(L,1):
for i2,j2 in enumerate(L,1):
if i2>i1:
if j2==j1 or (abs(j2-j1)==i2-i1): x+=1
return x
Da die Berechnung der Fitnessfunktion zeitaufwendig ist, speichern wir jede Lösung in der Population zusammen mit dem Wert der Fitnessfunktion. Lassen Sie uns die Anfangspopulation generieren:
def generate_one(N):
x = np.arange(1,N+1)
np.random.shuffle(x)
return (x,fit(x))
def generate(N,NP):
return [generate_one(N) for _ in range(NP)]
generate(8,5)
Jetzt müssen wir Mutations- und Kreuzungsfunktionen definieren. Die Kreuzung würde zwei Gene miteinander kombinieren, indem sie an einem zufälligen Punkt aufgebrochen und zwei Teile von verschiedenen Genen zusammengefügt werden.
def mutate(G):
x=random.randint(0,len(G)-1)
G[x]=random.randint(1,len(G))
return G
def xover(G1,G2):
x=random.randint(0,len(G1))
return np.concatenate((G1[:x],G2[x:]))
xover([1,2,3,4],[5,6,7,8])
def choose_rand(P):
N=len(P[0][0])
mf = N*(N-1)//2 # max fitness fn
z = [mf-x[1] for x in P]
tf = sum(z) # total fitness
w = [x/tf for x in z]
p = np.random.choice(len(P),2,False,p=w)
return p[0],p[1]
def choose(P):
def ch(w):
p=[]
while p==[]:
r = random.random()
p = [i for i,x in enumerate(P) if x[1]>=r]
return random.choice(p)
N=len(P[0][0])
mf = N*(N-1)//2 # max fitness fn
z = [mf-x[1] for x in P]
tf = sum(z) # total fitness
w = [x/tf for x in z]
p1=p2=0
while p1==p2:
p1 = ch(w)
p2 = ch(w)
return p1,p2
Nun definieren wir die Hauptschleife der Evolution. Wir werden die Logik leicht anders gestalten als im vorherigen Beispiel, um zu zeigen, dass man kreativ sein kann. Wir werden so lange iterieren, bis wir die perfekte Lösung gefunden haben (Fitnessfunktion = 0). In jedem Schritt nehmen wir die aktuelle Generation und erzeugen eine neue Generation derselben Größe. Dies geschieht mit der Funktion nxgeneration anhand der folgenden Schritte:
- Verwerfe die am wenigsten geeigneten Lösungen – dafür gibt es die Funktion
discard_unfit. - Füge der Generation einige zufällige Lösungen hinzu.
- Erstelle eine neue Generation der Größe
gen_size, indem du für jedes neue Gen die folgenden Schritte ausführst:- Wähle zwei zufällige Gene aus, mit einer Wahrscheinlichkeit proportional zur Fitnessfunktion.
- Berechne ein Crossover.
- Wende eine Mutation mit der Wahrscheinlichkeit
mutation_proban.
mutation_prob = 0.1
def discard_unfit(P):
P.sort(key=lambda x:x[1])
return P[:len(P)//3]
def nxgeneration(P):
gen_size=len(P)
P = discard_unfit(P)
P.extend(generate(len(P[0][0]),3))
new_gen = []
for _ in range(gen_size):
p1,p2 = choose_rand(P)
n = xover(P[p1][0],P[p2][0])
if random.random()<mutation_prob:
n=mutate(n)
nf = fit(n)
new_gen.append((n,nf))
'''
if (nf<=P[p1][1]) or (nf<=P[p2][1]):
new_gen.append((n,nf))
elif (P[p1][1]<P[p2][1]):
new_gen.append(P[p1])
else:
new_gen.append(P[p2])
'''
return new_gen
def genetic(N,pop_size=100):
P = generate(N,pop_size)
mf = min([x[1] for x in P])
n=0
while mf>0:
#print("Generation {0}, fit={1}".format(n,mf))
n+=1
mf = min([x[1] for x in P])
P = nxgeneration(P)
mi = np.argmin([x[1] for x in P])
return P[mi]
genetic(8)
Es ist interessant, dass wir meistens ziemlich schnell eine Lösung finden können, aber in einigen seltenen Fällen erreicht die Optimierung ein lokales Minimum, und der Prozess bleibt für lange Zeit stecken. Es ist wichtig, dies zu berücksichtigen, wenn man die durchschnittliche Zeit misst: Während der genetische Algorithmus in den meisten Fällen schneller als die vollständige Suche ist, kann er in einigen Fällen länger dauern. Um dieses Problem zu überwinden, macht es oft Sinn, die Anzahl der zu berücksichtigenden Generationen zu begrenzen, und wenn wir nicht in der Lage sind, die Lösung zu finden - können wir von vorne beginnen.
%timeit genetic(10)
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Genetische Algorithmen
Quiz vor der Vorlesung
Genetische Algorithmen (GA) basieren auf einem evolutionären Ansatz der KI, bei dem Methoden der Evolution einer Population genutzt werden, um eine optimale Lösung für ein gegebenes Problem zu finden. Sie wurden 1975 von John Henry Holland vorgeschlagen.
Genetische Algorithmen basieren auf den folgenden Ideen:
- Gültige Lösungen des Problems können als Gene dargestellt werden.
- Durch Crossover können zwei Lösungen kombiniert werden, um eine neue gültige Lösung zu erhalten.
- Selektion wird verwendet, um mithilfe einer Fitnessfunktion optimalere Lösungen auszuwählen.
- Mutationen werden eingeführt, um die Optimierung zu destabilisieren und uns aus lokalen Minima herauszuführen.
Wenn Sie einen genetischen Algorithmus implementieren möchten, benötigen Sie Folgendes:
- Eine Methode, um Problemlösungen mithilfe von Genen g∈Γ zu kodieren.
- Auf der Menge der Gene Γ muss eine Fitnessfunktion fit: Γ→R definiert werden. Kleinere Funktionswerte entsprechen besseren Lösungen.
- Einen Crossover-Mechanismus, um zwei Gene zu kombinieren und eine neue gültige Lösung zu erhalten: crossover: Γ²→Γ.
- Einen Mutationsmechanismus: mutate: Γ→Γ.
In vielen Fällen sind Crossover und Mutation recht einfache Algorithmen, die Gene als Zahlenfolgen oder Bitvektoren manipulieren.
Die spezifische Implementierung eines genetischen Algorithmus kann je nach Fall variieren, aber die allgemeine Struktur ist wie folgt:
- Wählen Sie eine Anfangspopulation G⊆Γ.
- Wählen Sie zufällig eine der Operationen aus, die in diesem Schritt ausgeführt werden sollen: Crossover oder Mutation.
- Crossover: * Wählen Sie zufällig zwei Gene g₁, g₂ ∈ G. * Berechnen Sie das Crossover g=crossover(g₁, g₂). * Wenn fit(g)<fit(g₁) oder fit(g)<fit(g₂), ersetzen Sie das entsprechende Gen in der Population durch g.
- Mutation - Wählen Sie ein zufälliges Gen g∈G und ersetzen Sie es durch mutate(g).
- Wiederholen Sie ab Schritt 2, bis ein ausreichend kleiner Wert von fit erreicht ist oder bis das Limit der Schrittanzahl erreicht ist.
Typische Aufgaben
Aufgaben, die typischerweise mit genetischen Algorithmen gelöst werden, umfassen:
- Optimierung von Zeitplänen
- Optimales Packen
- Optimales Schneiden
- Beschleunigung von erschöpfenden Suchverfahren
✍️ Übungen: Genetische Algorithmen
Setzen Sie Ihr Lernen in den folgenden Notebooks fort:
Gehen Sie zu diesem Notebook, um zwei Beispiele für die Verwendung genetischer Algorithmen zu sehen:
- Gerechte Aufteilung eines Schatzes
- 8-Damen-Problem
Fazit
Genetische Algorithmen werden verwendet, um viele Probleme zu lösen, einschließlich Logistik- und Suchprobleme. Dieses Feld ist inspiriert von Forschung, die Themen aus der Psychologie und der Informatik miteinander verbindet.
🚀 Herausforderung
"Genetische Algorithmen sind einfach zu implementieren, aber ihr Verhalten ist schwer zu verstehen." Quelle Recherchieren Sie eine Implementierung eines genetischen Algorithmus, z. B. zur Lösung eines Sudoku-Puzzles, und erklären Sie, wie er funktioniert, als Skizze oder Flussdiagramm.
Quiz nach der Vorlesung
Rückblick & Selbststudium
Sehen Sie sich dieses großartige Video an, das zeigt, wie ein Computer lernen kann, Super Mario zu spielen, indem neuronale Netzwerke mit genetischen Algorithmen trainiert werden. Wir werden mehr darüber lernen, wie Computer lernen, solche Spiele zu spielen, im nächsten Abschnitt.
Aufgabe: Diophantische Gleichung
Ihr Ziel ist es, die sogenannte diophantische Gleichung zu lösen – eine Gleichung mit ganzzahligen Lösungen. Betrachten Sie zum Beispiel die Gleichung a+2b+3c+4d=30. Sie müssen die ganzzahligen Lösungen finden, die diese Gleichung erfüllen.
Diese Aufgabe ist inspiriert von diesem Beitrag.
Hinweise:
- Sie können Lösungen im Intervall [0;30] betrachten.
- Verwenden Sie als Gen die Liste der Lösungswerte.
Nutzen Sie Diophantine.ipynb als Ausgangspunkt.
Training RL zur Balancierung des Cartpole
Dieses Notebook ist Teil des AI for Beginners Curriculum. Es wurde inspiriert von offiziellem PyTorch-Tutorial und dieser Cartpole-PyTorch-Implementierung.
In diesem Beispiel werden wir RL verwenden, um ein Modell zu trainieren, das eine Stange auf einem Wagen balancieren kann, der sich auf einer horizontalen Skala nach links und rechts bewegen kann. Wir nutzen die OpenAI Gym-Umgebung, um die Stange zu simulieren.
> Hinweis: Du kannst den Code dieser Lektion lokal ausführen (z. B. mit Visual Studio Code), wobei die Simulation in einem neuen Fenster geöffnet wird. Wenn du den Code online ausführst, musst du möglicherweise einige Anpassungen vornehmen, wie hier beschrieben.
Wir beginnen damit, sicherzustellen, dass Gym installiert ist:
import sys
!{sys.executable} -m pip install gym
Nun erstellen wir die CartPole-Umgebung und sehen uns an, wie man damit arbeitet. Eine Umgebung hat die folgenden Eigenschaften:
- Action space ist die Menge der möglichen Aktionen, die wir bei jedem Schritt der Simulation ausführen können.
- Observation space ist der Raum der Beobachtungen, die wir machen können.
import gym
env = gym.make("CartPole-v1")
print(f"Action space: {env.action_space}")
print(f"Observation space: {env.observation_space}")
Schauen wir uns an, wie die Simulation funktioniert. Die folgende Schleife führt die Simulation aus, bis env.step das Abbruchsignal done zurückgibt. Wir werden Aktionen zufällig mit env.action_space.sample() auswählen, was bedeutet, dass das Experiment wahrscheinlich sehr schnell scheitern wird (die CartPole-Umgebung endet, wenn die Geschwindigkeit des CartPole, seine Position oder sein Winkel bestimmte Grenzen überschreiten).
> Die Simulation wird in einem neuen Fenster geöffnet. Sie können den Code mehrmals ausführen und beobachten, wie er sich verhält.
env.reset()
done = False
total_reward = 0
while not done:
env.render()
obs, rew, done, info = env.step(env.action_space.sample())
total_reward += rew
print(f"{obs} -> {rew}")
print(f"Total reward: {total_reward}")
Du kannst feststellen, dass die Beobachtungen aus 4 Zahlen bestehen. Diese sind:
- Position des Wagens
- Geschwindigkeit des Wagens
- Winkel der Stange
- Rotationsgeschwindigkeit der Stange
rew ist die Belohnung, die wir bei jedem Schritt erhalten. Im CartPole-Umfeld erhältst du für jeden Simulationsschritt 1 Punkt als Belohnung, und das Ziel ist es, die Gesamtbelohnung zu maximieren, d.h. die Zeit, in der CartPole das Gleichgewicht halten kann, ohne umzufallen.
Während des Reinforcement Learnings ist es unser Ziel, eine Policy $\pi$ zu trainieren, die uns für jeden Zustand $s$ sagt, welche Aktion $a$ wir ausführen sollen, also im Wesentlichen $a = \pi(s)$.
Wenn du eine probabilistische Lösung möchtest, kannst du dir die Policy so vorstellen, dass sie eine Menge von Wahrscheinlichkeiten für jede Aktion zurückgibt, d.h. $\pi(a|s)$ würde die Wahrscheinlichkeit bedeuten, dass wir die Aktion $a$ im Zustand $s$ ausführen sollten.
Policy-Gradient-Methode
Im einfachsten RL-Algorithmus, der Policy Gradient genannt wird, trainieren wir ein neuronales Netzwerk, um die nächste Aktion vorherzusagen.
import numpy as np
import matplotlib.pyplot as plt
import torch
num_inputs = 4
num_actions = 2
model = torch.nn.Sequential(
torch.nn.Linear(num_inputs, 128, bias=False, dtype=torch.float32),
torch.nn.ReLU(),
torch.nn.Linear(128, num_actions, bias = False, dtype=torch.float32),
torch.nn.Softmax(dim=1)
)
Wir werden das Netzwerk trainieren, indem wir viele Experimente durchführen und unser Netzwerk nach jedem Durchlauf aktualisieren. Lassen Sie uns eine Funktion definieren, die das Experiment ausführt und die Ergebnisse zurückgibt (sogenannte Spur) - alle Zustände, Aktionen (und ihre empfohlenen Wahrscheinlichkeiten) und Belohnungen:
def run_episode(max_steps_per_episode = 10000,render=False):
states, actions, probs, rewards = [],[],[],[]
state = env.reset()
for _ in range(max_steps_per_episode):
if render:
env.render()
action_probs = model(torch.from_numpy(np.expand_dims(state,0)))[0]
action = np.random.choice(num_actions, p=np.squeeze(action_probs.detach().numpy()))
nstate, reward, done, info = env.step(action)
if done:
break
states.append(state)
actions.append(action)
probs.append(action_probs.detach().numpy())
rewards.append(reward)
state = nstate
return np.vstack(states), np.vstack(actions), np.vstack(probs), np.vstack(rewards)
Sie können eine Episode mit einem untrainierten Netzwerk ausführen und beobachten, dass die Gesamtbelohnung (auch bekannt als Episodenlänge) sehr niedrig ist:
s, a, p, r = run_episode()
print(f"Total reward: {np.sum(r)}")
Einer der kniffligen Aspekte des Policy-Gradient-Algorithmus ist die Verwendung von abgezinsten Belohnungen. Die Idee ist, dass wir den Vektor der Gesamtbelohnungen bei jedem Schritt des Spiels berechnen und dabei die frühen Belohnungen mit einem Koeffizienten $gamma$ abdiskontieren. Wir normalisieren auch den resultierenden Vektor, da wir ihn als Gewicht verwenden werden, um unser Training zu beeinflussen:
eps = 0.0001
def discounted_rewards(rewards,gamma=0.99,normalize=True):
ret = []
s = 0
for r in rewards[::-1]:
s = r + gamma * s
ret.insert(0, s)
if normalize:
ret = (ret-np.mean(ret))/(np.std(ret)+eps)
return ret
Jetzt geht's ans eigentliche Training! Wir werden 300 Episoden durchführen, und in jeder Episode werden wir Folgendes tun:
- Das Experiment ausführen und die Spur aufzeichnen.
- Die Differenz (
gradients) zwischen den ausgeführten Aktionen und den vorhergesagten Wahrscheinlichkeiten berechnen. Je geringer die Differenz, desto sicherer können wir sein, dass wir die richtige Aktion gewählt haben. - Diskontierte Belohnungen berechnen und die Gradienten mit den diskontierten Belohnungen multiplizieren – das stellt sicher, dass Schritte mit höheren Belohnungen einen größeren Einfluss auf das Endergebnis haben als solche mit niedrigeren Belohnungen.
- Die erwarteten Zielaktionen für unser neuronales Netzwerk werden teilweise aus den vorhergesagten Wahrscheinlichkeiten während des Laufs und teilweise aus den berechneten Gradienten abgeleitet. Wir verwenden den Parameter
alpha, um zu bestimmen, in welchem Maße Gradienten und Belohnungen berücksichtigt werden – dies wird als Lernrate des Verstärkungsalgorithmus bezeichnet. - Schließlich trainieren wir unser Netzwerk mit den Zuständen und den erwarteten Aktionen und wiederholen den Prozess.
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
def train_on_batch(x, y):
x = torch.from_numpy(x)
y = torch.from_numpy(y)
optimizer.zero_grad()
predictions = model(x)
loss = -torch.mean(torch.log(predictions) * y)
loss.backward()
optimizer.step()
return loss
alpha = 1e-4
history = []
for epoch in range(300):
states, actions, probs, rewards = run_episode()
one_hot_actions = np.eye(2)[actions.T][0]
gradients = one_hot_actions-probs
dr = discounted_rewards(rewards)
gradients *= dr
target = alpha*np.vstack([gradients])+probs
train_on_batch(states,target)
history.append(np.sum(rewards))
if epoch%100==0:
print(f"{epoch} -> {np.sum(rewards)}")
plt.plot(history)
Lassen Sie uns nun die Episode mit Rendering ausführen, um das Ergebnis zu sehen:
_ = run_episode(render=True)
Hoffentlich kannst du sehen, dass der Stab jetzt ziemlich gut balancieren kann!
Actor-Critic-Modell
Das Actor-Critic-Modell ist eine Weiterentwicklung der Policy-Gradient-Methoden, bei der wir ein neuronales Netzwerk erstellen, das sowohl die Policy als auch die geschätzten Belohnungen lernt. Das Netzwerk wird zwei Ausgaben haben (oder man kann es als zwei separate Netzwerke betrachten): * Actor wird die Aktion empfehlen, die ausgeführt werden soll, indem es uns die Zustandswahrscheinlichkeitsverteilung gibt, wie im Policy-Gradient-Modell. * Critic würde schätzen, wie die Belohnung aus diesen Aktionen aussehen könnte. Es gibt die insgesamt geschätzten zukünftigen Belohnungen im gegebenen Zustand zurück.
Lass uns ein solches Modell definieren:
from itertools import count
import torch.nn.functional as F
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
env = gym.make("CartPole-v1")
state_size = env.observation_space.shape[0]
action_size = env.action_space.n
lr = 0.0001
class Actor(torch.nn.Module):
def __init__(self, state_size, action_size):
super(Actor, self).__init__()
self.state_size = state_size
self.action_size = action_size
self.linear1 = torch.nn.Linear(self.state_size, 128)
self.linear2 = torch.nn.Linear(128, 256)
self.linear3 = torch.nn.Linear(256, self.action_size)
def forward(self, state):
output = F.relu(self.linear1(state))
output = F.relu(self.linear2(output))
output = self.linear3(output)
distribution = torch.distributions.Categorical(F.softmax(output, dim=-1))
return distribution
class Critic(torch.nn.Module):
def __init__(self, state_size, action_size):
super(Critic, self).__init__()
self.state_size = state_size
self.action_size = action_size
self.linear1 = torch.nn.Linear(self.state_size, 128)
self.linear2 = torch.nn.Linear(128, 256)
self.linear3 = torch.nn.Linear(256, 1)
def forward(self, state):
output = F.relu(self.linear1(state))
output = F.relu(self.linear2(output))
value = self.linear3(output)
return value
Wir müssten unsere Funktionen discounted_rewards und run_episode leicht modifizieren:
def discounted_rewards(next_value, rewards, masks, gamma=0.99):
R = next_value
returns = []
for step in reversed(range(len(rewards))):
R = rewards[step] + gamma * R * masks[step]
returns.insert(0, R)
return returns
def run_episode(actor, critic, n_iters):
optimizerA = torch.optim.Adam(actor.parameters())
optimizerC = torch.optim.Adam(critic.parameters())
for iter in range(n_iters):
state = env.reset()
log_probs = []
values = []
rewards = []
masks = []
entropy = 0
env.reset()
for i in count():
env.render()
state = torch.FloatTensor(state).to(device)
dist, value = actor(state), critic(state)
action = dist.sample()
next_state, reward, done, _ = env.step(action.cpu().numpy())
log_prob = dist.log_prob(action).unsqueeze(0)
entropy += dist.entropy().mean()
log_probs.append(log_prob)
values.append(value)
rewards.append(torch.tensor([reward], dtype=torch.float, device=device))
masks.append(torch.tensor([1-done], dtype=torch.float, device=device))
state = next_state
if done:
print('Iteration: {}, Score: {}'.format(iter, i))
break
next_state = torch.FloatTensor(next_state).to(device)
next_value = critic(next_state)
returns = discounted_rewards(next_value, rewards, masks)
log_probs = torch.cat(log_probs)
returns = torch.cat(returns).detach()
values = torch.cat(values)
advantage = returns - values
actor_loss = -(log_probs * advantage.detach()).mean()
critic_loss = advantage.pow(2).mean()
optimizerA.zero_grad()
optimizerC.zero_grad()
actor_loss.backward()
critic_loss.backward()
optimizerA.step()
optimizerC.step()
Jetzt werden wir die Haupttrainingsschleife ausführen. Wir verwenden den manuellen Netzwerk-Trainingsprozess, indem wir geeignete Verlustfunktionen berechnen und Netzwerkparameter aktualisieren:
actor = Actor(state_size, action_size).to(device)
critic = Critic(state_size, action_size).to(device)
run_episode(actor, critic, n_iters=100)
env.close()
Erkenntnisse
Wir haben in dieser Demo zwei RL-Algorithmen kennengelernt: den einfachen Policy-Gradient-Algorithmus und den anspruchsvolleren Actor-Critic-Algorithmus. Sie können sehen, dass diese Algorithmen mit abstrakten Konzepten wie Zustand, Aktion und Belohnung arbeiten – daher können sie auf sehr unterschiedliche Umgebungen angewendet werden.
Reinforcement Learning ermöglicht es uns, die beste Strategie zur Lösung eines Problems allein durch die Betrachtung der endgültigen Belohnung zu erlernen. Die Tatsache, dass wir keine gelabelten Datensätze benötigen, erlaubt es uns, Simulationen viele Male zu wiederholen, um unsere Modelle zu optimieren. Dennoch gibt es immer noch viele Herausforderungen im Bereich RL, die Sie kennenlernen können, wenn Sie sich entscheiden, sich intensiver mit diesem faszinierenden Bereich der KI zu beschäftigen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
RL-Training zur Balancierung eines Cartpoles
Dieses Notebook ist Teil des AI for Beginners Curriculum. Es wurde inspiriert von diesem Blogbeitrag, der offiziellen TensorFlow-Dokumentation und diesem Keras RL-Beispiel.
In diesem Beispiel werden wir RL verwenden, um ein Modell zu trainieren, das eine Stange auf einem Wagen balancieren kann, der sich auf einer horizontalen Skala nach links und rechts bewegen kann. Wir nutzen die OpenAI Gym-Umgebung, um die Stange zu simulieren.
> Hinweis: Du kannst den Code dieser Lektion lokal ausführen (z. B. mit Visual Studio Code), wobei die Simulation in einem neuen Fenster geöffnet wird. Wenn du den Code online ausführst, musst du möglicherweise einige Anpassungen vornehmen, wie hier beschrieben.
Wir beginnen damit, sicherzustellen, dass Gym installiert ist:
import sys
!{sys.executable} -m pip install gym pygame
Nun erstellen wir die CartPole-Umgebung und sehen uns an, wie man damit arbeitet. Eine Umgebung hat die folgenden Eigenschaften:
- Action space ist die Menge der möglichen Aktionen, die wir in jedem Schritt der Simulation ausführen können.
- Observation space ist der Raum der Beobachtungen, die wir machen können.
import gym
import pygame
import tqdm
env = gym.make("CartPole-v1")
print(f"Action space: {env.action_space}")
print(f"Observation space: {env.observation_space}")
Schauen wir uns an, wie die Simulation funktioniert. Die folgende Schleife führt die Simulation aus, bis env.step das Abbruchsignal done zurückgibt. Wir werden Aktionen zufällig mit env.action_space.sample() auswählen, was bedeutet, dass das Experiment wahrscheinlich sehr schnell scheitern wird (die CartPole-Umgebung endet, wenn die Geschwindigkeit des CartPole, seine Position oder sein Winkel bestimmte Grenzen überschreiten).
> Die Simulation wird in einem neuen Fenster geöffnet. Sie können den Code mehrmals ausführen und beobachten, wie er sich verhält.
env.reset()
done = False
total_reward = 0
while not done:
env.render()
obs, rew, done, info = env.step(env.action_space.sample())
total_reward += rew
print(f"{obs} -> {rew}")
print(f"Total reward: {total_reward}")
env.close()
Du kannst feststellen, dass die Beobachtungen aus 4 Zahlen bestehen. Diese sind: - Position des Wagens - Geschwindigkeit des Wagens - Winkel der Stange - Rotationsgeschwindigkeit der Stange
rew ist die Belohnung, die wir bei jedem Schritt erhalten. Im CartPole-Umfeld erhältst du für jeden Simulationsschritt 1 Punkt, und das Ziel ist es, die Gesamtbelohnung zu maximieren, d.h. die Zeit, in der CartPole das Gleichgewicht halten kann, ohne umzufallen.
Während des Reinforcement Learnings ist es unser Ziel, eine Policy $\pi$ zu trainieren, die uns für jeden Zustand $s$ sagt, welche Aktion $a$ wir ausführen sollen, also im Wesentlichen $a = \pi(s)$.
Wenn du eine probabilistische Lösung möchtest, kannst du dir die Policy so vorstellen, dass sie eine Menge von Wahrscheinlichkeiten für jede Aktion zurückgibt, d.h. $\pi(a|s)$ würde die Wahrscheinlichkeit bedeuten, dass wir im Zustand $s$ die Aktion $a$ ausführen sollten.
Policy-Gradient-Methode
Im einfachsten RL-Algorithmus, der Policy Gradient genannt wird, trainieren wir ein neuronales Netzwerk, um die nächste Aktion vorherzusagen.
import numpy as np
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
num_inputs = 4
num_actions = 2
model = keras.Sequential([
keras.layers.Dense(128, activation="relu",input_shape=(num_inputs,)),
keras.layers.Dense(num_actions, activation="softmax")
])
model.compile(loss='categorical_crossentropy', optimizer=keras.optimizers.Adam(learning_rate=0.01))
Wir werden das Netzwerk trainieren, indem wir viele Experimente durchführen und unser Netzwerk nach jedem Durchlauf aktualisieren. Lassen Sie uns eine Funktion definieren, die das Experiment ausführt und die Ergebnisse zurückgibt (den sogenannten Trace) - alle Zustände, Aktionen (und ihre empfohlenen Wahrscheinlichkeiten) und Belohnungen:
def run_episode(max_steps_per_episode = 10000,render=False):
states, actions, probs, rewards = [],[],[],[]
state = env.reset()
for _ in range(max_steps_per_episode):
if render:
env.render()
action_probs = model(np.expand_dims(state,0))[0]
action = np.random.choice(num_actions, p=np.squeeze(action_probs))
nstate, reward, done, info = env.step(action)
if done:
break
states.append(state)
actions.append(action)
probs.append(action_probs)
rewards.append(reward)
state = nstate
return np.vstack(states), np.vstack(actions), np.vstack(probs), np.vstack(rewards)
Sie können eine Episode mit einem untrainierten Netzwerk ausführen und beobachten, dass die Gesamtbelohnung (auch bekannt als Episodenlänge) sehr niedrig ist:
s,a,p,r = run_episode()
print(f"Total reward: {np.sum(r)}")
Einer der kniffligen Aspekte des Policy-Gradient-Algorithmus ist die Verwendung von abgezinsten Belohnungen. Die Idee ist, dass wir den Vektor der Gesamtbelohnungen bei jedem Schritt des Spiels berechnen und dabei die frühen Belohnungen mit einem Koeffizienten $gamma$ abdiskontieren. Wir normalisieren auch den resultierenden Vektor, da wir ihn als Gewicht verwenden werden, um unser Training zu beeinflussen:
eps = 0.0001
def discounted_rewards(rewards,gamma=0.99,normalize=True):
ret = []
s = 0
for r in rewards[::-1]:
s = r + gamma * s
ret.insert(0, s)
if normalize:
ret = (ret-np.mean(ret))/(np.std(ret)+eps)
return ret
Jetzt geht's ans eigentliche Training! Wir werden 300 Episoden durchführen, und in jeder Episode werden wir Folgendes tun:
- Das Experiment ausführen und die Spur (Trace) sammeln.
- Die Differenz (
Gradienten) zwischen den ausgeführten Aktionen und den vorhergesagten Wahrscheinlichkeiten berechnen. Je kleiner die Differenz, desto sicherer können wir sein, dass wir die richtige Aktion gewählt haben. - Diskontierte Belohnungen berechnen und die Gradienten mit den diskontierten Belohnungen multiplizieren – das stellt sicher, dass Schritte mit höheren Belohnungen einen größeren Einfluss auf das Endergebnis haben als solche mit niedrigeren Belohnungen.
- Die erwarteten Zielaktionen für unser neuronales Netzwerk werden teilweise aus den vorhergesagten Wahrscheinlichkeiten während des Laufs und teilweise aus den berechneten Gradienten abgeleitet. Wir verwenden den Parameter
alpha, um zu bestimmen, in welchem Maße Gradienten und Belohnungen berücksichtigt werden – dies wird als Lernrate des Verstärkungsalgorithmus bezeichnet. - Schließlich trainieren wir unser Netzwerk mit den Zuständen und den erwarteten Aktionen und wiederholen den Prozess.
alpha = 1e-4
history = []
for epoch in range(300):
states, actions, probs, rewards = run_episode()
one_hot_actions = np.eye(2)[actions.T][0]
gradients = one_hot_actions-probs
dr = discounted_rewards(rewards)
gradients *= dr
target = alpha*np.vstack([gradients])+probs
model.train_on_batch(states,target)
history.append(np.sum(rewards))
if epoch%100==0:
print(f"{epoch} -> {np.sum(rewards)}")
plt.plot(history)
Lassen Sie uns nun die Episode mit Rendering ausführen, um das Ergebnis zu sehen:
_ = run_episode(render=True)
Hoffentlich kannst du sehen, dass der Stab jetzt ziemlich gut balancieren kann!
Actor-Critic-Modell
Das Actor-Critic-Modell ist eine Weiterentwicklung der Policy-Gradient-Methoden, bei der wir ein neuronales Netzwerk erstellen, das sowohl die Policy als auch die geschätzten Belohnungen lernt. Das Netzwerk wird zwei Ausgaben haben (oder man kann es als zwei separate Netzwerke betrachten): * Actor wird die Aktion empfehlen, die ausgeführt werden soll, indem es uns die Zustandswahrscheinlichkeitsverteilung gibt, wie im Policy-Gradient-Modell. * Critic würde schätzen, welche Belohnung aus diesen Aktionen resultieren würde. Es gibt die insgesamt geschätzten zukünftigen Belohnungen im gegebenen Zustand zurück.
Lass uns ein solches Modell definieren:
num_inputs = 4
num_actions = 2
num_hidden = 128
inputs = keras.layers.Input(shape=(num_inputs,))
common = keras.layers.Dense(num_hidden, activation="relu")(inputs)
action = keras.layers.Dense(num_actions, activation="softmax")(common)
critic = keras.layers.Dense(1)(common)
model = keras.Model(inputs=inputs, outputs=[action, critic])
Wir müssten unsere run_episode-Funktion leicht modifizieren, um auch Kritikerergebnisse zurückzugeben:
def run_episode(max_steps_per_episode = 10000,render=False):
states, actions, probs, rewards, critic = [],[],[],[],[]
state = env.reset()
for _ in range(max_steps_per_episode):
if render:
env.render()
action_probs, est_rew = model(np.expand_dims(state,0))
action = np.random.choice(num_actions, p=np.squeeze(action_probs[0]))
nstate, reward, done, info = env.step(action)
if done:
break
states.append(state)
actions.append(action)
probs.append(tf.math.log(action_probs[0,action]))
rewards.append(reward)
critic.append(est_rew[0,0])
state = nstate
return states, actions, probs, rewards, critic
Jetzt werden wir die Haupttrainingsschleife ausführen. Wir verwenden den manuellen Netzwerk-Trainingsprozess, indem wir geeignete Verlustfunktionen berechnen und Netzwerkparameter aktualisieren:
optimizer = keras.optimizers.Adam(learning_rate=0.01)
huber_loss = keras.losses.Huber()
episode_count = 0
running_reward = 0
while True: # Run until solved
state = env.reset()
episode_reward = 0
with tf.GradientTape() as tape:
_,_,action_probs, rewards, critic_values = run_episode()
episode_reward = np.sum(rewards)
# Update running reward to check condition for solving
running_reward = 0.05 * episode_reward + (1 - 0.05) * running_reward
# Calculate discounted rewards that will be labels for our critic
dr = discounted_rewards(rewards)
# Calculating loss values to update our network
actor_losses = []
critic_losses = []
for log_prob, value, rew in zip(action_probs, critic_values, dr):
# When we took the action with probability `log_prob`, we received discounted reward of `rew`,
# while critic predicted it to be `value`
# First we calculate actor loss, to make actor predict actions that lead to higher rewards
diff = rew - value
actor_losses.append(-log_prob * diff)
# The critic loss is to minimize the difference between predicted reward `value` and actual
# discounted reward `rew`
critic_losses.append(
huber_loss(tf.expand_dims(value, 0), tf.expand_dims(rew, 0))
)
# Backpropagation
loss_value = sum(actor_losses) + sum(critic_losses)
grads = tape.gradient(loss_value, model.trainable_variables)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
# Log details
episode_count += 1
if episode_count % 10 == 0:
template = "running reward: {:.2f} at episode {}"
print(template.format(running_reward, episode_count))
if running_reward > 195: # Condition to consider the task solved
print("Solved at episode {}!".format(episode_count))
break
Lass uns die Episode starten und sehen, wie gut unser Modell ist:
_ = run_episode(render=True)
env.close()
Erkenntnisse
Wir haben in dieser Demo zwei RL-Algorithmen kennengelernt: den einfachen Policy Gradient und den anspruchsvolleren Actor-Critic. Sie können sehen, dass diese Algorithmen mit abstrakten Konzepten wie Zustand, Aktion und Belohnung arbeiten – daher können sie auf sehr unterschiedliche Umgebungen angewendet werden.
Reinforcement Learning ermöglicht es uns, die beste Strategie zur Lösung eines Problems allein durch die Betrachtung der endgültigen Belohnung zu erlernen. Die Tatsache, dass wir keine gelabelten Datensätze benötigen, erlaubt es uns, Simulationen viele Male zu wiederholen, um unsere Modelle zu optimieren. Dennoch gibt es immer noch viele Herausforderungen im Bereich RL, die Sie kennenlernen können, wenn Sie sich entscheiden, sich intensiver mit diesem faszinierenden Bereich der KI zu beschäftigen.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
# Training Mountain Car zur Flucht
Laboraufgabe aus dem AI for Beginners Curriculum.
Dein Ziel ist es, den RL-Agenten zu trainieren, das Mountain Car in der OpenAI-Umgebung zu steuern.
Lass uns mit der Erstellung der Umgebung beginnen:
import gym
env = gym.make('MountainCar-v0')
Lassen Sie uns sehen, wie das Zufallsexperiment aussieht:
state = env.reset()
while True:
env.render()
action = env.action_space.sample()
state, reward, done, info = env.step(action)
if done:
break
## Lost of code here
env.close()
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Die Umgebung
Die Mountain Car-Umgebung besteht aus einem Auto, das in einem Tal gefangen ist. Dein Ziel ist es, aus dem Tal herauszuspringen und die Fahne zu erreichen. Die Aktionen, die du ausführen kannst, sind: nach links beschleunigen, nach rechts beschleunigen oder nichts tun. Du kannst die Position des Autos entlang der x-Achse und die Geschwindigkeit beobachten.
Start-Notebook
Beginne das Lab, indem du MountainCar.ipynb öffnest.
Erkenntnis
Während dieses Labs solltest du lernen, dass die Anpassung von RL-Algorithmen an eine neue Umgebung oft recht unkompliziert ist, da OpenAI Gym für alle Umgebungen dieselbe Schnittstelle bietet und die Algorithmen im Allgemeinen nicht stark von der Art der Umgebung abhängen. Du kannst den Python-Code sogar so umstrukturieren, dass jede Umgebung als Parameter an den RL-Algorithmus übergeben werden kann.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
CartPole Skating
> Problem: Wenn Peter dem Wolf entkommen möchte, muss er sich schneller bewegen können als dieser. Wir werden sehen, wie Peter das Skaten lernen kann, insbesondere das Halten des Gleichgewichts, mithilfe von Q-Learning.
Zuerst installieren wir das Gym und importieren die benötigten Bibliotheken:
import sys
!pip install gym pygame
import gym
import matplotlib.pyplot as plt
import numpy as np
import random
Erstelle eine Cartpole-Umgebung
env = gym.make("CartPole-v1")
print(env.action_space)
print(env.observation_space)
print(env.action_space.sample())
Um zu sehen, wie die Umgebung funktioniert, lassen Sie uns eine kurze Simulation für 100 Schritte durchführen.
env.reset()
for i in range(100):
env.render()
env.step(env.action_space.sample())
env.close()
Während der Simulation müssen wir Beobachtungen erhalten, um zu entscheiden, wie wir handeln sollen. Tatsächlich gibt uns die step-Funktion die aktuellen Beobachtungen, die Belohnungsfunktion und das done-Flag zurück, das anzeigt, ob es sinnvoll ist, die Simulation fortzusetzen oder nicht:
env.reset()
done = False
while not done:
env.render()
obs, rew, done, info = env.step(env.action_space.sample())
print(f"{obs} -> {rew}")
env.close()
Wir können den Mindest- und Höchstwert dieser Zahlen erhalten:
print(env.observation_space.low)
print(env.observation_space.high)
def discretize(x):
return tuple((x/np.array([0.25, 0.25, 0.01, 0.1])).astype(np.int))
Lassen Sie uns auch eine andere Diskretisierungsmethode mit Bins erkunden:
def create_bins(i,num):
return np.arange(num+1)*(i[1]-i[0])/num+i[0]
print("Sample bins for interval (-5,5) with 10 bins\n",create_bins((-5,5),10))
ints = [(-5,5),(-2,2),(-0.5,0.5),(-2,2)] # intervals of values for each parameter
nbins = [20,20,10,10] # number of bins for each parameter
bins = [create_bins(ints[i],nbins[i]) for i in range(4)]
def discretize_bins(x):
return tuple(np.digitize(x[i],bins[i]) for i in range(4))
Lassen Sie uns nun eine kurze Simulation durchführen und diese diskreten Umgebungswerte beobachten.
env.reset()
done = False
while not done:
#env.render()
obs, rew, done, info = env.step(env.action_space.sample())
#print(discretize_bins(obs))
print(discretize(obs))
env.close()
Q-Tabellenstruktur
Q = {}
actions = (0,1)
def qvalues(state):
return [Q.get((state,a),0) for a in actions]
# hyperparameters
alpha = 0.3
gamma = 0.9
epsilon = 0.90
def probs(v,eps=1e-4):
v = v-v.min()+eps
v = v/v.sum()
return v
Qmax = 0
cum_rewards = []
rewards = []
for epoch in range(100000):
obs = env.reset()
done = False
cum_reward=0
# == do the simulation ==
while not done:
s = discretize(obs)
if random.random()<epsilon:
# exploitation - chose the action according to Q-Table probabilities
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
else:
# exploration - randomly chose the action
a = np.random.randint(env.action_space.n)
obs, rew, done, info = env.step(a)
cum_reward+=rew
ns = discretize(obs)
Q[(s,a)] = (1 - alpha) * Q.get((s,a),0) + alpha * (rew + gamma * max(qvalues(ns)))
cum_rewards.append(cum_reward)
rewards.append(cum_reward)
# == Periodically print results and calculate average reward ==
if epoch%5000==0:
print(f"{epoch}: {np.average(cum_rewards)}, alpha={alpha}, epsilon={epsilon}")
if np.average(cum_rewards) > Qmax:
Qmax = np.average(cum_rewards)
Qbest = Q
cum_rewards=[]
plt.plot(rewards)
Aus diesem Diagramm lässt sich nichts erkennen, da die Länge der Trainingssitzungen aufgrund der stochastischen Trainingsprozesse stark variiert. Um dieses Diagramm besser zu verstehen, können wir den gleitenden Durchschnitt über eine Reihe von Experimenten berechnen, sagen wir 100. Dies kann bequem mit np.convolve durchgeführt werden:
def running_average(x,window):
return np.convolve(x,np.ones(window)/window,mode='valid')
plt.plot(running_average(rewards,100))
Variieren von Hyperparametern und Beobachten der Ergebnisse in Aktion
Jetzt wäre es interessant zu sehen, wie sich das trainierte Modell tatsächlich verhält. Lassen Sie uns die Simulation durchführen, und wir werden die gleiche Aktionsauswahlstrategie wie während des Trainings verfolgen: Sampling entsprechend der Wahrscheinlichkeitsverteilung in der Q-Tabelle:
obs = env.reset()
done = False
while not done:
s = discretize(obs)
env.render()
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
obs,_,done,_ = env.step(a)
env.close()
Speichern des Ergebnisses als animiertes GIF
Wenn du deine Freunde beeindrucken möchtest, kannst du ihnen das animierte GIF-Bild der Balancierstange schicken. Dafür können wir env.render aufrufen, um ein Bildframe zu erzeugen, und diese dann mit der PIL-Bibliothek als animiertes GIF speichern:
from PIL import Image
obs = env.reset()
done = False
i=0
ims = []
while not done:
s = discretize(obs)
img=env.render(mode='rgb_array')
ims.append(Image.fromarray(img))
v = probs(np.array([Qbest.get((s,a),0) for a in actions]))
a = random.choices(actions,weights=v)[0]
obs,_,done,_ = env.step(a)
i+=1
env.close()
ims[0].save('images/cartpole-balance.gif',save_all=True,append_images=ims[1::2],loop=0,duration=5)
print(i)
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Deep Reinforcement Learning
Reinforcement Learning (RL) wird als eines der grundlegenden Paradigmen des maschinellen Lernens angesehen, neben überwachten und unüberwachten Lernen. Während wir beim überwachten Lernen auf Datensätze mit bekannten Ergebnissen angewiesen sind, basiert RL auf dem Prinzip des Lernens durch Handeln. Zum Beispiel: Wenn wir ein Computerspiel zum ersten Mal sehen, beginnen wir zu spielen, auch ohne die Regeln zu kennen, und verbessern unsere Fähigkeiten allein durch das Spielen und Anpassen unseres Verhaltens.
Quiz vor der Vorlesung
Um RL durchzuführen, benötigen wir:
- Eine Umgebung oder einen Simulator, der die Regeln des Spiels festlegt. Wir sollten in der Lage sein, Experimente im Simulator durchzuführen und die Ergebnisse zu beobachten.
- Eine Belohnungsfunktion, die anzeigt, wie erfolgreich unser Experiment war. Im Fall des Lernens, ein Computerspiel zu spielen, wäre die Belohnung unsere Endpunktzahl.
Basierend auf der Belohnungsfunktion sollten wir unser Verhalten anpassen und unsere Fähigkeiten verbessern, sodass wir beim nächsten Mal besser spielen. Der Hauptunterschied zwischen anderen Arten des maschinellen Lernens und RL besteht darin, dass wir bei RL normalerweise erst am Ende des Spiels wissen, ob wir gewonnen oder verloren haben. Daher können wir nicht sagen, ob ein bestimmter Zug allein gut oder schlecht ist – wir erhalten die Belohnung erst am Ende des Spiels.
Während des RL führen wir typischerweise viele Experimente durch. Bei jedem Experiment müssen wir zwischen der Anwendung der optimalen Strategie, die wir bisher gelernt haben (Exploitation), und der Erkundung neuer möglicher Zustände (Exploration) abwägen.
OpenAI Gym
Ein großartiges Werkzeug für RL ist das OpenAI Gym – eine Simulationsumgebung, die viele verschiedene Umgebungen simulieren kann, von Atari-Spielen bis hin zur Physik des Stangenbalancierens. Es ist eine der beliebtesten Simulationsumgebungen für das Training von Reinforcement-Learning-Algorithmen und wird von OpenAI gepflegt.
> Note: Alle verfügbaren Umgebungen von OpenAI Gym können hier eingesehen werden.
CartPole Balancing
Ihr habt wahrscheinlich alle moderne Balanciergeräte wie den Segway oder Gyroscooter gesehen. Sie können sich automatisch ausbalancieren, indem sie ihre Räder entsprechend einem Signal von einem Beschleunigungsmesser oder Gyroskop anpassen. In diesem Abschnitt lernen wir, ein ähnliches Problem zu lösen – das Balancieren einer Stange. Es ist vergleichbar mit der Situation, in der ein Zirkuskünstler eine Stange auf seiner Hand balancieren muss – aber dieses Balancieren erfolgt nur in einer Dimension.
Eine vereinfachte Version des Balancierens ist als CartPole-Problem bekannt. In der CartPole-Welt haben wir einen horizontalen Schlitten, der sich nach links oder rechts bewegen kann, und das Ziel ist es, eine vertikale Stange oben auf dem Schlitten zu balancieren, während er sich bewegt.
<img alt="a cartpole" src="../../../../../translated_images/de/cartpole.f52a67f27e058170.webp" width="200"/>
Um diese Umgebung zu erstellen und zu nutzen, benötigen wir ein paar Zeilen Python-Code:
import gym
env = gym.make("CartPole-v1")
env.reset()
done = False
total_reward = 0
while not done:
env.render()
action = env.action_space.sample()
observaton, reward, done, info = env.step(action)
total_reward += reward
print(f"Total reward: {total_reward}")
Jede Umgebung kann auf die gleiche Weise angesprochen werden:
* env.reset startet ein neues Experiment
* env.step führt einen Simulationsschritt aus. Es erhält eine Aktion aus dem Aktionsraum und gibt eine Beobachtung (aus dem Beobachtungsraum) sowie eine Belohnung und ein Abbruchflag zurück.
Im obigen Beispiel führen wir bei jedem Schritt eine zufällige Aktion aus, weshalb die Lebensdauer des Experiments sehr kurz ist:

Das Ziel eines RL-Algorithmus ist es, ein Modell zu trainieren – die sogenannte Policy π –, die die Aktion als Antwort auf einen gegebenen Zustand zurückgibt. Wir können die Policy auch als probabilistisch betrachten, z. B. für jeden Zustand s und jede Aktion a gibt sie die Wahrscheinlichkeit π(a|s) zurück, dass wir a im Zustand s ausführen sollten.
Policy-Gradient-Algorithmus
Die offensichtlichste Möglichkeit, eine Policy zu modellieren, besteht darin, ein neuronales Netzwerk zu erstellen, das Zustände als Eingabe nimmt und entsprechende Aktionen (oder vielmehr die Wahrscheinlichkeiten aller Aktionen) zurückgibt. In gewisser Weise wäre es ähnlich wie eine normale Klassifikationsaufgabe, mit einem wesentlichen Unterschied – wir wissen im Voraus nicht, welche Aktionen wir bei jedem Schritt ausführen sollten.
Die Idee ist hier, diese Wahrscheinlichkeiten zu schätzen. Wir erstellen einen Vektor von kumulierten Belohnungen, der unsere Gesamtbelohnung bei jedem Schritt des Experiments zeigt. Wir wenden auch Belohnungsdiskontierung an, indem wir frühere Belohnungen mit einem Koeffizienten γ=0.99 multiplizieren, um die Rolle früherer Belohnungen zu verringern. Dann verstärken wir die Schritte entlang des Experimentpfads, die größere Belohnungen bringen.
> Erfahren Sie mehr über den Policy-Gradient-Algorithmus und sehen Sie ihn in Aktion im Beispiel-Notebook.
Actor-Critic-Algorithmus
Eine verbesserte Version des Policy-Gradient-Ansatzes wird Actor-Critic genannt. Die Hauptidee dahinter ist, dass das neuronale Netzwerk so trainiert wird, dass es zwei Dinge zurückgibt:
- Die Policy, die bestimmt, welche Aktion ausgeführt werden soll. Dieser Teil wird Actor genannt.
- Die Schätzung der Gesamtbelohnung, die wir in diesem Zustand erwarten können – dieser Teil wird Critic genannt.
In gewisser Weise ähnelt diese Architektur einem GAN, bei dem wir zwei Netzwerke haben, die gegeneinander trainiert werden. Im Actor-Critic-Modell schlägt der Actor die Aktion vor, die wir ausführen müssen, und der Critic versucht kritisch zu sein und das Ergebnis zu schätzen. Unser Ziel ist jedoch, diese Netzwerke im Einklang zu trainieren.
Da wir sowohl die tatsächlichen kumulierten Belohnungen als auch die vom Critic während des Experiments zurückgegebenen Ergebnisse kennen, ist es relativ einfach, eine Verlustfunktion zu erstellen, die die Differenz zwischen ihnen minimiert. Das ergibt den Critic-Loss. Den Actor-Loss können wir mit dem gleichen Ansatz wie beim Policy-Gradient-Algorithmus berechnen.
Nach dem Ausführen eines dieser Algorithmen können wir erwarten, dass unser CartPole sich so verhält:

✍️ Übungen: Policy-Gradient und Actor-Critic RL
Setzen Sie Ihr Lernen in den folgenden Notebooks fort:
Andere RL-Aufgaben
Reinforcement Learning ist heutzutage ein schnell wachsendes Forschungsfeld. Einige interessante Beispiele für Reinforcement Learning sind:
- Das Lehren eines Computers, Atari-Spiele zu spielen. Die Herausforderung bei diesem Problem besteht darin, dass wir keinen einfachen Zustand als Vektor haben, sondern einen Screenshot – und wir müssen CNNs verwenden, um dieses Bildschirmbild in einen Feature-Vektor umzuwandeln oder Belohnungsinformationen zu extrahieren. Atari-Spiele sind im Gym verfügbar.
- Das Lehren eines Computers, Brettspiele wie Schach und Go zu spielen. Kürzlich wurden Programme wie Alpha Zero von Grund auf trainiert, indem zwei Agenten gegeneinander spielten und sich bei jedem Schritt verbesserten.
- In der Industrie wird RL verwendet, um Steuerungssysteme aus Simulationen zu erstellen. Ein Dienst namens Bonsai ist speziell dafür konzipiert.
Fazit
Wir haben nun gelernt, wie man Agenten trainiert, um gute Ergebnisse zu erzielen, indem man ihnen lediglich eine Belohnungsfunktion gibt, die den gewünschten Zustand des Spiels definiert, und ihnen die Möglichkeit gibt, den Suchraum intelligent zu erkunden. Wir haben erfolgreich zwei Algorithmen ausprobiert und in relativ kurzer Zeit ein gutes Ergebnis erzielt. Dies ist jedoch nur der Anfang Ihrer Reise in RL, und Sie sollten definitiv einen separaten Kurs in Betracht ziehen, wenn Sie tiefer eintauchen möchten.
🚀 Herausforderung
Erkunden Sie die Anwendungen, die im Abschnitt "Andere RL-Aufgaben" aufgeführt sind, und versuchen Sie, eine davon umzusetzen!
Quiz nach der Vorlesung
Überprüfung & Selbststudium
Erfahren Sie mehr über klassisches Reinforcement Learning in unserem Machine Learning for Beginners Curriculum.
Sehen Sie sich dieses großartige Video an, das zeigt, wie ein Computer lernen kann, Super Mario zu spielen.
Aufgabe: Trainieren Sie ein Mountain Car
Ihr Ziel bei dieser Aufgabe ist es, eine andere Gym-Umgebung zu trainieren – Mountain Car.
import numpy as np
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import gym
env = gym.make("CartPole-v1")
class REINFORCE:
def __init__(self, env, path=None):
self.env=env #import env
self.state_shape=env.observation_space.shape # the state space
self.action_shape=env.action_space.n # the action space
self.gamma=0.99 # decay rate of past observations
self.alpha=1e-4 # learning rate in the policy gradient
self.learning_rate=0.01 # learning rate in deep learning
if not path:
self.model=self._create_model() #build model
else:
self.model=self.load_model(path) #import model
# record observations
self.states=[]
self.gradients=[]
self.rewards=[]
self.probs=[]
self.discounted_rewards=[]
self.total_rewards=[]
def hot_encode_action(self, action):
'''encoding the actions into a binary list'''
action_encoded=np.zeros(self.action_shape, np.float32)
action_encoded[action]=1
return action_encoded
def remember(self, state, action, action_prob, reward):
'''stores observations'''
encoded_action=self.hot_encode_action(action)
self.gradients.append(encoded_action-action_prob)
self.states.append(state)
self.rewards.append(reward)
self.probs.append(action_prob)
def _create_model(self):
''' builds the model using keras'''
model=keras.Sequential()
# input shape is of observations
model.add(keras.layers.Dense(24, input_shape=self.state_shape, activation="relu"))
# add a relu layer
model.add(keras.layers.Dense(12, activation="relu"))
# output shape is according to the number of action
# The softmax function outputs a probability distribution over the actions
model.add(keras.layers.Dense(self.action_shape, activation="softmax"))
model.compile(loss="categorical_crossentropy",
optimizer=keras.optimizers.Adam(lr=self.learning_rate))
return model
def get_action(self, state):
'''samples the next action based on the policy probabilty distribution
of the actions'''
# transform state
state=state.reshape([1, state.shape[0]])
# get action probably
action_probability_distribution=self.model.predict(state).flatten()
# norm action probability distribution
action_probability_distribution/=np.sum(action_probability_distribution)
# sample action
action=np.random.choice(self.action_shape,1,
p=action_probability_distribution)[0]
return action, action_probability_distribution
def get_discounted_rewards(self, rewards):
'''Use gamma to calculate the total reward discounting for rewards
Following - \gamma ^ t * Gt'''
discounted_rewards=[]
cumulative_total_return=0
# iterate the rewards backwards and and calc the total return
for reward in rewards[::-1]:
cumulative_total_return=(cumulative_total_return*self.gamma)+reward
discounted_rewards.insert(0, cumulative_total_return)
# normalize discounted rewards
mean_rewards=np.mean(discounted_rewards)
std_rewards=np.std(discounted_rewards)
norm_discounted_rewards=(discounted_rewards-
mean_rewards)/(std_rewards+1e-7) # avoiding zero div
return norm_discounted_rewards
def update_policy(self):
'''Updates the policy network using the NN model.
This function is used after the MC sampling is done - following
\delta \theta = \alpha * gradient + log pi'''
# get X
states=np.vstack(self.states)
# get Y
gradients=np.vstack(self.gradients)
rewards=np.vstack(self.rewards)
discounted_rewards=self.get_discounted_rewards(rewards)
gradients*=discounted_rewards
gradients=self.alpha*np.vstack([gradients])+self.probs
history=self.model.train_on_batch(states, gradients)
self.states, self.probs, self.gradients, self.rewards=[], [], [], []
return history
def train(self, episodes, rollout_n=1, render_n=50):
'''train the model
episodes - number of training iterations
rollout_n- number of episodes between policy update
render_n - number of episodes between env rendering '''
env=self.env
total_rewards=np.zeros(episodes)
for episode in range(episodes):
# each episode is a new game env
state=env.reset()
done=False
episode_reward=0 #record episode reward
while not done:
# play an action and record the game state & reward per episode
action, prob=self.get_action(state)
next_state, reward, done, _=env.step(action)
self.remember(state, action, prob, reward)
state=next_state
episode_reward+=reward
#if episode%render_n==0: ## render env to visualize.
#env.render()
if done:
# update policy
if episode%rollout_n==0:
history=self.update_policy()
total_rewards[episode]=episode_reward
if episode%10==0:
print(f"{episode} -> {episode_reward}")
self.total_rewards=total_rewards
r = REINFORCE(env)
r.train(200)
plt.plot(r.total_rewards)
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
NetLogo Aufgabe
Nehmen Sie eines der Modelle aus der NetLogo-Bibliothek und verwenden Sie es, um eine reale Situation so genau wie möglich zu simulieren. Ein gutes Beispiel wäre, das Virus-Modell im Ordner Alternative Visualisierungen anzupassen, um zu zeigen, wie es verwendet werden kann, um die Ausbreitung von COVID-19 zu modellieren. Können Sie ein Modell erstellen, das die Ausbreitung eines echten Virus nachahmt?
Zeigen Sie Ihre Arbeit, indem Sie eine Kopie speichern und ein Video-Demo erstellen, das erklärt, wie das Modell mit einer realen Situation verbunden ist.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Multi-Agenten-Systeme
Eine mögliche Methode, Intelligenz zu erreichen, ist der sogenannte emergente (oder synergetische) Ansatz. Dieser basiert auf der Tatsache, dass das kombinierte Verhalten vieler relativ einfacher Agenten zu einem insgesamt komplexeren (oder intelligenteren) Verhalten des Systems als Ganzes führen kann. Theoretisch basiert dies auf den Prinzipien der kollektiven Intelligenz, des Emergentismus und der evolutionären Kybernetik, die besagen, dass höherstufige Systeme einen Mehrwert erhalten, wenn sie richtig aus niedrigeren Systemen kombiniert werden (das sogenannte Prinzip des Metasystemübergangs).
Quiz vor der Vorlesung
Die Richtung der Multi-Agenten-Systeme entstand in den 1990er Jahren als Reaktion auf das Wachstum des Internets und verteilter Systeme. Eines der klassischen Lehrbücher der KI, Artificial Intelligence: A Modern Approach, betrachtet die klassische KI aus der Perspektive von Multi-Agenten-Systemen.
Im Mittelpunkt des Multi-Agenten-Ansatzes steht der Begriff des Agenten – eine Entität, die in einer Umgebung lebt, die sie wahrnehmen und auf die sie einwirken kann. Dies ist eine sehr breite Definition, und es gibt viele verschiedene Typen und Klassifikationen von Agenten:
- Nach ihrer Fähigkeit zu denken:
- Reaktive Agenten haben normalerweise ein einfaches Anfrage-Antwort-Verhalten.
- Deliberative Agenten nutzen eine Art logisches Denken und/oder Planungsfähigkeiten.
- Nach dem Ort, an dem der Agent seinen Code ausführt:
- Statische Agenten arbeiten auf einem dedizierten Netzwerkknoten.
- Mobile Agenten können ihren Code zwischen Netzwerkknoten verschieben.
- Nach ihrem Verhalten:
- Passive Agenten haben keine spezifischen Ziele. Solche Agenten können auf externe Reize reagieren, initiieren jedoch keine eigenen Aktionen.
- Aktive Agenten verfolgen bestimmte Ziele.
- Kognitive Agenten beinhalten komplexe Planung und Denken.
Multi-Agenten-Systeme werden heute in einer Vielzahl von Anwendungen eingesetzt:
- In Spielen nutzen viele Nicht-Spieler-Charaktere eine Art KI und können als intelligente Agenten betrachtet werden.
- In der Videoproduktion wird das Rendern komplexer 3D-Szenen mit Menschenmengen typischerweise mithilfe von Multi-Agenten-Simulationen durchgeführt.
- In der Systemmodellierung wird der Multi-Agenten-Ansatz verwendet, um das Verhalten eines komplexen Modells zu simulieren. Beispielsweise wurde der Multi-Agenten-Ansatz erfolgreich eingesetzt, um die weltweite Ausbreitung der COVID-19-Krankheit vorherzusagen. Ein ähnlicher Ansatz kann verwendet werden, um den Verkehr in einer Stadt zu modellieren und zu sehen, wie er auf Änderungen der Verkehrsregeln reagiert.
- In komplexen Automatisierungssystemen kann jedes Gerät als unabhängiger Agent agieren, wodurch das gesamte System weniger monolithisch und robuster wird.
Wir werden nicht viel Zeit damit verbringen, tief in Multi-Agenten-Systeme einzutauchen, sondern ein Beispiel für Multi-Agenten-Modellierung betrachten.
NetLogo
NetLogo ist eine Multi-Agenten-Modellierungsumgebung, die auf einer modifizierten Version der Logo-Programmiersprache basiert. Diese Sprache wurde entwickelt, um Kindern Programmierkonzepte beizubringen, und ermöglicht es, einen Agenten namens Turtle zu steuern, der sich bewegen und dabei eine Spur hinterlassen kann. Dies ermöglicht die Erstellung komplexer geometrischer Figuren, was eine sehr visuelle Möglichkeit ist, das Verhalten eines Agenten zu verstehen.
In NetLogo können wir viele Turtles mit dem Befehl create-turtles erstellen. Wir können dann alle Turtles anweisen, bestimmte Aktionen auszuführen (im folgenden Beispiel - 10 Punkte vorwärts bewegen):
create-turtles 10
ask turtles [
forward 10
]
Natürlich ist es nicht interessant, wenn alle Turtles dasselbe tun, daher können wir Gruppen von Turtles mit ask ansprechen, z. B. diejenigen, die sich in der Nähe eines bestimmten Punktes befinden. Wir können auch Turtles verschiedener Rassen mit dem Befehl breed [cats cat] erstellen. Hier ist cat der Name einer Rasse, und wir müssen sowohl das Singular- als auch das Pluralwort angeben, da verschiedene Befehle unterschiedliche Formen für Klarheit verwenden.
> ✅ Wir werden nicht in die NetLogo-Sprache selbst eintauchen – Sie können die großartige Ressource Beginner's Interactive NetLogo Dictionary besuchen, wenn Sie mehr darüber lernen möchten.
Sie können NetLogo herunterladen und installieren, um es auszuprobieren.
Modellbibliothek
Ein großartiges Merkmal von NetLogo ist, dass es eine Bibliothek mit funktionierenden Modellen enthält, die Sie ausprobieren können. Gehen Sie zu Datei → Modellbibliothek, und Sie haben viele Kategorien von Modellen zur Auswahl.
<img alt="NetLogo Modellbibliothek" src="../../../../../translated_images/de/NetLogo-ModelLib.efe023afb4763c05.webp" width="60%"/>
> Ein Screenshot der Modellbibliothek von Dmitry Soshnikov
Sie können eines der Modelle öffnen, beispielsweise Biologie → Flocking.
Hauptprinzipien
Nach dem Öffnen des Modells gelangen Sie zum Hauptbildschirm von NetLogo. Hier ist ein Beispielmodell, das die Population von Wölfen und Schafen beschreibt, basierend auf begrenzten Ressourcen (Gras).

> Screenshot von Dmitry Soshnikov
Auf diesem Bildschirm sehen Sie:
- Den Interface-Bereich, der Folgendes enthält:
- Das Hauptfeld, in dem alle Agenten leben
- Verschiedene Steuerungen: Schaltflächen, Schieberegler usw.
- Diagramme, die Sie verwenden können, um Parameter der Simulation anzuzeigen
- Den Code-Tab, der den Editor enthält, in dem Sie NetLogo-Programme schreiben können
In den meisten Fällen enthält die Benutzeroberfläche eine Setup-Schaltfläche, die den Simulationszustand initialisiert, und eine Go-Schaltfläche, die die Ausführung startet. Diese werden von entsprechenden Handlern im Code gesteuert, die wie folgt aussehen:
to go [
...
]
Die Welt von NetLogo besteht aus den folgenden Objekten:
- Agenten (Turtles), die sich über das Feld bewegen und etwas tun können. Sie steuern Agenten mit der Syntax
ask turtles [...], und der Code in den Klammern wird von allen Agenten im Turtle-Modus ausgeführt. - Patches sind quadratische Bereiche des Feldes, auf denen Agenten leben. Sie können sich auf alle Agenten auf demselben Patch beziehen oder die Farben und einige andere Eigenschaften des Patches ändern. Sie können auch
ask patchesverwenden, um etwas zu tun. - Observer ist ein einzigartiger Agent, der die Welt kontrolliert. Alle Button-Handler werden im Observer-Modus ausgeführt.
> ✅ Die Schönheit einer Multi-Agenten-Umgebung liegt darin, dass der Code, der im Turtle-Modus oder im Patch-Modus ausgeführt wird, gleichzeitig von allen Agenten parallel ausgeführt wird. Indem Sie also wenig Code schreiben und das Verhalten eines einzelnen Agenten programmieren, können Sie ein komplexes Verhalten des gesamten Simulationssystems erzeugen.
Flocking
Als Beispiel für Multi-Agenten-Verhalten betrachten wir Flocking. Flocking ist ein komplexes Muster, das dem Flug von Vogelschwärmen sehr ähnlich ist. Wenn man sie fliegen sieht, könnte man denken, dass sie einem kollektiven Algorithmus folgen oder eine Form von kollektiver Intelligenz besitzen. Dieses komplexe Verhalten entsteht jedoch, wenn jeder einzelne Agent (in diesem Fall ein Vogel) nur einige andere Agenten in kurzer Entfernung beobachtet und drei einfache Regeln befolgt:
- Ausrichtung – es steuert in Richtung der durchschnittlichen Flugrichtung benachbarter Agenten.
- Kohäsion – es versucht, sich in Richtung der durchschnittlichen Position der Nachbarn zu bewegen (langfristige Anziehung).
- Trennung – wenn es anderen Vögeln zu nahe kommt, versucht es, sich zu entfernen (kurzfristige Abstoßung).
Sie können das Flocking-Beispiel ausführen und das Verhalten beobachten. Sie können auch Parameter wie den Grad der Trennung oder die Sichtweite anpassen, die definiert, wie weit jeder Vogel sehen kann. Beachten Sie, dass, wenn Sie die Sichtweite auf 0 reduzieren, alle Vögel blind werden und das Flocking aufhört. Wenn Sie die Trennung auf 0 reduzieren, sammeln sich alle Vögel in einer geraden Linie.
> ✅ Wechseln Sie zum Code-Tab und sehen Sie, wo die drei Regeln des Flockings (Ausrichtung, Kohäsion und Trennung) im Code implementiert sind. Beachten Sie, wie wir uns nur auf die Agenten beziehen, die in Sichtweite sind.
Weitere Modelle zum Ausprobieren
Es gibt einige weitere interessante Modelle, die Sie ausprobieren können:
- Kunst → Feuerwerk zeigt, wie ein Feuerwerk als kollektives Verhalten einzelner Feuerströme betrachtet werden kann.
- Sozialwissenschaften → Verkehr Basic und Sozialwissenschaften → Verkehr Grid zeigen das Modell des Stadtverkehrs in 1D und 2D-Gitter mit oder ohne Ampeln. Jedes Auto in der Simulation folgt den folgenden Regeln:
- Wenn der Raum vor ihm leer ist – beschleunigen (bis zu einer bestimmten Maximalgeschwindigkeit).
- Wenn es ein Hindernis vor sich sieht – bremsen (und Sie können anpassen, wie weit ein Fahrer sehen kann).
- Sozialwissenschaften → Party zeigt, wie sich Menschen während einer Cocktailparty gruppieren. Sie können die Kombination von Parametern finden, die zu einer schnelleren Steigerung des Glücks der Gruppe führt.
Wie Sie aus diesen Beispielen sehen können, können Multi-Agenten-Simulationen eine nützliche Möglichkeit sein, das Verhalten eines komplexen Systems zu verstehen, das aus Individuen besteht, die derselben oder ähnlichen Logik folgen. Sie können auch verwendet werden, um virtuelle Agenten wie NPCs in Computerspielen oder Agenten in 3D-animierten Welten zu steuern.
Deliberative Agenten
Die oben beschriebenen Agenten sind sehr einfach und reagieren auf Änderungen in der Umgebung mithilfe einer Art Algorithmus. Als solche sind sie reaktive Agenten. Manchmal können Agenten jedoch denken und ihre Aktionen planen, in diesem Fall werden sie als deliberative bezeichnet.
Ein typisches Beispiel wäre ein persönlicher Agent, der von einem Menschen die Anweisung erhält, eine Urlaubsreise zu buchen. Angenommen, es gibt viele Agenten im Internet, die ihm dabei helfen können. Er sollte dann andere Agenten kontaktieren, um zu sehen, welche Flüge verfügbar sind, welche Hotelpreise für verschiedene Daten gelten, und versuchen, den besten Preis auszuhandeln. Wenn der Urlaubsplan abgeschlossen und vom Besitzer bestätigt ist, kann er mit der Buchung fortfahren.
Um dies zu tun, müssen Agenten kommunizieren. Für eine erfolgreiche Kommunikation benötigen sie:
- Einige Standardsprachen zum Austausch von Wissen, wie Knowledge Interchange Format (KIF) und Knowledge Query and Manipulation Language (KQML). Diese Sprachen basieren auf der Sprechakttheorie.
- Diese Sprachen sollten auch einige Protokolle für Verhandlungen enthalten, basierend auf verschiedenen Auktionstypen.
- Eine gemeinsame Ontologie, damit sie sich auf dieselben Konzepte beziehen und deren Semantik kennen.
- Eine Möglichkeit, herauszufinden, was verschiedene Agenten tun können, ebenfalls basierend auf einer Art Ontologie.
Deliberative Agenten sind viel komplexer als reaktive, da sie nicht nur auf Änderungen in der Umgebung reagieren, sondern auch Aktionen initiieren können. Eine der vorgeschlagenen Architekturen für deliberative Agenten ist der sogenannte Belief-Desire-Intention (BDI)-Agent:
- Beliefs bilden eine Wissensbasis über die Umgebung des Agenten. Sie können als Wissensdatenbank oder Regelwerk strukturiert sein, das ein Agent auf eine bestimmte Situation in der Umgebung anwenden kann.
- Desires definieren, was ein Agent tun möchte, d. h. seine Ziele. Zum Beispiel ist das Ziel des persönlichen Assistenten-Agenten oben, eine Reise zu buchen, und das Ziel eines Hotel-Agenten ist es, den Gewinn zu maximieren.
- Intentions sind spezifische Aktionen, die ein Agent plant, um seine Ziele zu erreichen. Aktionen ändern typischerweise die Umgebung und führen zu Kommunikation mit anderen Agenten.
Es gibt einige Plattformen, die für den Aufbau von Multi-Agenten-Systemen verfügbar sind, wie JADE. Dieses Papier enthält eine Übersicht über Multi-Agenten-Plattformen sowie eine kurze Geschichte der Multi-Agenten-Systeme und ihrer verschiedenen Anwendungsszenarien.
Fazit
Multi-Agenten-Systeme können sehr unterschiedliche Formen annehmen und in vielen verschiedenen Anwendungen eingesetzt werden. Sie konzentrieren sich alle auf das einfachere Verhalten eines einzelnen Agenten und erreichen ein komplexeres Verhalten des Gesamtsystems durch den synergetischen Effekt.
🚀 Herausforderung
Übertragen Sie diese Lektion in die reale Welt und versuchen Sie, ein Multi-Agenten-System zu konzipieren, das ein Problem lösen kann. Was müsste ein Multi-Agenten-System beispielsweise tun, um eine Schulbusroute zu optimieren? Wie könnte es in einer Bäckerei funktionieren?
Quiz nach der Vorlesung
Überprüfung & Selbststudium
Überprüfen Sie die Verwendung dieses Systemtyps in der Industrie. Wählen Sie einen Bereich wie die Fertigung oder die Videospielindustrie und entdecken Sie, wie Multi-Agenten-Systeme verwendet werden können, um einzigartige Probleme zu lösen.
NetLogo Aufgabe
Ethische und verantwortungsvolle KI
Sie haben diesen Kurs fast abgeschlossen, und ich hoffe, dass Sie mittlerweile klar erkennen, dass KI auf einer Reihe formaler mathematischer Methoden basiert, die es uns ermöglichen, Beziehungen in Daten zu finden und Modelle zu trainieren, um bestimmte Aspekte menschlichen Verhaltens nachzubilden. Zu diesem Zeitpunkt in der Geschichte betrachten wir KI als ein sehr mächtiges Werkzeug, um Muster aus Daten zu extrahieren und diese Muster anzuwenden, um neue Probleme zu lösen.
Quiz vor der Vorlesung
In der Science-Fiction sehen wir jedoch oft Geschichten, in denen KI eine Gefahr für die Menschheit darstellt. Diese Geschichten drehen sich meist um eine Art KI-Rebellion, bei der die KI beschließt, sich gegen die Menschen zu stellen. Dies impliziert, dass KI eine Art Emotion besitzt oder Entscheidungen treffen kann, die von ihren Entwicklern nicht vorhergesehen wurden.
Die Art von KI, die wir in diesem Kurs kennengelernt haben, ist nichts anderes als umfangreiche Matrizenarithmetik. Es ist ein sehr mächtiges Werkzeug, das uns hilft, unsere Probleme zu lösen, und wie jedes andere mächtige Werkzeug kann es sowohl für gute als auch für schlechte Zwecke eingesetzt werden. Wichtig ist, dass es missbraucht werden kann.
Prinzipien der verantwortungsvollen KI
Um einen zufälligen oder absichtlichen Missbrauch von KI zu vermeiden, hat Microsoft die wichtigen Prinzipien der verantwortungsvollen KI definiert. Die folgenden Konzepte bilden die Grundlage dieser Prinzipien:
- Fairness bezieht sich auf das wichtige Problem der Modellverzerrungen, die durch die Verwendung von voreingenommenen Trainingsdaten verursacht werden können. Zum Beispiel, wenn wir versuchen, die Wahrscheinlichkeit vorherzusagen, dass eine Person einen Job als Softwareentwickler bekommt, wird das Modell wahrscheinlich Männern den Vorzug geben – einfach weil der Trainingsdatensatz wahrscheinlich auf eine männliche Zielgruppe ausgerichtet war. Wir müssen die Trainingsdaten sorgfältig ausbalancieren und das Modell untersuchen, um Verzerrungen zu vermeiden und sicherzustellen, dass das Modell relevantere Merkmale berücksichtigt.
- Zuverlässigkeit und Sicherheit. KI-Modelle können von Natur aus Fehler machen. Ein neuronales Netzwerk liefert Wahrscheinlichkeiten, und das müssen wir bei Entscheidungen berücksichtigen. Jedes Modell hat eine bestimmte Präzision und einen bestimmten Rückrufwert, und wir müssen das verstehen, um Schäden zu vermeiden, die durch falsche Ratschläge entstehen können.
- Privatsphäre und Sicherheit haben einige KI-spezifische Implikationen. Zum Beispiel wird die verwendete Trainingsdaten irgendwie in das Modell "integriert". Einerseits erhöht das die Sicherheit und Privatsphäre, andererseits müssen wir uns daran erinnern, welche Daten für das Training des Modells verwendet wurden.
- Inklusivität bedeutet, dass wir KI nicht entwickeln, um Menschen zu ersetzen, sondern um sie zu unterstützen und unsere Arbeit kreativer zu gestalten. Es steht auch in Zusammenhang mit Fairness, denn wenn wir mit unterrepräsentierten Gemeinschaften arbeiten, sind die meisten der gesammelten Datensätze wahrscheinlich voreingenommen. Wir müssen sicherstellen, dass diese Gemeinschaften einbezogen und korrekt von der KI behandelt werden.
- Transparenz. Dazu gehört, dass wir immer klarstellen, wenn KI verwendet wird. Außerdem möchten wir, wo immer möglich, KI-Systeme verwenden, die interpretierbar sind.
- Verantwortlichkeit. Wenn KI-Modelle Entscheidungen treffen, ist nicht immer klar, wer für diese Entscheidungen verantwortlich ist. Wir müssen sicherstellen, dass wir verstehen, wo die Verantwortung für KI-Entscheidungen liegt. In den meisten Fällen möchten wir Menschen in den Entscheidungsprozess einbeziehen, damit tatsächliche Personen zur Verantwortung gezogen werden können.
Werkzeuge für verantwortungsvolle KI
Microsoft hat das Responsible AI Toolbox entwickelt, das eine Reihe von Werkzeugen enthält:
- Interpretability Dashboard (InterpretML)
- Fairness Dashboard (FairLearn)
- Error Analysis Dashboard
-
Responsible AI Dashboard, das Folgendes umfasst:
-
EconML – ein Tool für Kausalanalysen, das sich auf Was-wäre-wenn-Fragen konzentriert
- DiCE – ein Tool für kontrafaktische Analysen, mit dem Sie sehen können, welche Merkmale geändert werden müssen, um die Entscheidung des Modells zu beeinflussen
Weitere Informationen zur KI-Ethik finden Sie in dieser Lektion im Machine Learning Curriculum, das auch Aufgaben enthält.
Überprüfung & Selbststudium
Nehmen Sie an diesem Lernpfad teil, um mehr über verantwortungsvolle KI zu erfahren.
Quiz nach der Vorlesung
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Überblick

> Sketchnote von Tomomi Imura
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Attribution-Weitergabe unter gleichen Bedingungen 4.0 International
=======================================================================
Die Creative Commons Corporation ("Creative Commons") ist keine Anwaltskanzlei und bietet keine juristischen Dienstleistungen oder Rechtsberatung an. Die Verbreitung von Creative-Commons-Lizenzen begründet keine Anwalts-Mandanten-Beziehung oder eine andere Beziehung. Creative Commons stellt seine Lizenzen und die dazugehörigen Informationen auf einer "wie besehen"-Basis zur Verfügung. Creative Commons übernimmt keine Garantien in Bezug auf seine Lizenzen, das unter deren Bedingungen lizenzierte Material oder die dazugehörigen Informationen. Creative Commons lehnt jegliche Haftung für Schäden, die aus ihrer Nutzung resultieren, im größtmöglichen gesetzlich zulässigen Umfang ab.
Verwendung von Creative-Commons-Lizenzen
Creative-Commons-Lizenzen bieten eine standardisierte Reihe von Bedingungen, die Urheber und andere Rechteinhaber nutzen können, um originale Werke und anderes urheberrechtlich geschütztes Material sowie bestimmte andere Rechte zu teilen, wie in der untenstehenden Lizenz beschrieben. Die folgenden Überlegungen dienen nur zu Informationszwecken, sind nicht abschließend und sind kein Bestandteil unserer Lizenzen.
Überlegungen für Lizenzgeber: Unsere Lizenzen sind für diejenigen gedacht, die berechtigt sind, der Öffentlichkeit die Nutzung von Material zu gestatten, das ansonsten durch Urheberrecht und bestimmte andere Rechte eingeschränkt ist. Unsere Lizenzen sind unwiderruflich. Lizenzgeber sollten die Bedingungen der gewählten Lizenz lesen und verstehen, bevor sie diese anwenden. Lizenzgeber sollten auch sicherstellen, dass sie alle notwendigen Rechte besitzen, bevor sie unsere Lizenzen anwenden, damit die Öffentlichkeit das Material wie erwartet wiederverwenden kann. Lizenzgeber sollten klar kennzeichnen, welches Material nicht unter die Lizenz fällt. Dies schließt anderes CC-lizenziertes Material oder Material ein, das unter eine Ausnahme oder Einschränkung des Urheberrechts fällt. Weitere Überlegungen für Lizenzgeber:
wiki.creativecommons.org/Considerations_for_licensors
Überlegungen für die Öffentlichkeit: Durch die Nutzung einer unserer Lizenzen gewährt ein Lizenzgeber der Öffentlichkeit die Erlaubnis, das lizenzierte Material unter den angegebenen Bedingungen zu nutzen. Wenn die Erlaubnis des Lizenzgebers aus irgendeinem Grund nicht erforderlich ist – zum Beispiel aufgrund einer anwendbaren Ausnahme oder Einschränkung des Urheberrechts – wird diese Nutzung nicht durch die Lizenz geregelt. Unsere Lizenzen gewähren nur Rechte im Rahmen des Urheberrechts und bestimmter anderer Rechte, die ein Lizenzgeber zu gewähren berechtigt ist. Die Nutzung des lizenzierten Materials kann aus anderen Gründen weiterhin eingeschränkt sein, einschließlich der Tatsache, dass andere Personen Urheberrechte oder andere Rechte an dem Material besitzen. Ein Lizenzgeber kann besondere Wünsche äußern, wie z. B. die Bitte, dass alle Änderungen gekennzeichnet oder beschrieben werden. Obwohl dies nicht durch unsere Lizenzen vorgeschrieben ist, wird empfohlen, solche Wünsche, soweit vernünftig, zu respektieren. Weitere Überlegungen für die Öffentlichkeit:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution-Weitergabe unter gleichen Bedingungen 4.0 Internationale Lizenz
Durch die Ausübung der lizenzierten Rechte (wie unten definiert) akzeptieren Sie die Bedingungen dieser Creative Commons Attribution-Weitergabe unter gleichen Bedingungen 4.0 Internationalen Lizenz ("Öffentliche Lizenz"). Soweit diese Öffentliche Lizenz als Vertrag ausgelegt werden kann, werden Ihnen die lizenzierten Rechte im Gegenzug für Ihre Annahme dieser Bedingungen gewährt, und der Lizenzgeber gewährt Ihnen diese Rechte im Gegenzug für die Vorteile, die der Lizenzgeber durch die Bereitstellung des lizenzierten Materials unter diesen Bedingungen erhält.
Abschnitt 1 – Definitionen.
a. Bearbeitetes Material bezeichnet Material, das dem Urheberrecht und ähnlichen Rechten unterliegt und das aus dem lizenzierten Material abgeleitet oder darauf basierend erstellt wurde, wobei das lizenzierte Material übersetzt, verändert, arrangiert, umgestaltet oder anderweitig in einer Weise modifiziert wurde, die eine Genehmigung gemäß dem Urheberrecht und ähnlichen Rechten des Lizenzgebers erfordert. Für die Zwecke dieser Öffentlichen Lizenz wird bearbeitetes Material immer dann erstellt, wenn das lizenzierte Material in zeitlicher Abstimmung mit einem bewegten Bild synchronisiert wird, sofern es sich um ein musikalisches Werk, eine Aufführung oder eine Tonaufnahme handelt.
b. Lizenz des Bearbeiters bezeichnet die Lizenz, die Sie auf Ihre Urheberrechte und ähnlichen Rechte an Ihren Beiträgen zu bearbeitetem Material gemäß den Bedingungen dieser Öffentlichen Lizenz anwenden.
c. BY-SA-kompatible Lizenz bezeichnet eine Lizenz, die unter creativecommons.org/compatiblelicenses aufgeführt ist und von Creative Commons als im Wesentlichen gleichwertig mit dieser Öffentlichen Lizenz anerkannt wurde.
d. Urheberrecht und ähnliche Rechte bezeichnet das Urheberrecht und/oder ähnliche Rechte, die eng mit dem Urheberrecht verbunden sind, einschließlich, aber nicht beschränkt auf Aufführungs-, Rundfunk-, Tonaufnahme- und Sui-Generis-Datenbankrechte, unabhängig davon, wie diese Rechte bezeichnet oder kategorisiert werden. Für die Zwecke dieser Öffentlichen Lizenz sind die in Abschnitt 2(b)(1)-(2) genannten Rechte keine Urheberrechte und ähnlichen Rechte.
e. Wirksame technische Maßnahmen bezeichnet Maßnahmen, die ohne ordnungsgemäße Autorisierung nicht umgangen werden dürfen, gemäß Gesetzen, die Verpflichtungen aus Artikel 11 des WIPO-Urheberrechtsvertrags vom 20. Dezember 1996 und/oder ähnlichen internationalen Abkommen erfüllen.
f. Ausnahmen und Einschränkungen bezeichnet Fair Use, Fair Dealing und/oder andere Ausnahmen oder Einschränkungen des Urheberrechts und ähnlicher Rechte, die für Ihre Nutzung des lizenzierten Materials gelten.
g. Lizenzbestandteile bezeichnet die Lizenzattribute, die im Namen einer Creative-Commons-Lizenz aufgeführt sind. Die Lizenzbestandteile dieser Öffentlichen Lizenz sind Namensnennung und Weitergabe unter gleichen Bedingungen.
h. Lizenziertes Material bezeichnet das künstlerische oder literarische Werk, die Datenbank oder anderes Material, auf das der Lizenzgeber diese Öffentliche Lizenz angewendet hat.
i. Lizenzierte Rechte bezeichnet die Ihnen unter den Bedingungen dieser Öffentlichen Lizenz gewährten Rechte, die auf alle Urheberrechte und ähnlichen Rechte beschränkt sind, die für Ihre Nutzung des lizenzierten Materials gelten und die der Lizenzgeber zu lizenzieren berechtigt ist.
j. Lizenzgeber bezeichnet die Person(en) oder Organisation(en), die Rechte unter dieser Öffentlichen Lizenz gewähren.
k. Teilen bezeichnet die Bereitstellung von Material für die Öffentlichkeit durch jegliche Mittel oder Verfahren, die eine Genehmigung gemäß den lizenzierten Rechten erfordern, wie Vervielfältigung, öffentliche Darstellung, öffentliche Aufführung, Verbreitung, Weitergabe, Kommunikation oder Import sowie die Bereitstellung von Material für die Öffentlichkeit, einschließlich auf eine Weise, die es Mitgliedern der Öffentlichkeit ermöglicht, das Material von einem Ort und zu einer Zeit ihrer Wahl zu nutzen.
l. Sui-Generis-Datenbankrechte bezeichnet andere als urheberrechtliche Rechte, die sich aus der Richtlinie 96/9/EG des Europäischen Parlaments und des Rates vom 11. März 1996 über den rechtlichen Schutz von Datenbanken ergeben, in der jeweils gültigen Fassung oder Nachfolgeversion, sowie andere im Wesentlichen gleichwertige Rechte weltweit.
m. Sie bezeichnet die Person oder Organisation, die die lizenzierten Rechte unter dieser Öffentlichen Lizenz ausübt. Ihr hat eine entsprechende Bedeutung.
Abschnitt 2 – Umfang.
a. Lizenzgewährung.
1. Vorbehaltlich der Bedingungen dieser Öffentlichen Lizenz gewährt der Lizenzgeber Ihnen hiermit eine weltweite, gebührenfreie, nicht unterlizenzierbare, nicht exklusive, unwiderrufliche Lizenz zur Ausübung der lizenzierten Rechte am lizenzierten Material, um:
a. das lizenzierte Material ganz oder teilweise zu vervielfältigen und zu teilen; und
b. bearbeitetes Material zu erstellen, zu vervielfältigen und zu teilen.
2. Ausnahmen und Einschränkungen. Zur Klarstellung: Wenn Ausnahmen und Einschränkungen für Ihre Nutzung gelten, findet diese Öffentliche Lizenz keine Anwendung, und Sie müssen ihre Bedingungen nicht einhalten.
3. Laufzeit. Die Laufzeit dieser Öffentlichen Lizenz ist in Abschnitt 6(a) festgelegt.
4. Medien und Formate; technische Änderungen erlaubt. Der Lizenzgeber autorisiert Sie, die lizenzierten Rechte in allen Medien und Formaten auszuüben, die jetzt bekannt sind oder später entwickelt werden, und technische Änderungen vorzunehmen, die dafür erforderlich sind. Der Lizenzgeber verzichtet auf und/oder erklärt sich damit einverstanden, keine Rechte oder Befugnisse geltend zu machen, die Sie daran hindern, technische Änderungen vorzunehmen, die für die Ausübung der lizenzierten Rechte erforderlich sind, einschließlich technischer Änderungen, die notwendig sind, um wirksame technische Maßnahmen zu umgehen. Für die Zwecke dieser Öffentlichen Lizenz führt das bloße Vornehmen von Änderungen, die gemäß diesem Abschnitt 2(a)(4) autorisiert sind, niemals zur Erstellung von bearbeitetem Material.
5. Nachgelagerte Empfänger.
a. Angebot des Lizenzgebers – Lizenziertes Material. Jeder Empfänger des lizenzierten Materials erhält automatisch ein Angebot des Lizenzgebers, die lizenzierten Rechte unter den Bedingungen dieser Öffentlichen Lizenz auszuüben.
b. Zusätzliches Angebot des Lizenzgebers – Bearbeitetes Material. Jeder Empfänger von bearbeitetem Material von Ihnen erhält automatisch ein Angebot des Lizenzgebers, die lizenzierten Rechte am bearbeiteten Material unter den Bedingungen der von Ihnen angewendeten Lizenz des Bearbeiters auszuüben.
c. Keine nachgelagerten Einschränkungen. Sie dürfen keine zusätzlichen oder abweichenden Bedingungen auferlegen oder wirksame technische Maßnahmen auf das lizenzierte Material anwenden, wenn dies die Ausübung der lizenzierten Rechte durch einen Empfänger des lizenzierten Materials einschränkt.
6. Keine Billigung. Nichts in dieser Öffentlichen Lizenz stellt eine Erlaubnis dar oder kann so ausgelegt werden, dass Sie oder Ihre Nutzung des lizenzierten Materials mit dem Lizenzgeber oder anderen, die gemäß Abschnitt 3(a)(1)(A)(i) genannt werden, verbunden, gesponsert, unterstützt oder offiziell anerkannt sind.
b. Andere Rechte.
1. Persönlichkeitsrechte, wie das Recht auf Integrität, sind nicht durch diese Öffentliche Lizenz lizenziert, ebenso wenig wie Rechte auf Öffentlichkeit, Privatsphäre und/oder andere ähnliche Persönlichkeitsrechte; jedoch verzichtet der Lizenzgeber, soweit möglich, auf und/oder erklärt sich damit einverstanden, keine solchen Rechte geltend zu machen, die der Lizenzgeber besitzt, soweit dies erforderlich ist, um Ihnen die Ausübung der lizenzierten Rechte zu ermöglichen, jedoch nicht darüber hinaus.
2. Patent- und Markenrechte sind nicht durch diese Öffentliche Lizenz lizenziert.
3. Soweit möglich, verzichtet der Lizenzgeber auf jegliches Recht, von Ihnen Lizenzgebühren für die Ausübung der lizenzierten Rechte zu erheben, sei es direkt oder über eine Verwertungsgesellschaft im Rahmen eines freiwilligen oder verzichtbaren gesetzlichen oder zwingenden Lizenzierungssystems. In allen anderen Fällen behält sich der Lizenzgeber ausdrücklich das Recht vor, solche Lizenzgebühren zu erheben.
Rechte, dann die Datenbank, in der Sie Sui Generis-Datenbankrechte haben (aber nicht deren einzelne Inhalte), ist angepasstes Material,
einschließlich für die Zwecke von Abschnitt 3(b); und
c. Sie müssen die Bedingungen in Abschnitt 3(a) einhalten, wenn Sie die gesamte oder einen wesentlichen Teil der Inhalte der Datenbank weitergeben.
Zur Klarstellung: Dieser Abschnitt 4 ergänzt und ersetzt nicht Ihre Verpflichtungen aus dieser öffentlichen Lizenz, wenn die lizenzierten Rechte andere Urheberrechte und ähnliche Rechte umfassen.
Abschnitt 5 – Haftungsausschluss und Haftungsbeschränkung.
a. SOFERN NICHT ANDERS VOM LIZENZGEBER SEPARAT VEREINBART, STELLT DER LIZENZGEBER DAS LIZENZIERTE MATERIAL SOWEIT MÖGLICH "WIE BESEHEN" UND "WIE VERFÜGBAR" ZUR VERFÜGUNG UND GIBT KEINE ZUSICHERUNGEN ODER GARANTIEN IRGENDEINER ART IN BEZUG AUF DAS LIZENZIERTE MATERIAL AB, WEDER AUSDRÜCKLICH, IMPLIZIT, GESETZLICH NOCH ANDERWEITIG. DIES UMFASST UNTER ANDEREM GARANTIEN BEZÜGLICH EIGENTUM, MARKTGÄNGIGKEIT, EIGNUNG FÜR EINEN BESTIMMTEN ZWECK, NICHTVERLETZUNG, ABWESENHEIT VON VERBORGENEN ODER ANDEREN MÄNGELN, GENAUIGKEIT ODER DAS VORHANDENSEIN ODER NICHTVORHANDENSEIN VON FEHLERN, OB BEKANNT ODER ENTDECKBAR. WO HAFTUNGSAUSSCHLÜSSE VON GARANTIEN NICHT VOLLSTÄNDIG ODER TEILWEISE ZULÄSSIG SIND, KANN DIESER HAFTUNGSAUSSCHLUSS FÜR SIE NICHT GELTEN.
b. SOWEIT MÖGLICH, HAFTET DER LIZENZGEBER UNTER KEINEN UMSTÄNDEN IHNEN GEGENÜBER AUF GRUNDLAGE IRGENDEINER RECHTSTHEORIE (EINSCHLIESSLICH, ABER NICHT BESCHRÄNKT AUF FAHRLÄSSIGKEIT) ODER ANDERWEITIG FÜR DIREKTE, BESONDERE, INDIREKTE, ZUFÄLLIGE, FOLGE-, STRAF-, EXEMPLARISCHE ODER ANDERE VERLUSTE, KOSTEN, AUSGABEN ODER SCHÄDEN, DIE AUS DIESER ÖFFENTLICHEN LIZENZ ODER DER NUTZUNG DES LIZENZIERTEN MATERIALS ENTSTEHEN, SELBST WENN DER LIZENZGEBER ÜBER DIE MÖGLICHKEIT SOLCHER VERLUSTE, KOSTEN, AUSGABEN ODER SCHÄDEN INFORMIERT WURDE. WO EINE HAFTUNGSBESCHRÄNKUNG NICHT VOLLSTÄNDIG ODER TEILWEISE ZULÄSSIG IST, KANN DIESE BESCHRÄNKUNG FÜR SIE NICHT GELTEN.
c. Der oben genannte Haftungsausschluss und die Haftungsbeschränkung sind so auszulegen, dass sie, soweit möglich, einem absoluten Haftungsausschluss und Verzicht auf jegliche Haftung am nächsten kommen.
Abschnitt 6 – Laufzeit und Beendigung.
a. Diese öffentliche Lizenz gilt für die Dauer der hier lizenzierten Urheberrechte und ähnlichen Rechte. Wenn Sie jedoch gegen diese öffentliche Lizenz verstoßen, enden Ihre Rechte aus dieser öffentlichen Lizenz automatisch.
b. Wenn Ihr Recht zur Nutzung des lizenzierten Materials gemäß Abschnitt 6(a) beendet wurde, wird es wiederhergestellt:
- automatisch ab dem Datum, an dem der Verstoß behoben wird, vorausgesetzt, dies geschieht innerhalb von 30 Tagen nach Ihrer Entdeckung des Verstoßes; oder
- durch ausdrückliche Wiederherstellung durch den Lizenzgeber.
Zur Klarstellung: Dieser Abschnitt 6(b) berührt nicht das Recht des Lizenzgebers, Rechtsmittel wegen Ihrer Verstöße gegen diese öffentliche Lizenz einzulegen.
c. Zur Klarstellung: Der Lizenzgeber kann das lizenzierte Material auch unter separaten Bedingungen oder Konditionen anbieten oder die Verbreitung des lizenzierten Materials jederzeit einstellen; dies beendet jedoch nicht diese öffentliche Lizenz.
d. Die Abschnitte 1, 5, 6, 7 und 8 bleiben auch nach Beendigung dieser öffentlichen Lizenz in Kraft.
Abschnitt 7 – Andere Bedingungen.
a. Der Lizenzgeber ist nicht an zusätzliche oder abweichende Bedingungen gebunden, die Sie mitteilen, es sei denn, sie wurden ausdrücklich vereinbart.
b. Alle Vereinbarungen, Absprachen oder Abmachungen in Bezug auf das lizenzierte Material, die hier nicht aufgeführt sind, sind unabhängig von und getrennt von den Bedingungen dieser öffentlichen Lizenz.
Abschnitt 8 – Auslegung.
a. Zur Klarstellung: Diese öffentliche Lizenz schränkt nicht ein, begrenzt nicht, beschränkt nicht und auferlegt keine Bedingungen für die Nutzung des lizenzierten Materials, die ohne Erlaubnis gemäß dieser öffentlichen Lizenz rechtmäßig erfolgen könnte.
b. Soweit möglich, wird jede Bestimmung dieser öffentlichen Lizenz, die als nicht durchsetzbar erachtet wird, automatisch auf das Mindestmaß reformiert, das erforderlich ist, um sie durchsetzbar zu machen. Wenn die Bestimmung nicht reformiert werden kann, wird sie von dieser öffentlichen Lizenz getrennt, ohne die Durchsetzbarkeit der verbleibenden Bedingungen zu beeinträchtigen.
c. Kein Begriff oder keine Bedingung dieser öffentlichen Lizenz wird aufgehoben, und kein Versäumnis, die Einhaltung zu verlangen, wird zugestimmt, es sei denn, dies wurde ausdrücklich vom Lizenzgeber vereinbart.
d. Nichts in dieser öffentlichen Lizenz stellt eine Einschränkung oder einen Verzicht auf Privilegien und Immunitäten dar, die für den Lizenzgeber oder Sie gelten, einschließlich solcher, die sich aus den rechtlichen Verfahren einer Gerichtsbarkeit oder Behörde ergeben.
=======================================================================
Creative Commons ist keine Partei ihrer öffentlichen Lizenzen. Ungeachtet dessen kann Creative Commons wählen, eine seiner öffentlichen Lizenzen auf von ihr veröffentlichte Materialien anzuwenden, und wird in diesen Fällen als „Lizenzgeber“ betrachtet. Der Text der Creative Commons-Lizenzen ist dem Gemeingut unter der CC0 Public Domain Dedication gewidmet. Mit Ausnahme des begrenzten Zwecks, anzuzeigen, dass Material unter einer Creative Commons-Lizenz geteilt wird, oder wie anderweitig in den Creative Commons-Richtlinien unter creativecommons.org/policies gestattet, autorisiert Creative Commons nicht die Verwendung der Marke „Creative Commons“ oder einer anderen Marke oder eines Logos von Creative Commons ohne vorherige schriftliche Zustimmung, einschließlich, aber nicht beschränkt auf, in Verbindung mit nicht autorisierten Änderungen an einer ihrer öffentlichen Lizenzen oder anderen Vereinbarungen, Absprachen oder Abmachungen in Bezug auf die Nutzung des lizenzierten Materials. Zur Klarstellung: Dieser Absatz ist nicht Teil der öffentlichen Lizenzen.
Creative Commons kann unter creativecommons.org kontaktiert werden.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Alle Sketchnotes des Lehrplans können hier heruntergeladen werden.
🎨 Erstellt von: Tomomi Imura (Twitter: @girlie_mac, GitHub: girliemac)
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Multimodale Modelle
Dieses Notebook stammt aus dem AI for Beginners Curriculum.
Experimentieren mit CLIP
CLIP von OpenAI wurde öffentlich zugänglich gemacht, sodass du es für verschiedene Aufgaben ausprobieren kannst, einschließlich Zero-Shot-Bildklassifikation. Beachte, dass es ziemlich ressourcenhungrig ist!
import sys
!{sys.executable} -m pip install git+https://github.com/openai/CLIP.git
Wir werden zuerst sicherstellen, dass wir die GPU verwenden können, falls sie verfügbar ist, und dann das CLIP-Modell laden.
import torch
import clip
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import os
np.set_printoptions(precision=2,suppress=True)
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device)
Lassen Sie uns auch eine Teilmenge von Katzenbildern aus dem Oxford-IIIT Dataset erhalten:
!wget https://mslearntensorflowlp.blob.core.windows.net/data/oxcats.tar.gz
!tar xfz oxcats.tar.gz
!rm oxcats.tar.gz
Zero-Shot-Bildklassifikation
Die Hauptfunktion von CLIP besteht darin, ein Bild mit einer Textaufforderung abzugleichen. Wenn wir also ein Bild nehmen, zum Beispiel von einer Katze, und versuchen, es mit den Textaufforderungen "eine Katze", "ein Pinguin", "ein Bär" abzugleichen, wird die erste Option wahrscheinlich die höchste Wahrscheinlichkeit haben. Daher können wir schließen, dass es sich um eine Katze handelt. Wir müssen kein Modell trainieren, da es bereits auf einem riesigen Datensatz vortrainiert wurde – daher wird es als Zero-Shot bezeichnet.
image = preprocess(Image.open("oxcats/Maine_Coon_1.jpg")).unsqueeze(0).to(device)
text = clip.tokenize(["a penguin", "a bear", "a cat"]).to(device)
with torch.no_grad():
image_features = model.encode_image(image)
text_features = model.encode_text(text)
logits_per_image, logits_per_text = model(image, text)
probs = logits_per_image.softmax(dim=-1).cpu().numpy()
print("Label probs:", probs)
Intelligente Bildersuche
Im vorherigen Beispiel gab es ein Bild und drei Textaufforderungen. Wir können CLIP in einem anderen Kontext verwenden, z. B. indem wir viele Bilder einer Katze nehmen und dann das Bild auswählen, das am besten zur textuellen Beschreibung passt:
cats_img = [ Image.open(os.path.join("oxcats",x)) for x in os.listdir("oxcats") ]
cats = torch.cat([ preprocess(i).unsqueeze(0) for i in cats_img ]).to(device)
text = clip.tokenize(["a very fat gray cat"]).to(device)
with torch.no_grad():
logits_per_image, logits_per_text = model(cats, text)
res = logits_per_text.softmax(dim=-1).argmax().cpu().numpy()
print("Img Index:", res)
plt.imshow(cats_img[res])
Erkenntnis
Das vortrainierte CLIP-Modell kann verwendet werden, um Aufgaben wie die Bildklassifikation von alltäglichen Objekten ohne domänenspezifisches Training durchzuführen. Außerdem ermöglicht es eine flexiblere Klassifikation/Bildsuche, bei der die räumliche Anordnung der Objekte auf dem Bild berücksichtigt wird.
Für eine weitere spannende Anwendung von CLIP, schauen Sie sich VQGAN+CLIP an.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Multi-Modale Netzwerke
Nach dem Erfolg von Transformer-Modellen bei der Lösung von NLP-Aufgaben wurden ähnliche Architekturen auch auf Aufgaben der Computer Vision angewendet. Es gibt ein wachsendes Interesse daran, Modelle zu entwickeln, die Vision- und Sprachfähigkeiten kombinieren. Ein solcher Versuch wurde von OpenAI unternommen und nennt sich CLIP und DALL.E.
Contrastive Image Pre-Training (CLIP)
Die Hauptidee von CLIP ist, Textaufforderungen mit einem Bild vergleichen zu können und zu bestimmen, wie gut das Bild zur Aufforderung passt.

> Bild aus diesem Blogbeitrag
Das Modell wird mit Bildern aus dem Internet und deren Beschreibungen trainiert. Für jede Batch nehmen wir N Paare aus (Bild, Text) und konvertieren sie in Vektorrepräsentationen I, ..., I / T, ..., T. Diese Repräsentationen werden dann miteinander abgeglichen. Die Verlustfunktion ist so definiert, dass die Kosinusähnlichkeit zwischen den Vektoren eines Paares (z. B. I und T) maximiert und die Kosinusähnlichkeit zwischen allen anderen Paaren minimiert wird. Aus diesem Grund wird dieser Ansatz als kontrastiv bezeichnet.
Die CLIP-Bibliothek/Modell ist verfügbar auf OpenAI GitHub. Der Ansatz wird in diesem Blogbeitrag beschrieben und ausführlicher in diesem Paper.
Sobald dieses Modell vortrainiert ist, können wir ihm eine Batch von Bildern und eine Batch von Textaufforderungen geben, und es wird einen Tensor mit Wahrscheinlichkeiten zurückgeben. CLIP kann für verschiedene Aufgaben verwendet werden:
Bildklassifikation
Angenommen, wir müssen Bilder zwischen Katzen, Hunden und Menschen klassifizieren. In diesem Fall können wir dem Modell ein Bild und eine Reihe von Textaufforderungen geben: "ein Bild einer Katze", "ein Bild eines Hundes", "ein Bild eines Menschen". Im resultierenden Vektor mit 3 Wahrscheinlichkeiten müssen wir nur den Index mit dem höchsten Wert auswählen.

> Bild aus diesem Blogbeitrag
Textbasierte Bildsuche
Wir können auch das Gegenteil tun. Wenn wir eine Sammlung von Bildern haben, können wir diese Sammlung dem Modell übergeben und eine Textaufforderung - dies wird uns das Bild geben, das am ähnlichsten zur gegebenen Aufforderung ist.
✍️ Beispiel: CLIP für Bildklassifikation und Bildsuche verwenden
Öffne das Clip.ipynb-Notebook, um CLIP in Aktion zu sehen.
Bildgenerierung mit VQGAN+CLIP
CLIP kann auch für die Bildgenerierung aus einer Textaufforderung verwendet werden. Dazu benötigen wir ein Generator-Modell, das Bilder basierend auf einer Vektoreingabe generieren kann. Eines dieser Modelle nennt sich VQGAN (Vector-Quantized GAN).
Die Hauptideen von VQGAN, die es von gewöhnlichen GAN unterscheiden, sind folgende: * Verwendung einer autoregressiven Transformer-Architektur, um eine Sequenz kontextreicher visueller Teile zu generieren, die das Bild zusammensetzen. Diese visuellen Teile werden wiederum von CNN gelernt. * Einsatz eines Sub-Bild-Diskriminators, der erkennt, ob Teile des Bildes "echt" oder "gefälscht" sind (im Gegensatz zum "Alles-oder-Nichts"-Ansatz bei traditionellen GANs).
Erfahre mehr über VQGAN auf der Taming Transformers Webseite.
Ein wichtiger Unterschied zwischen VQGAN und traditionellen GANs ist, dass letztere ein brauchbares Bild aus jedem Eingabevektor erzeugen können, während VQGAN wahrscheinlich ein Bild erzeugt, das nicht kohärent ist. Daher müssen wir den Bildgenerierungsprozess weiter steuern, und das kann mit CLIP erfolgen.

Um ein Bild zu erzeugen, das einer Textaufforderung entspricht, beginnen wir mit einem zufälligen Codierungsvektor, der durch VQGAN geleitet wird, um ein Bild zu erzeugen. Dann wird CLIP verwendet, um eine Verlustfunktion zu erzeugen, die zeigt, wie gut das Bild zur Textaufforderung passt. Ziel ist es, diesen Verlust zu minimieren, indem die Parameter des Eingabevektors mittels Backpropagation angepasst werden.
Eine großartige Bibliothek, die VQGAN+CLIP implementiert, ist Pixray.
![]() |
![]() |
![]() |
|---|---|---|
| Bild generiert aus der Aufforderung ein Nahaufnahme-Aquarellporträt eines jungen männlichen Literaturlehrers mit einem Buch | Bild generiert aus der Aufforderung ein Nahaufnahme-Ölporträt einer jungen weiblichen Informatiklehrerin mit einem Computer | Bild generiert aus der Aufforderung ein Nahaufnahme-Ölporträt eines alten männlichen Mathematiklehrers vor einer Tafel |
> Bilder aus der Artificial Teachers-Sammlung von Dmitry Soshnikov
DALL-E
DALL-E 1
DALL-E ist eine Version von GPT-3, die darauf trainiert ist, Bilder aus Aufforderungen zu generieren. Es wurde mit 12 Milliarden Parametern trainiert.
Im Gegensatz zu CLIP erhält DALL-E sowohl Text als auch Bild als einen einzigen Strom von Tokens für Bilder und Text. Daher können aus mehreren Aufforderungen Bilder basierend auf dem Text generiert werden.
DALL-E 2
Der Hauptunterschied zwischen DALL-E 1 und 2 besteht darin, dass es realistischere Bilder und Kunstwerke erzeugt.
Beispiele für Bildgenerierungen mit DALL-E:
|
|
----|----|----
Bild generiert aus der Aufforderung ein Nahaufnahme-Aquarellporträt eines jungen männlichen Literaturlehrers mit einem Buch | Bild generiert aus der Aufforderung ein Nahaufnahme-Ölporträt einer jungen weiblichen Informatiklehrerin mit einem Computer | Bild generiert aus der Aufforderung ein Nahaufnahme-Ölporträt eines alten männlichen Mathematiklehrers vor einer Tafel
Referenzen
- VQGAN Paper: Taming Transformers for High-Resolution Image Synthesis
- CLIP Paper: Learning Transferable Visual Models From Natural Language Supervision
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.
Künstliche Intelligenz für Anfänger - Ein Lehrplan
![]() |
|---|
| AI For Beginners - Sketchnote von @girlie_mac |
Erkunden Sie die Welt der Künstlichen Intelligenz (KI) mit unserem 12-wöchigen, 24-teiligen Lehrplan! Er beinhaltet praktische Lektionen, Quizze und Labore. Der Lehrplan ist anfängerfreundlich und behandelt Werkzeuge wie TensorFlow und PyTorch sowie Ethik in der KI.
🌐 Unterstützung mehrerer Sprachen
Unterstützt durch GitHub Action (Automatisiert & immer aktuell)
<!-- CO-OP TRANSLATOR LANGUAGES TABLE START --> Arabisch | Bengalisch | Bulgarisch | Birmanisch (Myanmar) | Chinesisch (Vereinfacht) | Chinesisch (Traditionell, Hong Kong) | Chinesisch (Traditionell, Macau) | Chinesisch (Traditionell, Taiwan) | Kroatisch | Tschechisch | Dänisch | Niederländisch | Estnisch | Finnisch | Französisch | Deutsch | Griechisch | Hebräisch | Hindi | Ungarisch | Indonesisch | Italienisch | Japanisch | Kannada | Khmer | Koreanisch | Litauisch | Malaiisch | Malayalam | Marathi | Nepali | Nigerianisches Pidgin | Norwegisch | Persisch (Farsi) | Polnisch | Portugiesisch (Brasilien) | Portugiesisch (Portugal) | Punjabi (Gurmukhi) | Rumänisch | Russisch | Serbisch (Kyrillisch) | Slowakisch | Slowenisch | Spanisch | Swahili | Schwedisch | Tagalog (Filipino) | Tamil | Telugu | Thailändisch | Türkisch | Ukrainisch | Urdu | Vietnamesisch
> Bevorzugen Sie das lokale Klonen?
>
> Dieses Repository enthält über 50 Sprachübersetzungen, wodurch die Downloadgröße erheblich zunimmt. Um ohne Übersetzungen zu klonen, verwenden Sie Sparse Checkout:
>
> Bash / macOS / Linux:
> bash
> git clone --filter=blob:none --sparse https://github.com/microsoft/AI-For-Beginners.git
> cd AI-For-Beginners
> git sparse-checkout set --no-cone '/*' '!translations' '!translated_images'
>
>
> CMD (Windows):
> cmd
> git clone --filter=blob:none --sparse https://github.com/microsoft/AI-For-Beginners.git
> cd AI-For-Beginners
> git sparse-checkout set --no-cone "/*" "!translations" "!translated_images"
>
>
> So erhalten Sie alles, was Sie brauchen, um den Kurs zu absolvieren, mit einem viel schnelleren Download.
<!-- CO-OP TRANSLATOR LANGUAGES TABLE END -->
Wenn Sie möchten, dass zusätzliche Übersetzungssprachen unterstützt werden, finden Sie diese hier
Treten Sie der Community bei
Was Sie lernen werden
In diesem Lehrplan lernen Sie:
- Verschiedene Ansätze der Künstlichen Intelligenz, einschließlich des "guten alten" symbolischen Ansatzes mit Wissensrepräsentation und Schlussfolgerung (GOFAI).
- Neuronale Netze und Deep Learning, die im Kern der modernen KI stehen. Wir veranschaulichen die Konzepte hinter diesen wichtigen Themen mit Code in zwei der beliebtesten Frameworks - TensorFlow und PyTorch.
- Neuronale Architekturen für die Arbeit mit Bildern und Text. Wir behandeln neuere Modelle, könnten aber im Bereich des neuesten Standes der Technik etwas eingeschränkt sein.
- Weniger populäre KI-Ansätze, wie Genetische Algorithmen und Multi-Agenten-Systeme.
Was wir in diesem Lehrplan nicht abdecken:
> Finden Sie alle zusätzlichen Ressourcen zu diesem Kurs in unserer Microsoft Learn-Collection
- Geschäftsanwendungen der KI im Business. Ziehen Sie in Betracht, den Lernpfad Einführung in KI für Business-Nutzer auf Microsoft Learn oder die AI Business School zu besuchen, entwickelt in Zusammenarbeit mit INSEAD.
- Klassisches Machine Learning, das in unserem Machine Learning for Beginners Lehrplan gut beschrieben ist.
- Praktische KI-Anwendungen, die mit Cognitive Services gebaut sind. Hier empfehlen wir, mit Microsoft Learn Modulen für Vision, Natural Language Processing, Generative KI mit Azure OpenAI Service und anderen zu starten.
- Spezifische ML-Cloud-Frameworks, wie Azure Machine Learning, Microsoft Fabric oder Azure Databricks. Nutzen Sie die Lernpfade Lösungen für maschinelles Lernen mit Azure Machine Learning erstellen und betreiben und Maschinelles Lernen mit Azure Databricks erstellen und betreiben.
- Konversationelle KI und Chat Bots. Es gibt einen separaten Lernpfad Conversational AI-Lösungen erstellen, und Sie können auch diesen Blogbeitrag für weitere Details lesen.
- Tiefe Mathematik hinter Deep Learning. Hierfür empfehlen wir Deep Learning von Ian Goodfellow, Yoshua Bengio und Aaron Courville, welches auch online unter https://www.deeplearningbook.org/ verfügbar ist.
Für eine sanfte Einführung in KI in der Cloud empfehlen wir den Lernpfad Erste Schritte mit künstlicher Intelligenz auf Azure.
Inhalt
Jede Lektion enthält
- Vorab-Lesematerial
- Ausführbare Jupyter-Notebooks, die oft spezifisch für das Framework (PyTorch oder TensorFlow) sind. Das ausführbare Notebook enthält auch viel theoretisches Material, daher muss man mindestens eine Version des Notebooks durchgehen (entweder PyTorch oder TensorFlow), um das Thema zu verstehen.
- Labs zu einigen Themen, die dir die Möglichkeit geben, das Gelernte an einem spezifischen Problem anzuwenden.
- Einige Abschnitte enthalten Links zu MS Learn-Modulen, die verwandte Themen behandeln.
Erste Schritte
🎯 Neu in KI? Hier anfangen!
Wenn du komplett neu in KI bist und schnelle, praktische Beispiele möchtest, schau dir unsere Einsteigerfreundlichen Beispiele an! Diese beinhalten:
- 🌟 Hello AI World – Dein erstes KI-Programm (Mustererkennung)
- 🧠 Einfache neuronale Netzwerke – Baue ein neuronales Netzwerk von Grund auf
- 🖼️ Bildklassifizierer – Klassifiziere Bilder mit ausführlichen Kommentaren
- 💬 Text-Sentiment – Analysiere positiven/negativen Text
Diese Beispiele wurden entworfen, um dir KI-Konzepte zu vermitteln, bevor du in das vollständige Curriculum eintauchst.
📚 Einrichtung des vollständigen Curriculums
- Wir haben eine Setup-Lektion erstellt, die dir beim Einrichten deiner Entwicklungsumgebung hilft. - Für Lehrkräfte gibt es ebenfalls eine Curriculum-Setup-Lektion!
- Wie man den Code in VSCode oder Codespace ausführt
Folge diesen Schritten:
Repository forken: Klicke auf den „Fork“-Button oben rechts auf dieser Seite.
Repository klonen: git clone https://github.com/microsoft/AI-For-Beginners.git
Vergiss nicht, dieses Repo mit einem Stern (🌟) zu markieren, damit du es später leichter findest.
Triff andere Lernende
Tritt unserem offiziellen AI Discord Server bei, um andere Lernende, die diesen Kurs absolvieren, kennenzulernen, dich zu vernetzen und Unterstützung zu erhalten.
Wenn du Produkt-Feedback oder Fragen während des Entwickelns hast, besuche unser Azure AI Foundry Developer Forum.
Quizze
> Hinweis zu Quizzen: Alle Quizze befinden sich im Ordner Quiz-app in etc\quiz-app, oder Online Hier. Sie sind in den Lektionen verlinkt. Die Quiz-App kann lokal ausgeführt oder auf Azure bereitgestellt werden; folge den Anweisungen im quiz-app-Ordner. Die Quizze werden nach und nach lokalisiert.
Unterstützung erwünscht
Hast du Vorschläge oder Fehler in Rechtschreibung oder Code gefunden? Erstelle ein Issue oder einen Pull Request.
Besonderer Dank
- ✍️ Hauptautor: Dmitry Soshnikov, PhD
- 🔥 Herausgeber: Jen Looper, PhD
- 🎨 Sketchnote-Illustratorin: Tomomi Imura
- ✅ Quiz-Ersteller: Lateefah Bello, MLSA
- 🙏 Kern-Mitwirkende: Evgenii Pishchik
Weitere Curricula
Unser Team entwickelt weitere Curricula! Sieh dir an:
<!-- CO-OP TRANSLATOR OTHER COURSES START -->
LangChain
Azure / Edge / MCP / Agents
Generative AI Reihe
Kernlernung
Copilot Reihe
<!-- CO-OP TRANSLATOR OTHER COURSES END -->
Hilfe bekommen
Wenn du feststeckst oder Fragen zum Entwickeln von KI-Anwendungen hast, tritt Gleichgesinnten und erfahrenen Entwicklern in Diskussionen über MCP bei. Es ist eine unterstützende Community, wo Fragen willkommen sind und Wissen frei geteilt wird.
Wenn du Produkt-Feedback oder Fehler beim Entwickeln hast, besuche:
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir auf Genauigkeit achten, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache ist als maßgebliche Quelle zu betrachten. Für wichtige Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Verwendung dieser Übersetzung entstehen.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Sicherheit
Microsoft nimmt die Sicherheit seiner Softwareprodukte und -dienste sehr ernst, einschließlich aller Quellcode-Repositories, die über unsere GitHub-Organisationen verwaltet werden. Dazu gehören Microsoft, Azure, DotNet, AspNet, Xamarin und unsere GitHub-Organisationen.
Wenn Sie der Meinung sind, eine Sicherheitslücke in einem von Microsoft verwalteten Repository gefunden zu haben, die Microsofts Definition einer Sicherheitslücke entspricht, melden Sie diese bitte wie unten beschrieben.
Melden von Sicherheitsproblemen
Bitte melden Sie Sicherheitslücken nicht über öffentliche GitHub-Issues.
Stattdessen melden Sie diese bitte dem Microsoft Security Response Center (MSRC) unter https://msrc.microsoft.com/create-report.
Falls Sie lieber ohne Anmeldung einreichen möchten, senden Sie eine E-Mail an secure@microsoft.com. Wenn möglich, verschlüsseln Sie Ihre Nachricht mit unserem PGP-Schlüssel; laden Sie diesen von der Microsoft Security Response Center PGP Key-Seite herunter.
Sie sollten innerhalb von 24 Stunden eine Antwort erhalten. Falls dies aus irgendeinem Grund nicht geschieht, folgen Sie bitte per E-Mail nach, um sicherzustellen, dass wir Ihre ursprüngliche Nachricht erhalten haben. Weitere Informationen finden Sie unter microsoft.com/msrc.
Bitte geben Sie die unten aufgeführten Informationen (so weit wie möglich) an, um uns zu helfen, die Art und den Umfang des möglichen Problems besser zu verstehen:
- Art des Problems (z. B. Buffer Overflow, SQL-Injection, Cross-Site-Scripting usw.)
- Vollständige Pfade der Quellcodedatei(en), die mit dem Problem in Zusammenhang stehen
- Der Ort des betroffenen Quellcodes (Tag/Branch/Commit oder direkte URL)
- Besondere Konfigurationen, die erforderlich sind, um das Problem zu reproduzieren
- Schritt-für-Schritt-Anleitung zur Reproduktion des Problems
- Proof-of-Concept- oder Exploit-Code (falls möglich)
- Auswirkungen des Problems, einschließlich der möglichen Ausnutzung durch einen Angreifer
Diese Informationen helfen uns, Ihren Bericht schneller zu priorisieren.
Wenn Sie im Rahmen eines Bug-Bounty-Programms berichten, können vollständigere Berichte zu einer höheren Prämie führen. Besuchen Sie unsere Seite zum Microsoft Bug Bounty Program, um weitere Details zu unseren aktiven Programmen zu erhalten.
Bevorzugte Sprachen
Wir bevorzugen alle Kommunikation in Englisch.
Richtlinie
Microsoft folgt dem Prinzip der koordinierten Offenlegung von Sicherheitslücken.
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.
AI-For-Beginners Fehlerbehebungshandbuch
Dieses Handbuch hilft Ihnen, häufige Probleme zu lösen, die beim Verwenden oder Beitragen zum AI-For-Beginners-Repository auftreten können. Jedes Problem enthält Hintergrundinformationen, Symptome, Erklärungen und Schritt-für-Schritt-Lösungen.
Inhaltsverzeichnis
- Allgemeine Probleme
- Installationsprobleme
- Konfigurationsprobleme
- Notebooks ausführen
- Leistungsprobleme
- Probleme mit der Lehrbuch-Website
- Probleme beim Beitragen
- FAQ
- Hilfe erhalten
Allgemeine Probleme
1. Repository wird nicht richtig geklont
Hintergrund: Beim Klonen können Sie das Repository auf Ihren Computer kopieren.
Symptome:
- Fehler: fatal: repository not found
- Fehler: Permission denied (publickey)
Mögliche Ursachen: - Falsche Repository-URL - Unzureichende Berechtigungen - SSH-Schlüssel nicht konfiguriert
Lösungen:
1. Überprüfen Sie die Repository-URL.
Verwenden Sie die HTTPS-URL:
git clone https://github.com/microsoft/AI-For-Beginners.git
2. Wechseln Sie zu HTTPS, wenn SSH fehlschlägt.
Wenn Sie Permission denied (publickey) sehen, verwenden Sie stattdessen den oben genannten HTTPS-Link.
3. SSH-Schlüssel konfigurieren (optional).
Wenn Sie SSH verwenden möchten, folgen Sie GitHubs SSH-Anleitung.
Installationsprobleme
2. Probleme mit der Python-Umgebung
Hintergrund: Das Repository basiert auf Python und verschiedenen Bibliotheken.
Symptome:
- Fehler: ModuleNotFoundError: No module named '<package>'
- Importfehler beim Ausführen von Skripten oder Notebooks
Mögliche Ursachen: - Abhängigkeiten nicht installiert - Falsche Python-Version
Lösungen:
1. Richten Sie eine virtuelle Umgebung ein.
bash
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
2. Installieren Sie die Abhängigkeiten.
bash
pip install -r requirements.txt
3. Überprüfen Sie die Python-Version.
Verwenden Sie Python 3.7 oder neuer.
bash
python --version
3. Jupyter ist nicht installiert
Hintergrund: Notebooks sind eine zentrale Lernressource.
Symptome:
- Fehler: jupyter: command not found
- Notebooks lassen sich nicht starten
Mögliche Ursachen: - Jupyter ist nicht installiert
Lösungen:
1. Installieren Sie Jupyter Notebook.
bash
pip install notebook
oder, wenn Sie Anaconda verwenden:
bash
conda install notebook
2. Starten Sie Jupyter Notebook.
bash
jupyter notebook
4. Konflikte bei Abhängigkeitsversionen
Hintergrund: Projekte können fehlschlagen, wenn Paketversionen nicht übereinstimmen.
Symptome: - Fehler oder Warnungen zu inkompatiblen Versionen
Mögliche Ursachen: - Alte oder widersprüchliche Python-Pakete
Lösungen:
1. Installieren Sie in einer sauberen Umgebung.
Löschen Sie alte venv/conda-Umgebungen und erstellen Sie eine neue.
2. Verwenden Sie genaue Versionen.
Führen Sie immer aus:
bash
pip install -r requirements.txt
Wenn dies fehlschlägt, installieren Sie fehlende Pakete manuell, wie im README beschrieben.
Konfigurationsprobleme
5. Umgebungsvariablen nicht gesetzt
Hintergrund: Einige Module benötigen Schlüssel, Tokens oder Konfigurationseinstellungen.
Symptome:
- Fehler: KeyError oder Warnungen zu fehlender Konfiguration
Mögliche Ursachen: - Erforderliche Umgebungsvariablen nicht gesetzt
Lösungen:
1. Überprüfen Sie .env.example oder ähnliche Dateien.
2. Erstellen Sie eine .env-Datei und füllen Sie die erforderlichen Werte aus.
3. Laden Sie Ihr Terminal oder Ihre IDE neu, nachdem Sie Umgebungsvariablen gesetzt haben.
Notebooks ausführen
6. Notebook lässt sich nicht öffnen oder ausführen
Hintergrund: Jupyter-Notebooks benötigen eine ordnungsgemäße Einrichtung.
Symptome: - Notebook lässt sich nicht starten - Browser öffnet sich nicht automatisch
Mögliche Ursachen: - Jupyter ist nicht installiert - Probleme mit der Browserkonfiguration
Lösungen:
1. Installieren Sie Jupyter (siehe Installationsprobleme oben).
2. Öffnen Sie Notebooks manuell.
- Kopieren Sie die URL aus dem Terminal (z. B. http://localhost:8888/?token=...) und fügen Sie sie in Ihren Browser ein.
7. Kernel stürzt ab oder friert ein
Hintergrund: Notebook-Kernel können aufgrund von Ressourcenbeschränkungen oder Codefehlern abstürzen.
Symptome: - Kernel stirbt oder startet wiederholt neu - Speicherfehler
Mögliche Ursachen: - Große Datensätze - Inkompatibler Code oder Pakete
Lösungen:
1. Starten Sie den Kernel neu.
Verwenden Sie die Schaltfläche "Kernel neu starten" in Jupyter.
2. Überprüfen Sie die Speichernutzung.
Schließen Sie nicht benötigte Anwendungen.
3. Führen Sie Notebooks auf Cloud-Plattformen aus.
Verwenden Sie Google Colab oder Azure Notebooks.
Leistungsprobleme
8. Notebooks laufen langsam
Hintergrund: Einige KI-Aufgaben erfordern erheblichen Speicher und CPU.
Symptome: - Langsame Ausführung - Laptop-Lüfter läuft laut
Mögliche Ursachen: - Große Datensätze oder Modelle - Begrenzte Systemressourcen
Lösungen: 1. Verwenden Sie eine Cloud-Plattform. - Laden Sie das Notebook auf Colab oder Azure Notebooks hoch. 2. Reduzieren Sie die Datensatzgröße. - Verwenden Sie Beispieldaten zum Üben. 3. Schließen Sie unnötige Programme. - Geben Sie Systemspeicher frei.
Probleme mit der Lehrbuch-Website
9. Kapitel lädt nicht
Hintergrund: Das Online-Lehrbuch zeigt Lektionen und Kapitel an.
Symptome: - Ein Kapitel (z. B. Transformers/BERT) fehlt oder lässt sich nicht öffnen
Bekanntes Problem:
- Issue #303: „18 Transformers. BERT. kann auf der Lehrbuch-Website nicht geöffnet werden.“ Verursacht durch einen Dateinamenfehler (READMEtransformers.md statt README.md).
Lösungen:
1. Überprüfen Sie Dateinamenfehler.
Wenn Sie Mitwirkender sind, stellen Sie sicher, dass Kapiteldateien README.md heißen.
2. Melden Sie fehlende Dateien.
Öffnen Sie ein GitHub-Issue mit dem Kapitelnamen und den Fehlerdetails.
Probleme beim Beitragen
10. PR wird nicht akzeptiert oder Builds schlagen fehl
Hintergrund: Beiträge müssen Tests bestehen und Richtlinien einhalten.
Symptome: - Pull-Request abgelehnt - CI/CD-Pipeline-Fehler
Mögliche Ursachen: - Fehlende Tests - Nicht eingehaltene Codierungsstandards
Lösungen: 1. Lesen Sie die Beitragsrichtlinien. - Befolgen Sie die CONTRIBUTING.md des Repositorys. 2. Führen Sie Tests lokal aus, bevor Sie Änderungen hochladen. 3. Überprüfen Sie Linting-Regeln oder Formatierungsanforderungen.
FAQ
Wo finde ich Hilfe zu spezifischen Modulen?
- Jedes Modul hat normalerweise eine eigene README-Datei. Beginnen Sie dort mit Einrichtung und Nutzungstipps.
Wie melde ich einen Fehler oder fordere ein Feature an?
- Öffnen Sie ein GitHub-Issue mit einer klaren Beschreibung und Schritten zur Reproduktion.
Kann ich um Hilfe bitten, wenn mein Problem nicht aufgeführt ist?
- Ja! Suchen Sie zuerst nach bestehenden Issues, und wenn Sie Ihr Problem nicht finden, erstellen Sie ein neues Issue.
Hilfe erhalten
- Issues überprüfen: GitHub Issues
- Fragen stellen: Verwenden Sie GitHub Discussions oder öffnen Sie ein Issue.
- Community: Siehe Repository-Links für Chat-/Forum-Optionen.
Letzte Aktualisierung: 20.09.2025
Haftungsausschluss:
Dieses Dokument wurde mithilfe des KI-Übersetzungsdienstes Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.





















































