InternLM
EndoCoT
Python

[ECCV 2026] An official implementation of "EndoCoT". Scaling endogenous Chain-of-Thought (CoT) reasoning in diffusion models for complex structured generation.

Last updated Aug 7, 2026
44
Stars
0
Forks
0
Issues
+1
Stars/day
Attention Score
45
Language breakdown
Python 92.2%
Shell 7.8%
Files click to expand
README

EndoCoT




Teaser

EndoCoT: Scaling Endogenous Chain-of-Thought Reasoning in Diffusion Models

📝TODO

  • [x] Open source the training code
  • [x] Open source the training data
  • [x] Open source the main task ckpt
  • [ ] Open source the edit model ckpt
  • [ ] Refactor the codebase for better usability and maintainability

📰News

  • 🎉 [2026/6/26] Our paper has been accepted to ECCV 2026!
  • 🚀 [2026/3/18] We have released the EndoCoT-Data.
  • 🚀 [2026/3/12] We have released the EndoCoT repository and ckpts.

🌟Highlight

main

  • EndoCoT is a reasoning paradigm for diffusion models that enables step-by-step inference. It outperforms conventional training methods on Qwen-Image-Edit-2511.
exp
  • And provide transparent, intermediate reasoning trajectories.
case

⚡Quick Start

Setup environment

git clone https://github.com/InternLM/EndoCoT
cd EndoCoT
conda create -n EndoCoT python=3.10
conda activate EndoCot

Please install the version of torch compatible with your machine.

pip install -r requirements.txt

Please install the version of vLLM compatible with your machine.

Inference

  • Download the ckpt:
- You may find our pretrained weights at: EndoCoT

> Following the configuration of Diffthinker, we provide a customized checkpoint for Qwen-Image-Edit. This checkpoint has been merged from the original safetensors to ensure compatibility withDiffsynth-Studio training. Please use the checkpoint provided in this repository instead of the official version for correct loading and inference.

  • Test Single Case
cd test
   python test.py \
       --task Maze \
       --modelroot /path/to/mergedckpts \
       --lorapath /path/to/yourlora_weight.safetensors \
       --inputimage ./data/sudokusample.png \
       --outputdir ./outputs/sudokuresults
  • Eval Our Ckpt
> We follow the exact same setting as Diffthinker
cd Maze
   bash eval/genandparse.sh
   bash eval/eval_path.sh

Training

  • Download the datasets & metadata.csv
- You may find our training data at: EndoCoT dataset

> Since the metadata uses relative paths, please ensure the dataset files are placed in the same directory as metadata.csv

  • Train your model
cd DiffSynth-Studio
   bash add/Maze/stage1.sh
   python changeckptprefix.py --src /path/to/the/Maze/save/dir/Maze_stage1	
   bash add/Maze/stage2.sh
   python changeckptprefix.py --src /path/to/the/Maze/save/dir/Maze_stage2

How to change the latent reasoning steps?

Note on Customization: Since the current implementation is straightforward, you can only manually adjust the latent reasoning steps in DiffSynth-Studio/diffsynth/pipelines/qwen_image.py:
>
- Line 442: Modify infer_steps.
- Line 471: Modify training_steps.
>
##### We plan to optimize this in future releases.
def encodepromptedit(self, pipe: QwenImagePipeline, prompt, editimage, isfinal, gt_prompt=None, idx=None):

drop_idx = 64 if type(prompt[0])==str: template = "<|imstart|>system\nDescribe the key features of the input image (color, shape, size, texture, objects, background), then explain how the user's text instruction should alter or modify the image. Generate a new image that meets the user's requirements while maintaining consistency with the original input where appropriate.<|imend|>\n<|imstart|>user\n<|visionstart|><|imagepad|><|visionend|>{}<|imend|>\n<|imstart|>assistant\n" txt = template.format(prompt[0]) modelinputs = pipe.processor(text=txt, images=editimage, padding=True, return_tensors="pt").to(pipe.device) embeddinglayers = pipe.textencoder.model.languagemodel.getinput_embeddings() with torch.no_grad(): inputsembeds = embeddinglayers(modelinputs.inputids) self.attentionmask = modelinputs.attention_mask self.pixelvalues = modelinputs.pixel_values self.imagegridthw = modelinputs.imagegrid_thw else: inputs_embeds= prompt[0] # dxl: test use if is_final==None or idx!=None: print("现在在inference。或者stage2训练") if idx!=None: iter_times = idx-2 else: # infer step iter_times = 50 with torch.no_grad(): inputsembeds = self.manualgenerate_eval( pipe, inputsembeds=inputsembeds, maxnewtokens=iter_times, ).detach() # dxl: only update the last 2 tokens if idx!=None: inputsembeds = self.manualgenerate_eval( pipe, inputsembeds=inputsembeds, maxnewtokens=2, )

generatedembeds = inputsembeds

... ... # dxl:training if is_final!=None and idx==None: try: generatedembeds, = self.manual_generate( pipe, inputsembeds=inputsembeds, isfinal=isfinal, # training steps maxnewtokens=2, ) except Exception as e: print(f"Error!: {type(e).name} - {e}") print(inputs_embeds.shape) assert False

try: return splithiddenstates, generatedembeds, eosloss except: print(f"[WARNING] Prompt was not updated correctly for inference.") return splithiddenstates

📖 Citation

@article{dai2026endocot,
  title={EndoCoT: Scaling Endogenous Chain-of-Thought Reasoning in Diffusion Models},
  author={Dai, Xuanlang and Zhou, Yujie and Xing, Long and Bu, Jiazi and Wei, Xilin and Liu, Yuhong and Zhang, Beichen and Chen, Kai and Zang, Yuhang},
  journal={arXiv preprint arXiv:2603.12252},
  year={2026}
}

⚖️ License

Code License Data License

🔗 More in this category

© 2026 GitRepoTrend · InternLM/EndoCoT · Updated daily from GitHub