Skip to content

Conversation

@HashakGik
Copy link

@HashakGik HashakGik commented Nov 22, 2025

Executive summary

This PR rewrites entirely the UI of OneTrainer with a modern graphical engine (QT6). Conflicts should be minimal, as changes are limited to modules.ui and modules.util.enum, performance improvements are given by a more efficient rendering engine (compared to tkinter) and a completely rewritten concurrent execution model.
The old UI code has been decoupled into a Model-View-Controller architecture, making future maintenance easier.

It works on my machine™

Closes

Issues: #584 #618
PRs: #749

Breaks

Every PR modifying something in modules.ui (anything else can be updated transparently and without issues). The sooner this PR is accepted, the fewer conflicts we should expect.

Simplifies (but does not solve yet)

Issues: #220 #316 #570 #765 #1022 #958 #956 #955
PRs: #908 (must be reimplemented), possibly renders #1111 obsolete?

Expected bugs

  • I have no way to test cloud training
  • Some UI to TrainConfig associations may be incorrect (I triple checked everything, but I cannot guarantee everything is correct)
  • Spinboxes may have incorrect min-max-step values set (there were really too many to set and I definitely forgot some) [See comment below]

Bugs found so far

  • Bulk Image tool sequential renaming sometimes overwrites images by reusing the same filename (could not reproduce)

These bugs do not affect training (I have successfully trained SD1.5 and SDXL fine tunes and loras, it seems parameters are read correctly), but help is definitely needed to check for all the cases.

Contents of modules.ui.README.md

QT6 GUI Overview

QT6 GUI Overview

Overall Architecture

The GUI has been completely re-implemented as a Model-View-Controller architecture, for better future-proofing.
The folder structure is the following:

  • modules/ui/models: OneTrainer functionalities, abstracted from GUI implementation
  • modules/ui/controllers: Linker classes, managing how models should be invoked, validating (complex) user inputs and orchestrating GUI behavior
  • modules/ui/views: *.ui files drawing each component, in a way which is as data-agnostic as possible
  • modules/ui/utils: auxiliary classes.

Models

Model classes collect original OneTrainer functionalities, abstracting from the specific user interface.
As models can potentially be invoked from different processes/threads/event loops, each operation modifying internal states must be thread-safe.

Models subclassing SingletonConfigModel wrap modules.util.config classes, exposing a singleton interface and a thread-safe dot-notation-based read/write mechanism.

Other models provide auxiliary utilities (e.g., open the browser, load files, etc.) and are mostly grouped conceptually (i.e., all file operations are handled by the same class).

Thread-safe access to model objects is mediated by a global QSimpleMutex, shared by every subclass of SingletonConfigModel. Multiple levels of synchronization are possible:

  • Each model has a self.config attribute which can be accessed safely with Whatever.instance().get_state(var) and Whatever.instance().set_state(var, value) (or unsafely with Whatever.instance().config.var)
  • Multiple variables can be read/written atomically with the self.bulk_read() and self.bulk_write() methods. These should be used to make sure that users editing UI controls while a multiple variables are read consecutively do not result in an inconsistent state.
  • There are four context managers wrapping blocks of code in critical regions:
    1. with self.critical_region_read() and with self.critical_region_write() mediate access to a shared resource with an instance-specific reentrant read-write lock. Most, if not all, synchronizations should use these two context managers.
    2. with self.critical_region() uses a generic reentrant lock which is instance-specific
    3. with self.critical_region_global() uses a generic reentrant lock which is shared across every subclass of SingletonConfigModel.

Controllers

Controller classes are finite-state machines that initialize themselves with a specific sequence of events, and then react to external events (slots/signals).
Each controller is associated with a view (self.ui) and is optionally associated with a parent controller (self.parent), creating a hierarchy with the OneTrainerController at the root.

At construction, each controller executes these operations:

  1. BaseController.__init__: initializes the view
  2. _setup(): setups additional attributes (e.g., references to model classes)
  3. _loadPresets(): for controls that contain variable data (e.g., QComboBox), loads the list of values (typically from a modules.util.enum class, or from files)
  4. Connect static controls according to self.state_ui_connections dict: connects ui elements to StateModel variables bidirectionally (every time a control is changed, the TrainConfig is updated, and every time stateChanged is emitted, the control is updated)
  5. _connectUIBehavior(): forms static connections between signals and slots (e.g., button behaviors)
  6. _connectInputValidation(): associates complex validation functions (QValidators, slots, or other mechanisms) to each control (simple validations are defined in view files)
  7. Invalidation of controls connected with update_after_connect=True
  8. self.__init__: Additional controller-specific initializations.

