convert_model_macos_float32.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. """
  2. Model dtype converter for Apple Silicon compatibility
  3. This script converts all model weights to float32 and saves a compatible version
  4. """
  5. import os
  6. import torch
  7. from transformers.models.auto.modeling_auto import AutoModelForCausalLM
  8. from transformers.models.auto.processing_auto import AutoProcessor
  9. def convert_model_to_float32(model_path, output_path=None):
  10. """
  11. Convert a model to float32 and optionally save it
  12. """
  13. if output_path is None:
  14. output_path = model_path + "_float32"
  15. print(f"Loading model from: {model_path}")
  16. # Load model with float32
  17. model = AutoModelForCausalLM.from_pretrained(
  18. model_path,
  19. torch_dtype=torch.float32,
  20. trust_remote_code=True,
  21. low_cpu_mem_usage=True,
  22. device_map="cpu"
  23. )
  24. print("Converting all parameters to float32...")
  25. # Force convert all parameters
  26. with torch.no_grad():
  27. converted_count = 0
  28. for name, param in model.named_parameters():
  29. if param.dtype != torch.float32:
  30. param.data = param.data.to(torch.float32)
  31. converted_count += 1
  32. print(f" Converted {name}: {param.dtype} -> float32")
  33. for name, buffer in model.named_buffers():
  34. if buffer.dtype not in [torch.float32, torch.int64, torch.long, torch.bool]:
  35. buffer.data = buffer.data.to(torch.float32)
  36. converted_count += 1
  37. print(f" Converted buffer {name}: {buffer.dtype} -> float32")
  38. print(f"✅ Converted {converted_count} parameters/buffers to float32")
  39. # Save the converted model
  40. if not os.path.exists(output_path):
  41. os.makedirs(output_path)
  42. print(f"Saving converted model to: {output_path}")
  43. model.save_pretrained(output_path, safe_serialization=True)
  44. # Also copy the processor
  45. try:
  46. processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True)
  47. processor.save_pretrained(output_path)
  48. print("✅ Processor also saved")
  49. except Exception as e:
  50. print(f"Warning: Could not save processor: {e}")
  51. print("✅ Model conversion completed!")
  52. return output_path
  53. def test_converted_model(model_path):
  54. """
  55. Test the converted model with a simple inference
  56. """
  57. print(f"Testing converted model: {model_path}")
  58. try:
  59. model = AutoModelForCausalLM.from_pretrained(
  60. model_path,
  61. torch_dtype=torch.float32,
  62. trust_remote_code=True,
  63. device_map="cpu"
  64. )
  65. processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True)
  66. # Verify all parameters are float32
  67. non_float32_params = []
  68. for name, param in model.named_parameters():
  69. if param.dtype != torch.float32:
  70. non_float32_params.append((name, param.dtype))
  71. if non_float32_params:
  72. print("❌ Still have non-float32 parameters:")
  73. for name, dtype in non_float32_params[:5]: # Show first 5
  74. print(f" {name}: {dtype}")
  75. else:
  76. print("✅ All parameters are float32")
  77. print("✅ Converted model loads successfully!")
  78. return True
  79. except Exception as e:
  80. print(f"❌ Error testing converted model: {e}")
  81. return False
  82. if __name__ == "__main__":
  83. model_path = "./weights/DotsOCR"
  84. if not os.path.exists(model_path):
  85. print(f"❌ Model not found at {model_path}")
  86. print("Please ensure the model is downloaded first.")
  87. exit(1)
  88. print("🔧 DotsOCR Model Converter for Apple Silicon")
  89. print("=" * 50)
  90. # Convert the model
  91. try:
  92. output_path = model_path + "_float32"
  93. # 如果 output_path不存在,转换
  94. if not os.path.exists(output_path):
  95. output_path = convert_model_to_float32(model_path, output_path)
  96. # Test the converted model
  97. if test_converted_model(output_path):
  98. print(f"\n🎉 Success! Use the converted model at: {output_path}")
  99. print("You can now run inference with this converted model:")
  100. print(f" python demo/demo_hf_macos_ultimate.py --model_path {output_path}")
  101. else:
  102. print(f"\n❌ Conversion completed but testing failed.")
  103. except Exception as e:
  104. print(f"❌ Conversion failed: {e}")
  105. print("\nTrying alternative approach...")
  106. # Alternative: try to load and immediately convert
  107. try:
  108. print("Loading model with explicit float32 conversion...")
  109. model = AutoModelForCausalLM.from_pretrained(
  110. model_path,
  111. trust_remote_code=True,
  112. device_map="cpu",
  113. torch_dtype=torch.float32
  114. )
  115. # Check if this worked
  116. mixed_precision = False
  117. for name, param in model.named_parameters():
  118. if param.dtype != torch.float32:
  119. mixed_precision = True
  120. break
  121. if mixed_precision:
  122. print("Model still has mixed precision - this explains the dtype errors.")
  123. print("The model weights themselves contain mixed dtypes that cannot be easily converted.")
  124. print("\nRecommendations:")
  125. print("1. Use the online demo: https://dotsocr.xiaohongshu.com/")
  126. print("2. Run on a Linux machine with NVIDIA GPU")
  127. print("3. Wait for a native Apple Silicon compatible model release")
  128. else:
  129. print("✅ Model is actually float32 compatible!")
  130. except Exception as alt_error:
  131. print(f"❌ Alternative approach also failed: {alt_error}")