Training von Loras // Civitai-Variante

Im Bereich der Contentproduktion inkl. Befüllung von Blogs + SocialMedia-Accounts wird der Einsatz moderner KI-Methoden immer interessanter u. eine Variante ist die Bildgenerierung mit Hilfe von StableDiffusion.

Ich mag SD / SDXL (StableDiffusion) wegen der unkomplizierten Organisation und der beachtlichen Qualität. Ein wichtiges Kernelement sind die Loras, hierbei möchte ich nicht zuviel Technik erklären und nur auf EINE Trainingsmöglichkeit eingehen.

Wozu das Training? Antwort: Loras kann man im Grunde als „kleine“ trainierte Modelle, die Informationen zu der Darstellung von „Umgebungen“, „Lichtverhältnisse“ oder auch kleine + große Objekte beinhalten können.

Ich trainiere aktuell unsere Loras mit Hilfe der Plattform: https://civitai.com/login?ref_code=WOB-CEH (Ref.-Link). Diese Plattform vergleiche ich gerne mit einer Art Facebook für Digital-Künstler:innen.

Zum Training (Achtung: Besorge Dir da einen Account!)

  1. https://civitai.com/models/train
  2. Dem Lora einen Namen geben (Bspw: KB_Kentmere400 für das Training auf Basis meiner Negativscans | Fotolanor)
  3. Auf die Kachel „Concept“ Clicken
  4. Alles Bestätigen
  5. Bilder hochladen und Label definieren (Label dient im Nachgang auch als „Triggerword“, daher Label GUT definieren und notieren!)

Rest: siehe Galerie.

Hier alles bestätigen, die 500 „Buzz“ bezahlen und den Trainingsprozess auslösen!

Tipps & Tricks für die Erstellung von CSV-Produktkatalogen für Affiliate-Webseiten

[Hinweis: Dieser Artikel erschien auf dieser Seite bereits im Jahre 2014. Da er noch immer aktuell ist, haben wir ihn im März 2024 überarbeitet und neu publiziert.]

Für unsere Affiliate-Blogs sind wir auf qualitativ hochwertige Produktkataloge im Format CSV oder XML angewiesen. Leider passiert es recht häufig, dass diese Dateien fehlerhaft oder nur sehr unzureichend mit Informationen ausgestattet sind. Aus diesem Grund fasse ich hier zusammen, worauf wir besonderen Wert legen.

In aller Kürze:

✔ CSV-Dateien aktuell und übersichtlich halten mit einer Anzahl von Produkten zwischen 150 bis ca. 3.000
✔ Eindeutige und aussagekräftige Produkttitel bzw. Produktnamen
✔ Individuelle Produktbeschreibungen (auch gern mit HTML/CSS) für individuelle Produkte, keine Produkt-Dubletten vom gleichen Produkt in z. B. anderen Farben
✔ Strukturierung in Form von Produktkategorien
✔ Aussagekräftige Produktfotos

Die ausführliche Variante:

Der Produkttitel bzw. Produktname sollte eindeutig und aussagekräftig sein. Vermeiden Sie z.B. dreihundert verschiedene Produkte mit demselben Produktnamen „Esstisch“. So sind Produkte sowohl übers Frontend, Backend als auch via Suchmaschinen besser auffindbar, leichter zu verwalten und schneller wiederzuerkennen.

Halten Sie Ihre CSVs bzw. die Produkte darin unbedingt aktuell. Stellen Sie sich den Frust vor, wenn Kundschaft glaubt, ein Produkt auf einer Affiliate-Seite gefunden zu haben und im Zielshop feststellen muss, dass es dort längst nicht mehr verkauft wird.

✔ Wenn Sie ein Produkt in verschiedenen Ausführungen im Sortiment haben (z.B. eine Lampe in 10 verschiedenen Farben) und jede Variation davon einzeln in die CSV einbinden, achten Sie bitte unbedingt auf individuelle Produkttitel und individuelle Produktbeschreibungen. Leider müssen wir regelmäßig komplette CSV-Datensätze mit teilweise tollen Produkten verwerfen, die zu großen Teilen aus Produkt-Dubletten bestehen und es in keinem Verhältnis zur aufgewendeten Zeit stünde, diese händisch (auch nach regelmäßigen Updates) zu editieren. Gerade für Affiliate-Marketing empfiehlt es sich daher, in die CSV nur ein Artikel einer Reihe aufzunehmen und in der Produktbeschreibung auf die verschiedenen Varianten im Zielshop hinzuweisen. Positiver Nebeneffekt hierbei ist, dass Sie nur eine aussagekräftige Produktbeschreibung brauchen und Ihre CSV automatisch übersichtlicher wird.

