Skip to content

Commit 91e9433

Browse files
committed
Add image handling and denoise parameter support in inference and model components
1 parent 75dfdd9 commit 91e9433

20 files changed

Lines changed: 581 additions & 237 deletions

.github/workflows/docker.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ jobs:
2929
with:
3030
persist-credentials: false
3131

32+
- name: Free disk space for CUDA layers
33+
run: |
34+
sudo rm --recursive --force /usr/share/dotnet /usr/local/lib/android /opt/hostedtoolcache
35+
df -h /
36+
3237
- name: Set up Docker Buildx
3338
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
3439

@@ -59,8 +64,7 @@ jobs:
5964
tags: ${{ steps.metadata.outputs.tags }}
6065
labels: ${{ steps.metadata.outputs.labels }}
6166
annotations: ${{ steps.metadata.outputs.annotations }}
62-
load: ${{ env.PUBLISH != 'true' }}
63-
push: ${{ env.PUBLISH == 'true' }}
67+
outputs: ${{ env.PUBLISH == 'true' && 'type=image,push=true' || 'type=cacheonly' }}
6468
provenance: ${{ env.PUBLISH == 'true' }}
6569
sbom: ${{ env.PUBLISH == 'true' }}
6670
cache-from: type=gha,scope=genesia-docker

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,10 @@ target_link_libraries(
127127
PUBLIC
128128
CCCL::libcudacxx
129129
CUDA::toolkit
130-
genesia::cudnn-frontend
130+
cuDNN::cuDNN
131131
CUDA::cublasLt
132132
PRIVATE
133+
genesia::cudnn-frontend
133134
CUDA::cudart
134135
CUDA::cuda_driver
135136
CUDA::nvrtc

Dockerfile

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
# syntax=docker/dockerfile:1
22
# hadolint global ignore=DL3007
33

4-
FROM archlinux:latest AS build
4+
FROM archlinux:latest AS cuda
55

66
SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
77

88
RUN --mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \
9-
pacman -Syu --noconfirm --needed \
9+
pacman -Syu --noconfirm --needed cuda cudnn gcc-libs
10+
11+
ENV PATH="/opt/cuda/bin:${PATH}"
12+
13+
14+
FROM cuda AS build
15+
16+
RUN --mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \
17+
pacman -S --noconfirm --needed \
1018
base-devel \
1119
cmake \
12-
cuda \
13-
cudnn \
1420
git \
1521
ninja
1622

17-
ENV PATH="/opt/cuda/bin:${PATH}"
18-
1923
WORKDIR /src
2024
COPY --link . .
2125

@@ -30,11 +34,9 @@ RUN cmake -S . -B cmake-build-release -G Ninja \
3034
&& cmake --build cmake-build-release --target genesia --parallel
3135

3236

33-
FROM archlinux:latest AS runtime
37+
FROM cuda AS runtime
3438

35-
RUN --mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \
36-
pacman -Syu --noconfirm --needed cuda cudnn gcc-libs \
37-
&& groupadd --gid 10001 genesia \
39+
RUN groupadd --gid 10001 genesia \
3840
&& useradd --uid 10001 --gid 10001 --home-dir /workspace --shell /usr/bin/nologin genesia \
3941
&& install --directory --owner=10001 --group=10001 /opt/genesia/bin /workspace
4042

genesia/core/generation/defaults.ixx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export namespace genesia::defaults {
66
inline constexpr int height = 1536;
77
inline constexpr int steps = 50;
88
inline constexpr float cfg = 4.5F;
9+
inline constexpr float denoise = 0.50F;
910
inline constexpr bool random_seed = true;
1011
inline constexpr std::array<std::uint64_t, 1> seeds{16494404764960740964ULL};
1112
inline constexpr int warmup = 0;

genesia/core/generation/output.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ namespace genesia {
4949
const auto started = std::chrono::steady_clock::now();
5050
const auto model = record.model.u8string();
5151
nlohmann::json metadata{{"version", 1}, {"model", std::string{model.begin(), model.end()}}, {"seed", record.seed}, {"steps", record.parameters.steps}, {"cfg", record.parameters.cfg}, {"sampler", "euler"}, {"scheduler", "simple"}};
52+
if (!record.source.empty()) {
53+
const auto source = record.source.u8string();
54+
metadata["repaint"] = {{"source", std::string{source.begin(), source.end()}}, {"denoise", record.parameters.denoise}};
55+
}
5256
for (const auto& [name, side, text] : {std::tuple{"positive", &record.prompt.positive, &record.parameters.positive}, std::tuple{"negative", &record.prompt.negative, &record.parameters.negative}}) {
5357
auto& saved = metadata["prompt"][name];
5458
saved["text"] = *text;

genesia/core/generation/output.ixx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export namespace genesia {
1212
std::filesystem::path model;
1313
prompt::Pair prompt;
1414
std::shared_ptr<const prompt::Catalog> catalog;
15+
std::filesystem::path source;
1516
};
1617
struct ImageWriter final {
1718
std::filesystem::path directory;

genesia/core/neural/inference-runtime.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,25 @@ module genesia.neural.inference_runtime;
1212
import std;
1313

1414
namespace genesia::neural {
15+
struct InferenceRuntime::ConvPlan final {
16+
std::array<int, 10> key;
17+
cudnn_frontend::graph::Graph graph;
18+
19+
explicit ConvPlan(const std::array<int, 10>& key);
20+
};
21+
22+
struct InferenceRuntime::AttentionPlan final {
23+
std::array<int, 10> key;
24+
cudnn_frontend::graph::Graph graph;
25+
::cuda::device_buffer<std::int32_t> query_lengths;
26+
27+
AttentionPlan(::cuda::stream_ref stream, const std::array<int, 10>& shape);
28+
};
29+
30+
void check(cudnn_frontend::error_t status) {
31+
if (status.is_bad()) throw std::runtime_error{status.get_message()};
32+
}
33+
1534
nlohmann::json read_plan(const std::filesystem::path& path) {
1635
std::ifstream file{path, std::ios::binary};
1736
file.exceptions(std::ios::failbit | std::ios::badbit);
@@ -50,7 +69,7 @@ namespace genesia::neural {
5069
check(cublasLtMatrixLayoutCreate(std::out_ptr(output), result_dtype, n, m, n));
5170
}
5271

53-
ConvPlan::ConvPlan(const std::array<int, 10>& shape) : key{shape} {
72+
InferenceRuntime::ConvPlan::ConvPlan(const std::array<int, 10>& shape) : key{shape} {
5473
const auto [n, h, w, input_width, output_width, kernel, stride, padding, scalar, residual] = shape;
5574
const auto dtype = scalar == 1 ? cudnn_frontend::DataType_t::HALF : cudnn_frontend::DataType_t::BFLOAT16;
5675
graph.set_io_data_type(dtype).set_intermediate_data_type(cudnn_frontend::DataType_t::FLOAT).set_compute_data_type(cudnn_frontend::DataType_t::FLOAT);
@@ -320,7 +339,4 @@ namespace genesia::neural {
320339
void check(const cudnnStatus_t status) {
321340
if (status != CUDNN_STATUS_SUCCESS) throw std::runtime_error{cudnnGetErrorString(status)};
322341
}
323-
void check(cudnn_frontend::error_t status) {
324-
if (status.is_bad()) throw std::runtime_error{status.get_message()};
325-
}
326342
} // namespace genesia::neural

genesia/core/neural/inference-runtime.ixx

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module;
22

33
#include <cublasLt.h>
4-
#include <cudnn_frontend.h>
4+
#include <cudnn.h>
55
#include <genesia/cuda.h>
66

77
export module genesia.neural.inference_runtime;
@@ -69,19 +69,15 @@ export namespace genesia::neural {
6969
MatmulPlan& operator=(const MatmulPlan&) = delete;
7070
};
7171

72-
struct ConvPlan final {
73-
std::array<int, 10> key;
74-
cudnn_frontend::graph::Graph graph;
75-
76-
explicit ConvPlan(const std::array<int, 10>& key);
77-
};
78-
7972
struct InferenceRuntime final {
8073
::cuda::stream_ref stream;
8174
std::size_t cache_hits{};
8275
std::size_t cache_misses{};
8376

8477
private:
78+
struct ConvPlan;
79+
struct AttentionPlan;
80+
8581
std::unique_ptr<std::remove_pointer_t<cublasLtHandle_t>, decltype(&cublasLtDestroy)> blas{nullptr, cublasLtDestroy};
8682
std::unique_ptr<std::remove_pointer_t<cudnnHandle_t>, decltype(&cudnnDestroy)> dnn{nullptr, cudnnDestroy};
8783
::cuda::device_buffer<std::byte> workspace;
@@ -94,12 +90,6 @@ export namespace genesia::neural {
9490
std::size_t intermediate_bytes{};
9591
std::list<MatmulPlan> matmuls;
9692
std::list<ConvPlan> convolutions;
97-
struct AttentionPlan final {
98-
std::array<int, 10> key;
99-
cudnn_frontend::graph::Graph graph;
100-
::cuda::device_buffer<std::int32_t> query_lengths;
101-
AttentionPlan(::cuda::stream_ref stream, const std::array<int, 10>& shape);
102-
};
10393
std::list<AttentionPlan> attentions;
10494

10595
public:
@@ -124,5 +114,4 @@ export namespace genesia::neural {
124114
void check(cudaError_t status);
125115
void check(cublasStatus_t status);
126116
void check(cudnnStatus_t status);
127-
void check(cudnn_frontend::error_t status);
128117
} // namespace genesia::neural

genesia/core/sdxl/kernels.cu

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,18 @@ namespace genesia::sdxl::kernels {
7171
if (threadIdx.x * 4 + j < 1000) training[threadIdx.x * 4 + j] = sqrtf(expm1f(-values[j]));
7272
}
7373

74-
__global__ void schedule_kernel(SamplingStep* output, float* times, const float* training, const int steps) {
74+
__global__ void schedule_kernel(SamplingStep* output, float* times, const float* training, const int steps, const int total) {
7575
const int i = blockIdx.x * blockDim.x + threadIdx.x;
7676
if (i > steps) return;
77-
const float sigma = i == steps ? 0.0F : training[999 - i * 1000 / steps];
78-
const float next = i + 1 >= steps ? 0.0F : training[999 - (i + 1) * 1000 / steps];
77+
const int position = total - steps + i;
78+
const int time = 999 - int(static_cast<long long>(position) * 1000 / total);
79+
const float sigma = i == steps ? 0.0F : training[time];
80+
const float next = i + 1 >= steps ? 0.0F : training[999 - int(static_cast<long long>(position + 1) * 1000 / total)];
7981
output[i] = {sigma, next - sigma, rsqrtf(fmaf(sigma, sigma, 1.0F))};
80-
if (i < steps) times[i] = float(999 - i * 1000 / steps);
82+
if (i < steps) times[i] = float(time);
8183
}
8284

83-
__global__ void initialize_kernel(float* state, __half* input, int* step, const std::uint64_t* seed, const SamplingStep* schedule, const int count) {
85+
__global__ void initialize_kernel(float* state, __half* input, int* step, const std::uint64_t* seed, const SamplingStep* schedule, const int count, const float* source, const bool full_noise) {
8486
const int i = blockIdx.x * blockDim.x + threadIdx.x;
8587
if (i >= count / 4) return;
8688
uint4 counter{static_cast<unsigned>(i), 0, 0, 0};
@@ -98,8 +100,15 @@ namespace genesia::sdxl::kernels {
98100
sincosf(float(counter.w) * 0x1p-32F * 6.283185307179586F, &sine1, &cosine1);
99101
const float radius0 = sqrtf(-2.0F * logf((float(counter.x) + 1.0F) * 0x1p-32F));
100102
const float radius1 = sqrtf(-2.0F * logf((float(counter.z) + 1.0F) * 0x1p-32F));
101-
const float scale = sqrtf(fmaf(schedule[0].sigma, schedule[0].sigma, 1.0F));
102-
const float4 values{radius0 * sine0 * scale, radius0 * cosine0 * scale, radius1 * sine1 * scale, radius1 * cosine1 * scale};
103+
const float scale = full_noise ? sqrtf(fmaf(schedule[0].sigma, schedule[0].sigma, 1.0F)) : schedule[0].sigma;
104+
float4 values{radius0 * sine0 * scale, radius0 * cosine0 * scale, radius1 * sine1 * scale, radius1 * cosine1 * scale};
105+
if (source) {
106+
const float4 original = reinterpret_cast<const float4*>(source)[i];
107+
values.x += original.x;
108+
values.y += original.y;
109+
values.z += original.z;
110+
values.w += original.w;
111+
}
103112
reinterpret_cast<float4*>(state)[i] = values;
104113
const float data[4]{values.x, values.y, values.z, values.w};
105114
#pragma unroll
@@ -148,6 +157,24 @@ namespace genesia::sdxl::kernels {
148157
if (stopped || completed == count) ::cuda::atomic_ref<std::uint32_t, ::cuda::thread_scope_system>{control->stage}.store(static_cast<std::uint32_t>(stopped ? Stage::cancelled : Stage::decoding), ::cuda::memory_order_release);
149158
}
150159

160+
__global__ void image_encode_kernel(__nv_bfloat16* output, const std::uint8_t* input, const int count) {
161+
const int i = blockIdx.x * blockDim.x + threadIdx.x;
162+
if (i < count) output[i] = __nv_bfloat16(float(input[i]) * (2.0F / 255.0F) - 1.0F);
163+
}
164+
165+
__global__ void encoder_pad_kernel(__nv_bfloat16* output, const __nv_bfloat16* input, const int height, const int width, const int channels) {
166+
const int i = blockIdx.x * blockDim.x + threadIdx.x;
167+
if (i >= (height + 1) * (width + 1) * channels) return;
168+
const int x = i / channels % (width + 1);
169+
const int y = i / channels / (width + 1);
170+
output[i] = x < width && y < height ? input[(y * width + x) * channels + i % channels] : __nv_bfloat16(0.0F);
171+
}
172+
173+
__global__ void latent_encode_kernel(float* output, const __nv_bfloat16* moments, const int count) {
174+
const int i = blockIdx.x * blockDim.x + threadIdx.x;
175+
if (i < count) output[i] = float(moments[i / 4 * 8 + i % 4]) * 0.13025F;
176+
}
177+
151178
__global__ void latent_decode_kernel(__nv_bfloat16* output, const float* input, const int count) {
152179
const int i = blockIdx.x * blockDim.x + threadIdx.x;
153180
if (i < count) output[i] = __nv_bfloat16(input[i] / 0.13025F);
@@ -184,11 +211,11 @@ namespace genesia::sdxl::kernels {
184211
void training_sigmas(const ::cuda::stream_ref stream, float* output) {
185212
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims(1), ::cuda::block_dims(256))), training_kernel, output);
186213
}
187-
void prepare_schedule(const ::cuda::stream_ref stream, SamplingStep* output, float* times, const float* training, const int steps) {
188-
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims((steps + 256) / 256), ::cuda::block_dims(256))), schedule_kernel, output, times, training, steps);
214+
void prepare_schedule(const ::cuda::stream_ref stream, SamplingStep* output, float* times, const float* training, const int steps, const float denoise) {
215+
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims((steps + 256) / 256), ::cuda::block_dims(256))), schedule_kernel, output, times, training, steps, static_cast<int>(steps / double(denoise)));
189216
}
190-
void initialize(const ::cuda::stream_ref stream, float* state, void* input, int* step, const std::uint64_t* seed, const SamplingStep* schedule, const int count) {
191-
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims((count / 4 + 255) / 256), ::cuda::block_dims(256))), initialize_kernel, state, static_cast<__half*>(input), step, seed, schedule, count);
217+
void initialize(const ::cuda::stream_ref stream, float* state, void* input, int* step, const std::uint64_t* seed, const SamplingStep* schedule, const int count, const float* source, const bool full_noise) {
218+
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims((count / 4 + 255) / 256), ::cuda::block_dims(256))), initialize_kernel, state, static_cast<__half*>(input), step, seed, schedule, count, source, full_noise);
192219
}
193220
void snapshot_begin(const ::cuda::stream_ref stream, int* selected, SnapshotSlot* slots) {
194221
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims(1), ::cuda::block_dims(1))), snapshot_begin_kernel, selected, slots);
@@ -206,6 +233,15 @@ namespace genesia::sdxl::kernels {
206233
void advance(const ::cuda::stream_ref stream, int* step, const int count, const cudaGraphConditionalHandle loop, const cudaGraphConditionalHandle decode, Control* control) {
207234
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims(1), ::cuda::block_dims(1))), advance_kernel, step, count, loop, decode, control);
208235
}
236+
void image_encode(const ::cuda::stream_ref stream, void* output, const std::uint8_t* pixels, const int count) {
237+
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims((count + 255) / 256), ::cuda::block_dims(256))), image_encode_kernel, static_cast<__nv_bfloat16*>(output), pixels, count);
238+
}
239+
void encoder_pad(const ::cuda::stream_ref stream, void* output, const void* input, const int height, const int width, const int channels) {
240+
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims(((height + 1) * (width + 1) * channels + 255) / 256), ::cuda::block_dims(256))), encoder_pad_kernel, static_cast<__nv_bfloat16*>(output), static_cast<const __nv_bfloat16*>(input), height, width, channels);
241+
}
242+
void latent_encode(const ::cuda::stream_ref stream, float* output, const void* moments, const int count) {
243+
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims((count + 255) / 256), ::cuda::block_dims(256))), latent_encode_kernel, output, static_cast<const __nv_bfloat16*>(moments), count);
244+
}
209245
void latent_decode(const ::cuda::stream_ref stream, void* output, const float* latent, const int count) {
210246
::cuda::launch(stream, ::cuda::make_config(::cuda::make_hierarchy(::cuda::grid_dims((count + 255) / 256), ::cuda::block_dims(256))), latent_decode_kernel, static_cast<__nv_bfloat16*>(output), latent, count);
211247
}

