Bootstrap eines „OG“-Textklassifikators über ChatGPT: Bewerber-Screening | von Alexandre Paris | Juni 2023

0
37


Einführung

„Wir haben die digitale Kluft geschlossen. Jeder ist ein Programmierer. Jetzt müssen Sie nur noch etwas zum Pc sagen. Diesem Pc ist es egal, wie Sie ihn programmieren, er wird versuchen zu verstehen, was Sie meinen, weil er über diese unglaublich große Sprachmodellfähigkeit verfügt. Daher ist die Programmierhürde unglaublich niedrig“,

– Nvidia-CEO Jensen Huang, 29. Mai 2023

Massive Language Fashions (LLMs) sind unbestreitbar ein Recreation-Changer für den Bereich der Verarbeitung natürlicher Sprache. Historisch gesehen bestand eines der größten Hindernisse bei der Entwicklung erfolgreicher Sprachsysteme darin, genügend domänenspezifische Trainingsbeispiele aus der Wildnis für eine bestimmte Aufgabe zu sammeln (POS, NER, Textklassifizierung, Entailment, Fragen und Antworten usw.). Dies gilt insbesondere für kommerzielle Projekte, die sich mit sensiblen, Nischen- oder proprietären Daten befassen, die für die Massenvernichtung im Web nicht ohne weiteres zugänglich sind.

LLMs können mit minimalen Trainingsdaten beeindruckende Ergebnisse erzielen, indem sie das Lernen mit wenigen Schüssen innerhalb von Eingabeaufforderungen nutzen. Der Einsatz individuell abgestimmter Modelle mit geringer Latenz und hohem Durchsatz stellt KMU jedoch vor zahlreiche DevOps/MLOps-Herausforderungen. Praktiker müssen verschiedene aktuelle Themen verstehen, darunter die Auswahl der Modellarchitektur, Multi-GPU-Coaching und Modellkomprimierung für schnelle Bereitstellung. Schlechte Entscheidungen in diesen Bereichen können zu übermäßigen Cloud-Kosten, hoher Latenz oder schlechter Modellleistung führen.

Glücklicherweise können wir die Leistungsfähigkeit von LLMs nutzen, um leichte „klassische“ NLP-Modelle zu entwickeln, die relativ kostengünstig zu trainieren und zu produzieren sind und den zusätzlichen Vorteil einer besseren Modellinterpretierbarkeit bieten.

In den folgenden Abschnitten erstellen wir mit ChatGPT generierte synthetische Trainingsbeispiele, um ein Hybridsystem zu erstellen, bei dem ein kleiner Encoder zur Texteinbettung an einen leichten SVM-Klassifikator (Assist Vector Machine) gespeist wird, um Lebenslaufkategorien für Bewerber vorherzusagen.

Anschauliches Beispiel: Klassifizierung von Lebensläufen

Angenommen, Sie leiten die Personalabteilung eines beliebten Begin-ups. Zum ersten Mal stellen Sie nach Abschluss einer Finanzierungsrunde einen Senior DevOps Engineer ein. Sie haben gerade Tausende von Lebensläufen für die Stelle erhalten und möchten KI nutzen, um einen schnellen First-Previous-Take a look at durchzuführen und Nicht-DevOps-Kandidaten aus der Auswahl auszuschließen.

Was sollte man tun? (Denken Sie daran, dass Sie nur wenige beschriftete Trainingsdaten haben, mit denen Sie arbeiten können.)

Ein hypothetischer Ansatz zum Bootstrapping eines Klassifikators:

I. Verwenden Sie die ChatGPT-REST-API, um 10.000 gleichermaßen ausgewogene synthetische Lebenslauf-Schulungsbeispiele für Senior-DevOps-Rollen und Nicht-DevOps-Rollen zu erstellen, die mit Beispielen aus der Praxis versehen sind. Jeder Lebenslauf hat die Bezeichnung 0, 1 für DevOps/Nicht-DevOps

II. Leiten Sie die rohen Trainingsbeispiele durch ein kleines Texteinbettungsmodell (z. B Hugging Face’s Satztransformators) um eingebettete Merkmalsvektoren zu erhalten, die abstrakte Bedeutungen im Textual content erfassen. Geben Sie die Einbettungen anschließend zum Coaching an einen nachgeschalteten klassischen binären Klassifikator wie eine SVM oder ein logistisches Regressionsmodell weiter.

