Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Control Net support + Textual Inversion (embeddings) #131

Merged
merged 33 commits into from
Jan 29, 2024

Conversation

FSSRepo
Copy link
Contributor

@FSSRepo FSSRepo commented Dec 29, 2023

I implemented a Control Net here; it's somewhat similar to the encoder phase of stable diffusion, but with some convolutional layers.

Usage

./bin/sd --mode txt2img -p "a person" -m ../models/sd-v1-4.ckpt --control-net models/control_openpose-fp16.safetensors --control-image assets/control.png

Some examples

Conditioning Result 1 Result 2
none output output
control output_controlnet output_net2
control_2 output output_net
control_3 output

NOTE: Requires more of 4 GB of VRAM, peak memory usage 3.6 GB (Out Of Memory in Windows). Use --control-net-cpu to keep Control Net with CPU backend

@ggerganov
Copy link
Contributor

For me it fails in a different way:

make -j && ./bin/sd --mode txt2img -p "a person" -m ../models/sd-v1-4.ckpt
[INFO]  stable-diffusion.cpp:6105 - loading model from '../models/sd-v1-4.ckpt'
[INFO]  model.cpp:641  - load ../models/sd-v1-4.ckpt using checkpoint format
[INFO]  stable-diffusion.cpp:6131 - Stable Diffusion 1.x 
[INFO]  stable-diffusion.cpp:6137 - Stable Diffusion weight type: f32
[INFO]  stable-diffusion.cpp:6296 - total memory buffer size = 2731.37MB (clip 470.66MB, unet 2165.24MB, vae 95.47MB)
[INFO]  stable-diffusion.cpp:6298 - loading model from '../models/sd-v1-4.ckpt' completed, taking 9.89s
[INFO]  stable-diffusion.cpp:6312 - running in eps-prediction mode
[INFO]  stable-diffusion.cpp:5334 - loading control net from 'models/control_openpose-fp16.safetensors'
[INFO]  model.cpp:638  - load models/control_openpose-fp16.safetensors using safetensors format
ggml_tallocr_alloc: not enough space in the buffer (needed 1376030498560, largest block available 109550971676)
GGML_ASSERT: /Users/ggerganov/development/github/stable-diffusion.cpp/ggml/src/ggml-alloc.c:116: !"not enough space in the buffer"
Abort trap: 6

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Dec 29, 2023

Try specifying --type f16 -v

@ggerganov
Copy link
Contributor

Now it completes, but output.png is black

Option: 
    n_threads:         16
    mode:              txt2img
    model_path:        ../models/sd-v1-4.ckpt
    wtype:             f16
    vae_path:          
    taesd_path:        
    esrgan_path:       
    output_path:       output.png
    init_img:          
    prompt:            a person
    negative_prompt:   
    cfg_scale:         7.00
    clip_skip:         -1
    width:             512
    height:            512
    sample_method:     euler_a
    schedule:          default
    sample_steps:      20
    strength(img2img): 0.75
    rng:               cuda
    seed:              42
    batch_count:       1
    vae_tiling:        false
System Info: 
    BLAS = 1
    SSE3 = 0
    AVX = 0
    AVX2 = 0
    AVX512 = 0
    AVX512_VBMI = 0
    AVX512_VNNI = 0
    FMA = 0
    NEON = 1
    ARM_FMA = 1
    F16C = 0
    FP16_VA = 1
    WASM_SIMD = 0
    VSX = 0
