santa hat
deerdeer nosedeer glow
Sign In

LoRA Training - Dataset Creation - ChatGPT (GPT4 / Plus Account)

LoRA Training - Dataset Creation - ChatGPT (GPT4 / Plus Account)

This is a small workflow guide on how to generate a dataset of images using ChatGPT! This requires a paid OpenAI account, but doesn't cost "per generation". It's still a fairly manual-labour intensive way of getting a high-quality generated dataset.

This is part of a series on how to generate datasets with: ChatGPT API, ChatGPT, Bing, ComfyUI.

The Workflow

This is actually fairly straight-forward. I will give you a prompt that you can use with ChatGPT. You will need to customize the prompt to instruct it better and in the style that you want.

After this, it will be "half-automatic". What I mean by this is that OpenAI keeps changing how it works. It used to be that it gave you 4 images each time you asked it to generate something. Then they changed the limits to 2 images, and now I think it may be 1 image each time? I'm not sure any more.

ChatGPT Limits

Additionally, there's a limit to the number of images you're allowed to generate. This is based on the traffic at OpenAI, so it's not in your control. It will warn you when you need to wait, and tell you for how long you are on cooldown. Sometimes you can start a bit earlier.

The Prompt

Hi!

I need your help to generate a bunch of images. Please generate them in a square 1024x1024 resolution.

I'm trying to create an art style LoRA (image generation model), using some images as a base, so I need the results to be stylishly consistent.

I need the style to be consistent across the images. I want the subject itself to transformed / morphed into a version of that subject that matches the theme. Example: If I asked for a Batman-styled image, and the Subject was "car", I would expect a result like the batmobile.

I would like you to use a shared prompt for all images, to maintain the same style. But I will need the [subject] to be replaced for each set of images. Please add 2 random words at the end of each generation that relates to the style I'm trying to achieve.

Here's my prompt. The subject is in [brackets].

Photo of a delicious-looking cinnamon-bun [SUBJECT]. The entire aircraft is constructed from fresh, golden-brown cinnamon bun material, with swirls of cinnamon and icing visible.

For each subject below, please generate 4 images, and replace the [SUBJECT] with the following items:

Send each 4 images in a separate message. Continue without asking for permission to continue until all subjects have 4 images each. Thank you very much!

List of Subjects:

majestic airplane soaring through the skies
humanoid mechanical robotic cyborg character inside a spaceship
battle mech on a battlefield
bookshelf in a living room
camera on a table in an office
car driving on a road
castle in the mountains
city skyline, closeup daytime
cloud in the skies, fluffy
coffee machine in a kitchen
combine harvester plowing the fields on the farm, planted harvest crops
cube hovering in the air, artifact
dirigible soaring the skies on a sunny day
excavator working the construction site
forest trees, close up of trees, stems and roots, branches in forest
grass closeup blade of grass in grassy field
industrial boiler, technical parts, pipes, gauges, in a warehouse
lake in nature with water, ripples of a pond
landscape with hills, terrain, nature
light rays from a glowing center in space
cells and molecules and macro photography
magical energy swirling magic energies, glowing
mystical runes and magic energies
planet in space, detailed and realistic, stars and cosmos in the background
pyramids in the desert
recliner in a living room
space station in outer space, ISS, hi-tech, starry cosmos background in space
spaceship in outer space, millennium falcon, stars and cosmos background
sphere with hi-tech details, alien artifact
submarine deep under water
tank panzer wagon, gun barrel, driving through the jungle and desert, tech
toaster on a kitchen counter in a modern kitchen
tree in the forest, detailed leaves
truck driving in a city
vintage TV in a living room
water closeup of a liquid surface, wet, dripping puddle
wooden chair in a living room

The Base Prompt

Photo of a delicious-looking cinnamon-bun [SUBJECT]. The entire aircraft is constructed from fresh, golden-brown cinnamon bun material, with swirls of cinnamon and icing visible.

This part of the ChatGPT prompt, is what will actually be prompted by the image generator. ChatGPT should replace the word in the brackets [SUBJECT], with each line in the list of subjects.

Common Problems

At one point, this worked flawlessly. You got a list of 4 images for each subject, and then it moved on to the next subject and did 4 more there, until it hit the image generation limit.

Now, you can run into all sorts of problems.

  • It only generates one of each image

    • You're gonna have to ask it in a different way, or just repeat the list once it's done and sort a lot of files manually

  • It generates "split" images, all images in one image, instead of multiple full images

Essentially, you're gonna have to wrestle ChatGPT until you get it sorted. Good luck!

File Name Issues

There are 2 ways to download the image from ChatGPT.

When you hover with the mouse over an image, you get a download-button in the top-left corner. I recommend using this method, it's the fastest, and you get the images in a PNG format.

However, you will also get a file name from hell.

"DALL·E 2023-12-11 01.36.17 - Create a 1024x1024 image of a blue tank on a dirt road, inspired by the Transformers movies. The tank should incorporate advanced mechanical and futur.PNG"

You are gonna have to rename this manually, as it contains both bad characters, and it can be too long for even some file renaming tools to rename. I have written a script where it actually renames the images even though it's crazy long. You will need to download my "RenameScripter" to run the script, so it's a bit of a setup. Alternatively you can just rename them manually.

Here's the script:

