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.
[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.
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
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.
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.
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.
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)
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.
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."
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.
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 **.
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 ())
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.
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
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.
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.
@ 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 :).
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.
* args
und ** kwargs
richtigIch 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.
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.
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
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.
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)
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.
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)
[Haftungsausschluss] Der Inhalt dieses Artikels selbst ist die Meinung / Übermittlung des Autors, nicht die offizielle Meinung des Unternehmens, zu dem der Autor gehört.