Machen Sie sich Gedanken über Ihre Produktkategorien. Unseren Erfahrungen nach lassen sich Inhalte von Affiliate-Blogs sehr gut mit Hilfe von Produktkategorien strukturieren, über die wiederum potentielle Käufer*innen schnell und einfach innerhalb der Seiten navigieren können. „Möbel“ taugt gut als eine Oberkategorie für Möbelstücke, lässt aber auch viel Spielraum für Konkretisierungen: Esszimmerstühle, Beistelltische, Garderoben etc. „Sonstiges“ oder auch „Sale“ eignen sich nicht als Produktkategorie. Je vielfältiger und genauer Ihre Produktkategorisierungen, desto größer sind unsere Möglichkeiten, die Affiliate-Webseite thematisch zu optimieren. Das Gleiche gilt übrigens auch für Produktschlagwörter.

✔ Noch ein, zwei Bemerkungen zu den Produktbeschreibungen. Nicht zu unterschätzen sind wie immer korrekte Orthographie & Grammatik. Beschreiben Sie Ihre Produkte so ausführlich wie möglich. Hierbei können Sie mit der Editiersprache HTML direkten Einfluss nehmen auf die Darstellung Ihres Produkttextes. Bedenken Sie auch, dass sich potentielle Kundschaft noch nicht auf Ihrem Webshop befindet, sondern Ihre Produkte in dem Moment auf einer Affiliate-Seite studiert, die viele Informationen und Zusammenhänge nicht transportiert, die auf Ihren Seiten für die Kund*innen sofort ersichtlich wären. Es sind Ihre Texte, Fotos und Details, die potentielle Kund*innen animieren (können), Ihren Webshop zu besuchen und eventuell eines Ihrer Produkte zu kaufen.

✔ Im Absatz über Produkt-Dubletten habe ich bereits die Übersichtlichkeit von CSV-Dateien angesprochen. Gelegentlich stolpern wir über CSVs, die komplett vollgestopft sind mit Tausenden von Artikeln und oft die riesige Produktbandbreite eines einzelnen Onlineshops abbilden. Mit diesen CSVs können wir leider gar nichts anfangen, seitdem wir aufgehört haben, externe CSVs eigenhändig zu editieren (und wir spätestens beim ersten Update der CSV wieder vor demselben Problem stünden).
Überlegen Sie sich daher genau, welche Produkte Sie in Ihre Affiliate-CSV aufnehmen. Unseren Erfahrungen nach lohnt es sich, eine Auswahl an z.B. hochpreisigen Produkten („Knallerprodukte“) Ihres Kerngeschäfts bereitzustellen und auf all die kleinen „Nebenprodukte“ wie z.B. Ersatzteile zu verzichten. Ziehen Sie auch in Betracht, mehrere CSVs mit verschiedenen thematischen Schwerpunkten für das Affiliate-Marketing anzubieten. Für unseren Gebrauch hat eine CSV eine annehmbare, gut einzupflegende Größe, wenn sie zwischen 150 und 3.000 Produkte enthält.

Haben Sie unbedingt ein besonderes Augenmerk auf die Fotos in Ihren Produktkatalogen. Eine CSV-Datei ohne Fotos bzw. den URLs zu diesen Fotos ist für uns unbrauchbar. Dies ist zum Glück eher selten der Fall. Öfter kommt es aber vor, dass einzelne Foto-URLs falsch sind oder auf fehlende Dateien auf Servern verweisen. Von uns gern gesehen sind auch CSVs mit einem Angebot an verschieden großen Fotos (Thumbnail, mittel bis sehr groß). Achten Sie hierbei bitte auf eine userfreundliche Auflösung und Dateigröße der Fotos.

Testreihe // Validierung von Modellen (KI-generierte Portraits (6)

Prompt: „front shot, portrait photo of a 25 y.o french woman, looks away, natural skin, skin moles, cozy interior, (cinematic,kodak portra 200, 35mm film grain)1.1“

