@@ -1641,6 +1641,142 @@ struct T5CLIPEmbedder : public Conditioner {
16411641 }
16421642};
16431643
1644+ struct AnimaConditioner : public Conditioner {
1645+ std::shared_ptr<LLM ::BPETokenizer> qwen_tokenizer;
1646+ T5UniGramTokenizer t5_tokenizer;
1647+ std::shared_ptr<LLM ::LLMRunner> llm;
1648+
1649+ AnimaConditioner (ggml_backend_t backend,
1650+ bool offload_params_to_cpu,
1651+ const String2TensorStorage& tensor_storage_map = {}) {
1652+ qwen_tokenizer = std::make_shared<LLM ::Qwen2Tokenizer>();
1653+ llm = std::make_shared<LLM ::LLMRunner>(LLM ::LLMArch::QWEN3 ,
1654+ backend,
1655+ offload_params_to_cpu,
1656+ tensor_storage_map,
1657+ " text_encoders.llm" ,
1658+ false );
1659+ }
1660+
1661+ void get_param_tensors (std::map<std::string, struct ggml_tensor *>& tensors) override {
1662+ llm->get_param_tensors (tensors, " text_encoders.llm" );
1663+ }
1664+
1665+ void alloc_params_buffer () override {
1666+ llm->alloc_params_buffer ();
1667+ }
1668+
1669+ void free_params_buffer () override {
1670+ llm->free_params_buffer ();
1671+ }
1672+
1673+ size_t get_params_buffer_size () override {
1674+ return llm->get_params_buffer_size ();
1675+ }
1676+
1677+ void set_flash_attention_enabled (bool enabled) override {
1678+ llm->set_flash_attention_enabled (enabled);
1679+ }
1680+
1681+ void set_weight_adapter (const std::shared_ptr<WeightAdapter>& adapter) override {
1682+ llm->set_weight_adapter (adapter);
1683+ }
1684+
1685+ std::tuple<std::vector<int >, std::vector<float >, std::vector<int >, std::vector<float >> tokenize (std::string text) {
1686+ auto parsed_attention = parse_prompt_attention (text);
1687+
1688+ {
1689+ std::stringstream ss;
1690+ ss << " [" ;
1691+ for (const auto & item : parsed_attention) {
1692+ ss << " ['" << item.first << " ', " << item.second << " ], " ;
1693+ }
1694+ ss << " ]" ;
1695+ LOG_DEBUG (" parse '%s' to %s" , text.c_str (), ss.str ().c_str ());
1696+ }
1697+
1698+ std::vector<int > qwen_tokens;
1699+ std::vector<float > qwen_weights;
1700+ std::vector<int > t5_tokens;
1701+ std::vector<float > t5_weights;
1702+
1703+ for (const auto & item : parsed_attention) {
1704+ const std::string& curr_text = item.first ;
1705+ std::vector<int > curr_tokens = qwen_tokenizer->tokenize (curr_text, nullptr );
1706+ qwen_tokens.insert (qwen_tokens.end (), curr_tokens.begin (), curr_tokens.end ());
1707+ // Anima uses uniform Qwen token weights.
1708+ qwen_weights.insert (qwen_weights.end (), curr_tokens.size (), 1 .f );
1709+ }
1710+ if (qwen_tokens.empty ()) {
1711+ qwen_tokens.push_back (151643 ); // qwen3 pad token
1712+ qwen_weights.push_back (1 .f );
1713+ }
1714+
1715+ for (const auto & item : parsed_attention) {
1716+ const std::string& curr_text = item.first ;
1717+ float curr_weight = item.second ;
1718+ std::vector<int > curr_tokens = t5_tokenizer.Encode (curr_text, true );
1719+ t5_tokens.insert (t5_tokens.end (), curr_tokens.begin (), curr_tokens.end ());
1720+ t5_weights.insert (t5_weights.end (), curr_tokens.size (), curr_weight);
1721+ }
1722+
1723+ return {qwen_tokens, qwen_weights, t5_tokens, t5_weights};
1724+ }
1725+
1726+ SDCondition get_learned_condition (ggml_context* work_ctx,
1727+ int n_threads,
1728+ const ConditionerParams& conditioner_params) override {
1729+ int64_t t0 = ggml_time_ms ();
1730+
1731+ auto tokenized = tokenize (conditioner_params.text );
1732+ auto & qwen_tokens = std::get<0 >(tokenized);
1733+ auto & qwen_weights = std::get<1 >(tokenized);
1734+ auto & t5_tokens = std::get<2 >(tokenized);
1735+ auto & t5_weights = std::get<3 >(tokenized);
1736+
1737+ auto input_ids = vector_to_ggml_tensor_i32 (work_ctx, qwen_tokens);
1738+
1739+ struct ggml_tensor * hidden_states = nullptr ; // [N, n_token, 1024]
1740+ llm->compute (n_threads,
1741+ input_ids,
1742+ nullptr ,
1743+ {},
1744+ {},
1745+ &hidden_states,
1746+ work_ctx);
1747+
1748+ {
1749+ auto tensor = hidden_states;
1750+ float original_mean = ggml_ext_tensor_mean (tensor);
1751+ for (int i2 = 0 ; i2 < tensor->ne [2 ]; i2++) {
1752+ for (int i1 = 0 ; i1 < tensor->ne [1 ]; i1++) {
1753+ for (int i0 = 0 ; i0 < tensor->ne [0 ]; i0++) {
1754+ float value = ggml_ext_tensor_get_f32 (tensor, i0, i1, i2);
1755+ value *= qwen_weights[i1];
1756+ ggml_ext_tensor_set_f32 (tensor, value, i0, i1, i2);
1757+ }
1758+ }
1759+ }
1760+ float new_mean = ggml_ext_tensor_mean (tensor);
1761+ if (new_mean != 0 .f ) {
1762+ ggml_ext_tensor_scale_inplace (tensor, (original_mean / new_mean));
1763+ }
1764+ }
1765+
1766+ struct ggml_tensor * t5_ids_tensor = nullptr ;
1767+ struct ggml_tensor * t5_weight_tensor = nullptr ;
1768+ if (!t5_tokens.empty ()) {
1769+ t5_ids_tensor = vector_to_ggml_tensor_i32 (work_ctx, t5_tokens);
1770+ t5_weight_tensor = vector_to_ggml_tensor (work_ctx, t5_weights);
1771+ }
1772+
1773+ int64_t t1 = ggml_time_ms ();
1774+ LOG_DEBUG (" computing condition graph completed, taking %" PRId64 " ms" , t1 - t0);
1775+
1776+ return {hidden_states, t5_weight_tensor, t5_ids_tensor};
1777+ }
1778+ };
1779+
16441780struct LLMEmbedder : public Conditioner {
16451781 SDVersion version;
16461782 std::shared_ptr<LLM ::BPETokenizer> tokenizer;
0 commit comments