genesia/core/sdxl/kernels.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@ namespace genesia::sdxl::kernels {
2020
void conditions(const ::cuda::stream_ref stream, void* output, const void* pooled, const void* geometry);
2121
void time_condition(const ::cuda::stream_ref stream, void* output, const void* times, const void* labels, const int steps);
2222
void training_sigmas(const ::cuda::stream_ref stream, float* output);
23-
void prepare_schedule(const ::cuda::stream_ref stream, SamplingStep* output, float* times, const float* training, const int steps);
24-
void initialize(const ::cuda::stream_ref stream, float* state, void* input, int* step, const std::uint64_t* seed, const SamplingStep* schedule, const int count);
23+
void prepare_schedule(::cuda::stream_ref stream, SamplingStep* output, float* times, const float* training, int steps, float denoise = 1);
24+
void initialize(::cuda::stream_ref stream, float* state, void* input, int* step, const std::uint64_t* seed, const SamplingStep* schedule, int count, const float* source = nullptr, bool full_noise = true);
2525
void snapshot_begin(::cuda::stream_ref stream, int* selected, SnapshotSlot* slots);
2626
void snapshot_publish(::cuda::stream_ref stream, const int* selected, SnapshotSlot* slots, const int* step);
2727
void euler(const ::cuda::stream_ref stream, float* state, void* input, const void* epsilon, const SamplingStep* schedule, const int* step, const float cfg, const int count, float* snapshots = nullptr, const int* selected = nullptr);
2828
void advance(::cuda::stream_ref stream, int* step, int count, cudaGraphConditionalHandle loop, cudaGraphConditionalHandle decode, Control* control);
29+
void image_encode(::cuda::stream_ref stream, void* output, const std::uint8_t* pixels, int count);
30+
void encoder_pad(::cuda::stream_ref stream, void* output, const void* input, int height, int width, int channels);
31+
void latent_encode(::cuda::stream_ref stream, float* output, const void* moments, int count);
2932
void latent_decode(const ::cuda::stream_ref stream, void* output, const float* latent, const int count);
3033
void pixels(const ::cuda::stream_ref stream, std::uint8_t* output, const void* input, const int count);
3134
} // namespace genesia::sdxl::kernels

0 commit comments

Comments
 (0)