Negativ-Prompt: „(worst quality, low quality, normal quality, lowres, low details, oversaturated, undersaturated, overexposed, underexposed, grayscale, bw, bad photo, bad photography, bad art)1.4, (watermark, signature, text font, username, error, logo, words, letters, digits, autograph, trademark, name)1.2, (blur, blurry, grainy)+, morbid, ugly, asymmetrical, mutated malformed, mutilated, poorly lit, bad shadow, draft, cropped, out of frame, cut off, censored, jpeg artifacts, out of focus, glitch, duplicate, (airbrushed, cartoon, anime, semi-realistic, cgi, render, blender, digital art, manga, amateur)1.3, (3D ,3D Game, 3D Game Scene, 3D Character)1.1, (bad hands, bad anatomy, bad body, bad face, bad teeth, bad arms, bad legs, deformities)1.3“

Model: sdvn6Realxl_detailface

Testreihe // Validierung von Modellen (KI-generierte Portraits (5)

Prompt: „front shot, portrait photo of a 25 y.o french woman, looks away, natural skin, skin moles, cozy interior, (cinematic,kodak portra 200, 35mm film grain)1.1“

Negativ-Prompt: „(worst quality, low quality, normal quality, lowres, low details, oversaturated, undersaturated, overexposed, underexposed, grayscale, bw, bad photo, bad photography, bad art)1.4, (watermark, signature, text font, username, error, logo, words, letters, digits, autograph, trademark, name)1.2, (blur, blurry, grainy)+, morbid, ugly, asymmetrical, mutated malformed, mutilated, poorly lit, bad shadow, draft, cropped, out of frame, cut off, censored, jpeg artifacts, out of focus, glitch, duplicate, (airbrushed, cartoon, anime, semi-realistic, cgi, render, blender, digital art, manga, amateur)1.3, (3D ,3D Game, 3D Game Scene, 3D Character)1.1, (bad hands, bad anatomy, bad body, bad face, bad teeth, bad arms, bad legs, deformities)1.3“

Model: theTrualityEngine_trualityENGINEPRO.safetensors.diff

Testreihe // Validierung von Modellen (KI-generierte Portraits (4)

Prompt: „front shot, portrait photo of a 25 y.o french woman, looks away, natural skin, skin moles, cozy interior, (cinematic,kodak portra 200, 35mm film grain)1.1“

Negativ-Prompt: „(worst quality, low quality, normal quality, lowres, low details, oversaturated, undersaturated, overexposed, underexposed, grayscale, bw, bad photo, bad photography, bad art)1.4, (watermark, signature, text font, username, error, logo, words, letters, digits, autograph, trademark, name)1.2, (blur, blurry, grainy)+, morbid, ugly, asymmetrical, mutated malformed, mutilated, poorly lit, bad shadow, draft, cropped, out of frame, cut off, censored, jpeg artifacts, out of focus, glitch, duplicate, (airbrushed, cartoon, anime, semi-realistic, cgi, render, blender, digital art, manga, amateur)1.3, (3D ,3D Game, 3D Game Scene, 3D Character)1.1, (bad hands, bad anatomy, bad body, bad face, bad teeth, bad arms, bad legs, deformities)1.3“

Model: epicphotogasm_lastUnicorn.safetensors.diff

Testreihe // Validierung von Modellen (KI-generierte Portraits (3)

Prompt: „front shot, portrait photo of a 25 y.o french woman, looks away, natural skin, skin moles, cozy interior, (cinematic,kodak portra 200, 35mm film grain)1.1“

Negativ-Prompt: „(worst quality, low quality, normal quality, lowres, low details, oversaturated, undersaturated, overexposed, underexposed, grayscale, bw, bad photo, bad photography, bad art)1.4, (watermark, signature, text font, username, error, logo, words, letters, digits, autograph, trademark, name)1.2, (blur, blurry, grainy)+, morbid, ugly, asymmetrical, mutated malformed, mutilated, poorly lit, bad shadow, draft, cropped, out of frame, cut off, censored, jpeg artifacts, out of focus, glitch, duplicate, (airbrushed, cartoon, anime, semi-realistic, cgi, render, blender, digital art, manga, amateur)1.3, (3D ,3D Game, 3D Game Scene, 3D Character)1.1, (bad hands, bad anatomy, bad body, bad face, bad teeth, bad arms, bad legs, deformities)1.3“

SG161222-RealVisXL_V3.0

Testreihe // Validierung von Modellen (KI-generierte Portraits (2)

Prompt: „front shot, portrait photo of a 25 y.o french woman, looks away, natural skin, skin moles, cozy interior, (cinematic,kodak portra 200, 35mm film grain)1.1“