import os
import tkinter as tk
from tkinterdnd2 import DND_FILES, TkinterDnD

class RenamerApp:
    def __init__(self, root):
        self.root = root
        self.previous_state = []
        self.files = []

        root.title('File Renamer')
        root.geometry('1200x600')  # Make the window 50% wider by default

        self.create_widgets()
        self.configure_grid()

    def create_widgets(self):
        self.left_label = tk.Label(self.root, text="Drag / drop your files or folders here")
        self.left_label.grid(row=0, column=0, padx=10, pady=5)

        self.right_label = tk.Label(self.root, text="Rename previews")
        self.right_label.grid(row=0, column=1, padx=10, pady=5)

        self.file_list_var = tk.Variable(value=[])
        self.preview_list_var = tk.Variable(value=[])

        self.file_listbox = tk.Listbox(self.root, listvariable=self.file_list_var, width=90, height=15)
        self.file_listbox.grid(row=1, column=0, padx=10, pady=10, sticky='nsew')

        self.preview_listbox = tk.Listbox(self.root, listvariable=self.preview_list_var, width=45, height=15)
        self.preview_listbox.grid(row=1, column=1, padx=10, pady=10, sticky='nsew')

        self.rename_button = tk.Button(self.root, text='RENAME', command=self.on_rename)
        self.rename_button.grid(row=2, column=0, pady=5)

        self.undo_button = tk.Button(self.root, text='UNDO', command=self.on_undo)
        self.undo_button.grid(row=2, column=1, pady=5)

        self.status_label = tk.Label(self.root, text="", fg="green")
        self.status_label.grid(row=3, column=0, columnspan=2, pady=5)

        self.root.drop_target_register(DND_FILES)
        self.root.dnd_bind('<<Drop>>', self.on_drop)

    def configure_grid(self):
        self.root.grid_rowconfigure(1, weight=1)
        self.root.grid_columnconfigure(0, weight=3)  # Left column (file list) is 3 times wider
        self.root.grid_columnconfigure(1, weight=1)  # Right column (preview) is thinner

    def get_files_from_paths(self, paths):
        files = []
        for path in paths:
            if os.path.isfile(path):
                files.append(path)
            elif os.path.isdir(path):
                for root, _, filenames in os.walk(path):
                    for filename in filenames:
                        files.append(os.path.join(root, filename))
        return files

    def rename_files(self, files):
        folder_counts = {}
        self.previous_state = []  # Clear previous state before renaming
        for file_path in files:
            directory, file_name = os.path.split(file_path)
            folder_name = os.path.basename(directory)
            file_extension = os.path.splitext(file_name)[1]
            folder_counts[directory] = folder_counts.get(directory, 0) + 1
            count_str = str(folder_counts[directory]).zfill(3)
            new_name = f"{folder_name} {count_str}{file_extension}"
            new_path = os.path.join(directory, new_name)
            os.rename(file_path, new_path)
            self.previous_state.append((new_path, file_path))  # Store new and old names for undo

    def on_drop(self, event):
        paths = self.root.tk.splitlist(event.data)
        self.files = self.get_files_from_paths(paths)
        original_file_paths = [file for file in self.files]
        new_file_names = [self.get_new_name(file, i) for i, file in enumerate(self.files)]
        self.file_list_var.set(original_file_paths)
        self.preview_list_var.set(new_file_names)
        self.status_label.config(text="")
        self.previous_state = []  # Clear previous state on new drop

    def get_new_name(self, file_path, index):
        directory, file_name = os.path.split(file_path)
        folder_name = os.path.basename(directory)
        file_extension = os.path.splitext(file_name)[1]
        count_str = str(index + 1).zfill(3)
        return f"{folder_name} {count_str}{file_extension}"

    def on_rename(self):
        self.rename_files(self.files)
        original_file_paths = [file for file in self.files]
        new_file_names = [self.get_new_name(file, i) for i, file in enumerate(self.files)]
        self.file_list_var.set(original_file_paths)
        self.preview_list_var.set(new_file_names)
        self.status_label.config(text="Files renamed successfully", fg="green")

    def on_undo(self):
        if not self.previous_state:
            self.status_label.config(text="Nothing to undo", fg="red")
            return
        for new_name, old_name in self.previous_state:
            os.rename(new_name, old_name)
        self.previous_state = []
        self.status_label.config(text="Undo completed", fg="blue")
        original_file_paths = [file for file in self.files]
        new_file_names = [self.get_new_name(file, i) for i, file in enumerate(self.files)]
        self.file_list_var.set(original_file_paths)
        self.preview_list_var.set(new_file_names)

if __name__ == '__main__':
    root = TkinterDnD.Tk()
    app = RenamerApp(root)
    root.mainloop()

Save this as RenameScript.py and place it anywhere. Launch the script, and it will open a user interface. Then drag/drop the files or folders onto the left side of the program.

Press RENAME and check out the renamed files. If you are not happy, press UNDO.

Alternatively, you can just right-click on each image and choose "Save Image As", but you will get it in .webp format, for which you will then need to convert it into JPG/PNG.

You can do this with a tool like Vovsoft WEBP Converter: https://vovsoft.com/software/webp-converter/

Big thanks to Konicony for writing the original guide to this workflow, and for Navimixu for teaching me additional tips and tricks, and providing the core for the list of concepts below.

51

Comments