File size: 10,597 Bytes
75b8dbb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
import os
import sys
import json

if sys.stdout and hasattr(sys.stdout, 'reconfigure'):
    sys.stdout.reconfigure(encoding='utf-8')

def read_file(path):
    with open(path, 'r', encoding='utf-8') as f:
        return f.read()

def main():
    print("📦 Bắt đầu đóng gói Kaggle Notebook huấn luyện V24...")
    
    # 1. Đọc mã nguồn các script cục bộ
    dict_extension_code = read_file('ocr-training/scripts/dict_extension_v24.py')
    weight_surgery_code = read_file('ocr-training/scripts/weight_surgery_v24.py')
    generate_data_v24_code = read_file('ocr-training/scripts/generate_data_v24.py')
    config_v24_code = read_file('ocr-training/configs/rec_cham_v24.yml')
    
    kaggle_dict_extension = dict_extension_code
    kaggle_weight_surgery = weight_surgery_code
    
    cells = []
    
    def add_md(text):
        cells.append({
            "cell_type": "markdown",
            "metadata": {},
            "source": [line + '\n' for line in text.splitlines()]
        })
        
    def add_code(code_str):
        cells.append({
            "cell_type": "code",
            "execution_count": None,
            "metadata": {},
            "outputs": [],
            "source": [line + '\n' for line in code_str.splitlines()]
        })

    # Tiêu đề
    add_md("""# Huấn Luyện Mô Hình Nhận Diện Chữ Chăm PP-OCRv4 V24 (Dual GPU T4x2)
Mô hình giải quyết triệt để:
- Số thứ tự khổ thơ Chăm 1-99 (`꩑꩞` - `꩙꩙꩞`)
- Dấu kết thúc câu kép Double Danda (`꩝꩝`)
- Dấu phụ đối kháng `ꨲ` (Au, U+AA32) vs `ꨶ` (O, U+AA36)
- Tổ hợp 3 tầng dấu phụ và bảo toàn nguyên âm trước `ꨯ`, `ꨯꨱ`
- Khả năng chống chịu Mờ rung (Motion Blur) và Nhiễu giấy cổ""")

    # Phase 1: Environment & GPU Check
    add_md("## Phase 1: Cài đặt thư viện & Kiểm tra GPU T4x2")
    add_code("""# 1. Cài đặt PaddlePaddle GPU và các thư viện phụ trợ
!pip install --quiet "paddlepaddle-gpu>=2.6.0" "albumentations>=1.4.0" fonttools pyyaml opencv-python Pillow

# 2. Kiểm tra môi trường GPU
import os
import sys
import paddle

print("="*60)
print("PADDLE ENVIRONMENT STATUS:")
print("Paddle Version:", paddle.__version__)
print("Compiled with CUDA:", paddle.is_compiled_with_cuda())
gpu_count = paddle.device.cuda.device_count()
print(f"Detected GPU Count: {gpu_count}")
print("="*60)

if gpu_count < 1:
    print("⚠️ CẢNH BÁO: Không tìm thấy GPU! Vui lòng chọn Accelerator = GPU T4 x2 trong Settings.")
else:
    for i in range(gpu_count):
        print(f" - GPU {i}: {paddle.device.cuda.get_device_name(i)}")
""")

    # Phase 2: Setup Workspace & PaddleOCR
    add_md("## Phase 2: Khởi tạo thư mục làm việc & Clone PaddleOCR")
    add_code("""import os
import shutil

os.makedirs('/kaggle/working/data/fonts', exist_ok=True)
os.makedirs('/kaggle/working/data/output_v24_temp', exist_ok=True)
os.makedirs('/kaggle/working/configs', exist_ok=True)
os.makedirs('/kaggle/working/scripts', exist_ok=True)
os.makedirs('/kaggle/working/output/rec_cham_v24', exist_ok=True)
os.makedirs('/kaggle/working/output/v24_training', exist_ok=True)

# Tự động phát hiện đường dẫn Assets Input trên Kaggle
candidate_asset_dirs = [
    "/kaggle/input/cham-ocr-v5-assets",
    "/kaggle/input/datasets/gustavnguyen/cham-ocr-v5-assets"
]
ASSETS_DIR = None
for d in candidate_asset_dirs:
    if os.path.exists(d):
        ASSETS_DIR = d
        break

if not ASSETS_DIR and os.path.exists('/kaggle/input'):
    for root, dirs, files in os.walk('/kaggle/input'):
        if 'v23_checkpoint' in dirs:
            ASSETS_DIR = root
            break

if not ASSETS_DIR:
    raise FileNotFoundError(f"❌ LỖI: Không tìm thấy thư mục Assets trong /kaggle/input")

print(f"✅ Đã tìm thấy Assets Input tại: {ASSETS_DIR}")

# Copy fonts
fonts_src = os.path.join(ASSETS_DIR, "fonts", "fonts")
if not os.path.exists(fonts_src):
    fonts_src = os.path.join(ASSETS_DIR, "fonts")

for f in os.listdir(fonts_src):
    if f.endswith(('.ttf', '.otf')):
        shutil.copy2(os.path.join(fonts_src, f), os.path.join('/kaggle/working/data/fonts', f))

print("✅ Đã sao chép fonts:", os.listdir('/kaggle/working/data/fonts'))

# Clone PaddleOCR nếu chưa có
if not os.path.exists('/kaggle/working/PaddleOCR'):
    print("⏳ Đang clone PaddleOCR...")
    !git clone --depth 1 https://github.com/PaddlePaddle/PaddleOCR.git /kaggle/working/PaddleOCR
    !pip install --quiet -r /kaggle/working/PaddleOCR/requirements.txt
else:
    print("✅ PaddleOCR đã tồn tại sẵn.")
""")

    # Phase 3: Ghi mã nguồn các script
    add_md("## Phase 3: Nạp kịch bản Sinh dữ liệu, Mở rộng từ điển & Phẫu thuật trọng số")
    add_code(f"%%writefile /kaggle/working/scripts/dict_extension_v24.py\n{kaggle_dict_extension}")
    add_code(f"%%writefile /kaggle/working/scripts/weight_surgery_v24.py\n{kaggle_weight_surgery}")
    add_code(f"%%writefile /kaggle/working/scripts/generate_data_v24.py\n{generate_data_v24_code}")
    add_code(f"%%writefile /kaggle/working/configs/rec_cham_v24.yml\n{config_v24_code}")

    # Phase 4: Chạy chuẩn bị dữ liệu và phẫu thuật trọng số
    add_md("## Phase 4: Mở rộng từ điển, Phẫu thuật trọng số & Sinh 50K dữ liệu V24 đặc trị")
    add_code("""import os, sys, time
%cd /kaggle/working

print("=== BƯỚC 1: MỞ RỘNG TỪ ĐIỂN V24 ===")
!python3 scripts/dict_extension_v24.py

print("\\n=== BƯỚC 2: PHẪU THUẬT TRỌNG SỐ V24 ===")
!python3 scripts/weight_surgery_v24.py

print("\\n=== BƯỚC 3: SINH DỮ LIỆU TỔNG HỢP V24 ĐẶC TRỊ (45K TRAIN, 4.5K VAL) ===")
t_start = time.time()
# Chạy với 4 vCPU
!python3 scripts/generate_data_v24.py --output-dir /kaggle/working/data/cham_synthetic_v24 --fonts-dir /kaggle/working/data/fonts --num-train 45000 --num-val 4500 --num-workers 4
print(f"🎉 Hoàn thành toàn bộ dữ liệu trong {(time.time()-t_start)/60:.2f} phút!")
""")

    # Phase 5: Khởi chạy huấn luyện song song phân tán trên GPU T4x2
    add_md("## Phase 5: Huấn luyện phân tán song song trên Dual GPU Tesla T4x2 (20 Epochs)")
    add_code("""import os
import paddle

gpu_count = paddle.device.cuda.device_count()
print(f"🔥 Khởi chạy huấn luyện với {gpu_count} GPU...")

os.environ["PYTHONUNBUFFERED"] = "1"
os.environ["FLAGS_fraction_of_gpu_memory_to_use"] = "0.90"

%cd /kaggle/working/PaddleOCR

if gpu_count > 1:
    print("🚀 Sử dụng lệnh phân tán song song đa GPU (paddle.distributed.launch --gpus '0,1'):")
    !python3 -m paddle.distributed.launch --gpus '0,1' tools/train.py -c /kaggle/working/configs/rec_cham_v24.yml
else:
    print("⚡ Huấn luyện trên Single GPU:")
    !python3 tools/train.py -c /kaggle/working/configs/rec_cham_v24.yml
""")

    # Phase 6: Xuất mô hình Inference & Đóng gói ZIP
    add_md("## Phase 6: Xuất mô hình Inference & Đóng gói rec_cham_v24_best.zip")
    add_code("""import os
import shutil
import zipfile

%cd /kaggle/working/PaddleOCR

best_ckpt = "/kaggle/working/output/rec_cham_v24/best_accuracy"
latest_ckpt = "/kaggle/working/output/rec_cham_v24/latest"

target_ckpt = best_ckpt if os.path.exists(best_ckpt + ".pdparams") else latest_ckpt
print(f"🎯 Sử dụng checkpoint: {target_ckpt}")

infer_dir = "/kaggle/working/output/rec_cham_inference_v24"
os.makedirs(infer_dir, exist_ok=True)

# Xuất mô hình inference
!python3 tools/export_model.py -c /kaggle/working/configs/rec_cham_v24.yml -o Global.pretrained_model={target_ckpt} Global.save_inference_dir={infer_dir} Global.export_with_pir=False

# Copy từ điển vào thư mục inference
shutil.copy2('/kaggle/working/data/cham_dict_v24.txt', os.path.join(infer_dir, 'cham_dict_v24.txt'))

print("✅ Thư mục Inference:", os.listdir(infer_dir))

# Đóng gói toàn bộ kết quả thành file zip trong /kaggle/working
zip_path = "/kaggle/working/rec_cham_v24_best.zip"
print(f"📦 Đang nén kết quả vào {zip_path}...")

with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
    # Nén inference model
    for root, dirs, files in os.walk(infer_dir):
        for f in files:
            full_p = os.path.join(root, f)
            rel_p = os.path.relpath(full_p, "/kaggle/working")
            zipf.write(full_p, rel_p)
            
    # Nén best accuracy pdparams
    for ext in [".pdparams", ".pdopt", ".states"]:
        p = target_ckpt + ext
        if os.path.exists(p):
            zipf.write(p, os.path.join("best_checkpoint", os.path.basename(p)))
            
    # Nén từ điển
    zipf.write('/kaggle/working/data/cham_dict_v24.txt', 'cham_dict_v24.txt')

print(f"🎉 HOÀN TẤT TRỌN GÓI! File zip sẵn sàng ({os.path.getsize(zip_path) / (1024*1024):.2f} MB): {zip_path}")
""")

    # 5. Lưu Notebook JSON
    notebook_dict = {
        "cells": cells,
        "metadata": {
            "kernelspec": {
                "display_name": "Python 3",
                "language": "python",
                "name": "python3"
            },
            "language_info": {
                "name": "python",
                "version": "3.10.12"
            }
        },
        "nbformat": 4,
        "nbformat_minor": 4
    }
    
    submission_dir = 'ocr-training/output/kaggle_v24_submission'
    os.makedirs(submission_dir, exist_ok=True)
    
    nb_path = os.path.join(submission_dir, 'paddleocr_cham_v24_train.ipynb')
    with open(nb_path, 'w', encoding='utf-8') as f:
        json.dump(notebook_dict, f, indent=1, ensure_ascii=False)
        
    meta_path = os.path.join(submission_dir, 'kernel-metadata.json')
    metadata = {
        "id": "gustavnguyen/paddleocr-cham-finetune",
        "title": "paddleocr-cham-finetune",
        "code_file": "paddleocr_cham_v24_train.ipynb",
        "language": "python",
        "kernel_type": "notebook",
        "is_private": "true",
        "enable_gpu": "true",
        "enable_tpu": "false",
        "enable_internet": "true",
        "dataset_sources": [
            "gustavnguyen/cham-ocr-v5-assets"
        ],
        "competition_sources": [],
        "kernel_sources": [],
        "model_sources": []
    }
    with open(meta_path, 'w', encoding='utf-8') as f:
        json.dump(metadata, f, indent=2)
        
    print(f"✅ Đã tạo thành công Notebook tại: {nb_path}")
    print(f"✅ Đã tạo kernel-metadata tại: {meta_path}")
    return nb_path, meta_path

if __name__ == '__main__':
    main()