Zusammenfassung des Python-Implementierungs-Know-hows und Tipps, mit denen KI-Ingenieure vorsichtig sein möchten

In diesem Artikel habe ich die Punkte, Tipps und das Know-how zusammengefasst, die Datenwissenschaftler und KI-Ingenieure bei der Implementierung von Programmen in Python beachten sollten.


● 16. Mai 2020: Hinzugefügt Buch: Selbstfahrender Programmierer Autor: Herr Shimizukawa hat diesen Artikel ausführlich ergänzt und meine Fragen beantwortet. Über diesen Link gelangen Sie zum Kommentar.


Das Buch wurde im April 2020 veröffentlicht.

【Qiita】 Ich habe ein Buch geschrieben, in dem maschinelle Lernimplementierungen und -algorithmen auf ausgewogene Weise vermittelt werden

[Buch] [Einführung in das maschinelle Lernen für diejenigen, die KI-Ingenieure werden möchten Lernen Sie den Ablauf von Algorithmen während der Implementierung (Internationaler Informationsdienst von Dentsu, Takuya Shimizu, Yutaro Ogawa, Technical Review)](https://www.amazon.co.jp/ dp / 4297112094 /) https://www.amazon.co.jp/dp/4297112094/

Dieser Beitrag konnte nicht in das obige Buch geschrieben werden ** "Zusammenfassung der Dinge, die KI-Ingenieure bei der Implementierung von Programmen in Python beachten sollten" ** ist.

Der Inhalt dieses Artikels ist nur der Punkt, den der Autor kennt. Dies ist nicht die einzige Antwort, aber wir hoffen, dass Sie sie hilfreich finden.

Zunächst wird der Inhalt dieses Artikels angezeigt.

Danach wird die Erklärung jedes Inhalts beschrieben.

Punkte der Python-Implementierung, bei denen KI-Ingenieure vorsichtig sein möchten

Level 1 1.1 Beachten Sie die Namenskonventionen für Variablen, Funktionen, Klassen und Methoden 1.2 Benennungsmethode 1: Entfernen Sie redundante Teile aus Variablennamen und Methodennamen 1.3 Die Importbeschreibung folgt den Regeln 1.4 Feste Zufallszahl, um die Reproduzierbarkeit zu gewährleisten 1.5 Programm wird als Funktion ausgeführt

Level 2 2.1 Benennungsmethode 2: Benennung mit umgekehrter Notation, um das Lesen zu erleichtern 2.2 Wenn Sie sich S in SOLID bewusst sind, verkürzen Sie Funktionen und Methoden mit einer einzigen Verantwortung 2.3 Fügen Sie Funktionen und Methoden Typhinweise hinzu 2.4 Dokumentzeichenfolge für Klassen, Methoden und Funktionen 2.5 Speichern Sie beim Speichern eines trainierten Modells Informationen wie Vorverarbeitung und Hyperparameter zusammen

Stufe 3 3.1 Benennungsmethode 3: Geben Sie einen Namen an, der Ihre Verantwortlichkeiten mit geeigneten englischen Wörtern und Teilen versteht. 3.2 Implementieren Sie die Ausnahmebehandlung entsprechend 3.3 Implementieren Sie die Protokolle ordnungsgemäß 3.4 Machen Sie die Anzahl der Funktions- und Methodenargumente auf 3 oder weniger 3.5 Verwenden Sie * args und ** kwargs richtig

Level 4 4.1 Kurze if-Anweisung mit ternärem Operator 4.2 Implementieren Sie Vorverarbeitungs- und Modellklassen in sklearn Compliance 4.3 Dekorateure gut gebrauchen 4.4 Editoreinstellungen für die Teamentwicklung vereinheitlichen 4.5 Bereiten Sie eine Vorlage für die Pull-Anforderung von GitHub vor und beschreiben Sie Notizen

Kommentar

Level 1

1.1 Beachten Sie die Namenskonventionen für Variablen, Funktionen, Klassen und Methoden

Das Benennen von Funktionen und Variablen ist ein Problem. Die Benennungsmethode ist ebenfalls wichtig, aber befolgen Sie zunächst die Benennungsregeln in der Regel. (Die Namenskonvention wird als ["PEP8: Python Code Style Guide"] eingeführt (https://pep8-ja.readthedocs.io/ja/latest/))

● Variablen, Funktionen, Methoden, Module ⇒ Nur Kleinbuchstaben, Wörter nach Bedarf mit Unterstrichen trennen Beispiel small_case_with_underscores

● Klassenname ⇒ Verbinden Sie die oberen Wörter nur am Anfang, verwenden Sie keinen Unterstrich Beispiel CapWords

● Private Variablen, die nur innerhalb der Klasse verwendet werden ⇒ Unterstrich vor Variablenname Beispiel _single_leading_underscores

"Private Methoden, die nur innerhalb der Klasse verwendet werden" ⇒ Unterstrich vor Methodenname Beispiel _single_leading_underscore (self, ...)

● Konstante ⇒ Nur Großbuchstaben, Wörter mit Unterstrich trennen Beispiel ALL_CAPS_WITH_UNDERSCORES

● Paketname ⇒ Nur Kleinbuchstaben Beispiel senkt

** * Bemerkung 1 **: Unterschied zwischen Funktion und Methode Funktionen sind unabhängige Prozeduren, die nicht in der Klasse enthalten sind. Die Methode zeigt auf eine Funktion innerhalb der Klasse.

** * Bemerkung 2 **: Modul und Paket Das Paket ist die größte oberste Ebene. Module sind Dateien in Paketen. Zum Beispiel ist sklearn ein Paket. linear_model in sklearn.linear_model ist ein Modul.

1.2 Benennungsmethode 1: Entfernen Sie redundante Teile aus Variablennamen und Methodennamen

Wenn die Klasse class_1 beispielsweise die Variable max_length hat, lautet der Name der Mitgliedsvariablen

Setzen Sie es nicht auf "class_1_max_length", sondern setzen Sie es einfach auf "max_length".

Denn beim Zugriff auf diese Klassenvariable von einer anderen Klasse

class_1.class_1_max_length = 10

Dies liegt daran, dass der Klassenname redundant wird.

class_1.max_length = 10

Es ist besser zu sein.

Mitgliedsvariablen werden benannt, indem man sich vorstellt, dass sie bei Verwendung "Klassenname.Variablenname" sind.

1.3 Die Importbeschreibung folgt den Regeln

Beachten Sie beim Importieren externer Klassen und Funktionen die folgenden drei Punkte.

● Reihenfolge des Schreibimports Beschreiben Sie die drei Arten von Bibliotheken, die wie unten gezeigt durch Leerzeilen getrennt sind.

Standardbibliothek importieren
Leerzeile
Import mit Drittanbietern (Pip-Installation von PyPI)
Leerzeile
importieren Was wir für diese Zeit erstellt haben`
Leerzeile

● Wie wird der Import beschrieben?

from pkg.module_1 import class_1

from pkg import module_1

my_class = module_1.class_1()

Wenn es beispielsweise eine Klasse class_1 des Moduls module_1 des Pakets pkg gibt, wird diese nicht verwendet, sondern im Programm beispielsweise auf Modulebene. ● Beschreibung des Imports 2 Importieren Sie nicht mehrere Pakete mit Import.

import pkg, pkg2 Nicht import pkg import pkg2

Es wird beschrieben als.

Mehrere Beschreibungen für Module sind jedoch in Ordnung. Zum Beispiel:

from pkg import module_1, module_2

** * Bemerkungen ** Ich habe auch eine ziemlich geeignete Importmethode. Es ist nicht gut. Autoformatter und andere Tools korrigieren die Beschreibung der Importanweisung. Es wird daher auch empfohlen, sie zu verwenden.

1.4 Feste Zufallszahl, um die Reproduzierbarkeit zu gewährleisten

Da es bei der Implementierung von Data Science und AI viele zufällige Teile gibt, ist der Startwert der Zufallszahl immer festgelegt, um die Reproduzierbarkeit des Programms sicherzustellen.

Das Implementierungsbeispiel lautet wie folgt.


import os
import random
import numpy as np
import torch

SEED_VALUE = 1234  #Das kann alles sein
os.environ['PYTHONHASHSEED'] = str(SEED_VALUE)
random.seed(SEED_VALUE)
np.random.seed(SEED_VALUE)
torch.manual_seed(SEED_VALUE)  #Bei Verwendung von PyTorch

Wenn Sie jedoch eine GPU mit PyTorch verwenden,

torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False

Einstellen. Wenn diese nicht eingestellt sind, kann die Reproduzierbarkeit bei Verwendung der GPU nicht garantiert werden.

Torch.backends.cudnn.deterministic = True verlangsamt jedoch die Berechnung auf der GPU. Daher gebe ich in meinem Fall der Ausführungsgeschwindigkeit Priorität und fordere keine Garantie für die Reproduzierbarkeit des Lernens auf der GPU.

Klicken Sie hier, um Einzelheiten zum Verfahren zur Gewährleistung der Reproduzierbarkeit mit PyTorch zu erfahren. PyTorch REPRODUCIBILITY

Außerdem gibt es im Fall von Scicit-Learn einen Teil, der in jedem Algorithmus einen zufälligen Startwert erhält. Korrigieren Sie dies ebenfalls.

Beispiel: Scikit-Learn

from sklearn.linear_model import LogisticRegression

SEED_VALUE = 1234  #Das kann alles sein
clf = LogisticRegression(random_state=SEED_VALUE)

1.5 Programm wird als Funktion ausgeführt

Nicht funktionalisierte Programme werden langsamer ausgeführt, egal ob in Jupyter Notebook oder in der Python-Befehlszeilenausführung.

Zum Beispiel bei Google Colaboratory

import time
import numpy as np

start = time.time()

data = np.random.rand(5000)
sum = 0

for i in range(len(data)):
    for j in range(len(data)):
        sum += data[j]

elapsed_time = time.time() - start
print(elapsed_time)

Der Lauf dauerte 8,4 Sekunden.

Dies ist der Zustand, in dem das Programm in einer Zelle geschrieben und ausgeführt wird.

Auf die gleiche Weise wird es in einer Zelle ausgeführt, aber wir führen es als Funktion um die main for-Anweisung aus.

import time
import numpy as np


def main():
    data = np.random.rand(5000)
    sum = 0

    for i in range(len(data)):
        for j in range(len(data)):
            sum += data[j]
    return 0


start = time.time()
main()
elapsed_time = time.time() - start
print(elapsed_time)

Das Ergebnis ist 6,2 Sekunden. Was 8 Sekunden dauerte, sind jetzt 6 Sekunden.

Selbst wenn Sie es in Jupyter Notebook wie folgt ausführen, machen Sie es zu einer Funktion wie main () und führen Sie diese Funktion aus, anstatt die Verarbeitung auszuführen, die in soliden Schreibvorgängen lange dauert.

Gleiches gilt für die Implementierung einer Python-Datei, die über die Befehlszeile ausgeführt wird, z. B. hogehoge.py.

python hogehoge.py Hogehoge.py ist wie folgt geschrieben, damit es bei der Ausführung mit nicht langsam wird.

#System importieren
import fuga

#Funktionen und Klassen, die in der Hauptfunktion verwendet werden
def piyo():
    your code

#Hauptfunktion
def main():
    your code

if __name__ == "__main__":
    main()

Am Ende if __name__ ==" __main__ ": ist die Ausführung vonmain ()in der if-Anweisung enthalten.

import hogehoge Dies soll verhindern, dass diese main () - Funktion ausgeführt wird, wenn Sie dies tun.

Ohne diese if-Anweisung würde main () nur durch Importieren ausgeführt.

Level 2

2.1 Benennungsmethode 2: Benennung mit umgekehrter Notation, um das Lesen zu erleichtern

Wenn Sie beispielsweise drei Arten von Variablen erstellen möchten, z. B. die Länge von a, die Länge von b und die Länge von c, a_length b_length c_length Ohne length_a length_b length_c Wird besorgt.

Diese Notation wird als umgekehrte Notation bezeichnet.

Bei der umgekehrten Notation sind die Anfänge der Wörter gleich, was das Lesen des Programms erleichtert.

Auch wenn Sie sich auf eine statt auf Länge konzentrieren a_length a_width a_max_length Es wird so geschrieben.

Mein Gefühl ist: "Schreiben Sie das Objekt, auf das Sie sich am Anfang konzentrieren, und vereinheitlichen Sie den Anfang der Variablen."

2.2 Beachten Sie S in SOLID und halten Sie die Anzahl der Funktions- und Methodenzeilen so kurz wie möglich.

Bücher [Geheimnis der agilen Softwareentwicklung, sauberer Code, sauberer Codierer, saubere Architektur usw.](https://www.amazon.co.jp/%E6%9C%AC-%E3%83%AD%E3%83% 90% E3% 83% BC% E3% 83% 88% E3% 83% BBC% E3% 83% BB% E3% 83% 9E% E3% 83% BC% E3% 83% 81% E3% 83% B3 / s? rh = n% 3A465392% 2Cp_27% 3A% E3% 83% AD% E3% 83% 90% E3% 83% BC% E3% 83% 88% E3% 83% BBC% E3% 83% BB% E3% 83% 9E% E3% 83% BC% E3% 83% 81% E3% 83% B3) Autor von Robert C. Martin (eines der Mitglieder der Agile Software Development Declaration) Das von SOLID befürwortete Prinzip des Software-Designs ist.

Auf der Ebene dieses Beitrags müssen Sie jedoch nicht über SOLID informiert sein.

Beachten Sie jedoch unbedingt das erste SOLID, ** S: Prinzip der Einzelverantwortung **.

Einzelverantwortung bedeutet "Funktionen, Klassen und Methoden sollten nur eine Verantwortung erfüllen."

Die Definition der Größe, die hier durch ** "single" ** angegeben wird, das Gleichgewicht zwischen Abstraktion und Konkretheit ist schwierig, ** Der Punkt ist, dass Funktionen, Klassen und Methoden so kurz wie möglich sind und nicht von Änderungen in übergeordneten Konzepten beeinflusst werden **.

Die Arbeit von Datenwissenschaftlern und KI-Ingenieuren ist Es ist ein sehr prozeduraler und flussähnlicher Inhalt wie "Datenvorverarbeitung, Lernen, Inferenz, ...".

Dann wird das zu implementierende Programm prozedural und eine Hauptklasse oder Methode wird aufgebläht. Es ist einfach, viele Dinge (mit vielen Verantwortlichkeiten) in einer einzigen Klasse oder Methode von oben nach unten zu erledigen.

Es ist gut, wenn es mit Jupyter Notebook geschlossen wird, aber dieser Zustand ist schwierig, Data Science und KI in die Systementwicklung einzuführen.

Entwicklung von SoE (System of Engagement) wie AI-System Es gibt viele agile Entwicklungen, keine Wasserfallentwicklungen wie SoR (System of Records), bei denen die Anforderungsdefinition und das externe / interne Design genau durchgeführt werden.

In der agilen Entwicklung ist es grundlegend, einen automatischen CI-Test (Continuous Integration) durchzuführen. Und weil es agil ist, werden wir es tatsächlich schaffen, sehen, wie es auf Prototypenebene funktioniert, Kaizen-Änderungen finden und etwas Besseres anstreben.

Zum Zeitpunkt dieses Kaizen steigt die Anzahl der neu zu erstellenden Codezeilen, wenn die Verantwortung für eine einzelne Klasse oder Methode sehr groß ist.

Je mehr Codezeilen Sie neu erstellen, desto größer ist die Auswirkung.

Dann gibt es viele Komponententests, die neu erstellt werden müssen.

Gleichzeitig werden viele der von uns erstellten Komponententests weggeworfen.

** Wenn Sie mit der Entwicklung in einer Situation fortfahren, in der solche größeren Ersetzungen von Komponententests häufig auftreten, werden die Komponententests nicht ordnungsgemäß geschrieben und die Qualität des Systems verschlechtert sich. ** **.

Darüber hinaus wirkt sich das Remaking von Kaizen auf unerwartete Orte aus und erleichtert das Auftreten von Fehlern.

Datenwissenschaftler und KI-Ingenieure möchten Kaizen auch aktiv in die agile Entwicklung einbeziehen. Die zu implementierenden Funktionen, Klassen und Methoden sollten kurz sein und eine einzige Verantwortung haben. Wir werden ** eine Implementierung berücksichtigen, die gegen Kaizen-Änderungen resistent ist **.

Anstatt eine lange Funktion, Klasse, Methode zu haben ** Ist es zu kurz? Es ist wünschenswert, dass es so viele Funktionen, Klassen und Methoden gibt, über die Sie sich Sorgen machen **.

Je nach Buch oder Artikel kann gesagt werden, dass die Anzahl der Zeilen in einer Funktion oder Methode innerhalb von 5 Zeilen liegen sollte. Ich denke, dass die Verwendung von 5 Zeilen als Standard für AI-basierte Implementierungen zu kurz und zu streng ist, was kontraproduktiv ist.

Anstelle des Standards für die Anzahl der Zeilen versuchen wir, eine Länge zu haben, die eine einzelne Verantwortung erfüllt, eine Implementierung, die beim Ändern von Kaizen einen engen Einflussbereich hat, und eine Implementierung, die Unit-Tests selten verwirft.

Ein Trick dafür ist, am Anfang der Funktion, Klasse oder Methode zu kommentieren. "" Diese Methode ist für die Implementierung von ●● verantwortlich. "" "

Es ist auch eine gute Praxis, zunächst Ihre Verantwortlichkeiten explizit aufzuschreiben.

2.3 Fügen Sie Funktionen und Methoden Typhinweise hinzu

Wenn Sie eine Funktion oder Methode unter Berücksichtigung von "SOLID S: Einzelverantwortung" unterteilen, können Sie viele Funktionen und Methoden erstellen.

Es ist schwer zu verstehen, ob es viele Funktionen und Methoden gibt. Es ist in Ordnung, wenn Sie Code schreiben, aber wenn Sie diesen Code nach 3 Monaten überprüfen oder jemand anderes versucht, ihn zu verwenden

"Was steht im Argument dieser Funktion und was ist die Ausgabe?"

Und verwirrt werden.

Fügen Sie daher beim Implementieren einer Funktion einen Typhinweis hinzu. Typhinweise werden wie folgt geschrieben.

def calc_billing_amount(amount: int, price: int) -> int:
    billing_amount = amount*price
    return billing_amount

Schreiben Sie den Typ nach dem Argumentnamen, damit Sie den Typ der Argumentvariablen kennen.

Beschreiben Sie außerdem den Typ, damit Sie den Typ der von der Funktion ausgegebenen Variablen sehen können.

Dieser Typ-Hinweis ist, wie der Name schon sagt, ein Hinweis, kein Zwang. Geben Sie daher in der obigen Funktion float anstelle von int für den ersten Betrag an.

calc_billing_amount(0.5, 100)

Kann auch ausgeführt werden. Es wird kein Fehler auftreten. Sie müssen in diesem Punkt vorsichtig sein.

Wenn Sie eine Liste oder ein Wörterbuch mit einem Typhinweis verwenden oder wenn mehrere Typen wie float auch mit int in Ordnung sind, schreiben Sie wie folgt.

from typing import Dict, List, Union


def calc_billing_amount(
    amount_list: List[int], price_dictionary: Dict[str, Union[int, float]]
) -> int:
    billing_amount = 0
    for index, (key, value) in enumerate(price_dictionary.items()):
        billing_amount += amount_list[index] * value

    return int(billing_amount)

Importieren Sie mit from typing Import List, Dict, Union eine Liste für Typhinweise, ein Wörterbuch und eine Union, die verwendet werden sollen, wenn beides in Ordnung ist.

Wenn das Element beispielsweise eine Liste vom Typ int ist, verwenden Sie List [int]. Wenn der Schlüssel vom Typ string ist und der Wert entweder int oder float sein kann, lautet das Wörterbuch Dict[str, Union[int, float]] Schreiben.

Ausführung

amount = [3, 10]
price = {"item1": 100, "item2": 30.5}
calc_billing_amount(amount, price)

Dann wird "605" ausgegeben.

Wenn Sie die ursprüngliche Klasse verwenden möchten, die Sie als Typhinweis definiert haben, schreiben Sie wie folgt.

class User:
    def __init__(self, name: str, user_type: str):
        self.name = name
        self.user_type = user_type


def print_user_type(user: "User") -> str:
    print(user.user_type)

Ich definiere meine eigene Klasse User und definiere die Funktion print_user_type, die mit diesem User ausgeführt wird, als Argument.

Wenn Sie Python Version 3.7 oder höher haben from __future__ import annotations Sie können "Benutzer" in "Benutzer" ändern, aber Google Colaboratory verfügt auch über eine Python-Version 3.6. Wir empfehlen die oben beschriebene Schreibmethode.

Um die Klasse mit den obigen Typhinweisen wie gewohnt auszuführen,

taro = User("taro", "admin")
print_user_type(taro)

Wird besorgt. Die Ausgabe zeigt dann "admin".

Das Schreiben von Typhinweisen ist mühsam, aber wenn Sie es in viele Klassen und Methoden mit einer einzigen Verantwortung aufteilen und implementieren, wird es später ein Problem sein.

Besonders wenn es um die Arbeit geht, sehen und verwenden Teammitglieder häufig den Code, den sie schreiben. ** Ich werde die Implementierung berücksichtigen, die für andere einfach zu bedienen und einfach zu bedienen ist **.

2.4 Dokumentzeichenfolge für Klassen, Methoden und Funktionen

docstring ist eine Beschreibung der Klassen-, Methoden- und Funktionsspezifikationen und -verwendung.

Wenn es um viele Klassen und Funktionen mit einer einzigen Verantwortung geht, ist es schwierig zu verstehen, wenn sie wiederverwendet werden.

Da es schwierig ist, nur den Typ-Hinweis zu verstehen, werde ich eine Dokumentzeichenfolge als detailliertere Erklärung schreiben.

Da dies jedoch problematisch ist, denke ich, dass eine einzeilige Dokumentzeichenfolge für private Methoden und Methoden mit einer kleinen Anzahl von Zeilen ausreicht.

Auf der anderen Seite Klassen und Methoden, die von anderen Teammitgliedern verwendet werden, Hauptklassen, die eine wichtige Position in KI-Systemen einnehmen, Klassen mit langer Verarbeitung usw.

Wenn es für andere Mitglieder einfacher ist, die ausführliche Erklärung zu verwenden, schreiben Sie die Dokumentzeichenfolge im Detail.

Sie können den Docstring auf jede Art und Weise schreiben, aber normalerweise ・ ReStructuredText ・ Google-Stil ・ Numpy Style Schreiben Sie in eines von.

Ich schreibe in einem dieser drei Typen, weil ich dann Sphinx verwenden kann, um es automatisch zu dokumentieren. Daher verwenden wir die Docstring-Notation, die Sphinx unterstützt.

Klicken Sie hier, um eine detaillierte Erläuterung der drei Arten von Dokumentzeichenfolgen zu erhalten. Beispiel für 3 Arten von Dokumentzeichenfolgen

Ich mag reStructuredText, weil der Google-Stil und der Numpy-Stil in der Regel groß sind.

Die Dokumentzeichenfolge in reStructuredText wird wie folgt geschrieben.

class User:
    """Diese Klasse gibt den Kontonutzer an, der dieses System verwendet.

    :param name:Kontoname des Benutzers
    :param user_Typ: Kontotyp (Administrator oder normal)

    :Example:

    >>> import User
    >>> taro = User("taro", "admin")
    """

    def __init__(self, name: str, user_type: str):
        self.name = name
        self.user_type = user_type

    def print_user_type(self):
        """Drucken Sie den Benutzertyp mit einer Druckanweisung

        :pram None:Keine Eingabeargumente
        :return: user_Ausgabetyp als Zeichenfolge
        :rtype: str

        :Example:

        >>> import User
        >>> taro = User("taro", "admin")
        >>> taro.print_user_type()
        admin
        """
        print(self.user_type)

Wenn Sie zu Example schreiben, werden Sie sofort wissen, wie man es benutzt, so dass es für andere einfach zu benutzen ist, und ich mag es. Es hängt von der Situation ab, wie viele Details Sie schreiben und ob Sie Beispiele, Argumente und Erklärungen für die Rückgabe schreiben.

Wenn Sie wie oben beschrieben schreiben, in Editor wie VS-Code, Wie in der folgenden Abbildung gezeigt, wird beim Platzieren des Mauszeigers auf dem entsprechenden Programmteil diese Dokumentzeichenfolge angezeigt, um das Verständnis des Programms zu erleichtern. (In der folgenden Abbildung befindet sich der Mauszeiger auf print_user_type ())

図1.png

2.5 Speichern Sie beim Speichern eines trainierten Modells Informationen wie Vorverarbeitung und Hyperparameter zusammen

In der KI, beim maschinellen Lernen und beim Tiefenlernen werden nicht nur das trainierte Modell gespeichert, sondern auch die Informationen, die das Training reproduzieren können, wie die Vorverarbeitungspipeline, die Einstellung der Hyperparameter des Modells und alle für die Inferenz erforderlichen Objekte. Sparen.

Es spielt keine Rolle, wie Sie es speichern, solange alle diese Informationen enthalten sind. Hier ist jedoch ein Beispiel für das Speichern mit scicit-learn und PyTorch.

Beispiel: für scicit-learn

from datetime import datetime, timedelta, timezone

import numpy as np
from joblib import dump, load
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures, StandardScaler

#Bereiten Sie die Iris als geeignete Daten vor
X, y = load_iris(return_X_y=True)

#Vorverarbeitung (standardisierte und hinzugefügte Funktionen des quadratischen Terms)
preprocess_pipeline = Pipeline(steps=[("standard_scaler", StandardScaler())])
preprocess_pipeline.steps.append(("polynominal_features_2", PolynomialFeatures(2)))

#Anwendung der Vorbehandlung
X_preprocessed = preprocess_pipeline.fit_transform(X)

#Vorbereitung des Lerngeräts
C = 1.2  #Hyper-Parametereinstellungen
model = LogisticRegression(random_state=0, C=C)

#Umsetzung des Lernens
model.fit(X_preprocessed, y)

#Leistung in Trainingsdaten
accuracy_training = model.score(X_preprocessed, y)

#Bereit zum Speichern verschiedener Daten
JST = timezone(timedelta(hours=+9), "JST")  #In Japan Zeit
now = datetime.now(JST).strftime("%Y%m%d_%H%M%S")  #Aktuelle Zeit abrufen

training_info = {
    "training_data": "iris",
    "model_type": "LogisticRegression",
    "hyper_pram_logreg_C": C,
    "accuracy_training": accuracy_training,
    "save_date": now,
}

save_data = {
    "preprocess_pipeline": preprocess_pipeline,
    "trained_mode": model,
    "training_info": training_info,
}
filename = "./iris_model_" + now + ".joblib"

#sparen
dump(save_data, filename)

Wenn Sie den auf diese Weise gespeicherten Inhalt laden möchten,

load_data = load(filename)

#Laden Sie den geladenen Inhalt
preprocess_pipeline = load_data["preprocess_pipeline"]
model = load_data["trained_mode"]
print(load_data["training_info"])

ist. In diesem Ladebeispiel wird training_info also gedruckt {'training_data': 'iris', 'model_type': 'LogisticRegression', 'hyper_pram_logreg_C': 1.2, 'accuracy_training': 0.9866666666666667, 'save_date': '20200503_205145'} Wird ausgegeben.

Beispiel: Für PyTorch Referenz PyTorch SPAREN UND LADEN VON MODELLEN

PATH = './checkpoint_' + str(epoch) + '.pt'

torch.save({
    'epoch': epoch,
    'total_epoch': total_epoch,
    'model_state_dict': model.state_dict(),
    'scheduler.state_dict': scheduler.state_dict()
    'optimizer_state_dict': optimizer.state_dict(),
    'loss_train': loss_train,
    'loss_eval': loss_eval,
}, PATH)

Beim Laden

#Erstellen Sie zuerst Objekte wie Modelle
model = TheModelClass()  #Dies ist das gleiche Modell, das ich gespeichert habe
scheduler = TheSchedulerClass()  #Dies ist dieselbe Scheduler-Klasse, die Sie gespeichert haben
optimizer = TheOptimizerClass()  #Dies ist dieselbe Optimierungsklasse, die Sie gespeichert haben

#Laden und geben
checkpoint = torch.load(PATH)
model.load_state_dict(checkpoint['model_state_dict'])
scheduler.load_state_dict(checkpoint['scheduler_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
total_epoch = checkpoint['total_epoch']
epoch = checkpoint['epoch']
loss_train = checkpoint['loss_train']
loss_eval = checkpoint['loss_eval']

#Gehen Sie je nach Lernen oder Argumentation wie folgt vor
model.train()
# model.eval()

Wenn Sie das Deep-Learning-Dataset und den Datenlader am Prüfpunkt speichern, ist die Sicherungsdatei zu groß. Speichern Sie sie daher separat.

#Datensatz, Speicher des Datenladers
torch.save(trainset, './trainset.pt')
torch.save(trainloader, './dataloader.pt')

Beim Laden

trainset = torch.load('./trainset.pt')
trainloader = torch.load('./dataloader.pt')

Das ist alles zum Speichern und Laden mit PyTorch.

Ob Scikit-Learn oder PyTorch, es spielt keine Rolle, wie Sie es speichern.

Ich habe jedoch nur das Modell und später gespeichert

** "Wie wurde dieses Modell gelernt?" ** ** "Was für eine Leistung ist dieses Modell !?" ** ** "Es gibt kein geschultes Vorverarbeitungsrohr, um dieses Modell zu füllen !!" **

Achten Sie darauf, nicht in eine solche Situation zu geraten.

** * Bemerkung 1 **: Der Grund, warum die Vorverarbeitung und das Modell im Beispiel von scicit-learn nicht in einer Pipeline kombiniert werden, besteht darin, dass die Vorverarbeitung von einer anderen Ressource ausgeführt und in die Modell-API geworfen werden kann. Insbesondere wenn Sie eine große Datenmenge mit hoher Geschwindigkeit verarbeiten möchten, möchten Sie die Verwendung vereinfachen, wenn nur die Vorverarbeitung an anderen Orten verteilt wird. Auch die Vorverarbeitung ist dieselbe, und es besteht der Wunsch, nur diese Vorverarbeitungspipeline umzuleiten, wenn verschiedene Modelle trainiert werden.

** * Bemerkung 2 **: Ich werde die Punkte erläutern, die beim Erstellen Ihrer eigenen Vorverarbeitungsklasse zu beachten sind. Wenn Sie eine Vorverarbeitungspipeline laden, die eine selbst erstellte Klasse usw. verwendet, importieren Sie hier vor dem Laden nicht nur die normale sckit-learn-Vorverarbeitungsklasse, sondern auch die selbst erstellte Klasse usw. Dann laden Sie es. Beachten Sie, dass beim Laden ein Fehler auftritt, wenn die erweiterte Klasse beim Laden nicht importiert wird.

Stufe 3

3.1 Benennungsmethode 3: Geben Sie einen Namen an, der Ihre Verantwortlichkeiten mit geeigneten englischen Wörtern und Teilen versteht.

Je mehr Klassen, Methoden und Funktionen unterteilt sind, desto wichtiger wird ihre Benennung.

Wenn Sie sich den Namen ansehen: "Was machen Sie? Das heißt, welche Verantwortung haben Sie, was ist Input und was ist Output?" Idealerweise sollten Sie dies wissen.

Für Japaner ist es jedoch schwierig.

In der Programmierwelt sind keine Kommentare erforderlich. Wenn Sie sich die Codenamen ansehen, handelt es sich um einen Kommentar. Es gibt auch eine allgemeine Denkweise, Die Fähigkeit der Japaner, den Unterschied zwischen englischem Wortschatz und Nuancen zu verstehen, ist schwierig.

Auch im Fall von Data Science und AI ist der Algorithmus selbst kompliziert Für Anfänger ist es schwierig, die unkommentierte Implementierung zu sehen und den Inhalt einer Klasse oder Methode zu verstehen.

Die Benennungsmethode sollte jedoch so einfach wie möglich zu vermitteln sein.

Das Minimum, das ich schützen möchte, ist

[1] Verwenden Sie die Nomenklatur für Klassennamen und Variablennamen

[2] Methoden- und Funktionsnamen beginnen mit einem Verb

[3] Im Fall des Wahrheitswertes (Boolescher Typ) einer Mitgliedsvariablen kann er mit den folgenden Verben beginnen. (Beispiel) is_admin, has_item, can_drive usw.

[4] Verwenden wir Codic usw. https://codic.jp/engine

キャプチャ.PNG

3.2 Implementieren Sie die Ausnahmebehandlung entsprechend

Der Fehler (Ausnahme) Try-Catch ist ein langwieriger Teil, der überhaupt keinen Spaß macht, und es ist ein Schmerz (glaube ich) für Datenwissenschaftler und KI-Ingenieure.

Es gibt kein Problem, wenn die Projektskala nur mit Jupyter Notebook endet, aber die Fehlerbehandlung ist wichtig, wenn AI im System implementiert wird. Wenn eine Ausnahme auftritt, wird der gesamte Systemprozess gestoppt.

Daher im Implementierungscode Stellen Sie sicher, dass sich der Versuch auf der obersten Ebene befindet (vermeiden Sie Situationen, in denen sich der Code nicht im Versuch befindet :).

Lesen Sie unbedingt den offiziellen Python-Kommentar. Offizielle 8. Fehler und Ausnahmen

Beispiel: Beim Definieren einer zu teilenden Funktion

def func_division(a, b):
    ret = a/b
    return ret

Wenn du das tust, ans = func_division(10, 0) Wenn so etwas kommt, tritt ein Fehler auf und das gesamte Programm stoppt.

Damit

def func_division(a, b):
   try:
      ret = a/b
      return ret
   except:
      print("Ausnahme aufgetreten")

Schreiben.

Dies reicht jedoch nicht aus. Wenn eine Ausnahme, die vom Verarbeitungsinhalt auftritt, vorhergesagt werden kann, behandeln Sie sie ordnungsgemäß mit diesem Fehler und behandeln Sie die Ausnahme entsprechend.

def func_division(a, b):
   try:
      ret = a/b
      return ret
   except ZeroDivisionError as err:
      print('0 Divisionsausnahme aufgetreten:', err)
   except:
      print("Eine unerwartete Ausnahme ist aufgetreten")

Wenn dies der Fall ist

ans = func_division(10, 0) Wann kommt 0 Division Ausnahme aufgetreten: Division durch Null Wird ausgegeben,

ans = func_division("hoge", "fuga") Und wenn eine nicht numerische Eingabe gegeben ist

"Eine unerwartete Ausnahme ist aufgetreten" Wird ausgegeben.

Da sich die Implementierung von KI in realen Systemen in Zukunft beschleunigen wird, wird dies ein Problem für Menschen sein, die nur Programme auf Jupyter Notebook-Ebene schreiben können (glaube ich).

Der Punkt ist zu beachten, dass "try auf der obersten Ebene ist (dh Situationen vermeiden, in denen der Code nicht in try enthalten ist :)".

** * Anmerkungen **: Grenzen Sie den Versuchsbereich ein Try-Catch allein kann ein Ärger sein, aber das bedeutet nicht, dass Sie viel Verarbeitung (viele Zeilen) in einen Versuch stecken müssen. Ich weiß nicht, wo die Ausnahme aufgetreten ist. Try-Catch in einer sinnvollen Verarbeitungseinheit. Wie ich später erläutern werde, ist es häufig erforderlich, eine Zeile in eine andere Methode aufzuteilen, wenn sie viele Zeilen enthält.

3.3 Implementieren Sie die Protokolle ordnungsgemäß

Für Datenwissenschaftler und KI-Ingenieure ist es üblich, eine Druckanweisung auszugeben und den Status zu überprüfen. Wenn Sie sie jedoch in das System integrieren, ist die Druckanweisung problematisch. Schreiben Sie sie daher ordnungsgemäß als Protokoll.

Die Verwendung des Protokolls ist wie folgt.

import logging

logger = logging.getLogger(__name__)

#Erstellen Sie einen Wert, der entsprechend protokolliert werden soll
total_epoch = 1000
epoch = 100
loss_train = 5.44444

#Inhalt, der per Protokoll aufgezeichnet werden soll
log_list = [total_epoch, epoch, loss_train]

#Im Protokoll aufzeichnen
logger.info(
    "total_epoch: {0[0]}, epoch: {0[1]}, loss_train: {0[2]:.2f}".format(log_list)
)

#Geben Sie den im Protokoll aufgezeichneten Inhalt aus und überprüfen Sie ihn (zur Bestätigung jetzt. Ursprünglich nicht erforderlich).
print("total_epoch: {0[0]}, epoch: {0[1]}, loss_train: {0[2]:.2f}".format(log_list))

Wenn Sie in diesem Fall den protokollierten Inhalt mit der print-Anweisung überprüfen, total_epoch: 1000, epoch: 100, loss_train: 5.44 Es ist geworden.

Hier bedeutet "{0 [2]: .2f}", dass die zweite in .format empfangene Liste mit bis zu 2 Ziffern angezeigt wird.

Es gibt viele Möglichkeiten, in Python zu schreiben, egal ob es sich um einen Logger oder eine Druckanweisung handelt. Wenn Sie viele Variablen zu schreiben haben, schreibe ich sie wie oben in eine Liste.

Nicht nur logger.info, sondern auch logger.debug, logger.warning, logger.error usw. ändert sich die Protokollstufe je nach Situation.

Zumindest ist die Atmosphäre im obigen Beispiel in Ordnung, aber die Holzwelt ist tief.

Es ist auch eine gute Idee, die offizielle Protokolldokumentation zu lesen.

Python Logging


@ Paulxll, weitere Ratschläge hinzugefügt: sonnig:

Ich habe ein Beispiel mit f-string erhalten (unter der Annahme von Python 3.8). Bitte beachten Sie auch dies ♪

#Erstellen Sie einen Wert, der entsprechend protokolliert werden soll
total_epoch = 1000
epoch = 100
loss_train = 5.44444

#Im Protokoll aufzeichnen
logger.info(f"{total_epoch=}, {epoch=}, loss_train: {loss_train=:.2f}")

Anmerkungen: Im Folgenden wird beschrieben, wie Sie in Python 3.8 oder höher schreiben. Für Version 3.7 oder niedriger

logger.info(f"total_epoch: {total_epoch}, epoch: {epoch}, loss_train: {loss_train:.2f}")

(Danke für deinen Rat: sonnig :).


3.4 Machen Sie die Anzahl der Funktions- und Methodenargumente auf 3 oder weniger

Die maximale Anzahl von Funktions- und Methodenargumenten beträgt drei. Vermeiden Sie mehr als 4 (in meinem Fall).

Wenn es viele Argumente gibt, ist es schwierig zu verstehen, wie die Funktion verwendet wird, und es wird schwierig sein, Komponententests vorzubereiten und zu verwalten.

Wenn Sie viele Argumente verwenden möchten, verwenden Sie eine Variable vom Typ Wörterbuch wie hogehoge_config usw. und übergeben Sie sie als eine Wörterbuchvariable an die Funktion.

Beispiel: Komplexe Rechenfunktion (Es tut mir leid, dass ich oben erklärt habe, wie man eine Ausnahmebehandlung schreibt, aber die Ausnahmebehandlung wird weggelassen, weil sie problematisch ist.)

def func_many_calculation(a, b, c, d, e):
    ret = a*b*c/d/e
    return ret

Definiert als ans = func_many_calculation(10, 2, 3, 5, 2) Wenn Sie verwenden, gibt es zu viele Argumente und es ist problematisch. Es kann eine Fehlerquelle sein.

So zum Beispiel

def func_many_calculation(func_config):
    a = func_config["a"]
    b = func_config["b"]
    c = func_config["c"]
    d = func_config["d"]
    e = func_config["e"]
    ret = a*b*c/d/e
    return ret

Definiert als func_config = {"a": 10, "b": 2, "c": 3, "d": 5, "e": 2} Erstellen Sie eine Variable, der Sie in einem Wörterbuch zuweisen möchten

ans = func_many_calculation(func_config) Und Renn.

Diese Schreibweise ist jedoch zu kompliziert, um die Funktion zu definieren

def func_many_calculation(a, b, c, d, e):
    ret = a*b*c/d/e
    return ret

Und schreiben Sie im Definitionsteil der Funktion viele Argumente,

Versuchen Sie in dem auszuführenden Teil, die Anzahl der Argumente zu reduzieren

func_config = {"a": 10, "b": 2, "c": 3, "d": 5, "e": 2}
ans = func_many_calculation(**func_config)

Es ist gut zu sagen.

** * Anmerkungen **: Dies ist eine unbekannte Methode zum Schreiben von Argumenten mit dem Namen ** func_config. Dieses ** bedeutet einen Entpackvorgang für Wörterbuchvariablen. Also hier, func_many_calculation(**func_config) Ist func_many_calculation (func_config [" a "], func_config [" b "], ..., func_config [" e "]) Meint. Das Entpacken von Wörterbuchvariablen mit ** ist praktisch, also machen wir es verfügbar.

3.5 Verwenden Sie * args und ** kwargs richtig

Ich weiß nicht, was "* args" und "** kwargs" sind, aber ich benutze sie positiv! !! Es gibt keinen solchen Datenwissenschaftler oder KI-Ingenieur.

"Ich weiß nicht, was es ist, aber wenn ich mir das Artikelimplementierungs-Repository ansehe, sehe ich viele" * args "und" ** kwargs "."

Ich denke, es gibt viele solche Erfahrungen. Freunde dich mit * args und ** kwargs an.

Nach der Erläuterung des Entpackvorgangs von Variablen vom Typ Wörterbuch in 3.4 sind * args und ** kwargs nicht beängstigend.

args ist eine Abkürzung für Argumente, was auf Japanisch Argument bedeutet. kwargs ist eine Abkürzung für Keyword-Argumente.

Wobei * die Entpackungsoperation für Listenvariablen ist. ** ist eine Entpackoperation für Wörterbuchvariablen, wie in 3.4 erläutert.

Wenn diese "*" und "**" im Argument der Funktion verwendet werden, wird es wie folgt.

Zum Beispiel

def func_args_kwargs(*args, **kwargs):
    print(args)
    if len(args) >= 2:
        print(args[1])
    print(kwargs)
    flg_a = kwargs.pop("flg_a", False)
    print(flg_a)

Wenn Sie eine Funktion wie definieren

func_args_kwargs(10, 20) Setzt die Eingabeargumente 10 und 20 in Argumente (10, 20) 20 {} False Wird ausgegeben.

Verwenden Sie dann Variablen vom Typ Wörterbuch für die Eingabe. func_args_kwargs(10, **{"flg_a":True}) Wenn Sie ausführen, gehen die anderen Argumente als das erste Wörterbuch in Argumente, das Wörterbuch in kwargs,

(10,) {'flg_a': True} True Wird ausgegeben.

* args und ** kwargs heißen ** Argumente variabler Länge **.

Ich werde erklären, warum wir solche Argumente variabler Länge "* args" und "** kwargs" verwenden.

Es gibt drei Gründe, Argumente mit variabler Länge zu verwenden.

Der erste Grund ist, dass es ausgeführt werden kann, auch wenn das Funktionsargument Extras enthält.

Zum Beispiel

def func_args_kwargs2(a, *args, **kwargs):
    print(a)

Wenn du rennst func_args_kwargs2(10, 20, 30) Die Ausgabe von 10

Und kann fehlerfrei ausgeführt werden.

Der zweite Grund ist, dass Sie eine Funktion, wenn Sie sie später erweitern und die Anzahl der Argumente erhöhen möchten, mit "* args" empfangen können, damit Sie den Inhalt der Funktion oder den Teil der Argumentdefinition nicht neu schreiben müssen.

Der dritte Grund besteht darin, "* args" und "** kwargs" als Teil zu verwenden, der die Argumente empfängt, die optional sind und zur Laufzeit als Argumente beim Ausführen einer Funktion oder Methode übergeben werden können oder nicht. Machen.

Stellen Sie in diesem Fall den Standardwert ein, wenn "* args" oder "** kwargs" nicht empfangen wird.

Beispiel:

def func_args_kwargs3(a, *args, **kwargs):
    b = kwargs.pop("b", 2.0)
    print(a*b)

Definiert als

func_args_kwargs3(3.0) Die Ausgabe von ist 6.0. Der Standardwert 2.0 wird für b in der Funktion verwendet.

func_args_kwargs3(3, **{"b":4.0}) Im Fall von wird die Ausgabe 12.0 sein. B in der Funktion ist 4.0 als Argument angegeben.

Das Obige ist die Funktion von * args und ** kwargs.

** * Anmerkungen : Zum Zeitpunkt der Implementierung verwende ich selten * args und ** kwargs. Für OSS- und veröffentlichte Papierimplementierungen werden üblicherweise " args" und "* kwargs" verwendet. Bei diesen Entwicklungen besteht ein hohes Maß an Unsicherheit, da viele Personen den Implementierungscode verwenden. Verwenden Sie also, wie im ersten Grund gezeigt, "* args", "** kwargs", damit es auch dann funktioniert, wenn es unnötige Argumente enthält? Ich denke.

Level 4

4.1 Gewöhnen Sie sich mit dem ternären Operator an die if-Anweisung

In Python werden if-Anweisungen häufig mit einem ternären Operator geschrieben und in einer Zeile zusammengefasst. Gewöhnen wir uns daran. (Ich benutze es nicht oft beim Schreiben von Büchern, aber ich benutze es, weil der Implementierungscode weniger Zeilen enthält und leichter zu lesen ist.)

#Bestimmen Sie, ob es gerade oder ungerade ist
num = 10

if num % 2 == 0:
    print("Sogar")
else:
    print("Seltsam")

Ist

#Bestimmen Sie, ob es gerade oder ungerade ist
num = 10

print("Sogar") if num % 2 == 0 else print("Seltsam")

Schreiben.

Das Beispiel in der print-Anweisung ist nicht gut. Zum Zeitpunkt der Substitution wird es wie folgt sein.

num = 10
a = "Sogar" if num % 2 == 0 else "Seltsam"
# a = "Sogar" if num % 2 == 0 else a = "Seltsam"  #Dies führt zu einem Fehler

print(a)

@Nabetani, weitere Ratschläge hinzugefügt: sonnig:

print("Sogar") if num % 2 == 0 else print("Seltsam")
#Als
print("Sogar" if num % 2 == 0 else "Seltsam")
#Ich halte das für vorzuziehen.

Meine Situation

Es wird gesagt.


4.2 Implementieren Sie Vorverarbeitungs- und Modellklassen in sklearn Compliance

sklearn-konform ist eine Klasse, die BaseEstimator, TransformerMixin, ClassifierMixin usw. von scikit-learn erbt und so implementiert, dass sie von der Pipeline-Klasse von scikit-learn zusammen mit anderen scikit-learn-Objekten verarbeitet werden kann.

Wenn Sie Ihre eigene Vorverarbeitungsklasse oder Ihr eigenes Modell mit sklearn kompatibel machen, ist dies praktisch, da es verwendet werden kann, indem es in die Pipeline von scicit-learn integriert wird.

Wenn es sich beispielsweise um eine Vorverarbeitungsklasse handelt, schreiben Sie wie folgt. Inherit Transformer Mixin und Base Estimator.

from sklearn.base import BaseEstimator, ClassifierMixin, TransformerMixin
from sklearn.utils.validation import check_array, check_is_fitted, check_X_y


class TemplateTransformer(TransformerMixin, BaseEstimator):
    """Beispielvorverarbeitungsklasse"""

    def __init__(self, demo_param='demo'):
        self.demo_param = demo_param  #Später zu verwendende Parameter werden von init vorbereitet

    def fit(self, X, y=None):
        """Implementierung des für die Vorverarbeitung erforderlichen Lernens. y auch wenn y nicht existiert=Geben Sie mit niemandem"""
        
        X = check_array(X, accept_sparse=True)  # check_Array ist eine Validierungsfunktion für die Eingabe von sklearn

        #Der Prozess, etwas zu lernen. Hier ist ein Beispiel n_features_Lernt den Parameter
        self.n_features_ = X.shape[1]

        #Gibt den vorverarbeiteten Transformator selbst zurück
        return self

    def transform(self, X):
        """Wenden Sie die Vorverarbeitung auf Argument X an"""

        #Parameter, die beim Anwenden der Vorverarbeitung gelernt werden müssen (hier n_features_) Überprüfen Sie, ob es gibt
        check_is_fitted(self, 'n_features_')

        #Validierung der sklearn-Eingabe
        X = check_array(X, accept_sparse=True)

        #Einige Konvertierungsprozesse
        X_transformed = hogehoge(X)

        return X_transformed

Bei einer Modellklasse werden ClassifierMixin und BaseEstimator vererbt. Das Folgende ist ein Bild des Lernens mit einem Lehrer, aber ich werde es auf die gleiche Weise schreiben, um ohne Lehrer zu lernen.

from sklearn.base import BaseEstimator, ClassifierMixin, TransformerMixin
from sklearn.utils.validation import check_array, check_is_fitted, check_X_y


class TemplateClassifier(ClassifierMixin, BaseEstimator):
    """Modellklassenbeispiel"""

    def __init__(self, demo_param="demo"):
        self.demo_param = demo_param  #Später zu verwendende Parameter werden von init vorbereitet

    def fit(self, X, y):
        """Umsetzung des Lernens. Auch wenn y aufgrund von überwachtem Lernen usw. nicht existiert.=Geben Sie mit niemandem"""

        #Validierung der sklearn-Eingabe
        X, y = check_X_y(X, y)

        #Etwas lernen
        self.fugafuga = piyopiyo(X, y)

        #Gibt den gelernten Lernenden (Modell) selbst zurück
        return self

    def predict(self, X):
        """Rückschluss auf unbekannte Daten"""

        #Überprüfen Sie, ob Parameter (hier Fugafuga) vorhanden sind, die vor der Inferenz gelernt werden sollten
        check_is_fitted(self, ["fugafuga"])

        #Validierung der sklearn-Eingabe
        X = check_array(X)

        #Schließen
        y_predicted = self.fugafuga(X)

        return y_predicted

Bei der Implementierung der Sklearn-Konformität wird empfohlen, die Vorlage basierend auf der von scikit-learn veröffentlichten Vorlage zu ändern.

Developing scikit-learn estimators

Klicken Sie hier, um eine sklearn-konforme Implementierungsvorlage anzuzeigen

4.3 Dekorateure gut gebrauchen

Ein Dekorateur ist so etwas wie "@ hogehoge". Es wird oft über Methoden- und Funktionsnamen angehängt. Was ist das? Ich denke, es wird beim Nachdenken durchgehen.

Aber lasst uns mit Dekorateuren befreundet sein.

Es gibt Standarddekorateure in Python und selbstgemachte Dekorateure.

Ein gängiger Python-Standarddekorateur ist @property@staticmethod@classmethod@abstractmethod Es ist herum.

Überprüfen Sie eins nach dem anderen.

@ property macht seine Mitgliedsvariablen von außerhalb der Klasse unveränderlich.

(Beispiel)

class User:
    def __init__(self, name: str, user_type: str):
        self.name = name
        self.__user_type = user_type
        
    @property
    def user_type(self):
        return self.__user_type

As, der Benutzertyp der Benutzerklasse wird durch @ property definiert.

Dann taro = User("taro", "admin") print(taro.user_type) Kann problemlos ausgeführt werden und wird als "admin" ausgegeben.

aber, taro.user_type="normal" Und wenn ich versuche, die durch @ property definierte Mitgliedsvariable zu ändern, wird eine Fehlermeldung angezeigt.

Auf diese Weise können Sie Variablen definieren, die extern nicht geändert werden können.

(Beispiel) @staticmethod@classmethod

class User:
    def __init__(self, name: str, user_type: str):
        self.name = name
        self.user_type = user_type

    @staticmethod
    def say_hello(name):
        print("Hello " + name)

@ staticmethod und @ classmethod aktivieren die Methode, ohne die Klasse als Objekt materialisieren zu müssen.

Wenn Sie es wie oben definieren und Folgendes tun

User.say_hello("Hanako")

Die Ausgabe ist "Hallo Hanako".

Der Unterschied zwischen "@ staticmethod" und "@ classmethod" kann erneut untersucht werden, wenn man damit konfrontiert wird.

Ein weiterer Standard-Python-Dekorator, den Sie finden, ist "@ abstractmethod".

Wenn eine Methode einer Klasse diese "@ abstractmethod" hat, muss die untergeordnete Klasse, die diese Klasse erbt, diese Methode implementieren. Wenn nicht implementiert, tritt ein Fehler auf.

Verwenden Sie "@ abstractmethod", wenn Sie eine abstrakte Klasse definieren und eine Methodendefinition in einer geerbten untergeordneten Klasse erzwingen.

Wenn Sie diesen Bereich verstehen, ist er im Allgemeinen für Data Science und KI in Ordnung?

Wenn Sie eine Webanwendung mit Django erstellen, wird wieder ein Django-Dekorateur angezeigt, den Sie jedoch zu diesem Zeitpunkt überprüfen können.

Als nächstes werde ich über meinen eigenen Dekorateur erklären.

Angenommen, es gibt einen Prozess, der nur ausgeführt werden kann, wenn user_type in der User-Klasse admin ist.

class User:
    def __init__(self, name: str, user_type: str):
        self.name = name
        self.user_type = user_type
        
    def func_admin_can_do(self):
        if self.user_type=="admin":
          #Verarbeitung, die nur der Administrator ausführen kann
          print("I'm admin.")
        else:
          print("cannot do this func with auth error.")

Sie können es so schreiben, aber wenn es viele andere Prozesse gibt, die nur ausgeführt werden können, wenn user_type admin ist, ist es schwierig, jedes Mal mit der if-Anweisung zu überprüfen.

Wenn Sie also einen Dekorateur verwenden, sieht dieser folgendermaßen aus:

def admin_only(func):
    """Definition des Dekorateurs"""
    def wrapper(self, *args, **kwargs):
        if self.user_type == "admin":
            #Verarbeitung, die nur der Administrator ausführen kann
            return func(self, *args, **kwargs)
        else:
            print("cannot do this func with auth error.")

    return wrapper


class User:
    def __init__(self, name: str, user_type: str):
        self.name = name
        self.user_type = user_type

    @admin_only
    def func_admin_can_do(self):
        #Verarbeitung, die nur der Administrator ausführen kann
        print("Im admin.")

Mit dieser Definition können Sie den Dekorator "@ admin_only" nur hinzufügen und den Prozess nur ausführen, wenn der Benutzer admin ist.

Verwenden Sie in Fällen, in denen dasselbe häufig geschrieben wird, z. B. wenn es viele Methoden gibt, die bestimmen, ob es sich um einen Administrator handelt oder nicht, einen Dekorator.

4.4 Editoreinstellungen für die Teamentwicklung vereinheitlichen

Es ist praktisch, beim Codieren den automatischen Formatierer zu verwenden, da dieser automatisch formatiert wird. In Python ist Schwarz heutzutage beliebt.

Wenn Teammitglieder jedoch unterschiedliche Formatierer verwenden, erhöht das einfache Ändern des Formats die Wahrscheinlichkeit, dass die Datei überschrieben wird und der Inhalt des Git-Commits durcheinander gebracht wird.

Daher wird bei der Entwicklung als Team der automatische Formatierer vereinheitlicht.

Erstellen Sie beispielsweise einen Ordner ".vscode" direkt unter dem Repository und legen Sie die Datei "settings.json" darin ab.

in settings.json "python.formatting.provider": "black" Ich werde darüber schreiben, damit es schwarz formatiert wird.

Wenn ein Mitglied codiert, öffnen Sie diesen Ordner mit VS-Code und führen Sie ihn aus. Es spiegelt die Einstellungen in der .vscode-Einstellung.json des Repositorys wider, sodass alle Benutzer denselben Codierungsstil haben.

Dieser Artikel eignet sich sehr gut zum Festlegen von VS-Code für Python.

VSCode-Einstellungsnotiz zum Explodieren der Implementierung des Deep-Learning-Modells email & utm_source = Revue% 20newsletter)

4.5 Bereiten Sie eine Vorlage für die Pull-Anforderung von GitHub vor und beschreiben Sie Notizen

Ich werde den in diesem Beitrag erwähnten Inhalt und andere Punkte vorbereiten, die Sie als Vorlage für Pull-Anfragen auf GitHub kennen möchten.

Erstellen Sie einen Ordner ".github" direkt unter dem Repository und erstellen Sie darin eine Datei "PULL_REQUEST_TEMPLATE.md".

Diese PULL_REQUEST_TEMPLATE.md wird zum Zeitpunkt der Pull-Anforderung als Vorlage für den veröffentlichten Inhalt angezeigt.

Wenn Sie den in diesem Beitrag genannten Inhalt aufschreiben,


Level 1
- [ ]Befolgen Sie die Namenskonventionen für Variablen, Funktionen, Klassen und Methoden?
- [ ]Benennungsmethode 1: Werden redundante Teile aus Variablennamen und Methodennamen entfernt?
- [ ]Entspricht die Beschreibung des Imports den Regeln?
- [ ]Ist der Startwert der Zufallszahl festgelegt, um die Reproduzierbarkeit zu gewährleisten?
- [ ]Wird das Programm als Funktion ausgeführt?

Level 2
- [ ]Benennungsmethode 2: Ist es leicht zu lesen, weil es in umgekehrter Notation benannt ist?
- [ ]Sind die Funktionen und Methoden mit einer einzigen Verantwortung kurz und sind sich S in SOLID bewusst?
- [ ]Haben Funktionen und Methoden Typhinweise?
- [ ]Hat die Klasse, Methode oder Funktion eine Dokumentzeichenfolge?
- [ ]Speichern Sie beim Speichern des trainierten Modells Informationen wie Vorverarbeitung und Hyperparameter zusammen?

Stufe 3
- [ ]Benennungsmethode 3: Wird der Name mit geeigneten englischen Wörtern und Teilwörtern angegeben, um die Verantwortung zu verstehen?
- [ ]Ist die Ausnahmebehandlung ordnungsgemäß implementiert?
- [ ]Implementieren Sie die Protokollierung ordnungsgemäß?
- [ ]Ist die Anzahl der Funktions- und Methodenargumente 3 oder weniger?
- [ ] `*args`、`**kwargs`Verwenden Sie richtig?

Level 4
- [ ]Schreiben Sie eine kurze if-Anweisung mit einem ternären Operator?
- [ ]Sind Vorverarbeitungs- und Modellklassen in sklearn Compliance implementiert?
- [ ]Verwenden Sie den Dekorateur richtig?
- [ ]Sind die Editoreinstellungen im Team einheitlich?
- [ ]Haben Sie eine Vorlage für die Pull-Anfrage vorbereitet und verwendet?

ist.

Zusammenfassung

Das Obige ist eine Zusammenfassung der Punkte, die Datenwissenschaftler und KI-Ingenieure bei der Implementierung mit Python beachten sollten, sowie Implementierungs-Know-how und Tipps.

Ich habe einen Beitrag geschrieben, aber es gibt einige Regeln, die ich nicht vollständig befolgt habe. Außerdem bin ich selbst ein junger Mensch und habe wenig Erfahrung. Daher würde ich mich über jeden Rat meiner Vorgänger freuen, dass dies besser wäre.

Und es ist nicht gut, zu streng und eng zu sein, "Jeder im Team kann sich bequem entwickeln und die Qualität ist garantiert." Es kann gut sein, für jedes Team Regeln für solche Punkte festzulegen.

Vielen Dank für das Lesen der oben genannten.


** Liste der letzten Serialisierungen ** [1] [Erklärung zur Implementierung] Verwendung der japanischen Version von BERT in Google Colaboratory (PyTorch) [2] [Implementierung] Livedoor-Nachrichtenklassifizierung in der japanischen Version BERT: Google Colaboratory (PyTorch) [3] [Erklärung zur Implementierung] Gehirnforschung und unbeaufsichtigtes Lernen. Klassifizieren Sie MNIST nach Clustering zur Maximierung der Informationsmenge [4] [Erklärung zur Implementierung] Klassifizieren Sie lebende Nachrichten nach japanischem BERT x unbeaufsichtigtem Lernen (Clustering zur Maximierung der Informationsmenge)


[Anmerkungen] Das von mir geleitete Entwicklungsteam der AI-Technologieabteilung sucht Mitglieder. Klicken Sie hier, wenn Sie interessiert sind

[Haftungsausschluss] Der Inhalt dieses Artikels selbst ist die Meinung / Übermittlung des Autors, nicht die offizielle Meinung des Unternehmens, zu dem der Autor gehört.


Recommended Posts

Zusammenfassung des Python-Implementierungs-Know-hows und Tipps, mit denen KI-Ingenieure vorsichtig sein möchten
Zusammenfassung des Know-hows und der Tipps für die Planung neuer KI-Geschäftsabläufe, die KI-Ingenieure wissen möchten
[Einführung in Python] Zusammenfassung der Funktionen und Methoden, die häufig in Python vorkommen [Problemformat]
[Python] Einführung in das WEB-Scraping | Zusammenfassung der Methoden, die mit dem Webdriver verwendet werden können
Zusammenfassung der Dinge, die installiert werden müssen, um die tf-Pose-Schätzung auszuführen
Konzept der Serverlast, das neue Ingenieure wissen wollen
Python3-Verarbeitung, die in Paiza verwendbar zu sein scheint
[Python] Zusammenfassung der Verwendung von Split- und Join-Funktionen
Ich möchte die Natur von Python und Pip kennenlernen
[Python] Ein Programm, um die Anzahl der Äpfel und Orangen zu ermitteln, die geerntet werden können
Ich möchte sowohl den Schlüssel als auch den Wert des Python-Iterators verwenden
Dies und das von Python-Eigenschaften
Zusammenfassung der Python-Indizes und -Slices
[Python] Ein Programm, das die Anzahl der gepaarten Socken berechnet
Ich wollte vorsichtig mit dem Verhalten der Standardargumente von Python sein
Buchzusammenfassung, die für SRE- und Cloud-Ingenieure gut zu lesen ist
Implementierung des Partikelfilters durch Python und Anwendung auf das Zustandsraummodell
[Python2.7] Zusammenfassung der Verwendung von unittest
[Python3] Code, der verwendet werden kann, wenn Sie die Erweiterung eines Bildes sofort ändern möchten
Zusammenfassung der Verwendung der Python-Liste
[Python2.7] Zusammenfassung der Verwendung des Unterprozesses
Python-Übungsdatenanalyse Zusammenfassung des Lernens, dass ich ungefähr 10 mit 100 Schlägen getroffen habe
Atcoder-Anfängerwettbewerb A, B Zusammenfassung der Eingabe, die tendenziell ein Problem für Python darstellt
Ich möchte eine Prioritätswarteschlange erstellen, die mit Python (2.7) aktualisiert werden kann.
Ich möchte ein Programm ausführen und verteilen, das die Größe von Bildern in Python3 + Pyinstaller ändert
Erstellen Sie eine Python-Umgebung, um die Theorie und Implementierung von Deep Learning zu erlernen
So schreiben Sie eine Datei, bei der Sie in allen Sprachen vorsichtig sein sollten
Zusammenfassung der Korrespondenz zwischen Ruby- und Python-Array-Operationen
Zusammenfassung der Unterschiede zwischen PHP und Python
Zusammenfassung zum Importieren von Dateien in Python 3
Zusammenfassung von Beispielen, die nicht rückwärts pyTorch sein können
Zusammenfassung der Verwendung von MNIST mit Python
Installation von Python 3 und Flask [Zusammenfassung der Umgebungskonstruktion]
TRIE-Baumimplementierung mit Python und LOUDS
E / A-bezogene Zusammenfassung von Python und Fortan
Liste des zu verschiebenden und zu merkenden Python-Codes
Über flache und tiefe Kopien von Python / Ruby
Erläuterung der Bearbeitungsentfernung und Implementierung in Python
Zusammenfassung der statistischen Datenanalysemethoden mit Python, die im Geschäftsleben verwendet werden können
Sammeln Sie Tweets über "Corona" mit Python und erkennen Sie automatisch Wörter, die aufgrund des Einflusses von "Corona" zu einem heißen Thema geworden sind.