Negativ-Prompt: „(worst quality, low quality, normal quality, lowres, low details, oversaturated, undersaturated, overexposed, underexposed, grayscale, bw, bad photo, bad photography, bad art)1.4, (watermark, signature, text font, username, error, logo, words, letters, digits, autograph, trademark, name)1.2, (blur, blurry, grainy)+, morbid, ugly, asymmetrical, mutated malformed, mutilated, poorly lit, bad shadow, draft, cropped, out of frame, cut off, censored, jpeg artifacts, out of focus, glitch, duplicate, (airbrushed, cartoon, anime, semi-realistic, cgi, render, blender, digital art, manga, amateur)1.3, (3D ,3D Game, 3D Game Scene, 3D Character)1.1, (bad hands, bad anatomy, bad body, bad face, bad teeth, bad arms, bad legs, deformities)1.3“

Model: newrealityxlAllInOne_21.safetensors.diff

Testreihe // Validierung von Modellen (KI-generierte Portraits (1)

Prompt: „front shot, portrait photo of a 25 y.o french woman, looks away, natural skin, skin moles, cozy interior, (cinematic,kodak portra 200, 35mm film grain)1.1“

Negativ-Prompt: „(worst quality, low quality, normal quality, lowres, low details, oversaturated, undersaturated, overexposed, underexposed, grayscale, bw, bad photo, bad photography, bad art)1.4, (watermark, signature, text font, username, error, logo, words, letters, digits, autograph, trademark, name)1.2, (blur, blurry, grainy)+, morbid, ugly, asymmetrical, mutated malformed, mutilated, poorly lit, bad shadow, draft, cropped, out of frame, cut off, censored, jpeg artifacts, out of focus, glitch, duplicate, (airbrushed, cartoon, anime, semi-realistic, cgi, render, blender, digital art, manga, amateur)1.3, (3D ,3D Game, 3D Game Scene, 3D Character)1.1, (bad hands, bad anatomy, bad body, bad face, bad teeth, bad arms, bad legs, deformities)1.3“

Model: stablediffusionapi-juggernaut-xl-v8

Scriptbeispiel: automatische Textgenerierung mit GPT4All und em_german_mistral_v01.Q4_0.gguf

import os
from gpt4all import GPT4All
import keyboard

# Modell initialisieren
model = GPT4All("em_german_mistral_v01.Q4_0.gguf")

# Eingabeaufforderung für Titel abfragen
titel = input("Titel/Dateiname: ")

# Eingabeaufforderung für Anweisung abfragen
eingabeaufforderung = input("Hier bitte die Anweisung eintragen und mit Enter bestätigen: ")

# Ordner "output" erstellen, wenn er nicht existiert
output_ordner = "output"
if not os.path.exists(output_ordner):
    os.makedirs(output_ordner)

# Generierung der Texte 10-mal durchlaufen lassen
for i in range(1, 11):
    # Ausgabe generieren
    output = model.generate(eingabeaufforderung, max_tokens=5000)
    
    # Output in eine Datei im Ordner "output" speichern
    output_dateipfad = os.path.join(output_ordner, f"{titel}_{i}.txt")
    with open(output_dateipfad, "w", encoding="utf-8") as datei:
        datei.write(output)

    # Ausgabe anzeigen
    print(f"Output wurde unter dem Titel '{titel}_{i}' im Ordner 'output' gespeichert.")

Scriptbeispiel: Analyse von Deepfake-Videos via Pixelrauschenprüfung + KI

import cv2
import numpy as np
import os
import matplotlib.pyplot as plt