I. Erstellen synthetischer Trainingsbeispiele:

Hier erfahren Sie, wie Sie mithilfe von ChatGPT synthetische Trainingslebensläufe für Ihr SVM-Modell erstellen können. Beachten Sie, dass der unten stehende Startercode und die Eingabeaufforderungen nicht optimiert sind und nur zur Veranschaulichung dienen.

Bevor Sie beginnen, einige allgemeine Vorschläge:

  1. Führen Sie effektive zeitnahe technische Experimente durch, um sicherzustellen, dass Sie realistische Trainingsbeispiele generieren (Sehen Sie sich diesen hervorragenden Leitfaden an)
  2. Verwenden Sie einen Multithread-Ansatz für gleichzeitige Anfragen an OpenAI und respektieren Sie dabei Ratenlimits und Token-Kontingente um sicherzustellen, dass genügend Schulungsbeispiele rechtzeitig zurückgegeben werden
  3. Um bei einem Absturz keinen Fortschritt zu verlieren, ist es hilfreich, Zwischenergebnisse an eine Ausgabe-JSONL anzuhängen und gleichzeitig Race-Bedingungen durch Prozesssperren zu vermeiden
  4. Führen Sie regelmäßig eine Zufallsstichprobe und eine EDA Ihrer Ergebnisse durch, um sowohl die Verteilung als auch die Qualität der Lebensläufe auf Plausibilität zu überprüfen. Wenn Sie unzufrieden sind, experimentieren Sie mit verschiedenen Eingabeaufforderungen und wenden Sie Nachbearbeitungsmasken an, um Ihre Trainingsdaten zu bereinigen

Lebenslauf-Generierungscode

import openai
from datetime import datetime
import fcntl
import json
import time
from multiprocessing import Pool

openai.api_key = "YOUR_API_KEY"

DEVOPS_PROMPT= """
Please generate a Senior DevOps Resume whereas respecting the next standards:
- make it as real looking as attainable
- make certain to incorporate related DevOps and Software program Growth Abilities
- make certain they've at the very least 3 years of labor expertise

Return a JSON the place the hot button is 0 n
and the worth is the uncooked resume textual content

"""

NON_DEVOPS_PROMPT= """
Please generate a resume in any discipline exepct DevOps whereas respecting the next standards:
- make it's as real looking as attainable
- make certain it comprises nothing in the best way of DevOps and n
Software program Growth Abilities

Return a JSON the place the important thing for the is 1 n
and the worth is the uncooked resume

"""

def _write_to_jsonl(examples: str, output_file: str):
"""
Append intermediate request outcomes to a JSONL
lock the file to keep away from race circumstances
"""
with open(output_file, "a") as f:
# Purchase an unique lock on the file
fcntl.flock(f, fcntl.LOCK_EX)
for instance in examples:
json_string = json.dumps(instance)
f.write(json_string + "n")
fcntl.flock(f, fcntl.LOCK_UN)

def _open_ai_request(immediate: str, max_tokens: str, output_path: str):
"""
Make an OPENAI ChatGPT request
"""
print("Beginning Open AI Request")
attempt:
res = openai.ChatCompletion.create(
max_tokens=max_tokens,
mannequin="gpt-3.5-turbo",
messages=[
{"role": "user", "content": prompt},
],
)
if raw_str := res["choices"][0]["message"]["content"]:
examples = [{0: raw_str}]
print(examples)
print("n")
_write_to_jsonl(examples, output_path)
besides Exception as e:
print(e)
return None

def open_ai_requests_min(immediate: str,
max_tokens: int,
threads: int,
output_path: str):
"""
Batch of requests made in a minute.
"""
start_time = time.time()

with Pool(processes=threads) as pool:
pool.starmap(_open_ai_request, [(prompt, max_tokens, output_path)] * threads)

whereas time.time() - start_time < 60:
time.sleep(1)
print("sleeping...")

if __name__ == "__main__":
TPM = 90_000
RPM = 3_500
MAX_TOKENS = 1_000
THREADS_MIN = 100
MINUTES = 120

# Generate DevOps Resumes
for i in vary(MINUTES):
OUTPUT_PATH = "./devops_resumes.jsonl"
print(f"Beginning Batch for Minute {i}")
open_ai_requests_min(DEVOPS_PROMPT, MAX_TOKENS, THREADS_MIN, OUTPUT_PATH)