The state_ui_connections dictionary contains pairs {'train_config_variable': 'ui_element'} for ease of connection, and a similar pattern is often used for other connections. This dictionary involves only connections with StateModel.
Other models are connected to controls manually in _connectUIBehavior(), using a similar pattern on a local dictionary.
Every interaction with non-GUI code (e.g., progress bar updates, training, etc.) is mediated by signals/slots which invoke model methods.

Controllers also have the responsibility of owning and handling additional threads. This is to guarantee better encapsulation and future-proofing, as changing libraries or invocation patterns will allow to keep the models untouched.

Views

View files are created with QtCreator, or QtDesigner, and assumed to expose, whenever possible,data-agnostic controls (e.g., a QComboBox for data types, the values of which are populated at runtime).

Naming convention: each widget within a *.ui file is either a decoration (e.g., a static label or a spacer) with its default name (e.g. label_42), or is associated with a meaningful name in the form camelCaseControlNameXxx,
where Xxx is a class identifier:

  • Lbl: QLabel
  • Led: QLineEdit
  • Ted: QTextEdit
  • Cbx: QComboBox
  • Sbx: QSpinBox or QDoubleSpinBox
  • Cmb: QComboBox
  • Lay: QVerticalLayout, QHorizontalLayout or QGridLayout
  • Btn: QPushButton or QToolButton.

This convention has no real use, other than allowing contributors to quickly tell from the name which signals/slots are supported by a given UI element.

Suggested development checklist:

  1. Create UI layout
  2. Assign widget attributes (name, text, size policy, tooltip, etc.)
  3. Assign buddies for labels
  4. Edit tab order
  5. Assign simple validations (e.g., QSpinBox min/max values, QLineEdit masks, etc.)

Note that *.ui files allow for simple Signal-Slot connections to be defined directly from the WYSIWYG editor, however this can lead to maintenance headaches, when a connection is accidentally made both on the View and the Controller. I strongly advice to connect controls only in the _connectUIBehavior() and connectInputValidation() methods of the Controller.

Violations of the Model-View-Controller architecture:

  • The fields of the optimizer window are created dynamically from its controller. This was mostly to avoid having a hard to maintain .ui file.

Utils

Auxiliary, but QT-dependent, classes.

  • FigureWidget: Figure widget for plots and images. Can be instantiated with a toolbar (separate MaskDrawingToolbar class) for inspection or image editing (arbitrary tools are managed by the controller instantiating the widget).
  • OneTrainerApplication: Subclass of QApplication defining global signals which can be connected from any Controller
  • WorkerPool: Generic threaded processor executing functions on a thread pool automatically managed. Functions can be made reentrant (i.e., they will be executed once, even when multiple calls are made, useful for example when a user attempts to scan the same folder before the previous operation terminated) if they are associated with a name.

QT6 Notions

The following are some basic notions for useful QT6 features.

Signal-slot connections: QT's interactions are asynchronous and based on message passing. Each widget exposes two types of methods:

  • Signals are fired when a particular event occurs (e.g., a QPushButton is clicked) or when explicitly emit()ed. Some signals are associated with data with known type (e.g., QLineEdit.textChanged also transmits the text in a string parameter).
  • Slots are functions receiving a signal and processing its data. For efficiency reasons, they should be annotated with a @Slot(types) decorator, but arbitrary python functions can act as slots, as long as their parameters match the signal.
  • The @Slot decorator does not accept the idiom type|None, you can either use "normal" functions, or decorate them with @Slot(object) for nullable parameters.

A signal-slot connection can be created (connect()) and destroyed (disconnect()) dynamically.
Every time a signal is emitted, all the slots connected to it are executed.

Important considerations:

  • While slots can be also anonymous lambdas, signals must be class members, therefore subclassing a QWidget is needed in case new signals are needed.
  • If a slot modifies a UI element, it is possible that a new signal may be emitted, potentially causing infinite signal-slot calls. To avoid such cases, a slot should invoke widget.blockSignals(True) before changing its value.
  • QtCreator/QtDesigner allow to directly connect signals and slots with matching signatures (e.g., QLineEdit.textChanged(str) and QLabel.text(str) will automatically copy the text from the line edit to the label) from the UI editor, this is convenient, but there is the risk of forgetting to connect something, or connecting it twice (once in the UI editor and then again in python code)
  • The order in which slots are executed is by default FIFO. This can be a source of bugs if code relies on slots being fired in a specific order.