def process_frame(frame, threshold, grid_size, face_cascade):
    # Wandle das Bild in Graustufen um
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Suche nach Gesichtern im Bild
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)

    noise_frames = []

    # Wenn Gesichter gefunden wurden, sortiere sie nach Größe
    if len(faces) > 0:
        # Sortiere Gesichter nach Fläche (Größe)
        faces = sorted(faces, key=lambda x: x[2] * x[3], reverse=True)

        # Verwende nur das größte Gesicht
        (x, y, w, h) = faces[0]

        # Begrenze die Bildverarbeitung auf das Gesicht (ROI)
        face_roi = frame[y:y+h, x:x+w]

        # Teile das Gesicht in Bereiche auf
        regions = np.array_split(face_roi, grid_size[0], axis=0)
        regions = [np.array_split(region, grid_size[1], axis=1) for region in regions]

        std_deviations = [[np.std(region) for region in row] for row in regions]

        # Berechne den Durchschnitt des Pixelrauschens in der Gesichtsregion
        face_avg_noise = np.mean(std_deviations)

        for i, row in enumerate(std_deviations):
            for j, std_deviation in enumerate(row):
                # Vergleiche das Pixelrauschen mit dem Durchschnitt der Gesichtsregion
                if std_deviation > threshold * face_avg_noise:
                    noise_frames.append((i, j, (x, y, w, h)))

                    # Zeichne einen Rahmen um den erkannten Bereich
                    y_start = int(y + i * h / grid_size[0])
                    y_end = int(y + (i + 1) * h / grid_size[0])
                    x_start = int(x + j * w / grid_size[1])
                    x_end = int(x + (j + 1) * w / grid_size[1])

                    cv2.rectangle(frame, (x_start, y_start), (x_end, y_end), (0, 0, 255), 2)

    return noise_frames, frame

def detect_noise(video_path, threshold=1.5, grid_size=(50, 50), top_n_frames=5):
    # Erstelle den Ausgabeordner, falls er nicht existiert
    output_folder = "analyse/video"
    os.makedirs(output_folder, exist_ok=True)

    cap = cv2.VideoCapture(video_path)
    fps = cap.get(cv2.CAP_PROP_FPS)
    video_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    video_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    frame_number = 0
    noise_frames = []

    # Lade den Gesichts-Kaskadenklassifikator von OpenCV
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

    # Extrahiere den Dateinamen ohne Pfad und Erweiterung
    file_name = os.path.splitext(os.path.basename(video_path))[0]

    # Erstelle einen VideoWriter für die Ausgabe mit dem angepassten Dateinamen
    output_video_path = os.path.join(output_folder, f"{file_name}_analyzed.mp4")
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter(output_video_path, fourcc, fps, (video_width, video_height))

    # Erstelle ein Fenster für die Anzeige
    cv2.namedWindow("Frame", cv2.WINDOW_NORMAL)

    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    total_noise_frames = 0
    top_n_frames_info = []

    # Zusätzliche Variable für statistische Analyse
    frame_with_noise_count = np.zeros(total_frames)

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        # Führe die Bildverarbeitung in einem Thread aus
        noise_frames, frame_with_annotations = process_frame(frame.copy(), threshold, grid_size, face_cascade)

        # Schriftformausgabe im Video
        cv2.putText(frame_with_annotations, f"Pixelrauschen: {len(noise_frames)}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)

        # Schreibe den aktuellen Frame in die Ausgabedatei
        out.write(frame_with_annotations)

        # Zeige das aktuelle Frame in einem Fenster an
        cv2.imshow("Frame", frame_with_annotations)

        # Berechne Statistiken
        total_noise_frames += len(noise_frames)
        if len(noise_frames) > top_n_frames:
            top_n_frames_info.append((frame_number, len(noise_frames)))

        # Speichere die Anzahl der Auffälligkeiten für jedes Frame
        frame_with_noise_count[frame_number] = len(noise_frames)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

        frame_number += 1

    cap.release()
    out.release()
    cv2.destroyAllWindows()

    print(f"Analysevideo wurde gespeichert unter: {output_video_path}")
    print(f"Durchschnittliche Anzahl der Rauschframes pro Frame: {total_noise_frames / total_frames}")
    print(f"Durchschnittliche Anzahl der Rauschframes pro Sekunde: {total_noise_frames / fps}")

    # Statistik für die N frames mit den meisten Auffälligkeiten
    print(f"\nTop {top_n_frames} Frames mit den meisten Auffälligkeiten:")
    for idx, (frame_num, num_auffaelligkeiten) in enumerate(sorted(top_n_frames_info, key=lambda x: x[1], reverse=True)[:top_n_frames]):
        print(f"Frame Nummer: {frame_num}, Auffälligkeiten: {num_auffaelligkeiten}")

    # Zeichnen Sie ein Diagramm der zeitlichen Verteilung der Auffälligkeiten
    plt.plot(frame_with_noise_count)
    plt.xlabel('Frame Nummer')
    plt.ylabel('Anzahl der Auffälligkeiten')
    plt.title('Zeitliche Verteilung der Auffälligkeiten')
    plt.show()

# Beispielaufruf
video_path = input("Geben Sie den Pfad zur Videodatei ein: ")
detect_noise(video_path)