[DEBUG] stable-diffusion.cpp:6095 - Using CPU backend
[INFO]  stable-diffusion.cpp:6105 - loading model from '../models/sd-v1-4.ckpt'
[INFO]  model.cpp:641  - load ../models/sd-v1-4.ckpt using checkpoint format
[DEBUG] model.cpp:1142 - init from '../models/sd-v1-4.ckpt'
[INFO]  stable-diffusion.cpp:6131 - Stable Diffusion 1.x 
[INFO]  stable-diffusion.cpp:6137 - Stable Diffusion weight type: f16
[DEBUG] stable-diffusion.cpp:6139 - loading vocab
[DEBUG] stable-diffusion.cpp:739  - vocab size: 49408
[DEBUG] stable-diffusion.cpp:6149 - ggml tensor size = 384 bytes
[DEBUG] stable-diffusion.cpp:1510 - clip params backend buffer size =  236.18 MB (449 tensors)
[DEBUG] stable-diffusion.cpp:2527 - unet params backend buffer size =  1650.16 MB (720 tensors)
[DEBUG] stable-diffusion.cpp:3586 - vae params backend buffer size =  95.47 MB (164 tensors)
[DEBUG] stable-diffusion.cpp:6166 - preparing memory for the weights
[DEBUG] stable-diffusion.cpp:6198 - loading weights
[DEBUG] model.cpp:1224 - loading tensors from ../models/sd-v1-4.ckpt
[DEBUG] stable-diffusion.cpp:6286 - model size = 1969.67MB
[INFO]  stable-diffusion.cpp:6296 - total memory buffer size = 1981.80MB (clip 236.18MB, unet 1650.16MB, vae 95.47MB)
[INFO]  stable-diffusion.cpp:6298 - loading model from '../models/sd-v1-4.ckpt' completed, taking 9.97s
[INFO]  stable-diffusion.cpp:6312 - running in eps-prediction mode
[DEBUG] stable-diffusion.cpp:6339 - finished loaded file
[INFO]  stable-diffusion.cpp:5334 - loading control net from 'models/control_openpose-fp16.safetensors'
[INFO]  model.cpp:638  - load models/control_openpose-fp16.safetensors using safetensors format
[DEBUG] model.cpp:704  - init from 'models/control_openpose-fp16.safetensors'
[DEBUG] stable-diffusion.cpp:5263 - control net params backend buffer size =  693.43 MB (347 tensors)
[DEBUG] model.cpp:1224 - loading tensors from models/control_openpose-fp16.safetensors
[INFO]  stable-diffusion.cpp:5402 - control net model loaded
[DEBUG] stable-diffusion.cpp:7218 - prompt after extract and remove lora: "a person"
[INFO]  stable-diffusion.cpp:7223 - apply_loras completed, taking 0.00s
[DEBUG] stable-diffusion.cpp:1457 - parse 'a person' to [['a person', 1], ]
[DEBUG] stable-diffusion.cpp:889  - split prompt "a person" to tokens ["a</w>", "person</w>", ]
[DEBUG] stable-diffusion.cpp:1624 - learned condition compute buffer size: 2.58 MB
[DEBUG] stable-diffusion.cpp:6462 - computing condition graph completed, taking 40 ms
[DEBUG] stable-diffusion.cpp:1457 - parse '' to [['', 1], ]
[DEBUG] stable-diffusion.cpp:889  - split prompt "" to tokens []
[DEBUG] stable-diffusion.cpp:1624 - learned condition compute buffer size: 2.58 MB
[DEBUG] stable-diffusion.cpp:6462 - computing condition graph completed, taking 38 ms
[INFO]  stable-diffusion.cpp:7262 - get_learned_condition completed, taking 80 ms
[INFO]  stable-diffusion.cpp:7278 - sampling using Euler A method
[INFO]  stable-diffusion.cpp:7282 - generating image: 1/1 - seed 42
[DEBUG] stable-diffusion.cpp:5616 - controlnet compute buffer size: 547.79 MB -> 13 control output tensors
[DEBUG] stable-diffusion.cpp:2894 - diffusion compute buffer size: 559.71 MB
  |>                                                 | 0/20 - 0.00it/s[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |==>                                               | 1/20 - 4.14s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |=====>                                            | 2/20 - 3.96s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |=======>                                          | 3/20 - 3.95s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |==========>                                       | 4/20 - 4.00s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |============>                                     | 5/20 - 3.96s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |===============>                                  | 6/20 - 4.04s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |=================>                                | 7/20 - 4.00s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |====================>                             | 8/20 - 3.86s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |======================>                           | 9/20 - 4.01s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |=========================>                        | 10/20 - 3.96s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |===========================>                      | 11/20 - 4.00s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |==============================>                   | 12/20 - 3.96s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |================================>                 | 13/20 - 3.90s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |===================================>              | 14/20 - 3.92s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |=====================================>            | 15/20 - 3.94s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |========================================>         | 16/20 - 4.02s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |==========================================>       | 17/20 - 4.00s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |=============================================>    | 18/20 - 3.87s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |===============================================>  | 19/20 - 3.95s/it[DEBUG] stable-diffusion.cpp:6606 - control net start
[DEBUG] stable-diffusion.cpp:6608 - control net end
  |==================================================| 20/20 - 4.00s/it
[INFO]  stable-diffusion.cpp:7294 - sampling completed, taking 79.55s
[INFO]  stable-diffusion.cpp:7302 - generating 1 latent images completed, taking 79.57s
[INFO]  stable-diffusion.cpp:7304 - decoding 1 latents
[DEBUG] stable-diffusion.cpp:3717 - vae compute buffer size: 1664.00 MB
[DEBUG] stable-diffusion.cpp:7113 - computing vae [mode: DECODE] graph completed, taking 5.24s
[INFO]  stable-diffusion.cpp:7314 - latent 1 decoded, taking 5.24s
[INFO]  stable-diffusion.cpp:7318 - decode_first_stage completed, taking 5.24s
[INFO]  stable-diffusion.cpp:7335 - txt2img completed in 84.90s
[INFO]  main.cpp:541  - save result image to 'output.png'

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Dec 29, 2023

Try running it in debug mode.

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Dec 29, 2023

@ggerganov It was a variable that was causing an overflow. With debug mode, I managed to detect it, although NaNs (Not a Number) are still being generated somewhere in the unet computation graph, anyway thank you for your time. I am going to check.

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Dec 30, 2023

@ggerganov Is what I'm doing correct when extracting data from collected tensors into a vector? I suspect, it might be reading a memory address with residual data.

Read forwardfunction of ControlNet struct

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Jan 1, 2024

@leejet can you test this?

@leejet
Copy link
Owner

leejet commented Jan 1, 2024

@leejet can you test this?

@FSSRepo Where did you download the ControlNet model from? When I used the official provided weights from https://huggingface.co/lllyasviel/ControlNet-v1-1/tree/main, the tensor names didn't match.

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Jan 1, 2024

@leejet Control Net for stable diffusion 1.5:

Control Net v1
Control Net v1.1

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Jan 1, 2024

@leejet those pth models have the prefix control_model. that's why they have invalid names.

@leejet
Copy link
Owner

leejet commented Jan 1, 2024

@leejet Control Net for stable diffusion 1.5:

Control Net v1 Control Net v1.1

It looks like ControlNet is in effect.

.\bin\Release\sd.exe -m ..\..\stable-diffusion-webui\models\Stable-diffusion\v1-5-pruned-emaonly.safetensors -p "a person" --control-net  ..\models\control_openpose-fp16.safetensors  --control-image ..\assets\control.png -v

output

@Amin456789
Copy link

omg, u guys are bringing everything to sd cpp! thank u for all ur hard work, can't wait for inpainting and outpainting too be a part of controlnet

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Jan 1, 2024

@leejet Ready, the official pth models should also be working now. I should emphasize that they also include other t2i models; those are a different architecture. They make changes to the input blocks, while ControlNet makes changes to the output blocks and the middle block.

The missing part is to create the preprocessors. But that is cumbersome and somewhat complicated, as it requires implementing other models (image2depth and openpose) and algorithms to perform Canny (edge detection).

@leejet
Copy link
Owner

leejet commented Jan 2, 2024

Great job, and thank you for your contributions. I'll find some time to review and merge this PR.

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Jan 5, 2024

@Green-Sky Could you try this pull request if it works correctly for you? Also, if you try removing this #ifdef.

__STATIC_INLINE__ void ggml_backend_tensor_get_and_sync(ggml_backend_t backend, const struct ggml_tensor* tensor, void* data, size_t offset, size_t size) {
  // delete this to use just ggml_backend_tensor_get
#ifdef SD_USE_CUBLAS
    if(!ggml_backend_is_cpu(backend)) {
        ggml_backend_tensor_get_async(backend, tensor, data, offset, size);
        ggml_backend_synchronize(backend);
    } else {
        ggml_backend_tensor_get(tensor, data, offset, size);
    }
#else
    ggml_backend_tensor_get(tensor, data, offset, size);
#endif
}

with and without vae tiling

@Jonathhhan
Copy link

Jonathhhan commented Jan 5, 2024

@FSSRepo control net works very well for the first image after the model was loaded. Is it possible to make it work for more than one image after loading the model?

@Green-Sky
Copy link
Contributor

@Green-Sky Does it also solve the VAE tiling problem?

which one? the neony artifacts or the "some tiles look lower resolution" ?

I ran the branch rn and it appears the tiling is not executed? despite it being set.

    vae_tiling:        true
[DEBUG] ggml_extend.hpp:603  - clip compute buffer size: 2.58 MB
[DEBUG] stable-diffusion.cpp:460  - computing condition graph completed, taking 8 ms
[INFO ] stable-diffusion.cpp:1266 - get_learned_condition completed, taking 28 ms
[INFO ] stable-diffusion.cpp:1282 - sampling using Euler A method
[INFO ] stable-diffusion.cpp:1286 - generating image: 1/1 - seed 42
[DEBUG] ggml_extend.hpp:603  - unet compute buffer size: 2137.25 MB
  |==================================================| 20/20 - 1.11it/s
[INFO ] stable-diffusion.cpp:1298 - sampling completed, taking 18.37s
[INFO ] stable-diffusion.cpp:1306 - generating 1 latent images completed, taking 18.37s
[INFO ] stable-diffusion.cpp:1308 - decoding 1 latents
[DEBUG] ggml_extend.hpp:603  - vae compute buffer size: 3329.00 MB
[DEBUG] stable-diffusion.cpp:1111 - computing vae [mode: DECODE] graph completed, taking 1.49s
[INFO ] stable-diffusion.cpp:1318 - latent 1 decoded, taking 1.49s
[INFO ] stable-diffusion.cpp:1322 - decode_first_stage completed, taking 1.49s
[INFO ] stable-diffusion.cpp:1339 - txt2img completed in 19.89s

... if however I am wrong and the tiling is executed, then it's perfect now. Even the seams would be gone.

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Jan 5, 2024

@Green-Sky you can try again

@Green-Sky
Copy link
Contributor

Green-Sky commented Jan 5, 2024

toggling this section does not make a difference:

#ifdef SD_USE_CUBLAS
    if(!ggml_backend_is_cpu(backend)) {
        ggml_backend_tensor_get_async(backend, tensor, data, offset, size);
        ggml_backend_synchronize(backend);
    } else {
        ggml_backend_tensor_get(tensor, data, offset, size);
    }
#else
    ggml_backend_tensor_get(tensor, data, offset, size);
#endif

as is:
output_4

without:
output_4

at least it looks like it is deterministic. (besides github deciding randomly how large an image is displayed/processed)

@Green-Sky
Copy link
Contributor

also, if the tiles are overlapped, no steams should be visible.
(weak src: madebyollin/taesd#8 (comment) )

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Jan 5, 2024

When conducting tests, I am also obtaining results that seem to be of low resolution. I'm not sure what the cause might be.

EDIT:

It seems to be something inherent to VAE tiling, as I tried with a CPU backend and obtained the same low-resolution result.

@Jonathhhan
Copy link

Jonathhhan commented Jan 5, 2024

control net works very well for the first image after the model was loaded. Is it possible to make it work for more than one image after loading the model?

Adding control_net.end(); at line 1026 in stable-diffusion.cpp solves my issue.

Openpose and scribble work quite well, canny not so well (it depends on the input image, actually) and preprocess_canny crashes without an error message.

Screenshot 2024-01-06 003154

Screenshot 2024-01-06 003452

@Jonathhhan
Copy link

Segmentation with control_seg-fp16 is also working very well.

seg

Screenshot 2024-01-06 005456

@Jonathhhan
Copy link

Jonathhhan commented Jan 6, 2024

The missing part is to create the preprocessors. But that is cumbersome and somewhat complicated, as it requires implementing other models (image2depth and openpose) and algorithms to perform Canny (edge detection).

Not sure, if this is of any help. But I tried to do canny edge detection with openCv and it works quite well.
This is the code that I use for Open Frameworks:

						image.load(result.getPath());
						int lowThreshold = 50;
						const int max_lowThreshold = 100;
						const int ratio = 3;
						const int kernel_size = 3;
						cv::Mat src, src_gray;
						cv::Mat detected_edges;
						src = ofxCv::toCv(image);
						cv::cvtColor(src, src_gray, cv::COLOR_BGR2GRAY);
						cv::blur(src_gray, detected_edges, cv::Size(3, 3));
						cv::Canny(detected_edges, detected_edges, lowThreshold, lowThreshold* ratio, kernel_size);
						ofxCv::toOf(detected_edges, image);
						image.update();

And here a general example: https://docs.opencv.org/4.x/da/d5c/tutorial_canny_detector.html

And I use this for openpose generation:

						const int POSE_PAIRS[17][2] = {
							{1,2}, {1,5}, {2,3},
							{3,4}, {5,6}, {6,7},
							{1,8}, {8,9}, {9,10},
							{1,11}, {11,12}, {12,13},
							{1,0}, {0,14},
							{14,16}, {0,15}, {15,17}};
						const vector<Scalar> POSE_PAIRS_COLORS{
							Scalar(255.f, 0.f, 85.f), 
							Scalar(255.f, 0.f, 0.f), 
							Scalar(255.f, 85.f, 0.f), 
							Scalar(255.f, 170.f, 0.f), 
							Scalar(255.f, 255.f, 0.f), 
							Scalar(170.f, 255.f, 0.f), 
							Scalar(85.f, 255.f, 0.f), 
							Scalar(0.f, 255.f, 0.f), 
							Scalar(0.f, 255.f, 85.f), 
							Scalar(0.f, 255.f, 170.f), 
							Scalar(0.f, 255.f, 255.f), 
							Scalar(0.f, 170.f, 255.f), 
							Scalar(0.f, 85.f, 255.f), 
							Scalar(0.f, 0.f, 255.f), 
							Scalar(255.f, 0.f, 170.f), 
							Scalar(170.f, 0.f, 255.f), 
							Scalar(255.f, 0.f, 255.f),
							Scalar(85.f, 0.f, 255.f)};
						image.load(result.getPath());
						Mat src = ofxCv::toCv(image);
						Mat img;
						resize(src, img, Size(width, height), 0, 0, INTER_CUBIC);
						// read the network model
						Net net = readNet(ofToDataPath("pose_iter_440000.caffemodel"), ofToDataPath("openpose_pose_coco.prototxt.txt"));
						// send the image through the network
						Mat inputBlob = blobFromImage(img, 1.f / 255.f, Size(width, height), Scalar(0, 0, 0), false, false);
						net.setInput(inputBlob);
						Mat result = net.forward();
						// the result is an array of "heatmaps", the probability of a body part being in location x,y
						int H = result.size[2];
						int W = result.size[3];
						// find the position of the body parts
						vector<Point> points(22);
						for (int n = 0; n < 18; n++)
						{
							// Slice heatmap of corresponding body's part.
							Mat heatMap(H, W, CV_32F, result.ptr(0, n));
							// 1 maximum per heatmap
							Point p(-1, -1), pm;
							double conf;
							minMaxLoc(heatMap, 0, &conf, 0, &pm);
							if (conf > 0.0)
								p = pm;
							points[n] = p;
						}
						// connect body parts and draw it !
						img = Scalar(0, 0, 0);
						float SX = float(img.cols) / W;
						float SY = float(img.rows) / H;
						for (int n = 0; n < 17; n++)
						{
							// lookup 2 connected body/hand parts
							Point2f a = points[POSE_PAIRS[n][0]];
							Point2f b = points[POSE_PAIRS[n][1]];
							// we did not find enough confidence before
							if (a.x <= 0 || a.y <= 0 || b.x <= 0 || b.y <= 0)
								continue;
							// scale to image size
							a.x *= SX; a.y *= SY;
							b.x *= SX; b.y *= SY;
							line(img, a, b, POSE_PAIRS_COLORS[n], 5);
							circle(img, a, 3, POSE_PAIRS_COLORS[n], -1);
							circle(img, b, 3, POSE_PAIRS_COLORS[n], -1);
						}
						ofxCv::toOf(img, image);
						image.update();

Which is based on this example: https://docs.opencv.org/3.4/d7/d4f/samples_2dnn_2openpose_8cpp-example.html

And maybe this can be used for image segmentation: https://github.com/ggerganov/ggml/tree/master/examples/sam?

@FSSRepo
Copy link
Contributor Author

FSSRepo commented Jan 8, 2024

That implies using very heavy libraries that are not really necessary for the functioning of this project itself; it's better to have it integrated from scratch in ggml.

@Jonathhhan
Copy link

Jonathhhan commented Jan 8, 2024

That implies using very heavy libraries that are not really necessary for the functioning of this project itself; it's better to have it integrated from scratch in ggml.

True (at least sam.cpp works with ggml, but SamAutomaticMaskGenerator, which is needed for segmenting a whole image, is not part of sam.cpp yet).

@leejet
Copy link
Owner

leejet commented Jan 29, 2024

In the past few weeks, I have been busy with pull requests related to svd, so I didn't have a chance to merge this PR. Now that I've addressed some issues, I'm ready to merge this PR. Thank you for your contribution.

@leejet leejet merged commit 36ec16a into leejet:master Jan 29, 2024
7 checks passed
@FSSRepo
Copy link
Contributor Author

FSSRepo commented Jan 29, 2024

@leejet Thank you for continuing to maintain the project despite having other jobs. I'll see if in the next few days, when I have time to implement flash attention in llama.cpp, I can adapt the web UI that I already have created to the project.

@pwillia7
Copy link

pwillia7 commented Feb 2, 2024

Would controlnet with SDXL work with this update?

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.

7 participants