Spaces:
Running
Running
File size: 10,000 Bytes
a183ff9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | import os
import sys
import yaml
from PIL import Image
# Configure UTF-8 stdout to support printing Cham characters to the terminal on Windows
if sys.stdout and sys.stdout.encoding != 'utf-8':
try:
sys.stdout.reconfigure(encoding='utf-8')
except AttributeError:
pass
def run_integrity_check(model_dir):
"""
Kiểm tra sự tồn tại và tính hợp lệ vật lý của các file checkpoint hoặc inference.
"""
print("🔍 1. Kiểm tra tính toàn vẹn của tệp tin mô hình...")
if not os.path.exists(model_dir):
print(f"❌ Lỗi: Thư mục chứa mô hình không tồn tại tại: {model_dir}")
return False
found_files = os.listdir(model_dir)
# Kiểm tra xem đây có phải là thư mục mô hình inference không
if "inference.pdiparams" in found_files:
print("✅ Tìm thấy bộ mô hình Inference ('inference')")
file_path = os.path.join(model_dir, "inference.pdiparams")
sz_mb = os.path.getsize(file_path) / (1024 * 1024)
print(f" - inference.pdiparams ({sz_mb:.2f} MB)")
return True
required_extensions = [".pdparams", ".pdopt", ".states"]
prefixes = ["best_accuracy", "latest"]
passed = True
for prefix in prefixes:
has_prefix = any(f.startswith(prefix) for f in found_files)
if has_prefix:
print(f"✅ Tìm thấy bộ checkpoint loại: '{prefix}'")
# Kiểm tra xem có đủ các file cần thiết không
for ext in required_extensions:
expected_file = f"{prefix}{ext}"
file_path = os.path.join(model_dir, expected_file)
if expected_file not in found_files:
print(f"⚠️ Thiếu tệp: {expected_file}")
passed = False
else:
sz_mb = os.path.getsize(file_path) / (1024 * 1024)
if sz_mb == 0:
print(f"❌ Tệp tin bị rỗng (0 bytes): {expected_file}")
passed = False
else:
print(f" - {expected_file} ({sz_mb:.2f} MB)")
break
else:
print("❌ Không tìm thấy tệp checkpoint hoặc inference hợp lệ.")
passed = False
return passed
def calculate_cer(predicted, target):
"""Tính toán Levenshtein Distance để tìm Character Error Rate (CER)"""
# Mảng 2D cho Levenshtein distance
d = [[0] * (len(target) + 1) for _ in range(len(predicted) + 1)]
for i in range(len(predicted) + 1):
d[i][0] = i
for j in range(len(target) + 1):
d[0][j] = j
for i in range(1, len(predicted) + 1):
for j in range(1, len(target) + 1):
if predicted[i - 1] == target[j - 1]:
cost = 0
else:
cost = 1
d[i][j] = min(
d[i - 1][j] + 1, # Deletion
d[i][j - 1] + 1, # Insertion
d[i - 1][j - 1] + cost # Substitution
)
if not target:
return 0.0 if not predicted else 1.0
return d[len(predicted)][len(target)] / len(target)
def run_inference_qa(model_dir, dict_path, data_dir, num_test_samples=20):
"""
Tải mô hình và chạy nhận diện thử nghiệm để đánh giá chất lượng (Accuracy, CER).
"""
print("\n🔮 2. Khởi chạy kiểm tra độ chính xác nhận dạng mô hình...")
# 1. Kiểm tra tập dữ liệu validation
val_label_path = os.path.join(data_dir, "val_label.txt")
if not os.path.exists(val_label_path):
print(f"❌ Không tìm thấy nhãn tập Val: {val_label_path}")
return None
# 2. Đọc các mẫu kiểm thử từ file nhãn
test_samples = []
with open(val_label_path, 'r', encoding='utf-8') as f:
for line in f:
parts = line.strip().split('\t')
if len(parts) >= 2:
test_samples.append((parts[0], parts[1]))
if not test_samples:
print("❌ Tập nhãn Val rỗng, không có dữ liệu để chạy thử.")
return None
# Lấy ngẫu nhiên các mẫu để chạy QA nhanh
import random
random.seed(42) # Cố định ngẫu nhiên
if len(test_samples) > num_test_samples:
test_samples = random.sample(test_samples, num_test_samples)
# 3. Khởi tạo PaddleOCR Recognition engine sử dụng TextRecognizer cấp thấp để nạp checkpoint hoặc inference trực tiếp
try:
import sys
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
paddleocr_dir = os.path.join(PROJECT_ROOT, "PaddleOCR")
if paddleocr_dir not in sys.path:
sys.path.insert(0, paddleocr_dir)
from tools.infer.predict_rec import TextRecognizer
import tools.infer.utility as utility
best_model_prefix = None
if "inference.pdiparams" in os.listdir(model_dir):
best_model_prefix = model_dir
else:
for f in os.listdir(model_dir):
if f.startswith("best_accuracy") and f.endswith(".pdparams"):
best_model_prefix = os.path.join(model_dir, "best_accuracy")
break
elif f.startswith("latest") and f.endswith(".pdparams"):
best_model_prefix = os.path.join(model_dir, "latest")
break
if not best_model_prefix:
print("❌ Không tìm thấy tiền tố file pdparams để load.")
return None
print(f"🔄 Đang nạp mô hình từ: {best_model_prefix}")
# Backup sys.argv và xóa tạm thời để tránh argparse lỗi đối số chưa định nghĩa
sys_argv_backup = sys.argv
sys.argv = [sys.argv[0]]
args = utility.parse_args()
sys.argv = sys_argv_backup
args.rec_model_dir = best_model_prefix
args.rec_char_dict_path = dict_path
# Cấu hình sử dụng CPU hoặc GPU bằng paddle
import paddle
args.use_gpu = paddle.is_compiled_with_cuda()
args.rec_image_shape = "3, 48, 320"
args.use_space_char = True
ocr = TextRecognizer(args)
except Exception as e:
print(f"❌ Không thể tải bộ thư viện PaddleOCR hoặc trọng số mô hình: {e}")
import traceback
traceback.print_exc()
return None
# 4. Chạy kiểm thử từng ảnh
total_cer = 0.0
correct_predictions = 0
print("\n--- Báo cáo Chi tiết Nhận dạng ---")
for i, (rel_img_path, ground_truth) in enumerate(test_samples):
img_path = os.path.join(data_dir, rel_img_path)
if not os.path.exists(img_path):
continue
try:
# Chạy nhận diện bằng cv2.imread + TextRecognizer
import cv2
img = cv2.imread(img_path)
if img is not None:
rec_res, elapse = ocr([img])
if rec_res and rec_res[0]:
pred_text, confidence = rec_res[0]
else:
pred_text, confidence = "", 0.0
else:
pred_text, confidence = "", 0.0
cer = calculate_cer(pred_text, ground_truth)
total_cer += cer
is_correct = (pred_text == ground_truth)
if is_correct:
correct_predictions += 1
status_symbol = "✅ Đúng" if is_correct else f"❌ Sai (CER: {cer * 100:.1f}%)"
print(f"[{i+1:02d}] Ảnh: {os.path.basename(rel_img_path)}")
print(f" Nhãn gốc: '{ground_truth}'")
print(f" Nhận diện: '{pred_text}' (Độ tin cậy: {confidence:.2f})")
print(f" Kết quả: {status_symbol}")
except Exception as e:
print(f"⚠️ Lỗi khi chạy ảnh {rel_img_path}: {e}")
# 5. Tổng kết độ chính xác
avg_cer = total_cer / len(test_samples)
word_accuracy = correct_predictions / len(test_samples)
print("\n--- KẾT QUẢ ĐÁNH GIÁ TRỰC QUAN ---")
print(f"📈 Word-level Accuracy (Độ chính xác từ): {word_accuracy * 100:.2f}%")
print(f"📉 Average Character Error Rate (CER trung bình): {avg_cer * 100:.2f}%")
# Tiêu chuẩn thông qua QA: CER < 5%
qa_status = "PASS" if avg_cer < 0.05 else "WARNING" if avg_cer < 0.15 else "FAIL"
print(f"🏆 Trạng thái chất lượng mô hình: {qa_status.upper()}")
return {
"word_accuracy": word_accuracy,
"avg_cer": avg_cer,
"qa_status": qa_status
}
if __name__ == '__main__':
# Đường dẫn kiểm thử mặc định
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
default_model = os.path.join(PROJECT_ROOT, "data", "output", "rec_cham", "rec_ppocr_v4") # Hoặc đường dẫn đã giải nén
default_dict = os.path.join(PROJECT_ROOT, "data", "cham_dict.txt")
default_data = os.path.join(PROJECT_ROOT, "data", "cham_synthetic_images")
if len(sys.argv) > 1:
default_model = sys.argv[1]
if len(sys.argv) > 2:
default_dict = sys.argv[2]
if len(sys.argv) > 3:
default_data = sys.argv[3]
print("=== Khởi chạy Kiểm tra Chất lượng Mô hình ===")
integrity_ok = run_integrity_check(default_model)
if integrity_ok:
run_inference_qa(default_model, default_dict, default_data)
else:
print("\n❌ Thất bại: Không thể thực hiện kiểm tra độ chính xác do tệp tin checkpoints thiếu hoặc lỗi.")
|