#ifndef __SD_MODEL_DIFFUSION_SENSENOVA_U1_H__ #define __SD_MODEL_DIFFUSION_SENSENOVA_U1_H__ #include #include #include #include #include #include #include #include #include "core/ggml_extend.h" #include "model/diffusion/dit.hpp" #include "model/diffusion/model.hpp" #include "model/te/llm.hpp" #include "model_loader.h" namespace SenseNovaU1 { constexpr int SENSENOVA_U1_GRAPH_SIZE = 327680; struct SenseNovaU1Config { int64_t hidden_size = 4096; int64_t intermediate_size = 12288; int64_t num_layers = 42; int64_t num_heads = 32; int64_t num_kv_heads = 8; int64_t head_dim = 128; int64_t vocab_size = 151936; int64_t max_position_embeddings = 262144; int64_t max_position_embeddings_hw = 10000; int64_t vision_hidden_size = 1024; int64_t patch_size = 16; int64_t vision_downsample_factor = 2; int64_t in_channels = 3; int64_t timestep_embedding_size = 256; float rms_norm_eps = 1e-6f; float rope_theta = 5000000.f; float rope_theta_hw = 10000.f; float noise_scale_base_image_seq_len = 64.f; float noise_scale_max_value = 16.f; float t_eps = 0.02f; bool add_noise_scale_embedding = true; int64_t image_token_stride() const { return patch_size * vision_downsample_factor; } static SenseNovaU1Config detect_from_weights(const String2TensorStorage& tensor_storage_map, const std::string& prefix) { SenseNovaU1Config config; config.num_layers = 0; const std::string root = prefix.empty() ? "" : prefix + "."; for (const auto& [name, tensor_storage] : tensor_storage_map) { if (!starts_with(name, root)) { continue; } if (ends_with(name, "language_model.model.embed_tokens.weight") && tensor_storage.n_dims == 2) { config.hidden_size = tensor_storage.ne[0]; config.vocab_size = tensor_storage.ne[1]; } else if (ends_with(name, "language_model.model.layers.0.mlp.gate_proj.weight") && tensor_storage.n_dims == 2) { config.intermediate_size = tensor_storage.ne[1]; } else if (ends_with(name, "language_model.model.layers.0.self_attn.q_proj.weight") && tensor_storage.n_dims == 2) { config.num_heads = tensor_storage.ne[1] / config.head_dim; } else if (ends_with(name, "language_model.model.layers.0.self_attn.k_proj.weight") && tensor_storage.n_dims == 2) { config.num_kv_heads = tensor_storage.ne[1] / config.head_dim; } else if (ends_with(name, "fm_modules.vision_model_mot_gen.embeddings.patch_embedding.weight") && tensor_storage.n_dims == 4) { config.patch_size = tensor_storage.ne[0]; config.in_channels = tensor_storage.ne[2]; config.vision_hidden_size = tensor_storage.ne[3]; } else if (ends_with(name, "fm_modules.vision_model_mot_gen.embeddings.dense_embedding.weight") && tensor_storage.n_dims == 4) { config.vision_downsample_factor = tensor_storage.ne[0]; } const std::string layer_prefix = root + "language_model.model.layers."; if (starts_with(name, layer_prefix)) { const char* index_begin = name.c_str() + layer_prefix.size(); config.num_layers = std::max(config.num_layers, std::strtoll(index_begin, nullptr, 10) + 1); } } if (config.num_layers == 0) { config.num_layers = 42; } config.add_noise_scale_embedding = tensor_storage_map.find(root + "fm_modules.noise_scale_embedder.mlp.0.weight") != tensor_storage_map.end(); LOG_DEBUG("sensenova-u1.5: layers=%" PRId64 ", hidden=%" PRId64 ", intermediate=%" PRId64 ", heads=%" PRId64 ", kv_heads=%" PRId64 ", patch=%" PRId64 "x%" PRId64, config.num_layers, config.hidden_size, config.intermediate_size, config.num_heads, config.num_kv_heads, config.patch_size, config.vision_downsample_factor); return config; } }; class StorageConv2d : public Conv2d { protected: void init_params(ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override { this->prefix = prefix; ggml_type wtype = get_type(prefix + "weight", tensor_storage_map, GGML_TYPE_F16); params["weight"] = ggml_new_tensor_4d(ctx, wtype, kernel_size.second, kernel_size.first, in_channels, out_channels); if (bias) { params["bias"] = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, out_channels); } } public: StorageConv2d(int64_t in_channels, int64_t out_channels, std::pair kernel_size, std::pair stride = {1, 1}, std::pair padding = {0, 0}, bool bias = true) : Conv2d(in_channels, out_channels, kernel_size, stride, padding, {1, 1}, bias) {} }; struct TimestepEmbedder : public GGMLBlock { int64_t frequency_embedding_size; TimestepEmbedder(int64_t hidden_size, int64_t frequency_embedding_size = 256) : frequency_embedding_size(frequency_embedding_size) { blocks["mlp.0"] = std::make_shared(frequency_embedding_size, hidden_size, true); blocks["mlp.2"] = std::make_shared(hidden_size, hidden_size, true); } ggml_tensor* forward(GGMLRunnerContext* ctx, ggml_tensor* timesteps) { auto mlp_0 = std::dynamic_pointer_cast(blocks["mlp.0"]); auto mlp_2 = std::dynamic_pointer_cast(blocks["mlp.2"]); auto x = ggml_ext_timestep_embedding(ctx->ggml_ctx, timesteps, static_cast(frequency_embedding_size), 10000, 1.f); x = mlp_0->forward(ctx, x); x = ggml_silu_inplace(ctx->ggml_ctx, x); return mlp_2->forward(ctx, x); } }; inline ggml_tensor* apply_vision_rope(GGMLRunnerContext* ctx, ggml_tensor* x, ggml_tensor* position_x, ggml_tensor* position_y, float theta, int max_position) { GGML_ASSERT(x->ne[0] % 2 == 0); // ggml_rope_ext addresses positions through ne[2]. The vision // embeddings arrive as [hidden, tokens, batch], so add the singleton // head axis used by the RoPE kernel: [hidden, 1, tokens, batch]. x = ggml_reshape_4d(ctx->ggml_ctx, x, x->ne[0], 1, x->ne[1], x->ne[2]); const int64_t half = x->ne[0] / 2; auto x_part = ggml_ext_slice(ctx->ggml_ctx, x, 0, 0, half); auto y_part = ggml_ext_slice(ctx->ggml_ctx, x, 0, half, x->ne[0]); x_part = ggml_rope_ext(ctx->ggml_ctx, x_part, position_x, nullptr, static_cast(half), GGML_ROPE_TYPE_NORMAL, max_position, theta, 1.f, 0.f, 1.f, 32.f, 1.f); y_part = ggml_rope_ext(ctx->ggml_ctx, y_part, position_y, nullptr, static_cast(half), GGML_ROPE_TYPE_NORMAL, max_position, theta, 1.f, 0.f, 1.f, 32.f, 1.f); return ggml_concat(ctx->ggml_ctx, x_part, y_part, 0); } struct VisionEmbeddings : public GGMLBlock { SenseNovaU1Config config; explicit VisionEmbeddings(const SenseNovaU1Config& config) : config(config) { blocks["patch_embedding"] = std::make_shared(config.in_channels, config.vision_hidden_size, std::pair{static_cast(config.patch_size), static_cast(config.patch_size)}, std::pair{static_cast(config.patch_size), static_cast(config.patch_size)}, std::pair{0, 0}, true); blocks["dense_embedding"] = std::make_shared(config.vision_hidden_size, config.hidden_size, std::pair{static_cast(config.vision_downsample_factor), static_cast(config.vision_downsample_factor)}, std::pair{static_cast(config.vision_downsample_factor), static_cast(config.vision_downsample_factor)}, std::pair{0, 0}, true); } ggml_tensor* forward(GGMLRunnerContext* ctx, ggml_tensor* image, ggml_tensor* position_x, ggml_tensor* position_y) { auto patch_embedding = std::dynamic_pointer_cast(blocks["patch_embedding"]); auto dense_embedding = std::dynamic_pointer_cast(blocks["dense_embedding"]); auto x = patch_embedding->forward(ctx, image); x = ggml_gelu_erf(ctx->ggml_ctx, x); const int64_t grid_w = x->ne[0]; const int64_t grid_h = x->ne[1]; const int64_t batch = x->ne[3]; x = ggml_reshape_3d(ctx->ggml_ctx, x, grid_w * grid_h, x->ne[2], batch); x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 0, 2, 3)); x = apply_vision_rope(ctx, x, position_x, position_y, config.rope_theta_hw, static_cast(config.max_position_embeddings_hw)); x = ggml_reshape_4d(ctx->ggml_ctx, x, config.vision_hidden_size, grid_w, grid_h, batch); x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 2, 0, 1, 3)); x = dense_embedding->forward(ctx, x); const int64_t token_w = x->ne[0]; const int64_t token_h = x->ne[1]; x = ggml_reshape_3d(ctx->ggml_ctx, x, token_w * token_h, x->ne[2], x->ne[3]); return ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 0, 2, 3)); } }; inline ggml_tensor* pixel_shuffle(GGMLRunnerContext* ctx, ggml_tensor* x, int upscale_factor) { GGML_ASSERT(upscale_factor > 0); const int64_t h = x->ne[1]; const int64_t w = x->ne[0]; GGML_ASSERT(x->ne[2] % (upscale_factor * upscale_factor) == 0); x = ggml_ext_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, x, 2, 0, 1, 3)); x = ggml_reshape_3d(ctx->ggml_ctx, x, x->ne[0], x->ne[1] * x->ne[2], x->ne[3]); return DiT::unpatchify(ctx->ggml_ctx, x, h, w, upscale_factor, upscale_factor, true); } struct PixelDecoder : public GGMLBlock { explicit PixelDecoder(const SenseNovaU1Config& config) { blocks["conv1"] = std::make_shared(config.hidden_size / 4, 1024, std::pair{3, 3}, std::pair{1, 1}, std::pair{1, 1}, true); blocks["conv2"] = std::make_shared(256, 192, std::pair{3, 3}, std::pair{1, 1}, std::pair{1, 1}, true); } ggml_tensor* forward(GGMLRunnerContext* ctx, ggml_tensor* x) { auto conv1 = std::dynamic_pointer_cast(blocks["conv1"]); auto conv2 = std::dynamic_pointer_cast(blocks["conv2"]); x = pixel_shuffle(ctx, x, 2); x = conv1->forward(ctx, x); x = ggml_gelu_erf(ctx->ggml_ctx, x); x = pixel_shuffle(ctx, x, 2); x = conv2->forward(ctx, x); return pixel_shuffle(ctx, x, 8); } }; enum class Branch { UNDERSTANDING, GENERATION, }; struct Attention : public GGMLBlock { SenseNovaU1Config config; int layer_index; Attention(const SenseNovaU1Config& config, int layer_index) : config(config), layer_index(layer_index) { blocks["q_proj"] = std::make_shared(config.hidden_size, config.num_heads * config.head_dim, false); blocks["k_proj"] = std::make_shared(config.hidden_size, config.num_kv_heads * config.head_dim, false); blocks["v_proj"] = std::make_shared(config.hidden_size, config.num_kv_heads * config.head_dim, false); blocks["o_proj"] = std::make_shared(config.num_heads * config.head_dim, config.hidden_size, false); blocks["q_proj_mot_gen"] = std::make_shared(config.hidden_size, config.num_heads * config.head_dim, false); blocks["k_proj_mot_gen"] = std::make_shared(config.hidden_size, config.num_kv_heads * config.head_dim, false); blocks["v_proj_mot_gen"] = std::make_shared(config.hidden_size, config.num_kv_heads * config.head_dim, false); blocks["o_proj_mot_gen"] = std::make_shared(config.num_heads * config.head_dim, config.hidden_size, false); const int64_t axis_dim = config.head_dim / 2; blocks["q_norm"] = std::make_shared(axis_dim, config.rms_norm_eps); blocks["k_norm"] = std::make_shared(axis_dim, config.rms_norm_eps); blocks["q_norm_hw"] = std::make_shared(axis_dim, config.rms_norm_eps); blocks["k_norm_hw"] = std::make_shared(axis_dim, config.rms_norm_eps); blocks["q_norm_mot_gen"] = std::make_shared(axis_dim, config.rms_norm_eps); blocks["k_norm_mot_gen"] = std::make_shared(axis_dim, config.rms_norm_eps); blocks["q_norm_hw_mot_gen"] = std::make_shared(axis_dim, config.rms_norm_eps); blocks["k_norm_hw_mot_gen"] = std::make_shared(axis_dim, config.rms_norm_eps); } ggml_tensor* apply_axis_rope(GGMLRunnerContext* ctx, ggml_tensor* x, ggml_tensor* positions, int dimensions, float theta, int max_position) { return ggml_rope_ext(ctx->ggml_ctx, x, positions, nullptr, dimensions, GGML_ROPE_TYPE_NEOX, max_position, theta, 1.f, 0.f, 1.f, 32.f, 1.f); } ggml_tensor* normalize_and_rotate(GGMLRunnerContext* ctx, ggml_tensor* x, ggml_tensor* position_t, ggml_tensor* position_h, ggml_tensor* position_w, const std::string& norm_name, const std::string& norm_hw_name) { const int64_t temporal_dim = config.head_dim / 2; const int64_t spatial_dim = config.head_dim - temporal_dim; const int64_t axis_dim = spatial_dim / 2; auto temporal = ggml_ext_slice(ctx->ggml_ctx, x, 0, 0, temporal_dim); auto spatial = ggml_ext_slice(ctx->ggml_ctx, x, 0, temporal_dim, config.head_dim); temporal = std::dynamic_pointer_cast(blocks[norm_name])->forward(ctx, temporal); spatial = std::dynamic_pointer_cast(blocks[norm_hw_name])->forward(ctx, spatial); auto height = ggml_ext_slice(ctx->ggml_ctx, spatial, 0, 0, axis_dim); auto width = ggml_ext_slice(ctx->ggml_ctx, spatial, 0, axis_dim, spatial_dim); temporal = apply_axis_rope(ctx, temporal, position_t, static_cast(temporal_dim), config.rope_theta, static_cast(config.max_position_embeddings)); height = apply_axis_rope(ctx, height, position_h, static_cast(axis_dim), config.rope_theta_hw, static_cast(config.max_position_embeddings_hw)); width = apply_axis_rope(ctx, width, position_w, static_cast(axis_dim), config.rope_theta_hw, static_cast(config.max_position_embeddings_hw)); return ggml_concat(ctx->ggml_ctx, ggml_concat(ctx->ggml_ctx, temporal, height, 0), width, 0); } ggml_tensor* forward(GGMLRunnerContext* ctx, ggml_tensor* x, ggml_tensor* position_t, ggml_tensor* position_h, ggml_tensor* position_w, ggml_tensor* attention_mask, Branch branch, const std::string& cache_prefix) { const bool generation = branch == Branch::GENERATION; const std::string suffix = generation ? "_mot_gen" : ""; auto q_proj = std::dynamic_pointer_cast(blocks["q_proj" + suffix]); auto k_proj = std::dynamic_pointer_cast(blocks["k_proj" + suffix]); auto v_proj = std::dynamic_pointer_cast(blocks["v_proj" + suffix]); auto o_proj = std::dynamic_pointer_cast(blocks["o_proj" + suffix]); const int64_t n_tokens = x->ne[1]; const int64_t batch = x->ne[2]; auto q = ggml_reshape_4d(ctx->ggml_ctx, q_proj->forward(ctx, x), config.head_dim, config.num_heads, n_tokens, batch); auto k = ggml_reshape_4d(ctx->ggml_ctx, k_proj->forward(ctx, x), config.head_dim, config.num_kv_heads, n_tokens, batch); auto v = ggml_reshape_4d(ctx->ggml_ctx, v_proj->forward(ctx, x), config.head_dim, config.num_kv_heads, n_tokens, batch); q = normalize_and_rotate(ctx, q, position_t, position_h, position_w, "q_norm" + suffix, "q_norm_hw" + suffix); k = normalize_and_rotate(ctx, k, position_t, position_h, position_w, "k_norm" + suffix, "k_norm_hw" + suffix); const std::string layer_cache = cache_prefix + "." + std::to_string(layer_index); if (generation) { auto prefix_k = ctx->load_cache_tensor(layer_cache + ".k"); auto prefix_v = ctx->load_cache_tensor(layer_cache + ".v"); GGML_ASSERT(prefix_k != nullptr && prefix_v != nullptr); k = ggml_concat(ctx->ggml_ctx, prefix_k, k, 2); v = ggml_concat(ctx->ggml_ctx, prefix_v, v, 2); } else { // Keep dedicated graph outputs alive until the runner copies them // into its persistent cache buffer after graph execution. auto cache_k = ggml_dup_tensor(ctx->ggml_ctx, k); cache_k = ggml_cpy(ctx->ggml_ctx, k, cache_k); ggml_set_output(cache_k); auto cache_v = ggml_dup_tensor(ctx->ggml_ctx, v); cache_v = ggml_cpy(ctx->ggml_ctx, v, cache_v); ggml_set_output(cache_v); ctx->persist_cache_tensor(layer_cache + ".k", cache_k); ctx->persist_cache_tensor(layer_cache + ".v", cache_v); } q = ggml_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, q, 0, 2, 1, 3)); q = ggml_reshape_3d(ctx->ggml_ctx, q, q->ne[0], q->ne[1], q->ne[2] * q->ne[3]); k = ggml_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, k, 0, 2, 1, 3)); k = ggml_reshape_3d(ctx->ggml_ctx, k, k->ne[0], k->ne[1], k->ne[2] * k->ne[3]); auto out = ggml_ext_attention_ext(ctx->ggml_ctx, ctx->backend, q, k, v, config.num_heads, attention_mask, true, ctx->flash_attn_enabled); return o_proj->forward(ctx, out); } }; struct TransformerBlock : public GGMLBlock { TransformerBlock(const SenseNovaU1Config& config, int layer_index) { blocks["self_attn"] = std::make_shared(config, layer_index); blocks["mlp"] = std::make_shared(config.hidden_size, config.intermediate_size, false); blocks["mlp_mot_gen"] = std::make_shared(config.hidden_size, config.intermediate_size, false); blocks["input_layernorm"] = std::make_shared(config.hidden_size, config.rms_norm_eps); blocks["input_layernorm_mot_gen"] = std::make_shared(config.hidden_size, config.rms_norm_eps); blocks["post_attention_layernorm"] = std::make_shared(config.hidden_size, config.rms_norm_eps); blocks["post_attention_layernorm_mot_gen"] = std::make_shared(config.hidden_size, config.rms_norm_eps); } ggml_tensor* forward(GGMLRunnerContext* ctx, ggml_tensor* x, ggml_tensor* position_t, ggml_tensor* position_h, ggml_tensor* position_w, ggml_tensor* attention_mask, Branch branch, const std::string& cache_prefix) { const bool generation = branch == Branch::GENERATION; auto input_norm = std::dynamic_pointer_cast( blocks[generation ? "input_layernorm_mot_gen" : "input_layernorm"]); auto post_norm = std::dynamic_pointer_cast( blocks[generation ? "post_attention_layernorm_mot_gen" : "post_attention_layernorm"]); auto attention = std::dynamic_pointer_cast(blocks["self_attn"]); auto mlp = std::dynamic_pointer_cast(blocks[generation ? "mlp_mot_gen" : "mlp"]); auto residual = x; x = input_norm->forward(ctx, x); x = attention->forward(ctx, x, position_t, position_h, position_w, attention_mask, branch, cache_prefix); x = ggml_add_inplace(ctx->ggml_ctx, x, residual); residual = x; x = post_norm->forward(ctx, x); x = mlp->forward(ctx, x); return ggml_add_inplace(ctx->ggml_ctx, x, residual); } }; struct TextModel : public GGMLBlock { SenseNovaU1Config config; explicit TextModel(const SenseNovaU1Config& config) : config(config) { blocks["embed_tokens"] = std::make_shared(config.vocab_size, config.hidden_size); for (int i = 0; i < config.num_layers; ++i) { blocks["layers." + std::to_string(i)] = std::make_shared(config, i); } blocks["norm"] = std::make_shared(config.hidden_size, config.rms_norm_eps); blocks["norm_mot_gen"] = std::make_shared(config.hidden_size, config.rms_norm_eps); } ggml_tensor* embed(GGMLRunnerContext* ctx, ggml_tensor* input_ids) { return std::dynamic_pointer_cast(blocks["embed_tokens"])->forward(ctx, input_ids); } ggml_tensor* forward(GGMLRunnerContext* ctx, ggml_tensor* x, ggml_tensor* position_t, ggml_tensor* position_h, ggml_tensor* position_w, ggml_tensor* attention_mask, Branch branch, const std::string& cache_prefix) { for (int i = 0; i < config.num_layers; ++i) { auto layer = std::dynamic_pointer_cast(blocks["layers." + std::to_string(i)]); x = layer->forward(ctx, x, position_t, position_h, position_w, attention_mask, branch, cache_prefix); } auto norm = std::dynamic_pointer_cast( blocks[branch == Branch::GENERATION ? "norm_mot_gen" : "norm"]); return norm->forward(ctx, x); } }; struct SenseNovaU1Model : public GGMLBlock { SenseNovaU1Config config; explicit SenseNovaU1Model(const SenseNovaU1Config& config) : config(config) { blocks["language_model.model"] = std::make_shared(config); blocks["fm_modules.vision_model_mot_gen.embeddings"] = std::make_shared(config); blocks["fm_modules.timestep_embedder"] = std::make_shared(config.hidden_size, config.timestep_embedding_size); if (config.add_noise_scale_embedding) { blocks["fm_modules.noise_scale_embedder"] = std::make_shared(config.hidden_size, config.timestep_embedding_size); } blocks["fm_modules.fm_head"] = std::make_shared(config); } std::shared_ptr text_model() { return std::dynamic_pointer_cast(blocks["language_model.model"]); } std::shared_ptr vision_embeddings() { return std::dynamic_pointer_cast(blocks["fm_modules.vision_model_mot_gen.embeddings"]); } std::shared_ptr timestep_embedder() { return std::dynamic_pointer_cast(blocks["fm_modules.timestep_embedder"]); } std::shared_ptr noise_scale_embedder() { if (!config.add_noise_scale_embedding) { return nullptr; } return std::dynamic_pointer_cast(blocks["fm_modules.noise_scale_embedder"]); } std::shared_ptr pixel_decoder() { return std::dynamic_pointer_cast(blocks["fm_modules.fm_head"]); } }; struct SenseNovaU1Runner : public DiffusionModelRunner { SenseNovaU1Config config; SenseNovaU1Model model; std::unordered_set cached_prefix_hashes; std::vector position_t_vec; std::vector position_h_vec; std::vector position_w_vec; std::vector attention_mask_vec; std::vector noise_scale_vec; SenseNovaU1Runner(ggml_backend_t backend, const String2TensorStorage& tensor_storage_map = {}, const std::string& prefix = "", std::shared_ptr weight_manager = nullptr) : DiffusionModelRunner(backend, prefix, weight_manager), config(SenseNovaU1Config::detect_from_weights(tensor_storage_map, prefix)), model(config) { model.init(params_ctx, tensor_storage_map, prefix); } std::string get_desc() override { return "SenseNova U1.5"; } void get_param_tensors(std::map& tensors, const std::string& prefix) override { model.get_param_tensors(tensors, prefix); } static uint64_t hash_input_ids(const sd::Tensor& input_ids) { uint64_t hash = 1469598103934665603ULL; for (int32_t token : input_ids.values()) { uint32_t value = static_cast(token); for (int byte = 0; byte < 4; ++byte) { hash ^= static_cast(value & 0xffU); hash *= 1099511628211ULL; value >>= 8; } } hash ^= static_cast(input_ids.numel()); hash *= 1099511628211ULL; return hash; } static std::string cache_prefix(uint64_t hash) { return "snu15." + std::to_string(hash); } ggml_tensor* make_position_tensor(const std::vector& values, const std::string& name) { auto tensor = ggml_new_tensor_1d(compute_ctx, GGML_TYPE_I32, values.size()); ggml_set_name(tensor, name.c_str()); set_backend_tensor_data(tensor, values.data()); return tensor; } ggml_cgraph* build_prefix_graph(const sd::Tensor& input_ids_tensor, const std::string& prefix_cache) { ggml_cgraph* graph = new_graph_custom(SENSENOVA_U1_GRAPH_SIZE); ggml_tensor* ids = make_input(input_ids_tensor); const int64_t length = input_ids_tensor.numel(); position_t_vec.resize(length); position_h_vec.assign(length, 0); position_w_vec.assign(length, 0); for (int64_t i = 0; i < length; ++i) { position_t_vec[i] = static_cast(i); } auto position_t = make_position_tensor(position_t_vec, "snu15.prefix.position_t"); auto position_h = make_position_tensor(position_h_vec, "snu15.prefix.position_h"); auto position_w = make_position_tensor(position_w_vec, "snu15.prefix.position_w"); attention_mask_vec.assign(static_cast(length * length), 0.f); for (int64_t query = 0; query < length; ++query) { for (int64_t key = query + 1; key < length; ++key) { attention_mask_vec[static_cast(query * length + key)] = -INFINITY; } } auto attention_mask = ggml_new_tensor_2d(compute_ctx, GGML_TYPE_F32, length, length); ggml_set_name(attention_mask, "snu15.prefix.attention_mask"); set_backend_tensor_data(attention_mask, attention_mask_vec.data()); auto runner_ctx = get_context(); auto text_model = model.text_model(); auto hidden = text_model->embed(&runner_ctx, ids); hidden = text_model->forward(&runner_ctx, hidden, position_t, position_h, position_w, attention_mask, Branch::UNDERSTANDING, prefix_cache); ggml_build_forward_expand(graph, hidden); return graph; } bool ensure_prefix_cache(int n_threads, const sd::Tensor& input_ids, std::string* prefix_cache) { const uint64_t hash = hash_input_ids(input_ids); *prefix_cache = cache_prefix(hash); if (cached_prefix_hashes.find(hash) != cached_prefix_hashes.end() && get_cache_tensor_by_name(*prefix_cache + ".0.k") != nullptr) { return true; } if (cached_prefix_hashes.size() >= 2) { free_cache_ctx_and_buffer(); cached_prefix_hashes.clear(); } auto get_graph = [&]() { return build_prefix_graph(input_ids, *prefix_cache); }; auto result = GGMLRunner::compute(get_graph, n_threads, false, true); if (!result.has_value()) { LOG_ERROR("SenseNova U1.5 prefix cache computation failed"); return false; } cached_prefix_hashes.insert(hash); return true; } ggml_cgraph* build_graph(const sd::Tensor& x_tensor, const sd::Tensor& timestep_tensor, const std::string& prefix_cache, int64_t prefix_length) { ggml_cgraph* graph = new_graph_custom(SENSENOVA_U1_GRAPH_SIZE); ggml_tensor* x = make_input(x_tensor); ggml_tensor* t = make_input(timestep_tensor); GGML_ASSERT(x->ne[3] == 1); GGML_ASSERT(x->ne[0] % config.image_token_stride() == 0); GGML_ASSERT(x->ne[1] % config.image_token_stride() == 0); const int64_t grid_w = x->ne[0] / config.patch_size; const int64_t grid_h = x->ne[1] / config.patch_size; const int64_t token_w = grid_w / config.vision_downsample_factor; const int64_t token_h = grid_h / config.vision_downsample_factor; const int64_t tokens = token_w * token_h; position_h_vec.resize(grid_w * grid_h); position_w_vec.resize(grid_w * grid_h); for (int64_t index = 0; index < grid_w * grid_h; ++index) { position_h_vec[index] = static_cast(index / grid_w); position_w_vec[index] = static_cast(index % grid_w); } auto vision_position_x = make_position_tensor(position_w_vec, "snu15.vision.position_x"); auto vision_position_y = make_position_tensor(position_h_vec, "snu15.vision.position_y"); auto runner_ctx = get_context(); auto hidden = model.vision_embeddings()->forward(&runner_ctx, x, vision_position_x, vision_position_y); auto time_embedding = model.timestep_embedder()->forward(&runner_ctx, t); time_embedding = ggml_reshape_3d(compute_ctx, time_embedding, config.hidden_size, 1, 1); hidden = ggml_add(compute_ctx, hidden, time_embedding); if (config.add_noise_scale_embedding) { const float image_tokens = static_cast(tokens); const float noise_scale = std::min(config.noise_scale_max_value, std::sqrt(image_tokens / config.noise_scale_base_image_seq_len)); noise_scale_vec = {noise_scale / config.noise_scale_max_value}; auto noise_scale_tensor = ggml_new_tensor_1d(compute_ctx, GGML_TYPE_F32, 1); ggml_set_name(noise_scale_tensor, "snu15.noise_scale"); set_backend_tensor_data(noise_scale_tensor, noise_scale_vec.data()); auto noise_embedding = model.noise_scale_embedder()->forward(&runner_ctx, noise_scale_tensor); noise_embedding = ggml_reshape_3d(compute_ctx, noise_embedding, config.hidden_size, 1, 1); hidden = ggml_add(compute_ctx, hidden, noise_embedding); } position_t_vec.assign(tokens, static_cast(prefix_length)); position_h_vec.resize(tokens); position_w_vec.resize(tokens); for (int64_t index = 0; index < tokens; ++index) { position_h_vec[index] = static_cast(index / token_w); position_w_vec[index] = static_cast(index % token_w); } auto position_t = make_position_tensor(position_t_vec, "snu15.image.position_t"); auto position_h = make_position_tensor(position_h_vec, "snu15.image.position_h"); auto position_w = make_position_tensor(position_w_vec, "snu15.image.position_w"); hidden = model.text_model()->forward(&runner_ctx, hidden, position_t, position_h, position_w, nullptr, Branch::GENERATION, prefix_cache); hidden = ggml_reshape_4d(compute_ctx, hidden, config.hidden_size, token_w, token_h, x->ne[3]); hidden = ggml_cont(compute_ctx, ggml_permute(compute_ctx, hidden, 2, 0, 1, 3)); auto x_prediction = model.pixel_decoder()->forward(&runner_ctx, hidden); const float timestep = timestep_tensor.values()[0]; const float denom = std::max(1.f - timestep, config.t_eps); auto velocity = ggml_scale(compute_ctx, ggml_sub(compute_ctx, x_prediction, x), 1.f / denom); ggml_build_forward_expand(graph, velocity); return graph; } sd::Tensor compute(int n_threads, const sd::Tensor& x, const sd::Tensor& timestep, const sd::Tensor& input_ids) { std::string prefix_cache; if (!ensure_prefix_cache(n_threads, input_ids, &prefix_cache)) { return {}; } auto get_graph = [&]() { return build_graph(x, timestep, prefix_cache, input_ids.numel()); }; return restore_trailing_singleton_dims( GGMLRunner::compute(get_graph, n_threads, false), x.dim()); } sd::Tensor compute(int n_threads, const DiffusionParams& diffusion_params) override { GGML_ASSERT(diffusion_params.x != nullptr); GGML_ASSERT(diffusion_params.timesteps != nullptr); const auto* extra = diffusion_extra_as(diffusion_params); GGML_ASSERT(extra->input_ids != nullptr); return compute(n_threads, *diffusion_params.x, *diffusion_params.timesteps, *extra->input_ids); } }; } // namespace SenseNovaU1 #endif // __SD_MODEL_DIFFUSION_SENSENOVA_U1_H__