Buddies: Events involving QLabels can be redirected to different controls (e.g., clicking on a label may activate a text box on its right), to improve the user experience.
Buddies can be associated statically in *.ui files, or associated programmatically (e.g., when a label is created from python code).

Widget promotion: Widgets can be subclassed to provide additional functionalities, without losing the possibility of exploiting the WYSIWYG editor. It is sufficient to define a widget as belonging to a particular class, and registering at runtime the promotion.

Text masks and validators: Invalid QLineEdit input can be rejected automatically with either of two mechanisms:

  • Masks: force format adherence (e.g., imposing a hh:mm:ss format for times, or #hhhhhh for RGB colors) by altering the text as it is edited
  • Instances of QValidator: prevent the control to emit returnPressed and editingFinished signals as long as the text entered does not pass the checks, and optionally expose methods to correct invalid text (default QValidators, such a QRegexValidator, use these additional methods to automatically cancel invalid characters as they are typed).

Localization: Each string defined in *.ui files, as well as each string processed by QTranslator, tr() or QCoreApplication.translate() can be automatically extracted into an xml file by the lupdate tool, translated by native-language contributors, and loaded at runtime.
Since lupdate is a static analyzer, it is important that each string can be inspected from the source file (i.e., tr("A static string") will be translatable, my_var = "A not-so-static string"; tr(my_var) will not).

Concurrent Execution Model

The application uses multiple approaches for concurrent execution.

  • QT6 objects implicitly use the internal QThreadPool model. This is transparent from the programmer's perspective, but using only Signals and Slots for every non-trivial communication mechanism is important to prevent unintended behavior arising from this execution model.
  • The ImageModel and BulkModel rely on the MapReduce paradigm, therefore are implemented with a standard multiprocessing.Pool.map approach. Note that since it internally relies on pickle, not every function can be run on it (namely, class methods and lambdas are not pickleable)
  • WorkerPool offers three execution mechanisms, all exposing the same Signal-Slot-based interface:
    1. Anonymous QRunnable functions automatically handled by QThreadPool, which can be enqueued arbitrarily many times.
    2. Named QRunnable functions automatically handled by QThreadPool, which are reentrant based on a name (if a QRunnable with the same name is already running, the new worker is not enqueued).
    3. Traditional threading.Thread functions, manually launched. This addresses two limitations of QRunnable, at the expenses of sacrificing automatic load balancing: exceptions in the underlying C++ code can crash the application, and the absence of join().

Decisions and Caveats

  • Since the original OneTrainer code was strongly coupled with the user interface, many model classes were rewritten from scratch, with a high chance of introducing bugs.
  • Enums in modules/util/enum have been extended with methods for GUI pretty-printing (modules.util.enum.BaseEnum.BaseEnum class), without altering their existing functionality
  • I have more or less arbitrarily decided that strings should all be translated with QCoreApplication.translate(), because it groups them by context (e.g. QCoreApplication.translate(context="model_tab", sourceText="Data Type")), allowing explicit disambiguation every time, and providing translators with a somewhat ordered xml (every string with the same context will be close together).
  • At the moment Enum values are non-translatable, because pretty printing often relies on string manipulation.
  • Signal-slot connections are wrapped by BaseController._connect() to easily manage reconnections of dynamic widgets, and the "low level" methods should not be called directly.
  • The application exposes global signals (e.g., modelChanged, openedConcept(int), etc.), which are used to guarantee data consistency across all UI elements, by letting slots handle updates. This should be cleaner than asking the caller to modify UI elements other than its own.
  • For the time being, modules.ui.models classes simply handle the backend functionalities that were implemented in the old UI. In the future it may be reasonable to merge it with modules.util.config into thread-safe global states.

@dxqb
Copy link
Collaborator

dxqb commented Nov 27, 2025

Thank you for this PR!
I am currently download Qt and QtDesigner, so I can try to understand it. Besides the .ui files, the *Controller.py files also appear to be auto-generated. Are they? Are they auto-generated by QtDesigner?

This PR seems to include #749.
#749 has been inactive for a while and isn't finished. Unless @O-J1 's plans have changed, it will not be finished soon.

Is it possible to split your PR into 2, so we have a Qt PR against current main without #749? Your PR is difficult to review otherwise (because many changes that seem unrelated, like in models/). And it would have to wait for #749 otherwise, whenever this is.

@HashakGik
Copy link
Author

HashakGik commented Nov 27, 2025

No, modules.ui.controllers are manually generated classes.

Some guidance for review:

  • Classes in modules.ui.models are meant to be OneTrainer functionalities completely decoupled from QT6. The idea is that if those are bug-free and coherent with the old OT implementation, then it should be safe to switch without breaking anyone's workflow (in principle if we had unit tests, they would have targetted those functionalities). I started with the idea of just copy-pasting the old implementation, but some needed some heavy rewriting. Since it is code you are most familiar with, I would like you to have a very close look on those classes, as I may have lost something in translation. In the old OT implementation functionalities were grouped by UI, here I tried to group them by responsibility (e.g. the StateModel also deals with tensorboard) and to wrap a single *Config object (either real, in modules.util.config, or virtual, as dict defined within the class).
  • Classes in modules.ui.controllers make the model communicate with the UI. They are responsible of:
    1. Checking that input fields have valid values (I will add a separate comment with a checklist for those)
    2. Enabling/Disabling visual behavior
    3. Ensuring a consistent state across the application (e.g., when loading a new config)
      In theory controllers should be validated against visual behavior (i.e., if you see something not working, let me know and I will try to fix it, at least for now that you do not have familiarity with QT)

Regarding PR #749, the only files concerning it are:

  • modules.ui.controllers.BulkCaptionController, modules.ui.models.BulkCaptionModel: Bulk operations on captions (in Dataset Tools Rework #749 they were a button in the dataset tools, now they have first-citizen rights and are a separate tool in the tools tab. As the code was not ready yet, I tried to clean it up as much as possible)
  • modules.ui.controllers.BulkImageController, modules.ui.models.BulkImageModel: Bulk operations on images (as above. EDIT: To avoid confusion for end users, I replaced their names to "Bulk Caption Tools" and "Bulk Image Tools" in the UI)
  • modules.ui.DatasetController, which adds some additional functionalities from Dataset Tools Rework #749.

As I did not touch the backend, JXL support is not implemented, so the integration of #749 is not necessary to review this PR.

In the last days I have been hunting down bugs, in theory the modules.ui.models.* classes should be mature enough for a review on your side (especially the cloud-related methods, which I cannot test). There are still some important bugs in modules.ui.controllers.* which I am progressively fixing.
As of today, I can say that tools should all work correctly, and local training should be running without problems. The biggest problems, for now, are in the concepts tab.

EDIT: All the bugs I could identify on my own are now fixed. I will wait on your feedback for things that I may have missed.

@dxqb
Copy link
Collaborator

dxqb commented Nov 27, 2025

Did you evaluate my idea from earlier, to implement wrappers for the components in modules.util.ui.components that wrap the existing UI into Qt6? Then you have a working, but less-than-perfect UI, and could migrate existing code over slowly and in parts (as I understood now, from modules.util.ui into the new modules.ui.models).

You have opted for a complete rewrite of all UI code instead. Maybe that is the right decision, but I'd like to understand it, because I feel like it will be very difficult to do a big bang switch without introducing many new bugs.

@HashakGik
Copy link
Author

HashakGik commented Nov 27, 2025

At first I tried a conservative approach, however, coupling was so strong, that it was too difficult to carry on, and I ultimately decided to rewrite everything (attempting to move as many blocks of code as they were implemented as possible). In hindsight, I think that pushing towards a conservative approach would have bitten us later, and could have transformed in a considerable technical debt, nobody would be incentivized to fix later. As mentioned above, this also opens the doors to unit testing, but I understand that it will slow reviewing considerably for now.

PS: no, modules.util.ui contains old code I did not touch. The old ui is in modules.ui.legacy (and modules.util.enum.legacy).

EDIT: of course, there is no need for a big bang switch, we can proceed in parallel, as long as the main branch does not touch anything in modules.util.ui, merging is trivial. Small UI changes can be integrated progressively in both branches with limited effort, during this testing phase.


Anyway, here is the validation checklist of the controls that I could not initialize on my own with sensible values.

The following are the parameters which currently DO NOT have any sanity check (everything else has been assigned values I believed to be safe, but let me know otherwise):

  • All the optimizer parameters of type int can have values from -999999 to 999999, those of type float can range from -inf to inf. This is a limitation of the modules.util.optimizer_util.OPTIMIZER_DEFAULT_PARAMETERS dict, which can be addressed only if in the future it will also contain min/max values.
  • In the Training tab: all the controls of the Noise group have default ranges (min: 1.00, max: 99.99, step: 1.00). Min Noising Strength is constrained to be <= Max Noising Strength.

@HashakGik HashakGik marked this pull request as ready for review November 29, 2025 18:09
@HashakGik
Copy link
Author

I have cleared my backlog of changes to be made, and fixed all the bugs (except one in modules.ui.models.ImageBulkModel which happened only once and I could not reproduce again since) I could find in a week of tests.
From my perspective, if it passes your review, we should be ready for merge.

@dxqb
Copy link
Collaborator

dxqb commented Dec 6, 2025

will have a look when I find the time
been busy with new models

@dxqb
Copy link
Collaborator

dxqb commented Dec 26, 2025

apologies for taking so long to have a first look.
installation was no issue, and the UI is as quick a you'd expect from Qt.

I haven't done any code review yet, but here are some comments from using it for 10 minutes:

  1. tooltips don't work for me. tooltips are essential in OneTrainer.

  2. The frames were reordered, especially on the 'training' tab. Masked training is now at the middle and top, while it was on the right before. People are used to the current layout and some of it was chosen with some intention (ilke putting less important settings at the bottom)

  3. These are settings for custom schedulers. this is a very rarely used function that shouldn't be on the main page, but a window as before

grafik
  1. same with the timestep distribution preview:
grafik
  1. when I scroll using mousewheel as you usually do to move the scrollframe, but the mouse courser happens to be in an entry field, it changes the value of the entry field instead of scrolling the frame. this would cause many issues for users.

  2. Spacing and layouts

Many of the UI layouts are worse than before. Large fields are small now, small ones are big now. For example on the Sampling tab:
grafik

  1. The following error appeared when I switched preset a second time. The first switch worked:
QIODevice::read (QFile, "modules/ui/views/widgets/concept.ui"): device not open
Designer: An error has occurred while reading the UI file at line 1, column 0: Premature end of document.
Traceback (most recent call last):
  File ".../OneTrainer/modules/ui/controllers/tabs/ConceptsController.py", line 121, in f
  File ".../OneTrainer/modules/ui/controllers/widgets/ConceptController.py", line 14, in __init__
  File ".../OneTrainer/modules/ui/controllers/BaseController.py", line 25, in __init__
RuntimeError: Unable to open/read ui device
  1. Concepts are sorted differently
    I don't know how relevant this is, but a concept that was always on the top-left for me is now at the bottom

  2. When I tried to manually sample during training, the values of the window are not initialized:

grafik

and when I sample the following error appears

  File ".../OneTrainer/modules/modelSampler/ChromaSampler.py", line 55, in __sample_base
    generator.manual_seed(seed)
RuntimeError: manual_seed expected a long, but got str

this also happens when I entered an integer value as seed first.


The list above is from using it for 10 minutes, so I'd expect there to be more issues like this.

I really appreciate all the work that went into this, but as we've discussed previously it is going to be very difficult to rewrite a UI entirely without causing any regressions.
How would you like to continue with this? If a rewrite is the only way to do this, and not a step-by-step approach starting with a wrapper (see our earlier discussion), it will be a long time in my estimation until a state is reached that can be merged for all users.

What we could think about is maintaining a separate branch and or command line option that enables Qt, so people can choose to use it once it has reached a semi-stable state.

@dxqb dxqb marked this pull request as draft December 26, 2025 12:02
@HashakGik
Copy link
Author

I apologize for undiscovered bugs (especially those stemming from different configurations, I also discovered further bugs other than those initially fixed), but it was difficult to keep track of everything over 19k slocs without unit tests or internal documentation other than code comments. I think it is important to discriminate three "focus areas" and address them separately, and in order of importance:

  • core functionalities bugs (what I really care about at the moment, and what must be really checked thoroughly, because it allows backend and frontend to be developed independently and at independent paces, without duplicating code that needs to be debugged twice on both branchesm and constantly be realigned at each commit)
  • UI behavior issues
  • Aestethic issues.

The past month was relatively free and I could have fixed most of these issues you raised relatively quickly (even though they are mostly of aestethic nature, and thus, lowest priority), but unfortunately I am now knee-deep in preparing my PhD defense, and I cannot work on anything else for the next few months.
I would really apreciate it if you could manage some exhaustive testing by then (even outsourced to a few volounteers on Discord, as the only testing we can do at the moment, without documentation or unit tests, is actually behavior-based black-box and does not require technical expertise for UI behavior and aestethic issues).
We can keep track of problems as issues on my fork, to keep them separate from OT, and I could provide write access to others if they want to contribute during my absence (you, as maintainer of OT, should already have write access to the fork).

I like the idea of a separate branch, but it would really be important to unify core functionalities with main first. This means either accepting my approach of separating them in modules.ui.models (after thorough review on your part), or a different approach of your choice. The current one is too strongly coupled with tkinter to allow a different frontend, even attempting an Adapter or Facade pattern on top of it would be challenging. I have nothing against it though, if you can manage to do it.
In the end we just need a unified mechanism to read/write UI elements into config objects and functionalities to be wrapped by simple function calls.

apologies for taking so long to have a first look. installation was no issue, and the UI is as quick a you'd expect from Qt.

I haven't done any code review yet, but here are some comments from using it for 10 minutes:

1. tooltips don't work for me. tooltips are essential in OneTrainer.

This is strange. They have been a stable feature in QT since the very beginning and they are just a property of UI elements. What is your setup?
I noticed label buddies do not work as I thought (or I forgot to set something up), so tooltips are triggered when you are hovering a control, not the label next to it.

2. The frames were reordered, especially on the 'training' tab. Masked training is now at the middle and top, while it was on the right before. People are used to the current layout and some of it was chosen with some intention (ilke putting less important settings at the bottom)

This is something I took the liberty of rearranging, it can be reverted easily.

3. These are settings for custom schedulers. this is a very rarely used function that shouldn't be on the main page, but a window as before

This can be done.

grafik

Same as above.

4. same with the timestep distribution preview:
grafik

Same as above.

5. when I scroll using mousewheel as you usually do to move the scrollframe, but the mouse courser happens to be in an entry field, it changes the value of the entry field instead of scrolling the frame. this would cause many issues for users.

This is QT's default behavior. I think it can be overridden though.

6. Spacing and layouts

See above.

Many of the UI layouts are worse than before. Large fields are small now, small ones are big now. For example on the Sampling tab: grafik

See above.

7. The following error appeared when I switched preset a second time. The first switch worked:
QIODevice::read (QFile, "modules/ui/views/widgets/concept.ui"): device not open
Designer: An error has occurred while reading the UI file at line 1, column 0: Premature end of document.
Traceback (most recent call last):
  File ".../OneTrainer/modules/ui/controllers/tabs/ConceptsController.py", line 121, in f
  File ".../OneTrainer/modules/ui/controllers/widgets/ConceptController.py", line 14, in __init__
  File ".../OneTrainer/modules/ui/controllers/BaseController.py", line 25, in __init__
RuntimeError: Unable to open/read ui device

Probably your local copy of modules/ui/views/widgets/concept.ui was modified (between the two preset switches?) and is now invalid. No clue on how that could have happened.
*.ui files are source code, they should be read-only from python's perspective, probably some external program acted on them (did you have QtCreator open? Did an antivirus software mess with it? I have no other "reasonable" suspects in mind).

8. Concepts are sorted differently
   I don't know how relevant this is, but a concept that was always on the top-left for me is now at the bottom

This is because ListWidgets are stack based, and insertions are by default at the beginning. It can be fixed easily.

9. When I tried to manually sample during training, the values of the window are not initialized:
grafik

and when I sample the following error appears

  File ".../OneTrainer/modules/modelSampler/ChromaSampler.py", line 55, in __sample_base
    generator.manual_seed(seed)
RuntimeError: manual_seed expected a long, but got str

This is one of the bugs I found out in the last month of testing. Another one, for example, would be Lora dropout not being passed to the training config. These are of course feature breaking, but require one-liner minor fixes. However they are very hard to spot, especially when we only have one or two people testing.

I was also in the process of investigating some more serious bugs involving the tensorboard process, which can cause the entire application to crash on exit under some circumstances, but had to stop working on it before being able to pinpoint the problem.

this also happens when I entered an integer value as seed first.

The list above is from using it for 10 minutes, so I'd expect there to be more issues like this.

I really appreciate all the work that went into this, but as we've discussed previously it is going to be very difficult to rewrite a UI entirely without causing any regressions. How would you like to continue with this? If a rewrite is the only way to do this, and not a step-by-step approach starting with a wrapper (see our earlier discussion), it will be a long time in my estimation until a state is reached that can be merged for all users.

What we could think about is maintaining a separate branch and or command line option that enables Qt, so people can choose to use it once it has reached a semi-stable state.

@FurkanGozukara
Copy link

cant wait for this update to become final i hope it becomes much faster UI

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants