Vollständig Durchgang Hier optimieren wir einen Transformer für die Named-Entity Recognition (NER) mithilfe von Weak Supervision.
Schwache Supervision ist ein Ansatz für maschinelles Lernen, bei dem hochwertige und oft lautere Supervisionsquellen verwendet werden, um viel schneller viel größere Trainingssätze zu erstellen, als dies sonst durch manuelle Supervision möglich wäre
— Schnorchel-KI
In diesem Beitrag werden „viele“ Beschriftungs- und Aggregatfunktionen verwendet, um eine einzige Quelle für die Feinabstimmung unseres Transformers zu erstellen.
Die schwache Überwachung mit Token-Klassifizierung ist etwas umständlich, wenn verschiedene Ausgaben der Kennzeichnungsfunktion miteinander kombiniert werden. Um dies zu umgehen, werden wir die Methoden „Mehrheitsabstimmung“ und „Union Combination“ verwenden, um „viele“ Bezeichnungen auf eine einzige nutzbare Quelle zu reduzieren.
Dieser gesamte Prozess wird über die Befehlszeile mithilfe von verwaltet extr-ds Bibliothek (Github-Repository).
pip set up extr-ds
Der Code für dieses Projekt ist zu finden – Github-Repository.
Daten
Beschriftung
Einrichten von sechs kleinen Beschriftungsfunktionen, um unseren Datensatz programmgesteuert zu kennzeichnen. Die Ausgabe dieser Beschriftungsfunktionen wird zusammengeführt, um unseren schwach beschrifteten (IOB2) Datensatz zu erstellen.
from typing import Record, Dict, Optionally availableimport re
import nltk
from extr import RegExLabel, RegEx
from extr.entities import create_entity_extractor
from extr_ds.guidelines import StaticUnit
class RegExStaticUnit(StaticUnit):
def __init__(self,
regex_labels: Record[RegExLabel],
kb: Optionally available[Dict[str, List[str]]] = None) -> None:
tremendous().__init__(
nltk.tokenize.word_tokenize,
create_entity_extractor(
regex_labels=regex_labels,
kb=kb
)
)
Spieler
class Participant(RegExStaticUnit):
def __init__(self) -> None:
tremendous().__init__(
regex_labels=[
RegExLabel(
label='PLAYER',
regexes=[
RegEx(
expressions=[
r'b[A-Z][a-z]?.[A-Z][a-z]+b',
r'b[A-Z][a-z]?.[A-Z]'[A-Z][a-z]+b',
r'(?<=Go From ).+?(?= for)',
r'(?<=) ).+?(?= Go From)',
]
)
]
)
]
)
Crew
class Crew(RegExStaticUnit):
def __init__(self) -> None:
tremendous().__init__(
regex_labels=[],
kb={
'TEAM': [
'ARZ',
'Arizona',
'ATL',
...
]
}
)
Zeitraum
class Time(RegExStaticUnit):
def __init__(self):
tremendous().__init__(
regex_labels=[
RegExLabel(
label='TIME',
regexes=[
RegEx(
expressions=[
r'b[0-9]{1,2}:[0-9]{2}b',
]
)
]
)
]
)class Interval(RegExStaticUnit):
def __init__(self):
tremendous().__init__(
regex_labels=[],
kb={
'PERIOD': [
'1st',
'2nd',
'3rd',
'4th',
'OT',
],
}
)
Menge/Einheiten
class Amount(StaticUnit):
def __init__(self):
tremendous().__init__(
regex_labels=[
RegExLabel(
label='QUANTITY',
regexes=[
RegEx(expressions=[
r'(?<=[s(])-?d{1,3}(?=b)',
])
]
)
]
)class Models(StaticUnit):
def __init__(self):
tremendous().__init__(
regex_labels=[
RegExLabel(
label='UNITS',
regexes=[
RegEx(
expressions=[
r'b(y(?:ar)?ds)b',
],
flags=re.IGNORECASE
)
]
)
]
)
Verschmelzen
Wir werden ein grundlegendes Merge-Setup (Union) verwenden. Benutzen StaticUnit
erzeugt eine höhere Konfidenz für gefundene Entitäten (99 %) und eine etwas geringere, aber konsistente Konfidenz für nicht gefundene Anmerkungen (90 %).
labeling_functions = [
Player(),
Team(),
Time(),
Period(),
Quantity(),
Units(),
]def clear(textual content: str) -> str
...
return textual content
def annotate(doc: str) -> Dict[str, List[str]]:
textual content = clear(doc)
outcomes = labeling_functions[0](textual content)
for labeling_function in labeling_functions[1:]:
outcomes = create_static_inference_result(
labels=Majority().merge([
results,
labeling_function(text),
]),
weight=outcomes.weight
)
return {
'tokens': nltk.tokenize.word_tokenize(textual content),
'labels': outcomes.labels
}
[
'B-PLAYER',
'O',
'B-QUANTITY',
'B-UNITS',
'O',
'B-TEAM',
'B-QUANTITY',
'O',
'B-TEAM',
'B-QUANTITY',
'O',
'B-PLAYER',
'O',
'B-TEAM',
'B-QUANTITY',
'O',
'B-QUANTITY',
'B-UNITS',
'O',
'B-PLAYER',
'O',
'B-PLAYER',
'O',
'O'
]
*** Dies könnte leicht erweitert werden, sodass Beschriftungsfunktionen miteinander konkurrieren. — Sie könnten eine Reihe verschiedener NER-Modelle trainieren und eine Mehrheitsabstimmung auf ihre Beobachtungen anwenden, um einen beschrifteten Datensatz zu erstellen. ***
Feinabstimmung
Dieser Teil wurde in einem früheren Beitrag behandelt – siehe Erstellen benutzerdefinierter NER-Modelle (Named-Entity Recognition) – Transformers.
import randomokay = 1000
with open('./supply.txt', 'r') as source_input:
rows = source_input.learn().cut up('n')
random.seed(42)
random.shuffle(rows)
annotations = []
for row in rows[0:k]:
annotations.append(
annotate(row)
)
with open('./ents-iob.json', 'w') as output_iob:
output_iob.write(json.dumps(annotations))
Nach dem Coaching können wir sehen, dass es mit einem kleinen Datensatz einfach nicht möglich battle, 100 % zu erreichen. In diesem Fall findet unser Transformator tatsächlich Entitäten in unserem Trainings-/Testdatensatz, die nicht gekennzeichnet sind.
Im folgenden Beispiel ist unser Transformator beschriftet Okay.Van Noy
als [B-PLAYER, I-PLAYER]
was unser Participant
Die Beschriftungsfunktion hätte nur beschriftet Okay.Van
als B-PLAYER
[
{
'text': '(6:51 - 1st) (Shotgun) P.Mahomes scrambles right end to LAC 34 for 2 yards (S.Joseph; K.Van Noy). FUMBLES (S.Joseph), and recovers at LAC 34.',
'iob': [
{
'tokens': ['(', '6:51', '-', '1st', ')', '(', 'Shotgun', ')', 'P.Mahomes', 'scrambles', 'right', 'end', 'to', 'LAC', '34', 'for', '2', 'yards', '(', 'S.Joseph', ';', 'K.Van', 'Noy', ')', '.', 'FUMBLES', '(', 'S.Joseph', ')', ',', 'and', 'recovers', 'at', 'LAC', '34', '.'],
'labels': ['O', 'B-TIME', 'O', 'B-PERIOD', 'O', 'O', 'O', 'O', 'B-PLAYER', 'O', 'O', 'O', 'O', 'B-TEAM', 'B-QUANTITY', 'O', 'B-QUANTITY', 'B-UNITS', 'O', 'B-PLAYER', 'O', 'B-PLAYER', 'I-PLAYER', 'O', 'O', 'O', 'O', 'B-PLAYER', 'O', 'O', 'O', 'O', 'O', 'B-TEAM', 'B-QUANTITY', 'O']
}
]
}
]
An diesem Punkt könnten wir unseren Transformator in unsere Etikettierung integrieren oder die vorhandenen Etikettierungsfunktionen aktualisieren und noch einmal verfeinern. In jedem Fall wird dies zu einem iterativen Prozess.
Nutzen – Der Datensatz, den ich hier verwendet habe, enthält über 40.000 Zeilen. Dieser Ansatz erzeugte innerhalb weniger Minuten einen vollständig beschrifteten Datensatz.
Warnung – Wenn Sie sich die Mühe machen, den Datensatz zu überprüfen, stellen Sie sicher, dass Sie diese Anmerkungen speichern und sie bei jeder Iteration an Ihren Trainingssatz anhängen.
Es gibt verschiedene Methoden, um Ihre Ergebnisse iterativ zu verbessern, siehe Feinabstimmung eines vorab trainierten Sprachmodells mit schwacher Überwachung: Ein kontrastiv-regulierter Selbsttrainingsansatz zum Beispiel.