# Non DevOps Resumes
for i in vary(MINUTES):
OUTPUT_PATH = "./non_devops_resumes.jsonl"
print(f"Beginning Batch for Minute {i}")
open_ai_requests_min(NON_DEVOPS_PROMPT, MAX_TOKENS, THREADS_MIN, OUTPUT_PATH)

II. Einbettung & Schulung:

Als Nächstes nutzen wir einen leichten Texteinbettungstransformator von Hugging Face. In diesem Fall haben wir uns für das entschieden All-MiniLM-L6-v2 was aus folgenden Gründen attraktiv ist:

  • Geschwindigkeit: 14.200 Sätze/Sek. auf einer V100-GPU
  • Kleine Größe: nur 80 MB!
  • Vielseitigkeit: Auf mehr als 1 Milliarde Textpaare trainiert
  • Token-Fenster: 256 Wortteile (ungefähr 2/3 einer Textseite)

Nach der Einbettung unserer Trainingsdaten sind wir bereit, eine SVM für unsere binäre Klassifizierungsaufgabe zu trainieren. Dies würde den Rahmen dieses Artikels sprengen, aber SVMs eignen sich intestine für hochdimensionale Räume, da sie effektiv eine Entscheidungsgrenze finden können, indem sie den Spielraum zwischen Klassen maximieren, selbst in komplexen und nichtlinearen Merkmalsräumen. Unsere Einbettungsvektoren haben eine Länge von über 700 Gleitkommazahlen, sodass diese Wahl des Klassifikators zunächst eine gute Foundation darstellt.

Wenn eine SVM wie die folgende anhand von ca. 20.000 Trainingsbeispielen trainiert wird, serialisiert sie häufig zu einem ca. ca. 100 MB großen Modell, das viel kleiner und einfacher zu produzieren ist als ein Multi-Gig-LLM!

Viel Spaß beim Bauen!

Einbettungs-/Trainingscode

import pandas as pd
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.utils import resample
from sentence_transformers import SentenceTransformer, util
import pickle

def _get_embeddings(embed=True) -> pd.DataFrame:
"""
Get and serialize our embeddings, preload earlier embeddings
if embed set to False
"""

print("Getting Embeddings")

toc_path = "./coaching/devops_embeddings.pkl"
bt_path = "./coaching/non_devops_embeddings.pkl"

if embed:
mannequin = SentenceTransformer("all-MiniLM-L6-v2")
devops_df = pd.read_json("./coaching/devops_embeddings.jsonl", traces=True).assign(label=0)
non_devops_df = pd.read_json("./coaching/non_devops_embedding.jsonl", traces=True).assign(label=1)

df = pd.concat([devops_df, non_devops]).drop_duplicates()
df.columns = ["text", "label"]
df["features"] = df.textual content.apply(lambda x: mannequin.encode(x))

min_class = df[df.label == 0]
max_class = df[df.label == 1]
min_class.to_pickle(toc_path, protocol=pickle.HIGHEST_PROTOCOL)
max_class.to_pickle(bt_path, protocol=pickle.HIGHEST_PROTOCOL)

# in the event you're tinkering with mannequin architectures load beforehand saved embeddings
else:
min_class = pd.read_pickle(toc_path)
max_class = pd.read_pickle(bt_path)

# Match the variety of minority class samples
max_down = resample(
max_class,
substitute=False,
n_samples=len(min_class),
random_state=42,
)
balanced_df = pd.concat([min_class, max_down])

# Shuffle the DataFrame
balanced_df = balanced_df.pattern(frac=1).reset_index(drop=True)
return balanced_df

def _train_model(df: pd.DataFrame) -> dict:
"""
Practice the SVM on our embeddings
"""

print("coaching SVM")

X_train, X_test, y_train, y_test = train_test_split(
df["features"].tolist(), df["label"].tolist(), test_size=0.33, random_state=42
)
clf = SVC(gamma="auto")
clf.match(X_train, y_train)
y_pred = clf.predict(X_test)

print(accuracy_score(y_test, y_pred))

# dumping mannequin
with open("./fashions/resume_clf.pkl", "wb") as f:
pickle.dump(clf, f)

def predominant():
df = _get_embeddings(embed=True)
_train_model(df)

if __name__ == "__main__":
predominant()



Source link

HINTERLASSEN SIE EINE ANTWORT

Please enter your comment!
Please enter your name here