Hogyan Dolgozódnak Fel a Feliratok?
A process_caption
metódus egy átfogó függvény, amelyet arra terveztek, hogy a feliratokat nagy mértékű testreszabással dolgozza fel a BaseSubset objektumban meghatározott beállítások alapján. Nézzük meg ennek a módszernek a technikai részleteit és matematikai aspektusait.
Felirat Előtag és Utótag
A módszer azzal kezdődik, hogy ellenőrzi, vannak-e előtagok vagy utótagok definiálva a subset objektumban. Ha vannak, ezek hozzáadódnak a felirat elejéhez és végéhez. Ez egyszerű szöveg összefűzés:
if subset.caption_prefix:
caption = subset.caption_prefix + " " + caption
if subset.caption_suffix:
caption = caption + " " + subset.caption_suffix
Kiejtési Mechanizmus
Ezután a módszer meghatározza, hogy a feliratot ki kell-e ejteni. Ezt a caption_dropout_rate
és caption_dropout_every_n_epochs
paraméterek kiértékelésével teszi. A kiejtési mechanizmus véletlenszerűséget visz a folyamatba, ami hasznos lehet az adatbővítéshez vagy a túltanulás megelőzéséhez a tréning során. A kiejtés valószínűségét egy véletlenszám generálás és a kiejtési rátával való összehasonlítás határozza meg:
is_drop_out = subset.caption_dropout_rate > 0 and random.random() < subset.caption_dropout_rate
is_drop_out = (
is_drop_out
or (subset.caption_dropout_every_n_epochs > 0
and self.current_epoch % subset.caption_dropout_every_n_epochs == 0)
)
Helyettesítő Karakterek Feldolgozása
Ha az enable_wildcard
paraméter True
-ra van állítva, a függvény feldolgozza a feliratban található helyettesítő karaktereket.
A helyettesítő karakterek olyan helyőrzők {opció1|opció2|...}
formában, ahol az opciók közül véletlenszerűen választódik ki egy és kerül beillesztésre a helyettesítő karakter helyére.
A helyettesítő karakterek feldolgozása a következő lépésekből áll:
Ha a felirat tartalmaz újsor karaktereket \n
, a függvény véletlenszerűen kiválaszt egyet a sorok közül.
Az escapelt kapcsos zárójelek {{
és }}
ideiglenesen speciális Unicode karakterekre ⦅
és ⦆
cserélődnek, hogy elkerüljük a helyettesítő karakterekkel való keveredést.
Egy reguláris kifejezés r"\{([^}]+)\}"
szolgál a helyettesítő karakter minták egyeztetésére, és a replace_wildcard
függvény hívódik meg minden egyezésre:
def replace_wildcard(match):
return random.choice(match.group(1).split("|"))
Ez a függvény szétválasztja az egyező karakterláncot (a helyettesítő karakter opciókat) a |
elválasztó mentén, kiválaszt egy véletlenszerű opciót a létrejövő listából a random.choice segítségével, és ezt az opciót adja vissza a helyettesítő karakter helyettesítéseként.
Az összes helyettesítő karakter cseréje után az escapelt kapcsos zárójelek visszaállnak eredeti formájukba.
Ha a helyettesítő karakterek nincsenek engedélyezve és a felirat tartalmaz újsorokat, csak az első sor marad meg: caption = caption.split("\n")[0]
.
Token Manipuláció
A függvény fejlett token manipulációs funkciókat kínál, beleértve a keverést, a bemelegítést és a kiejtést. A tokenek a felirat egyes szavai vagy szimbólumai. A tokenek keverése segíthet a modellnek robusztusabb reprezentációkat tanulni azáltal, hogy az adatokat különböző sorrendben mutatja be. A token bemelegítési mechanizmus egy olyan tananyag-tanulási forma, ahol az adatok komplexitása fokozatosan növekszik a tréning során. A bemelegítési lépés alapján megtartandó tokenek számának kiszámítására szolgáló matematikai képlet a következő:
$$ \text{tokens_len} = \left\lfloor \left( \text{self.current_step} \right) \times \left( \frac{\text{len(flex_tokens)} - \text{subset.token_warmup_min}}{\text{subset.token_warmup_step}} \right) \right\rfloor + \text{subset.token_warmup_min} $$vagy Pythonban:
tokens_len = math.floor(self.current_step * ((len(flex_tokens) - subset.token_warmup_min) / subset.token_warmup_step)) + subset.token_warmup_min
- Token Kiejtés: Ha a
caption_tag_dropout_rate
nagyobb mint 0, adropout_tags
függvény használatos a tokenek véletlenszerű kiejtésére a megadott kiejtési ráta alapján. - Tokenek Keverése: Ha a
shuffle_caption
True
-ra van állítva a subset-ben, a függvény összekeveri a rugalmas tokenek sorrendjét. Ez a véletlenszerűsítés segíthet a modellnek elkerülni, hogy olyan mintákat tanuljon, amelyek a szavak sorrendjén alapulnak, ami esetleg nem releváns. - Token Kombinálás: A végső felirat a
fixed_tokens
,flex_tokens
ésfixed_suffix_tokens
kombinálásával jön létre, vesszővel elválasztva. - Másodlagos Elválasztó Cseréje: Ha egy
secondary_separator
van definiálva, az lecserélődik az elsődlegescaption_separator
-ra a végső feliratban.
A kód ezen része biztosítja, hogy a felirat dinamikusan módosuljon a subset beállításai szerint, potenciálisan beleértve a véletlenszerűsítést és bizonyos tokenek szelektív megtartását.
Szöveges Inverzió Helyettesítések
A függvény szöveges inverzió helyettesítéseket is alkalmaz, ami magában foglalja specifikus karakterláncok cseréjét előre definiált helyettesítésekre a feliratban. Ezek a helyettesítések a self.replacements szótárban tárolódnak, ahol a kulcsok a helyettesítendő karakterláncok és az értékek a megfelelő helyettesítések.
Ha a kulcs a self.replacements
szótárban egy üres karakterlánc, a teljes felirat lecserélődik egy véletlenszerű választásra a helyettesítések listájából (ha az érték egy lista) vagy magára a helyettesítő karakterláncra. Egyébként a kulcs karakterlánc minden előfordulása a feliratban lecserélődik a megfelelő helyettesítési értékre.
Az összes ilyen transzformáció alkalmazása után a feldolgozott felirat visszaadódik a függvény által.
Alább található a függvény kommentezett verziója az sd-scripts-ből.
def process_caption(self, subset: BaseSubset, caption: str) -> str:
"""
Feldolgoz egy feliratot a subset-ben definiált különböző paraméterek alapján.
A módszer előtagokat és utótagokat alkalmaz, kezeli a kiejtést a felirat törlésével vagy megtartásával,
feldolgozza a helyettesítő karaktereket, keveri a tokeneket és alkalmazza a szöveges inverzió helyettesítéseket.
Kezeli a többsoros feliratokat is, vagy egy véletlenszerű sor választásával (ha a helyettesítő karakterek engedélyezve vannak)
vagy az első sor használatával.
Paraméterek:
- subset (BaseSubset): Egy objektum, amely különböző beállításokat tartalmaz a felirat feldolgozásához.
- caption (str): A kezdeti felirat szöveg, amit fel kell dolgozni.
Visszatérési érték:
- str: A feldolgozott felirat az összes transzformáció alkalmazása után.
"""
# Előtag és utótag hozzáadása a felirathoz, ha definiálva vannak.
if subset.caption_prefix:
caption = subset.caption_prefix + " " + caption
if subset.caption_suffix:
caption = caption + " " + subset.caption_suffix
# Annak meghatározása, hogy a feliratot ki kell-e ejteni a kiejtési ráta és epoch beállítások alapján.
is_drop_out = subset.caption_dropout_rate > 0 and random.random() < subset.caption_dropout_rate
is_drop_out = (
is_drop_out
or (subset.caption_dropout_every_n_epochs > 0
and self.current_epoch % subset.caption_dropout_every_n_epochs == 0)
)
# Ha a kiejtési feltétel teljesül, töröljük a feliratot.
if is_drop_out:
caption = ""
else:
# Helyettesítő karakterek feldolgozása, ha engedélyezve van.
if subset.enable_wildcard:
# Ha a feliratnak több sora van, véletlenszerűen választunk egyet.
if "\n" in caption:
caption = random.choice(caption.split("\n"))
# Escapelt kapcsos zárójelek kezelése.
replacer1 = "⦅"
replacer2 = "⦆"
while replacer1 in caption or replacer2 in caption:
replacer1 += "⦅"
replacer2 += "⦆"
caption = caption.replace("{{", replacer1).replace("}}", replacer2)
# Függvény a helyettesítő karakterek véletlenszerű választással való cseréjéhez.
def replace_wildcard(match):
return random.choice(match.group(1).split("|"))
# Helyettesítő karakterek cseréje véletlenszerű választással az opciókból.
caption = re.sub(r"\{([^}]+)\}", replace_wildcard, caption)
# Kapcsos zárójelek visszaállítása.
caption = caption.replace(replacer1, "{").replace(replacer2, "}")
else:
# Ha a helyettesítő karakterek nincsenek engedélyezve és a felirat többsoros, használjuk az első sort.
caption = caption.split("\n")[0]
# Tokenek keverése, token bemelegítés alkalmazása és címkék kiejtése, ha meg van adva.
if subset.shuffle_caption or subset.token_warmup_step > 0 or subset.caption_tag_dropout_rate > 0:
fixed_tokens = []
flex_tokens = []
fixed_suffix_tokens = []
# A felirat felosztása fix és rugalmas részekre, ha van definiálva elválasztó.
if (hasattr(subset, "keep_tokens_separator") and subset.keep_tokens_separator
and subset.keep_tokens_separator in caption):
fixed_part, flex_part = caption.split(subset.keep_tokens_separator, 1)
if subset.keep_tokens_separator in flex_part:
flex_part, fixed_suffix_part = flex_part.split(subset.keep_tokens_separator, 1)
fixed_suffix_tokens = [t.strip() for t in fixed_suffix_part.split(subset.caption_separator) if t.strip()]
fixed_tokens = [t.strip() for t in fixed_part.split(subset.caption_separator) if t.strip()]
flex_tokens = [t.strip() for t in flex_part.split(subset.caption_separator) if t.strip()]
else:
# Ha nincs definiálva elválasztó, minden tokent rugalmasnak tekintünk.
tokens = [t.strip() for t in caption.strip().split(subset.caption_separator)]
flex_tokens = tokens[:]
if subset.keep_tokens > 0:
fixed_tokens = flex_tokens[: subset.keep_tokens]
flex_tokens = tokens[subset.keep_tokens:]
# A megtartandó tokenek számának kiszámítása a bemelegítési lépés alapján.
if subset.token_warmup_step < 1:
subset.token_warmup_step = math.floor(subset.token_warmup_step * self.max_train_steps)
if subset.token_warmup_step and self.current_step < subset.token_warmup_step:
tokens_len = (
math.floor(
(self.current_step) * ((len(flex_tokens) - subset.token_warmup_min) / (subset.token_warmup_step))
)
+ subset.token_warmup_min
)
flex_tokens = flex_tokens[:tokens_len]
# Függvény a címkék kiejtésére a kiejtési ráta alapján.
def dropout_tags(tokens):
if subset.caption_tag_dropout_rate <= 0:
return tokens
return [token for token in tokens if random.random() >= subset.caption_tag_dropout_rate]
# Rugalmas tokenek keverése, ha meg van adva.
if subset.shuffle_caption:
random.shuffle(flex_tokens)
# Címke kiejtés alkalmazása a rugalmas tokenekre.
flex_tokens = dropout_tags(flex_tokens)
# A fix, rugalmas és fix utótag tokenek kombinálása a végső feliratba.
caption = ", ".join(fixed_tokens + flex_tokens + fixed_suffix_tokens)
# A másodlagos elválasztó cseréje az elsődlegesre, ha definiálva van.
if subset.secondary_separator:
caption = caption.replace(subset.secondary_separator, subset.caption_separator)
# Szöveges inverzió helyettesítések alkalmazása.
for str_from, str_to in self.replacements.items():
if str_from == "":
# Ha a helyettesítő karakterlánc üres, cseréljük le az egész feliratot.
caption = random.choice(str_to) if type(str_to) == list else str_to
else:
# Specifikus karakterláncok cseréje a megfelelő helyettesítésekre.
caption = caption.replace(str_from, str_to)
return caption