Remove unused files
13
cope2n-ai-fi/modules/sdsvkie/.gitignore
vendored
@ -1,13 +0,0 @@
|
|||||||
*.pyc
|
|
||||||
__pycache__
|
|
||||||
.cache
|
|
||||||
/microsoft
|
|
||||||
weights/
|
|
||||||
workdirs/
|
|
||||||
wandb
|
|
||||||
sdsvkie/tools/sample_cvat
|
|
||||||
notebooks/workdirs
|
|
||||||
external/
|
|
||||||
notebooks/visualize
|
|
||||||
*.egg-info
|
|
||||||
./external/sdsv_dewarp
|
|
@ -1,75 +0,0 @@
|
|||||||
<p align="center">
|
|
||||||
<h1 align="center">SDSVKIE</h1>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
***Feature***
|
|
||||||
- Extract information from documents: VAT Invoice, Receipt
|
|
||||||
- Language: VI + EN
|
|
||||||
|
|
||||||
***What's news***
|
|
||||||
### - Ver 1.0.1:
|
|
||||||
- Improve postprocessing for receipts
|
|
||||||
- Support handling multiple pages for PDF files
|
|
||||||
- Lastest weight: /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/best
|
|
||||||
- Lastest config: /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/config.yaml
|
|
||||||
|
|
||||||
|
|
||||||
## I. Setup
|
|
||||||
***Dependencies***
|
|
||||||
- Python: 3.8
|
|
||||||
- Torch: 1.10.2
|
|
||||||
- CUDA: 11.6
|
|
||||||
- transformers: 4.28.1
|
|
||||||
```
|
|
||||||
pip install -v -e .
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## II. Inference
|
|
||||||
```
|
|
||||||
from sdsvkie import Predictor
|
|
||||||
import cv2
|
|
||||||
|
|
||||||
predictor = Predictor(
|
|
||||||
cfg="./workdirs/training/sdsap_receipt/exp_3/config.yaml",
|
|
||||||
weights="./workdirs/training/sdsap_receipt/exp_3/best",
|
|
||||||
device="cpu",
|
|
||||||
)
|
|
||||||
img = cv2.imread("./demos/4 Sep OPC to Home.jpg")
|
|
||||||
out = predictor(img)
|
|
||||||
output = out['end2end_results']
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## III. Training
|
|
||||||
- Prepare dataset: The structure of the dataset directory is organized as follows:
|
|
||||||
|
|
||||||
└── base_dataset \
|
|
||||||
├── train \
|
|
||||||
├──── sub_dir_1 \
|
|
||||||
├────── img1.txt \
|
|
||||||
├────── img1.txt \
|
|
||||||
├────── ... \
|
|
||||||
├──── sub_dir_2 \
|
|
||||||
├────── img2.txt \
|
|
||||||
├────── img2.txt \
|
|
||||||
├── test \
|
|
||||||
├──── imgn.jpg \
|
|
||||||
├──── imgn.txt
|
|
||||||
|
|
||||||
- Edit and run scripts:
|
|
||||||
```
|
|
||||||
sh ./scripts/train.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
# TODO
|
|
||||||
|
|
||||||
- [ ] Add more fields: sub_total, tips, seller_address, item list
|
|
||||||
- [x] Support muliple pages
|
|
||||||
- [x] Review result KIE for invoice (vnpt_exp_4_model)
|
|
||||||
- [x] Fix unnormalize box error in some cases
|
|
||||||
- [x] Support multiple pages
|
|
||||||
- [x] Create 200 multiple pages invoice
|
|
||||||
- [ ] Finalize multi page testset
|
|
||||||
- [ ] Eval result
|
|
Before Width: | Height: | Size: 222 KiB |
Before Width: | Height: | Size: 331 KiB |
Before Width: | Height: | Size: 513 KiB |
@ -1,73 +0,0 @@
|
|||||||
350 31 403 58 dịch
|
|
||||||
329 143 386 166 ngoài
|
|
||||||
104 298 174 321 CƯỚC
|
|
||||||
323 244 375 268 ĐẾN
|
|
||||||
739 67 810 91 (Price)
|
|
||||||
610 67 663 91 Unit)
|
|
||||||
1109 26 1174 55 Thuế
|
|
||||||
181 143 231 166 hãng
|
|
||||||
102 244 145 268 PHÍ
|
|
||||||
1021 27 1076 55 thuế
|
|
||||||
25 67 73 92 (No)
|
|
||||||
151 350 240 374 CHỨNG
|
|
||||||
893 25 949 54 Tiền
|
|
||||||
938 68 1033 92 (Amount)
|
|
||||||
150 244 198 268 XẾP
|
|
||||||
247 244 316 267 CẢNG
|
|
||||||
967 301 1080 323 68.730.120
|
|
||||||
998 354 1080 376 760.000
|
|
||||||
1394 31 1473 55 Thành
|
|
||||||
102 349 146 375 PHÍ
|
|
||||||
1477 25 1527 56 tiền
|
|
||||||
784 30 823 59 giá
|
|
||||||
241 68 374 92 (Description)
|
|
||||||
293 31 345 58 hóa,
|
|
||||||
228 32 288 58 hàng
|
|
||||||
1383 66 1447 92 (Total
|
|
||||||
247 350 333 374 TỪ-D/O
|
|
||||||
103 142 145 162 Thu
|
|
||||||
1196 82 1254 112 Tiền
|
|
||||||
203 244 242 268 DỠ
|
|
||||||
781 353 863 376 760.000
|
|
||||||
181 298 240 321 BIỂN
|
|
||||||
979 248 1080 270 6.342.336
|
|
||||||
174 31 222 54 Tên
|
|
||||||
533 66 579 92 (Qty
|
|
||||||
1254 354 1324 375 40.000
|
|
||||||
1486 353 1567 375 800.000
|
|
||||||
1467 247 1568 270 6.342.336
|
|
||||||
750 301 864 323 68.730.120
|
|
||||||
273 144 324 162 nước
|
|
||||||
956 32 1015 54 chưa
|
|
||||||
726 32 778 54 Đơn
|
|
||||||
1455 300 1568 323 68.730.120
|
|
||||||
148 142 177 166 hộ
|
|
||||||
1180 30 1321 59 GTGT✪(VAT)
|
|
||||||
1258 81 1316 111 thuế
|
|
||||||
531 30 568 54 SL
|
|
||||||
104 195 285 215 BL146201088385
|
|
||||||
604 31 663 53 ĐVT
|
|
||||||
763 248 863 270 6.342.336
|
|
||||||
22 31 76 54 STT
|
|
||||||
1451 68 1535 92 amount)
|
|
||||||
407 36 440 59 vụ
|
|
||||||
235 143 268 163 tàu
|
|
||||||
260 302 304 321 O.F.
|
|
||||||
1120 87 1149 112 %
|
|
||||||
583 66 605 88 &
|
|
||||||
573 30 598 54 &
|
|
||||||
591 301 624 322 BL
|
|
||||||
591 353 625 376 BL
|
|
||||||
1115 306 1154 322 XXX
|
|
||||||
41 301 57 322 2
|
|
||||||
1115 360 1154 375 XXX
|
|
||||||
1114 253 1154 269 XXX
|
|
||||||
42 354 56 375 3
|
|
||||||
591 247 625 270 BL
|
|
||||||
44 248 55 268 1
|
|
||||||
1310 301 1326 322 0
|
|
||||||
574 301 586 322 1
|
|
||||||
573 354 586 375 1
|
|
||||||
573 248 586 269 1
|
|
||||||
244 303 256 322 -
|
|
||||||
1310 247 1326 270 0
|
|
Before Width: | Height: | Size: 246 KiB |
@ -1,198 +0,0 @@
|
|||||||
749 41 785 60 suất
|
|
||||||
746 18 789 37 Thuế
|
|
||||||
746 70 788 86 (Rate)
|
|
||||||
192 35 226 52 dịch
|
|
||||||
812 30 850 49 Tiền
|
|
||||||
341 70 382 86 (Unit)
|
|
||||||
15 104 63 120 CƯỚC
|
|
||||||
632 29 670 48 Tiền
|
|
||||||
673 33 714 52 hàng
|
|
||||||
110 34 150 52 hàng
|
|
||||||
673 674 727 689 855.000
|
|
||||||
841 552 894 567 169.742
|
|
||||||
433 34 479 52 lượng
|
|
||||||
660 552 727 567 3.227.035
|
|
||||||
345 46 377 60 tính
|
|
||||||
841 228 894 243 169.742
|
|
||||||
154 34 188 51 hóa,
|
|
||||||
973 227 1040 243 3.396.777
|
|
||||||
66 103 102 120 TÀU
|
|
||||||
841 715 894 729 111.509
|
|
||||||
660 227 727 243 3.227.035
|
|
||||||
673 512 727 527 855.000
|
|
||||||
673 187 727 202 855.000
|
|
||||||
660 714 727 730 2.119.950
|
|
||||||
474 895 510 912 chiếu
|
|
||||||
118 58 207 75 (Description)
|
|
||||||
605 899 639 914 nhận
|
|
||||||
388 895 422 913 kiểm
|
|
||||||
973 552 1040 567 3.396.777
|
|
||||||
841 58 899 74 Amount)
|
|
||||||
75 34 107 49 Tên
|
|
||||||
988 29 1020 49 tiền
|
|
||||||
847 188 894 201 44.973
|
|
||||||
535 227 602 243 3.227.035
|
|
||||||
926 58 968 74 (Total
|
|
||||||
986 187 1039 202 899.973
|
|
||||||
334 23 368 37 Đơn
|
|
||||||
852 30 890 49 thuế
|
|
||||||
652 755 727 770 23.507.890
|
|
||||||
965 268 1040 283 38.111.990
|
|
||||||
973 390 1039 405 3.396.777
|
|
||||||
548 187 603 202 855.000
|
|
||||||
410 58 479 75 (Quantity)
|
|
||||||
547 59 589 74 Price)
|
|
||||||
841 390 894 405 169.742
|
|
||||||
652 593 727 608 38.111.990
|
|
||||||
535 552 602 568 3.227.035
|
|
||||||
847 512 894 526 44.973
|
|
||||||
965 106 1040 121 38.111.990
|
|
||||||
932 34 985 49 Thành
|
|
||||||
537 898 563 915 lập,
|
|
||||||
342 107 380 120 45GP
|
|
||||||
15 147 43 161 Thu
|
|
||||||
47 185 106 202 CHỨNG
|
|
||||||
673 349 727 364 855.000
|
|
||||||
847 674 894 689 44.973
|
|
||||||
548 674 603 689 855.000
|
|
||||||
567 900 601 915 giao,
|
|
||||||
555 33 580 52 giá
|
|
||||||
660 389 727 405 3.227.035
|
|
||||||
15 185 43 201 PHÍ
|
|
||||||
985 674 1039 689 899.973
|
|
||||||
652 268 727 284 38.111.990
|
|
||||||
351 895 386 915 (Cần
|
|
||||||
671 898 704 915 đơn)
|
|
||||||
675 59 731 74 amount)
|
|
||||||
970 59 1026 74 amount)
|
|
||||||
45 147 65 164 hộ
|
|
||||||
985 512 1039 527 899.973
|
|
||||||
973 714 1040 730 2.231.459
|
|
||||||
448 895 472 913 đối
|
|
||||||
535 715 603 730 2.119.950
|
|
||||||
652 106 727 121 38.111.990
|
|
||||||
965 593 1040 608 38.111.990
|
|
||||||
548 512 603 527 855.000
|
|
||||||
15 266 63 282 CƯỚC
|
|
||||||
508 58 544 74 (Unit
|
|
||||||
46 509 106 526 CHỨNG
|
|
||||||
408 30 429 49 Số
|
|
||||||
965 430 1040 446 38.111.990
|
|
||||||
46 225 79 242 XÉP
|
|
||||||
105 147 249 161 SNKO010220804769
|
|
||||||
15 428 62 444 CƯỚC
|
|
||||||
527 106 602 121 38.111.990
|
|
||||||
985 349 1039 364 899.973
|
|
||||||
15 590 63 607 CƯỚC
|
|
||||||
642 898 669 913 hóa
|
|
||||||
527 268 603 284 38.111.990
|
|
||||||
65 589 101 607 TÀU
|
|
||||||
15 752 63 769 CƯỚC
|
|
||||||
46 671 106 688 CHỨNG
|
|
||||||
15 225 43 242 PHÍ
|
|
||||||
341 228 380 242 45GP
|
|
||||||
14 633 43 648 Thu
|
|
||||||
847 350 894 364 44.973
|
|
||||||
547 349 603 365 855.000
|
|
||||||
65 427 101 445 TÀU
|
|
||||||
513 898 536 913 khi
|
|
||||||
14 471 43 485 Thu
|
|
||||||
673 837 727 851 855.000
|
|
||||||
15 309 43 323 Thu
|
|
||||||
14 508 44 526 PHÍ
|
|
||||||
965 755 1040 770 23.507.890
|
|
||||||
67 148 101 161 SNK
|
|
||||||
14 670 43 688 PHÍ
|
|
||||||
527 593 603 608 38.111.990
|
|
||||||
527 756 602 770 23.507.890
|
|
||||||
65 751 101 769 TÀU
|
|
||||||
44 470 65 489 hộ
|
|
||||||
517 34 551 48 Đơn
|
|
||||||
45 548 78 566 XÉP
|
|
||||||
14 549 43 567 PHÍ
|
|
||||||
65 265 102 283 TÀU
|
|
||||||
535 389 602 406 3.227.035
|
|
||||||
14 386 44 404 PHÍ
|
|
||||||
14 832 43 850 PHÍ
|
|
||||||
46 347 106 364 CHỨNG
|
|
||||||
44 633 65 651 hộ
|
|
||||||
548 837 602 850 855.000
|
|
||||||
46 833 106 850 CHỨNG
|
|
||||||
44 308 65 326 hộ
|
|
||||||
45 386 79 404 XÃP
|
|
||||||
14 346 43 364 PHÍ
|
|
||||||
14 795 43 810 Thu
|
|
||||||
526 430 602 446 38.111.990
|
|
||||||
802 58 840 74 (VAT
|
|
||||||
45 711 79 729 XÉP
|
|
||||||
848 837 893 850 44.973
|
|
||||||
80 225 107 242 DỠ
|
|
||||||
230 37 251 52 vụ
|
|
||||||
754 109 781 120 XXX
|
|
||||||
652 430 727 446 38.111.990
|
|
||||||
80 549 107 567 DỠ
|
|
||||||
350 188 372 202 BL
|
|
||||||
109 184 136 202 TỪ
|
|
||||||
616 58 672 73 (Pre-tax
|
|
||||||
44 795 65 813 hộ
|
|
||||||
986 837 1039 851 899.973
|
|
||||||
341 756 380 770 22GP
|
|
||||||
80 387 107 404 DỠ
|
|
||||||
424 900 445 912 tra
|
|
||||||
14 711 43 729 PHÍ
|
|
||||||
104 796 249 810 SNKO010220805559
|
|
||||||
104 309 248 323 SNKO010220805023
|
|
||||||
341 268 380 283 45GP
|
|
||||||
66 634 101 647 SNK
|
|
||||||
80 711 107 729 DỠ
|
|
||||||
372 22 389 40 vị
|
|
||||||
108 670 136 689 TỪ
|
|
||||||
104 633 248 648 SNKO010220805118
|
|
||||||
754 556 781 567 XXX
|
|
||||||
754 759 781 769 XXX
|
|
||||||
754 597 781 607 XXX
|
|
||||||
66 472 101 485 SNK
|
|
||||||
66 309 101 323 SNK
|
|
||||||
755 719 780 729 XXX
|
|
||||||
108 832 136 851 TỪ
|
|
||||||
341 431 380 445 45GP
|
|
||||||
754 515 781 526 XXX
|
|
||||||
754 840 781 850 XXX
|
|
||||||
341 715 380 729 22GP
|
|
||||||
108 345 136 364 TỪ
|
|
||||||
754 678 781 688 XXX
|
|
||||||
66 796 101 810 SNK
|
|
||||||
341 390 380 405 45GP
|
|
||||||
104 471 249 486 SNKO010220805117
|
|
||||||
341 553 380 567 45GP
|
|
||||||
108 508 136 527 TỪ
|
|
||||||
755 232 780 242 XXX
|
|
||||||
754 435 781 445 XXX
|
|
||||||
341 593 380 608 45GP
|
|
||||||
754 394 781 405 XXX
|
|
||||||
755 272 781 283 XXX
|
|
||||||
754 191 780 202 XXX
|
|
||||||
349 836 373 851 BL
|
|
||||||
754 353 780 364 XXX
|
|
||||||
349 349 372 364 BL
|
|
||||||
440 106 448 120 1
|
|
||||||
887 106 896 121 1
|
|
||||||
440 553 448 567 1
|
|
||||||
440 755 448 769 1
|
|
||||||
441 715 448 729 1
|
|
||||||
888 756 896 769 /
|
|
||||||
441 228 448 242 1
|
|
||||||
440 593 448 608 1
|
|
||||||
440 269 449 283 1
|
|
||||||
440 836 448 850 1
|
|
||||||
440 349 449 364 1
|
|
||||||
888 269 896 283 1
|
|
||||||
440 390 448 404 1
|
|
||||||
440 188 448 202 1
|
|
||||||
440 431 448 445 1
|
|
||||||
888 431 896 445 /
|
|
||||||
350 512 372 526 BL
|
|
||||||
440 674 448 688 1
|
|
||||||
888 594 896 607 /
|
|
||||||
349 675 372 689 BL
|
|
||||||
440 512 448 526 1
|
|
Before Width: | Height: | Size: 159 KiB |
@ -1,76 +0,0 @@
|
|||||||
162 92 206 111 hàng
|
|
||||||
263 152 303 175 gồm
|
|
||||||
133 124 188 142 chứng
|
|
||||||
132 26 176 46 hàng
|
|
||||||
224 26 261 45 dịch
|
|
||||||
267 124 311 142 nhập
|
|
||||||
928 23 974 43 Thuế
|
|
||||||
218 124 261 142 hàng
|
|
||||||
93 53 202 73 Descriptions
|
|
||||||
343 155 378 175 phụ
|
|
||||||
1110 23 1151 43 thuế
|
|
||||||
1067 23 1107 43 Tiền
|
|
||||||
181 26 219 45 hóa,
|
|
||||||
98 156 148 172 Cước
|
|
||||||
216 152 258 174 biển
|
|
||||||
26 54 56 70 No.
|
|
||||||
1185 26 1240 42 Thành
|
|
||||||
437 53 469 73 Qty
|
|
||||||
270 87 304 107 đến
|
|
||||||
92 26 127 43 Tên
|
|
||||||
1245 23 1279 44 tiền
|
|
||||||
979 23 1018 43 suất
|
|
||||||
640 26 669 47 giá
|
|
||||||
152 156 185 174 vận
|
|
||||||
98 124 129 140 Phí
|
|
||||||
98 92 129 109 Phí
|
|
||||||
1075 92 1144 109 166.904
|
|
||||||
813 92 900 109 3.171.168
|
|
||||||
866 23 906 43 thuế
|
|
||||||
97 178 127 198 phí
|
|
||||||
1223 54 1267 71 Total
|
|
||||||
26 26 52 43 Stt
|
|
||||||
308 155 340 171 các
|
|
||||||
684 54 728 70 Price
|
|
||||||
1246 92 1333 109 3.338.072
|
|
||||||
769 23 809 43 Tiền
|
|
||||||
1236 167 1333 184 36.393.480
|
|
||||||
673 26 728 46 (VND)
|
|
||||||
803 167 899 183 36.393.480
|
|
||||||
1085 124 1144 140 39.474
|
|
||||||
830 124 900 140 750.000
|
|
||||||
636 92 724 109 3.171.168
|
|
||||||
625 168 723 183 36.393.480
|
|
||||||
1082 54 1151 71 Amount
|
|
||||||
652 124 723 140 750.000
|
|
||||||
1284 26 1339 46 (VND)
|
|
||||||
1263 124 1333 140 789.474
|
|
||||||
487 92 542 108 CONT
|
|
||||||
837 54 906 71 Amount
|
|
||||||
132 92 158 108 dỡ
|
|
||||||
210 92 233 111 tại
|
|
||||||
643 54 679 70 Unit
|
|
||||||
813 27 862 43 trước
|
|
||||||
237 91 266 107 nơi
|
|
||||||
1271 54 1339 71 Amount
|
|
||||||
598 27 636 43 Đơn
|
|
||||||
482 54 519 70 Unit
|
|
||||||
190 155 212 172 tải
|
|
||||||
1039 54 1079 70 VAT
|
|
||||||
265 29 288 45 vụ
|
|
||||||
480 26 522 43 ĐVT
|
|
||||||
442 25 468 43 SL
|
|
||||||
975 54 1016 70 Rate
|
|
||||||
193 124 214 140 từ
|
|
||||||
485 123 517 141 B/L
|
|
||||||
485 166 510 184 Lô
|
|
||||||
931 53 972 71 VAT
|
|
||||||
31 167 43 183 3
|
|
||||||
31 124 44 140 2
|
|
||||||
1000 94 1014 110 X
|
|
||||||
32 92 42 108 1
|
|
||||||
1001 127 1014 142 X
|
|
||||||
1004 166 1014 185 /
|
|
||||||
1138 167 1147 184 /
|
|
||||||
451 92 461 108 1
|
|
||||||
451 124 461 140 1
|
|
Before Width: | Height: | Size: 201 KiB |
@ -1,82 +0,0 @@
|
|||||||
537 569 588 597 Tổng
|
|
||||||
233 161 291 182 chứng
|
|
||||||
593 573 641 597 cộng
|
|
||||||
290 35 332 57 dịch
|
|
||||||
467 78 524 99 (Unit)
|
|
||||||
577 35 632 57 lượng
|
|
||||||
472 50 511 68 tính
|
|
||||||
1124 18 1175 45 Tổng
|
|
||||||
190 161 227 183 nộp
|
|
||||||
647 573 715 596 (Total):
|
|
||||||
1012 160 1088 179 720.000
|
|
||||||
114 160 156 182 dịch
|
|
||||||
133 613 180 641 bằng
|
|
||||||
792 63 877 84 (Amount)
|
|
||||||
193 36 239 57 hàng
|
|
||||||
986 52 1029 76 Tiền
|
|
||||||
1138 78 1201 99 (Total)
|
|
||||||
797 159 892 180 9.000.000
|
|
||||||
322 156 364 179 xuất
|
|
||||||
1118 50 1170 68 thanh
|
|
||||||
244 35 285 56 hóa,
|
|
||||||
87 575 184 596 (Exchange
|
|
||||||
50 613 88 637 tiền
|
|
||||||
844 30 883 55 tiền
|
|
||||||
399 159 440 179 C/O
|
|
||||||
463 22 504 41 Đơn
|
|
||||||
1139 160 1235 179 9.720.000
|
|
||||||
703 64 758 84 price)
|
|
||||||
1140 119 1201 139 9=6+8
|
|
||||||
781 35 840 54 Thành
|
|
||||||
1178 17 1216 42 tiền
|
|
||||||
914 14 964 38 Thuế
|
|
||||||
915 160 949 180 8%
|
|
||||||
189 576 239 596 rate):
|
|
||||||
198 64 318 84 (Description)
|
|
||||||
91 613 129 637 viết
|
|
||||||
77 160 109 179 Phí
|
|
||||||
52 573 83 597 giá
|
|
||||||
256 619 323 640 words):
|
|
||||||
1032 53 1074 76 thuế
|
|
||||||
20 613 47 637 Số
|
|
||||||
1175 51 1217 68 toán
|
|
||||||
804 119 863 139 6=4x5
|
|
||||||
710 34 741 59 giá
|
|
||||||
664 35 707 54 Đơn
|
|
||||||
651 63 700 83 (Unit
|
|
||||||
546 30 573 54 Số
|
|
||||||
546 63 639 84 (Quantity)
|
|
||||||
151 36 188 54 Tên
|
|
||||||
368 159 396 179 xứ
|
|
||||||
184 618 221 637 chữ
|
|
||||||
482 619 531 638 trăm
|
|
||||||
20 573 48 597 Tỷ
|
|
||||||
1018 85 1092 105 Amount)
|
|
||||||
969 17 1082 41 GTGT(VAT)
|
|
||||||
634 618 692 642 nghìn
|
|
||||||
916 68 947 89 TS
|
|
||||||
696 613 754 644 đồng.
|
|
||||||
575 619 629 638 mươi
|
|
||||||
782 572 877 594 9.000.000
|
|
||||||
329 619 379 638 Chín
|
|
||||||
384 619 433 642 triệu
|
|
||||||
966 84 1015 104 (VAT
|
|
||||||
225 619 252 640 (In
|
|
||||||
296 160 318 179 từ
|
|
||||||
989 573 1065 592 720.000
|
|
||||||
17 63 66 84 (No.)
|
|
||||||
161 165 186 182 vụ
|
|
||||||
537 618 571 638 hai
|
|
||||||
336 39 362 57 vụ
|
|
||||||
507 21 529 45 vị
|
|
||||||
1119 572 1215 594 9.720.000
|
|
||||||
438 619 477 642 bảy
|
|
||||||
487 118 501 139 3
|
|
||||||
15 35 60 54 STT
|
|
||||||
1021 119 1037 140 8
|
|
||||||
925 119 940 139 7
|
|
||||||
585 118 600 139 4
|
|
||||||
252 119 266 139 2
|
|
||||||
697 117 712 140 5
|
|
||||||
37 160 47 178 1
|
|
||||||
37 120 47 138 1
|
|
Before Width: | Height: | Size: 269 KiB |
@ -1,68 +0,0 @@
|
|||||||
624 54 678 75 (Unit)
|
|
||||||
1049 23 1121 45 THÀNH
|
|
||||||
119 129 157 145 thuê
|
|
||||||
667 22 717 44 TÍNH
|
|
||||||
120 203 157 220 thuê
|
|
||||||
308 22 360 49 HÓA
|
|
||||||
185 161 217 183 đầu
|
|
||||||
185 198 217 220 đầu
|
|
||||||
749 54 838 76 (Quantity)
|
|
||||||
119 166 157 182 thuê
|
|
||||||
937 54 989 75 Price)
|
|
||||||
85 202 115 220 Phí
|
|
||||||
28 53 75 75 (No.)
|
|
||||||
185 124 217 146 đầu
|
|
||||||
774 25 850 48 LƯỢNG
|
|
||||||
1067 54 1153 75 (Amount)
|
|
||||||
270 54 382 76 (Description)
|
|
||||||
85 166 115 183 Phí
|
|
||||||
221 202 252 220 kéo
|
|
||||||
1067 202 1199 221 360.000.000.00
|
|
||||||
84 128 115 146 Phí
|
|
||||||
738 22 770 45 SỐ
|
|
||||||
245 23 304 45 HÀNG
|
|
||||||
221 165 252 183 kéo
|
|
||||||
221 128 252 146 kéo
|
|
||||||
1125 23 1173 45 TIỀN
|
|
||||||
423 421 505 449 STOP
|
|
||||||
1068 165 1198 185 138.461.550,00
|
|
||||||
586 26 634 45 ĐƠN
|
|
||||||
892 202 1012 221 72.000.000.00
|
|
||||||
1077 129 1198 148 47.076.927,00
|
|
||||||
39 95 65 116 (1)
|
|
||||||
885 54 933 74 (Unit
|
|
||||||
33 26 73 46 STT
|
|
||||||
199 22 242 45 TÊN
|
|
||||||
891 128 1012 148 47.076.927,00
|
|
||||||
891 165 1013 184 69.230.775.00
|
|
||||||
318 420 391 449 ONE
|
|
||||||
637 26 662 48 VỊ
|
|
||||||
697 128 726 145 XE
|
|
||||||
639 94 664 115 (3)
|
|
||||||
364 27 421 49 DỊCH
|
|
||||||
160 169 182 183 xe
|
|
||||||
698 165 726 182 XE
|
|
||||||
160 132 182 146 xe
|
|
||||||
925 95 950 116 (5)
|
|
||||||
782 95 807 116 (4)
|
|
||||||
160 207 182 220 xe
|
|
||||||
46 165 58 183 2
|
|
||||||
892 26 940 45 ĐƠN
|
|
||||||
315 94 339 116 (2)
|
|
||||||
46 202 58 220 3
|
|
||||||
943 22 984 46 GIÁ
|
|
||||||
841 166 853 183 2
|
|
||||||
47 129 57 146 1
|
|
||||||
691 421 724 449 M
|
|
||||||
842 203 853 220 5
|
|
||||||
424 26 456 50 VỤ
|
|
||||||
843 129 852 146 1
|
|
||||||
580 420 680 451 VICES,
|
|
||||||
733 421 787 449 ULTI
|
|
||||||
698 203 727 220 XE
|
|
||||||
399 425 414 447 -
|
|
||||||
1078 95 1159 115 )=(4)X(5)
|
|
||||||
1061 96 1084 115 (6)
|
|
||||||
796 420 854 449 BEN
|
|
||||||
515 420 572 449 SER
|
|
||||||
862 421 936 449 EFITS
|
|
Before Width: | Height: | Size: 245 KiB |
@ -1,76 +0,0 @@
|
|||||||
590 592 641 614 Cộng
|
|
||||||
141 131 193 153 ngoài
|
|
||||||
234 131 286 153 tháng
|
|
||||||
374 23 417 44 dịch
|
|
||||||
759 22 818 44 lượng
|
|
||||||
272 22 321 44 hàng
|
|
||||||
327 23 369 43 hóa,
|
|
||||||
731 47 815 67 (Quantity)
|
|
||||||
646 586 682 610 tiền
|
|
||||||
686 591 732 614 hàng
|
|
||||||
589 711 640 739 Tổng
|
|
||||||
620 47 671 66 (Unit)
|
|
||||||
282 47 393 68 (Description)
|
|
||||||
117 588 184 613 chuyển
|
|
||||||
590 628 639 652 Thuế
|
|
||||||
291 130 367 150 08/2022
|
|
||||||
792 593 867 613 amount):
|
|
||||||
590 670 634 693 Tiền
|
|
||||||
638 670 680 693 thuế
|
|
||||||
35 46 79 67 (No.)
|
|
||||||
643 628 682 652 suất
|
|
||||||
728 17 755 40 Số
|
|
||||||
104 130 136 149 Phí
|
|
||||||
198 131 230 154 giờ
|
|
||||||
940 48 992 66 Price)
|
|
||||||
71 591 112 613 lòng
|
|
||||||
228 22 267 41 Tên
|
|
||||||
949 21 982 44 giá
|
|
||||||
687 633 748 651 GTGT
|
|
||||||
644 716 691 738 cộng
|
|
||||||
34 21 79 40 STT
|
|
||||||
1189 17 1229 41 tiền
|
|
||||||
589 23 632 40 Đơn
|
|
||||||
750 675 807 696 (VAT):
|
|
||||||
838 717 900 737 (Grand
|
|
||||||
694 711 731 735 tiền
|
|
||||||
661 22 701 40 tính
|
|
||||||
684 674 745 693 GTGT
|
|
||||||
1120 22 1184 40 Thành
|
|
||||||
737 593 788 612 (Total
|
|
||||||
98 616 164 636 transfer
|
|
||||||
735 716 787 734 thanh
|
|
||||||
31 616 93 635 (Please
|
|
||||||
902 22 945 40 Đơn
|
|
||||||
753 634 799 654 (VAT
|
|
||||||
319 591 377 613 chúng
|
|
||||||
792 715 833 734 toán
|
|
||||||
891 47 936 66 (Unit
|
|
||||||
1135 47 1212 67 (Amount)
|
|
||||||
801 634 849 654 rate):
|
|
||||||
30 591 66 609 Vui
|
|
||||||
905 717 961 736 Total):
|
|
||||||
1187 131 1290 149 57.753.850
|
|
||||||
257 591 315 610 khoản
|
|
||||||
636 22 657 44 vị
|
|
||||||
224 616 266 633 bank
|
|
||||||
189 591 224 610 vào
|
|
||||||
339 616 383 636 No.):
|
|
||||||
421 27 448 46 vụ
|
|
||||||
410 586 435 611 số
|
|
||||||
1201 674 1292 693 4.620.308
|
|
||||||
228 591 253 610 tài
|
|
||||||
1189 591 1292 610 57.753.850
|
|
||||||
1257 632 1292 652 8%
|
|
||||||
381 590 408 611 tôi
|
|
||||||
1189 715 1292 734 62.374.158
|
|
||||||
1140 94 1207 111 6=4x5
|
|
||||||
269 619 336 633 account
|
|
||||||
190 621 220 633 our
|
|
||||||
168 619 186 633 to
|
|
||||||
331 93 344 111 2
|
|
||||||
767 93 780 110 4
|
|
||||||
639 93 651 111 3
|
|
||||||
935 93 948 110 5
|
|
||||||
52 130 62 149 1
|
|
||||||
53 94 62 110 1
|
|
Before Width: | Height: | Size: 448 KiB |
@ -1,150 +0,0 @@
|
|||||||
677 742 742 776 Tổng
|
|
||||||
1413 28 1476 63 Tổng
|
|
||||||
590 104 660 129 (Unit)
|
|
||||||
814 748 900 775 (Total):
|
|
||||||
1431 104 1509 129 (Total)
|
|
||||||
748 747 807 776 cộng
|
|
||||||
72 797 118 827 tiền
|
|
||||||
174 797 233 832 bằng
|
|
||||||
727 50 796 78 lượng
|
|
||||||
199 202 284 235 chuyển
|
|
||||||
369 50 421 77 dịch
|
|
||||||
596 68 645 92 tính
|
|
||||||
292 207 409 235 (trucking)
|
|
||||||
1480 28 1528 58 tiền
|
|
||||||
1150 24 1213 53 Thuế
|
|
||||||
305 515 358 542 định
|
|
||||||
884 86 954 111 price)
|
|
||||||
427 360 547 388 clearance)
|
|
||||||
1405 69 1471 91 thanh
|
|
||||||
1240 71 1294 101 Tiền
|
|
||||||
123 797 170 827 viết
|
|
||||||
247 51 305 78 hàng
|
|
||||||
1069 805 1141 833 nghìn
|
|
||||||
688 43 722 73 Số
|
|
||||||
995 85 1102 111 (Amount)
|
|
||||||
584 33 636 58 Đơn
|
|
||||||
148 516 199 542 dịch
|
|
||||||
1061 43 1109 75 tiền
|
|
||||||
242 516 300 543 giám
|
|
||||||
148 259 207 286 nâng
|
|
||||||
271 258 327 285 (Lift
|
|
||||||
1274 515 1368 539 160.000
|
|
||||||
1477 69 1529 91 toán
|
|
||||||
311 50 362 77 hóa,
|
|
||||||
982 50 1056 73 Thành
|
|
||||||
993 309 1120 334 13.309.081
|
|
||||||
148 464 205 491 giám
|
|
||||||
118 749 238 776 (Exchange
|
|
||||||
73 747 112 777 giá
|
|
||||||
253 86 404 111 (Description)
|
|
||||||
148 207 192 234 vận
|
|
||||||
148 412 199 439 dịch
|
|
||||||
820 85 880 110 (Unit
|
|
||||||
1413 799 1484 835 đồng.
|
|
||||||
1249 206 1368 230 4.055.959
|
|
||||||
1252 258 1367 281 1.973.455
|
|
||||||
1206 805 1269 828 trăm
|
|
||||||
101 206 143 230 Phí
|
|
||||||
689 85 805 111 (Quantity)
|
|
||||||
333 259 374 286 on)
|
|
||||||
304 309 351 337 off)
|
|
||||||
329 805 412 830 words):
|
|
||||||
832 805 893 828 trăm
|
|
||||||
990 257 1123 282 24.668.174
|
|
||||||
837 50 889 73 Đơn
|
|
||||||
101 258 143 281 Phí
|
|
||||||
149 361 199 384 khai
|
|
||||||
1273 463 1368 489 576.000
|
|
||||||
243 310 299 337 (Lift
|
|
||||||
33 797 67 827 Số
|
|
||||||
1432 515 1551 540 2.160.000
|
|
||||||
102 515 142 539 Phí
|
|
||||||
238 803 284 827 chữ
|
|
||||||
244 750 308 775 rate):
|
|
||||||
1005 514 1124 540 2.000.000
|
|
||||||
103 563 156 585 SEA
|
|
||||||
1434 463 1551 488 7.776.000
|
|
||||||
195 51 241 74 Tên
|
|
||||||
101 361 142 384 Phí
|
|
||||||
1298 72 1350 101 thuế
|
|
||||||
974 746 1117 771 113.180.694
|
|
||||||
1281 112 1372 137 Amount)
|
|
||||||
386 418 443 440 sung
|
|
||||||
1418 258 1550 281 26.641.629
|
|
||||||
991 206 1122 231 50.699.472
|
|
||||||
1432 156 1509 179 9=6+8
|
|
||||||
1434 412 1551 436 7.560.000
|
|
||||||
101 412 143 436 Phí
|
|
||||||
894 49 933 79 giá
|
|
||||||
1011 155 1085 179 6=4x5
|
|
||||||
314 362 420 388 (customs
|
|
||||||
102 309 143 333 Phí
|
|
||||||
1007 412 1123 437 7.000.000
|
|
||||||
34 747 69 777 Tỷ
|
|
||||||
1152 205 1194 231 8%
|
|
||||||
1419 206 1548 230 54.755.431
|
|
||||||
101 463 142 488 Phí
|
|
||||||
1152 256 1194 282 8%
|
|
||||||
1253 309 1367 333 1.064.725
|
|
||||||
1153 309 1194 334 8%
|
|
||||||
715 805 777 832 triệu
|
|
||||||
1005 360 1123 385 8.303.967
|
|
||||||
206 361 244 385 hải
|
|
||||||
1273 412 1369 436 560.000
|
|
||||||
1273 361 1368 384 664.317
|
|
||||||
1153 361 1194 385 8%
|
|
||||||
349 407 381 437 bổ
|
|
||||||
594 806 661 828 mươi
|
|
||||||
1276 805 1333 828 năm
|
|
||||||
1153 464 1193 488 8%
|
|
||||||
214 262 265 281 cont
|
|
||||||
242 412 280 437 hải
|
|
||||||
1220 29 1360 57 GTGT(VAT)
|
|
||||||
940 806 1006 828 mươi
|
|
||||||
477 805 539 828 trăm
|
|
||||||
1153 515 1194 539 8%
|
|
||||||
1422 309 1550 332 14.373.806
|
|
||||||
1006 463 1123 489 7.200.000
|
|
||||||
899 805 933 828 ba
|
|
||||||
1153 91 1192 117 TS
|
|
||||||
250 367 307 388 quan
|
|
||||||
1013 804 1061 828 lăm
|
|
||||||
1434 361 1551 384 8.968.284
|
|
||||||
639 32 667 62 vị
|
|
||||||
1340 806 1407 829 mươi
|
|
||||||
1149 805 1200 831 một
|
|
||||||
289 804 323 831 (In
|
|
||||||
1395 746 1540 771 122.235.150
|
|
||||||
1231 747 1350 771 9.054.456
|
|
||||||
784 805 826 828 hai
|
|
||||||
1153 413 1194 437 8%
|
|
||||||
545 804 588 829 hai
|
|
||||||
148 310 179 337 hạ
|
|
||||||
286 419 343 440 quan
|
|
||||||
667 805 709 829 hai
|
|
||||||
101 595 262 624 >07/08/2022)
|
|
||||||
1217 111 1277 135 (VAT
|
|
||||||
185 314 237 333 cont
|
|
||||||
204 521 236 543 vụ
|
|
||||||
419 805 471 832 Một
|
|
||||||
28 85 88 110 (No.)
|
|
||||||
211 464 269 491 định
|
|
||||||
165 561 447 589 INBOUND-(01/08/2022
|
|
||||||
427 55 459 78 vụ
|
|
||||||
615 155 633 180 3
|
|
||||||
737 154 757 179 4
|
|
||||||
31 49 86 74 STT
|
|
||||||
206 418 237 440 vụ
|
|
||||||
50 463 68 488 6
|
|
||||||
1285 154 1304 180 8
|
|
||||||
49 309 66 334 3
|
|
||||||
1165 155 1182 180 7
|
|
||||||
49 257 67 281 2
|
|
||||||
49 360 68 385 4
|
|
||||||
50 412 67 437 5
|
|
||||||
51 515 67 539 7
|
|
||||||
878 154 896 180 5
|
|
||||||
52 156 65 178 1
|
|
||||||
52 206 64 229 1
|
|
||||||
321 155 339 179 2
|
|
@ -1,948 +0,0 @@
|
|||||||
# Ultralytics YOLO 🚀, GPL-3.0 license
|
|
||||||
"""
|
|
||||||
Model validation metrics
|
|
||||||
"""
|
|
||||||
import math
|
|
||||||
import warnings
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import numpy as np
|
|
||||||
import torch
|
|
||||||
import torch.nn as nn
|
|
||||||
|
|
||||||
from sklearn.metrics import confusion_matrix
|
|
||||||
|
|
||||||
# boxes
|
|
||||||
def box_area(box):
|
|
||||||
# box = xyxy(4,n)
|
|
||||||
return (box[2] - box[0]) * (box[3] - box[1])
|
|
||||||
|
|
||||||
|
|
||||||
def bbox_ioa(box1, box2, eps=1e-7):
|
|
||||||
"""Returns the intersection over box2 area given box1, box2. Boxes are x1y1x2y2
|
|
||||||
box1: np.array of shape(nx4)
|
|
||||||
box2: np.array of shape(mx4)
|
|
||||||
returns: np.array of shape(nxm)
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Get the coordinates of bounding boxes
|
|
||||||
b1_x1, b1_y1, b1_x2, b1_y2 = box1.T
|
|
||||||
b2_x1, b2_y1, b2_x2, b2_y2 = box2.T
|
|
||||||
|
|
||||||
# Intersection area
|
|
||||||
inter_area = (
|
|
||||||
np.minimum(b1_x2[:, None], b2_x2) - np.maximum(b1_x1[:, None], b2_x1)
|
|
||||||
).clip(0) * (
|
|
||||||
np.minimum(b1_y2[:, None], b2_y2) - np.maximum(b1_y1[:, None], b2_y1)
|
|
||||||
).clip(
|
|
||||||
0
|
|
||||||
)
|
|
||||||
|
|
||||||
# box2 area
|
|
||||||
box2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1) + eps
|
|
||||||
|
|
||||||
# Intersection over box2 area
|
|
||||||
return inter_area / box2_area
|
|
||||||
|
|
||||||
|
|
||||||
def box_iou(box1, box2, eps=1e-7):
|
|
||||||
# https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py
|
|
||||||
"""
|
|
||||||
Return intersection-over-union (Jaccard index) of boxes.
|
|
||||||
Both sets of boxes are expected to be in (x1, y1, x2, y2) format.
|
|
||||||
Arguments:
|
|
||||||
box1 (Tensor[N, 4])
|
|
||||||
box2 (Tensor[M, 4])
|
|
||||||
Returns:
|
|
||||||
iou (Tensor[N, M]): the NxM matrix containing the pairwise
|
|
||||||
IoU values for every element in boxes1 and boxes2
|
|
||||||
"""
|
|
||||||
|
|
||||||
# inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2)
|
|
||||||
(a1, a2), (b1, b2) = box1.unsqueeze(1).chunk(2, 2), box2.unsqueeze(0).chunk(2, 2)
|
|
||||||
inter = (torch.min(a2, b2) - torch.max(a1, b1)).clamp(0).prod(2)
|
|
||||||
|
|
||||||
# IoU = inter / (area1 + area2 - inter)
|
|
||||||
return inter / ((a2 - a1).prod(2) + (b2 - b1).prod(2) - inter + eps)
|
|
||||||
|
|
||||||
|
|
||||||
def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7):
|
|
||||||
# Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4)
|
|
||||||
|
|
||||||
# Get the coordinates of bounding boxes
|
|
||||||
if xywh: # transform from xywh to xyxy
|
|
||||||
(x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
|
|
||||||
w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2
|
|
||||||
b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_
|
|
||||||
b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_
|
|
||||||
else: # x1, y1, x2, y2 = box1
|
|
||||||
b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1)
|
|
||||||
b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1)
|
|
||||||
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
|
|
||||||
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
|
|
||||||
|
|
||||||
# Intersection area
|
|
||||||
inter = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp(0) * (
|
|
||||||
b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)
|
|
||||||
).clamp(0)
|
|
||||||
|
|
||||||
# Union Area
|
|
||||||
union = w1 * h1 + w2 * h2 - inter + eps
|
|
||||||
|
|
||||||
# IoU
|
|
||||||
iou = inter / union
|
|
||||||
if CIoU or DIoU or GIoU:
|
|
||||||
cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(
|
|
||||||
b2_x1
|
|
||||||
) # convex (smallest enclosing box) width
|
|
||||||
ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1) # convex height
|
|
||||||
if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
|
|
||||||
c2 = cw**2 + ch**2 + eps # convex diagonal squared
|
|
||||||
rho2 = (
|
|
||||||
(b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2
|
|
||||||
+ (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2
|
|
||||||
) / 4 # center dist ** 2
|
|
||||||
if (
|
|
||||||
CIoU
|
|
||||||
): # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
|
|
||||||
v = (4 / math.pi**2) * (
|
|
||||||
torch.atan(w2 / h2) - torch.atan(w1 / h1)
|
|
||||||
).pow(2)
|
|
||||||
with torch.no_grad():
|
|
||||||
alpha = v / (v - iou + (1 + eps))
|
|
||||||
return iou - (rho2 / c2 + v * alpha) # CIoU
|
|
||||||
return iou - rho2 / c2 # DIoU
|
|
||||||
c_area = cw * ch + eps # convex area
|
|
||||||
return (
|
|
||||||
iou - (c_area - union) / c_area
|
|
||||||
) # GIoU https://arxiv.org/pdf/1902.09630.pdf
|
|
||||||
return iou # IoU
|
|
||||||
|
|
||||||
|
|
||||||
def mask_iou(mask1, mask2, eps=1e-7):
|
|
||||||
"""
|
|
||||||
mask1: [N, n] m1 means number of predicted objects
|
|
||||||
mask2: [M, n] m2 means number of gt objects
|
|
||||||
Note: n means image_w x image_h
|
|
||||||
return: masks iou, [N, M]
|
|
||||||
"""
|
|
||||||
intersection = torch.matmul(mask1, mask2.t()).clamp(0)
|
|
||||||
union = (
|
|
||||||
mask1.sum(1)[:, None] + mask2.sum(1)[None]
|
|
||||||
) - intersection # (area1 + area2) - intersection
|
|
||||||
return intersection / (union + eps)
|
|
||||||
|
|
||||||
|
|
||||||
def masks_iou(mask1, mask2, eps=1e-7):
|
|
||||||
"""
|
|
||||||
mask1: [N, n] m1 means number of predicted objects
|
|
||||||
mask2: [N, n] m2 means number of gt objects
|
|
||||||
Note: n means image_w x image_h
|
|
||||||
return: masks iou, (N, )
|
|
||||||
"""
|
|
||||||
intersection = (mask1 * mask2).sum(1).clamp(0) # (N, )
|
|
||||||
union = (mask1.sum(1) + mask2.sum(1))[
|
|
||||||
None
|
|
||||||
] - intersection # (area1 + area2) - intersection
|
|
||||||
return intersection / (union + eps)
|
|
||||||
|
|
||||||
|
|
||||||
def smooth_BCE(
|
|
||||||
eps=0.1,
|
|
||||||
): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441
|
|
||||||
# return positive, negative label smoothing BCE targets
|
|
||||||
return 1.0 - 0.5 * eps, 0.5 * eps
|
|
||||||
|
|
||||||
|
|
||||||
# losses
|
|
||||||
class FocalLoss(nn.Module):
|
|
||||||
# Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5)
|
|
||||||
def __init__(self, loss_fcn, gamma=1.5, alpha=0.25):
|
|
||||||
super().__init__()
|
|
||||||
self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss()
|
|
||||||
self.gamma = gamma
|
|
||||||
self.alpha = alpha
|
|
||||||
self.reduction = loss_fcn.reduction
|
|
||||||
self.loss_fcn.reduction = "none" # required to apply FL to each element
|
|
||||||
|
|
||||||
def forward(self, pred, true):
|
|
||||||
loss = self.loss_fcn(pred, true)
|
|
||||||
# p_t = torch.exp(-loss)
|
|
||||||
# loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability
|
|
||||||
|
|
||||||
# TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py
|
|
||||||
pred_prob = torch.sigmoid(pred) # prob from logits
|
|
||||||
p_t = true * pred_prob + (1 - true) * (1 - pred_prob)
|
|
||||||
alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha)
|
|
||||||
modulating_factor = (1.0 - p_t) ** self.gamma
|
|
||||||
loss *= alpha_factor * modulating_factor
|
|
||||||
|
|
||||||
if self.reduction == "mean":
|
|
||||||
return loss.mean()
|
|
||||||
elif self.reduction == "sum":
|
|
||||||
return loss.sum()
|
|
||||||
else: # 'none'
|
|
||||||
return loss
|
|
||||||
|
|
||||||
|
|
||||||
class ConfusionMatrix:
|
|
||||||
# Updated version of https://github.com/kaanakan/object_detection_confusion_matrix
|
|
||||||
def __init__(self, nc, conf=0.25, iou_thres=0.45):
|
|
||||||
self.matrix = np.zeros((nc + 1, nc + 1))
|
|
||||||
self.nc = nc # number of classes
|
|
||||||
self.conf = conf
|
|
||||||
self.iou_thres = iou_thres
|
|
||||||
|
|
||||||
def process_batch(self, detections, labels):
|
|
||||||
"""
|
|
||||||
Return intersection-over-union (Jaccard index) of boxes.
|
|
||||||
Both sets of boxes are expected to be in (x1, y1, x2, y2) format.
|
|
||||||
Arguments:
|
|
||||||
detections (Array[N, 6]), x1, y1, x2, y2, conf, class
|
|
||||||
labels (Array[M, 5]), class, x1, y1, x2, y2
|
|
||||||
Returns:
|
|
||||||
None, updates confusion matrix accordingly
|
|
||||||
"""
|
|
||||||
if detections is None:
|
|
||||||
gt_classes = labels.int()
|
|
||||||
for gc in gt_classes:
|
|
||||||
self.matrix[self.nc, gc] += 1 # background FN
|
|
||||||
return
|
|
||||||
|
|
||||||
detections = detections[detections[:, 4] > self.conf]
|
|
||||||
gt_classes = labels[:, 0].int()
|
|
||||||
detection_classes = detections[:, 5].int()
|
|
||||||
iou = box_iou(labels[:, 1:], detections[:, :4])
|
|
||||||
|
|
||||||
x = torch.where(iou > self.iou_thres)
|
|
||||||
if x[0].shape[0]:
|
|
||||||
matches = (
|
|
||||||
torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1)
|
|
||||||
.cpu()
|
|
||||||
.numpy()
|
|
||||||
)
|
|
||||||
if x[0].shape[0] > 1:
|
|
||||||
matches = matches[matches[:, 2].argsort()[::-1]]
|
|
||||||
matches = matches[np.unique(matches[:, 1], return_index=True)[1]]
|
|
||||||
matches = matches[matches[:, 2].argsort()[::-1]]
|
|
||||||
matches = matches[np.unique(matches[:, 0], return_index=True)[1]]
|
|
||||||
else:
|
|
||||||
matches = np.zeros((0, 3))
|
|
||||||
|
|
||||||
n = matches.shape[0] > 0
|
|
||||||
m0, m1, _ = matches.transpose().astype(int)
|
|
||||||
for i, gc in enumerate(gt_classes):
|
|
||||||
j = m0 == i
|
|
||||||
if n and sum(j) == 1:
|
|
||||||
self.matrix[detection_classes[m1[j]], gc] += 1 # correct
|
|
||||||
else:
|
|
||||||
self.matrix[self.nc, gc] += 1 # true background
|
|
||||||
|
|
||||||
if n:
|
|
||||||
for i, dc in enumerate(detection_classes):
|
|
||||||
if not any(m1 == i):
|
|
||||||
self.matrix[dc, self.nc] += 1 # predicted background
|
|
||||||
|
|
||||||
def matrix(self):
|
|
||||||
return self.matrix
|
|
||||||
|
|
||||||
def tp_fp(self):
|
|
||||||
tp = self.matrix.diagonal() # true positives
|
|
||||||
fp = self.matrix.sum(1) - tp # false positives
|
|
||||||
# fn = self.matrix.sum(0) - tp # false negatives (missed detections)
|
|
||||||
return tp[:-1], fp[:-1] # remove background class
|
|
||||||
|
|
||||||
# @TryExcept("WARNING ⚠️ ConfusionMatrix plot failure")
|
|
||||||
def plot(self, normalize=True, save_dir="", names=()):
|
|
||||||
import seaborn as sn
|
|
||||||
|
|
||||||
array = self.matrix / (
|
|
||||||
(self.matrix.sum(0).reshape(1, -1) + 1e-9) if normalize else 1
|
|
||||||
) # normalize columns
|
|
||||||
array[array < 0.005] = np.nan # don't annotate (would appear as 0.00)
|
|
||||||
|
|
||||||
fig, ax = plt.subplots(1, 1, figsize=(12, 9), tight_layout=True)
|
|
||||||
nc, nn = self.nc, len(names) # number of classes, names
|
|
||||||
sn.set(font_scale=1.0 if nc < 50 else 0.8) # for label size
|
|
||||||
labels = (0 < nn < 99) and (nn == nc) # apply names to ticklabels
|
|
||||||
ticklabels = (names + ["background"]) if labels else "auto"
|
|
||||||
with warnings.catch_warnings():
|
|
||||||
warnings.simplefilter(
|
|
||||||
"ignore"
|
|
||||||
) # suppress empty matrix RuntimeWarning: All-NaN slice encountered
|
|
||||||
sn.heatmap(
|
|
||||||
array,
|
|
||||||
ax=ax,
|
|
||||||
annot=nc < 30,
|
|
||||||
annot_kws={"size": 8},
|
|
||||||
cmap="Blues",
|
|
||||||
fmt=".2f",
|
|
||||||
square=True,
|
|
||||||
vmin=0.0,
|
|
||||||
xticklabels=ticklabels,
|
|
||||||
yticklabels=ticklabels,
|
|
||||||
).set_facecolor((1, 1, 1))
|
|
||||||
ax.set_xlabel("True")
|
|
||||||
ax.set_ylabel("Predicted")
|
|
||||||
ax.set_title("Confusion Matrix")
|
|
||||||
fig.savefig(Path(save_dir) / "confusion_matrix.png", dpi=250)
|
|
||||||
plt.close(fig)
|
|
||||||
|
|
||||||
def print(self):
|
|
||||||
for i in range(self.nc + 1):
|
|
||||||
print(" ".join(map(str, self.matrix[i])))
|
|
||||||
|
|
||||||
|
|
||||||
def smooth(y, f=0.05):
|
|
||||||
# Box filter of fraction f
|
|
||||||
nf = round(len(y) * f * 2) // 2 + 1 # number of filter elements (must be odd)
|
|
||||||
p = np.ones(nf // 2) # ones padding
|
|
||||||
yp = np.concatenate((p * y[0], y, p * y[-1]), 0) # y padded
|
|
||||||
return np.convolve(yp, np.ones(nf) / nf, mode="valid") # y-smoothed
|
|
||||||
|
|
||||||
|
|
||||||
def plot_pr_curve(px, py, ap, save_dir=Path("pr_curve.png"), names=()):
|
|
||||||
# Precision-recall curve
|
|
||||||
fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True)
|
|
||||||
py = np.stack(py, axis=1)
|
|
||||||
|
|
||||||
if 0 < len(names) < 21: # display per-class legend if < 21 classes
|
|
||||||
for i, y in enumerate(py.T):
|
|
||||||
ax.plot(
|
|
||||||
px, y, linewidth=1, label=f"{names[i]} {ap[i, 0]:.3f}"
|
|
||||||
) # plot(recall, precision)
|
|
||||||
else:
|
|
||||||
ax.plot(px, py, linewidth=1, color="grey") # plot(recall, precision)
|
|
||||||
|
|
||||||
ax.plot(
|
|
||||||
px,
|
|
||||||
py.mean(1),
|
|
||||||
linewidth=3,
|
|
||||||
color="blue",
|
|
||||||
label="all classes %.3f mAP@0.5" % ap[:, 0].mean(),
|
|
||||||
)
|
|
||||||
ax.set_xlabel("Recall")
|
|
||||||
ax.set_ylabel("Precision")
|
|
||||||
ax.set_xlim(0, 1)
|
|
||||||
ax.set_ylim(0, 1)
|
|
||||||
ax.legend(bbox_to_anchor=(1.04, 1), loc="upper left")
|
|
||||||
ax.set_title("Precision-Recall Curve")
|
|
||||||
fig.savefig(save_dir, dpi=250)
|
|
||||||
plt.close(fig)
|
|
||||||
|
|
||||||
|
|
||||||
def plot_mc_curve(
|
|
||||||
px,
|
|
||||||
py,
|
|
||||||
save_dir=Path("mc_curve.png"),
|
|
||||||
names=(),
|
|
||||||
xlabel="Confidence",
|
|
||||||
ylabel="Metric",
|
|
||||||
):
|
|
||||||
# Metric-confidence curve
|
|
||||||
fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True)
|
|
||||||
|
|
||||||
if 0 < len(names) < 21: # display per-class legend if < 21 classes
|
|
||||||
for i, y in enumerate(py):
|
|
||||||
ax.plot(px, y, linewidth=1, label=f"{names[i]}") # plot(confidence, metric)
|
|
||||||
else:
|
|
||||||
ax.plot(px, py.T, linewidth=1, color="grey") # plot(confidence, metric)
|
|
||||||
|
|
||||||
y = smooth(py.mean(0), 0.05)
|
|
||||||
ax.plot(
|
|
||||||
px,
|
|
||||||
y,
|
|
||||||
linewidth=3,
|
|
||||||
color="blue",
|
|
||||||
label=f"all classes {y.max():.2f} at {px[y.argmax()]:.3f}",
|
|
||||||
)
|
|
||||||
ax.set_xlabel(xlabel)
|
|
||||||
ax.set_ylabel(ylabel)
|
|
||||||
ax.set_xlim(0, 1)
|
|
||||||
ax.set_ylim(0, 1)
|
|
||||||
ax.legend(bbox_to_anchor=(1.04, 1), loc="upper left")
|
|
||||||
ax.set_title(f"{ylabel}-Confidence Curve")
|
|
||||||
fig.savefig(save_dir, dpi=250)
|
|
||||||
plt.close(fig)
|
|
||||||
|
|
||||||
|
|
||||||
def compute_ap(recall, precision):
|
|
||||||
"""Compute the average precision, given the recall and precision curves
|
|
||||||
# Arguments
|
|
||||||
recall: The recall curve (list)
|
|
||||||
precision: The precision curve (list)
|
|
||||||
# Returns
|
|
||||||
Average precision, precision curve, recall curve
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Append sentinel values to beginning and end
|
|
||||||
mrec = np.concatenate(([0.0], recall, [1.0]))
|
|
||||||
mpre = np.concatenate(([1.0], precision, [0.0]))
|
|
||||||
|
|
||||||
# Compute the precision envelope
|
|
||||||
mpre = np.flip(np.maximum.accumulate(np.flip(mpre)))
|
|
||||||
|
|
||||||
# Integrate area under curve
|
|
||||||
method = "interp" # methods: 'continuous', 'interp'
|
|
||||||
if method == "interp":
|
|
||||||
x = np.linspace(0, 1, 101) # 101-point interp (COCO)
|
|
||||||
ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate
|
|
||||||
else: # 'continuous'
|
|
||||||
i = np.where(mrec[1:] != mrec[:-1])[0] # points where x-axis (recall) changes
|
|
||||||
ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) # area under curve
|
|
||||||
|
|
||||||
return ap, mpre, mrec
|
|
||||||
|
|
||||||
|
|
||||||
def ap_per_class(
|
|
||||||
tp,
|
|
||||||
conf,
|
|
||||||
pred_cls,
|
|
||||||
target_cls,
|
|
||||||
plot=False,
|
|
||||||
save_dir=Path(),
|
|
||||||
names=(),
|
|
||||||
eps=1e-16,
|
|
||||||
prefix="",
|
|
||||||
):
|
|
||||||
"""Compute the average precision, given the recall and precision curves.
|
|
||||||
Source: https://github.com/rafaelpadilla/Object-Detection-Metrics.
|
|
||||||
# Arguments
|
|
||||||
tp: True positives (nparray, nx1 or nx10).
|
|
||||||
conf: Objectness value from 0-1 (nparray).
|
|
||||||
pred_cls: Predicted object classes (nparray).
|
|
||||||
target_cls: True object classes (nparray).
|
|
||||||
plot: Plot precision-recall curve at mAP@0.5
|
|
||||||
save_dir: Plot save directory
|
|
||||||
# Returns
|
|
||||||
The average precision as computed in py-faster-rcnn.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Sort by objectness
|
|
||||||
i = np.argsort(-conf)
|
|
||||||
tp, conf, pred_cls = tp[i], conf[i], pred_cls[i]
|
|
||||||
|
|
||||||
# Find unique classes
|
|
||||||
unique_classes, nt = np.unique(target_cls, return_counts=True)
|
|
||||||
nc = unique_classes.shape[0] # number of classes, number of detections
|
|
||||||
|
|
||||||
# Create Precision-Recall curve and compute AP for each class
|
|
||||||
px, py = np.linspace(0, 1, 1000), [] # for plotting
|
|
||||||
ap, p, r = np.zeros((nc, tp.shape[1])), np.zeros((nc, 1000)), np.zeros((nc, 1000))
|
|
||||||
for ci, c in enumerate(unique_classes):
|
|
||||||
i = pred_cls == c
|
|
||||||
n_l = nt[ci] # number of labels
|
|
||||||
n_p = i.sum() # number of predictions
|
|
||||||
if n_p == 0 or n_l == 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Accumulate FPs and TPs
|
|
||||||
fpc = (1 - tp[i]).cumsum(0)
|
|
||||||
tpc = tp[i].cumsum(0)
|
|
||||||
|
|
||||||
# Recall
|
|
||||||
recall = tpc / (n_l + eps) # recall curve
|
|
||||||
r[ci] = np.interp(
|
|
||||||
-px, -conf[i], recall[:, 0], left=0
|
|
||||||
) # negative x, xp because xp decreases
|
|
||||||
|
|
||||||
# Precision
|
|
||||||
precision = tpc / (tpc + fpc) # precision curve
|
|
||||||
p[ci] = np.interp(-px, -conf[i], precision[:, 0], left=1) # p at pr_score
|
|
||||||
|
|
||||||
# AP from recall-precision curve
|
|
||||||
for j in range(tp.shape[1]):
|
|
||||||
ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j])
|
|
||||||
if plot and j == 0:
|
|
||||||
py.append(np.interp(px, mrec, mpre)) # precision at mAP@0.5
|
|
||||||
|
|
||||||
# from IPython import embed; embed()
|
|
||||||
# Compute F1 (harmonic mean of precision and recall)
|
|
||||||
f1 = 2 * p * r / (p + r + eps)
|
|
||||||
names = [
|
|
||||||
v for k, v in names.items() if k in unique_classes
|
|
||||||
] # list: only classes that have data
|
|
||||||
names = dict(enumerate(names)) # to dict
|
|
||||||
if plot:
|
|
||||||
plot_pr_curve(px, py, ap, save_dir / f"{prefix}PR_curve.png", names)
|
|
||||||
plot_mc_curve(px, f1, save_dir / f"{prefix}F1_curve.png", names, ylabel="F1")
|
|
||||||
plot_mc_curve(
|
|
||||||
px, p, save_dir / f"{prefix}P_curve.png", names, ylabel="Precision"
|
|
||||||
)
|
|
||||||
plot_mc_curve(px, r, save_dir / f"{prefix}R_curve.png", names, ylabel="Recall")
|
|
||||||
|
|
||||||
i = smooth(f1.mean(0), 0.1).argmax() # max F1 index
|
|
||||||
p, r, f1 = p[:, i], r[:, i], f1[:, i]
|
|
||||||
tp = (r * nt).round() # true positives
|
|
||||||
fp = (tp / (p + eps) - tp).round() # false positives
|
|
||||||
return tp, fp, p, r, f1, ap, unique_classes.astype(int)
|
|
||||||
|
|
||||||
|
|
||||||
class Metric:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.p = [] # (nc, )
|
|
||||||
self.r = [] # (nc, )
|
|
||||||
self.f1 = [] # (nc, )
|
|
||||||
self.all_ap = [] # (nc, 10)
|
|
||||||
self.ap_class_index = [] # (nc, )
|
|
||||||
self.nc = 0
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ap50(self):
|
|
||||||
"""AP@0.5 of all classes.
|
|
||||||
Return:
|
|
||||||
(nc, ) or [].
|
|
||||||
"""
|
|
||||||
return self.all_ap[:, 0] if len(self.all_ap) else []
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ap(self):
|
|
||||||
"""AP@0.5:0.95
|
|
||||||
Return:
|
|
||||||
(nc, ) or [].
|
|
||||||
"""
|
|
||||||
return self.all_ap.mean(1) if len(self.all_ap) else []
|
|
||||||
|
|
||||||
@property
|
|
||||||
def mp(self):
|
|
||||||
"""mean precision of all classes.
|
|
||||||
Return:
|
|
||||||
float.
|
|
||||||
"""
|
|
||||||
return self.p.mean() if len(self.p) else 0.0
|
|
||||||
|
|
||||||
@property
|
|
||||||
def mr(self):
|
|
||||||
"""mean recall of all classes.
|
|
||||||
Return:
|
|
||||||
float.
|
|
||||||
"""
|
|
||||||
return self.r.mean() if len(self.r) else 0.0
|
|
||||||
|
|
||||||
@property
|
|
||||||
def map50(self):
|
|
||||||
"""Mean AP@0.5 of all classes.
|
|
||||||
Return:
|
|
||||||
float.
|
|
||||||
"""
|
|
||||||
return self.all_ap[:, 0].mean() if len(self.all_ap) else 0.0
|
|
||||||
|
|
||||||
@property
|
|
||||||
def map75(self):
|
|
||||||
"""Mean AP@0.75 of all classes.
|
|
||||||
Return:
|
|
||||||
float.
|
|
||||||
"""
|
|
||||||
return self.all_ap[:, 5].mean() if len(self.all_ap) else 0.0
|
|
||||||
|
|
||||||
@property
|
|
||||||
def map(self):
|
|
||||||
"""Mean AP@0.5:0.95 of all classes.
|
|
||||||
Return:
|
|
||||||
float.
|
|
||||||
"""
|
|
||||||
return self.all_ap.mean() if len(self.all_ap) else 0.0
|
|
||||||
|
|
||||||
def mean_results(self):
|
|
||||||
"""Mean of results, return mp, mr, map50, map"""
|
|
||||||
return [self.mp, self.mr, self.map50, self.map]
|
|
||||||
|
|
||||||
def class_result(self, i):
|
|
||||||
"""class-aware result, return p[i], r[i], ap50[i], ap[i]"""
|
|
||||||
return self.p[i], self.r[i], self.ap50[i], self.ap[i]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def maps(self):
|
|
||||||
"""mAP of each class"""
|
|
||||||
maps = np.zeros(self.nc) + self.map
|
|
||||||
for i, c in enumerate(self.ap_class_index):
|
|
||||||
maps[c] = self.ap[i]
|
|
||||||
return maps
|
|
||||||
|
|
||||||
def fitness(self):
|
|
||||||
# Model fitness as a weighted combination of metrics
|
|
||||||
w = [0.0, 0.0, 0.1, 0.9] # weights for [P, R, mAP@0.5, mAP@0.5:0.95]
|
|
||||||
return (np.array(self.mean_results()) * w).sum()
|
|
||||||
|
|
||||||
def update(self, results):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
results: tuple(p, r, ap, f1, ap_class)
|
|
||||||
"""
|
|
||||||
self.p, self.r, self.f1, self.all_ap, self.ap_class_index = results
|
|
||||||
|
|
||||||
|
|
||||||
class DetMetrics:
|
|
||||||
def __init__(self, save_dir=Path("."), plot=False, names=()) -> None:
|
|
||||||
self.save_dir = save_dir
|
|
||||||
self.plot = plot
|
|
||||||
self.names = names
|
|
||||||
self.box = Metric()
|
|
||||||
self.speed = {
|
|
||||||
"preprocess": 0.0,
|
|
||||||
"inference": 0.0,
|
|
||||||
"loss": 0.0,
|
|
||||||
"postprocess": 0.0,
|
|
||||||
}
|
|
||||||
self.probs = {}
|
|
||||||
self.tp, self.fp = [], []
|
|
||||||
|
|
||||||
def process(self, tp, conf, pred_cls, target_cls):
|
|
||||||
|
|
||||||
if len(conf) > 0:
|
|
||||||
for cls_id in range(len(self.names)):
|
|
||||||
conf_with_cls = conf[np.where(pred_cls == cls_id)]
|
|
||||||
if len(conf_with_cls) > 0:
|
|
||||||
highest_prob = conf_with_cls.max()
|
|
||||||
self.probs[self.names[cls_id]] = [highest_prob]
|
|
||||||
|
|
||||||
results = ap_per_class(
|
|
||||||
tp,
|
|
||||||
conf,
|
|
||||||
pred_cls,
|
|
||||||
target_cls,
|
|
||||||
plot=self.plot,
|
|
||||||
save_dir=self.save_dir,
|
|
||||||
names=self.names,
|
|
||||||
)
|
|
||||||
self.tp, self.fp = results[:2]
|
|
||||||
|
|
||||||
results = results[2:]
|
|
||||||
self.box.nc = len(self.names)
|
|
||||||
self.box.update(results)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def keys(self):
|
|
||||||
return [
|
|
||||||
"metrics/precision(B)",
|
|
||||||
"metrics/recall(B)",
|
|
||||||
"metrics/mAP50(B)",
|
|
||||||
"metrics/mAP50-95(B)",
|
|
||||||
]
|
|
||||||
|
|
||||||
def mean_results(self):
|
|
||||||
return self.box.mean_results()
|
|
||||||
|
|
||||||
def class_result(self, i):
|
|
||||||
return self.box.class_result(i)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def maps(self):
|
|
||||||
return self.box.maps
|
|
||||||
|
|
||||||
@property
|
|
||||||
def fitness(self):
|
|
||||||
return self.box.fitness()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ap_class_index(self):
|
|
||||||
return self.box.ap_class_index
|
|
||||||
|
|
||||||
@property
|
|
||||||
def results_dict(self):
|
|
||||||
return dict(zip(self.keys + ["fitness"], self.mean_results() + [self.fitness]))
|
|
||||||
|
|
||||||
def custom_result(self, instances_info =None, iou_match_dict: dict = None, prob_of_classes: dict = None):
|
|
||||||
"""_summary_
|
|
||||||
|
|
||||||
Args:
|
|
||||||
instances_info (np.ndarray, optional): _description_. Defaults to None.
|
|
||||||
iou_list (list, optional): _description_. Defaults to None.
|
|
||||||
iou_match_dict (dict, optional): _description_. Defaults to None.
|
|
||||||
prob_of_classes (dict, optional): _description_. Defaults to None.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
_type_: _description_
|
|
||||||
"""
|
|
||||||
|
|
||||||
instances_info = instances_info.tolist() if isinstance(instances_info, np.ndarray) else instances_info
|
|
||||||
total_instances = sum(instances_info)
|
|
||||||
total_instances = total_instances.item() if not isinstance(total_instances, int) else total_instances
|
|
||||||
|
|
||||||
custom_res = {}
|
|
||||||
|
|
||||||
for ci, c in self.names.items():
|
|
||||||
iou_match = iou_match_dict[c]
|
|
||||||
average_iou = np.mean(iou_match).item() if len(iou_match) > 0 else 0
|
|
||||||
_tp = self.tp[ci] if len(self.tp) == len(self.names) else 0
|
|
||||||
_fp = self.fp[ci] if len(self.fp) == len(self.names) else 0
|
|
||||||
_miss = instances_info[ci] - _tp
|
|
||||||
custom_res.update(
|
|
||||||
{
|
|
||||||
self.names[ci]: {
|
|
||||||
"actual": instances_info[ci],
|
|
||||||
"correct": int(_tp),
|
|
||||||
"missed_detection": int(_miss),
|
|
||||||
"false_detection": int(_fp),
|
|
||||||
"average_iou": round(average_iou, 4),
|
|
||||||
"average_dice": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
custom_res.update({
|
|
||||||
"probability": prob_of_classes,
|
|
||||||
"average": {
|
|
||||||
"actual": int(total_instances // len(self.names)),
|
|
||||||
"correct": int(self.tp.sum() // len(self.names)) if len(self.tp) > 0 else 0,
|
|
||||||
"missed_detection": 0,
|
|
||||||
"false_detection": int(self.fp.sum() // len(self.names)) if len(self.fp) > 0 else 0,
|
|
||||||
"average_iou": round(np.mean([custom_res[cls_name]['average_iou'] for cls_name in self.names.values()]).item(), 4),
|
|
||||||
"average_dice": 0,
|
|
||||||
},
|
|
||||||
"total": {
|
|
||||||
"actual": total_instances,
|
|
||||||
"correct": int(self.tp.sum()) if len(self.tp) > 0 else 0 ,
|
|
||||||
"missed_detection": 0,
|
|
||||||
"false_detection": int(self.fp.sum()) if len(self.fp) > 0 else 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
custom_res["total"]["missed_detection"] = (
|
|
||||||
custom_res["total"]["actual"] - custom_res["total"]["correct"]
|
|
||||||
)
|
|
||||||
custom_res["average"]["missed_detection"] = custom_res["total"][
|
|
||||||
"missed_detection"
|
|
||||||
] // len(self.names)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return custom_res
|
|
||||||
|
|
||||||
|
|
||||||
class SegmentMetrics:
|
|
||||||
def __init__(self, save_dir=Path("."), plot=False, names=()) -> None:
|
|
||||||
self.save_dir = save_dir
|
|
||||||
self.plot = plot
|
|
||||||
self.names = names
|
|
||||||
self.box = Metric()
|
|
||||||
self.seg = Metric()
|
|
||||||
self.speed = {
|
|
||||||
"preprocess": 0.0,
|
|
||||||
"inference": 0.0,
|
|
||||||
"loss": 0.0,
|
|
||||||
"postprocess": 0.0,
|
|
||||||
}
|
|
||||||
self.tp = []
|
|
||||||
self.fp = []
|
|
||||||
self.probs = {}
|
|
||||||
|
|
||||||
|
|
||||||
def process(self, tp_m, tp_b, conf, pred_cls, target_cls):
|
|
||||||
|
|
||||||
if len(conf) > 0:
|
|
||||||
for cls_id in range(len(self.names)):
|
|
||||||
conf_with_cls = conf[np.where(pred_cls == cls_id)]
|
|
||||||
if len(conf_with_cls) > 0:
|
|
||||||
highest_prob = conf_with_cls.max()
|
|
||||||
self.probs[self.names[cls_id]] = [highest_prob]
|
|
||||||
|
|
||||||
|
|
||||||
res_mask = ap_per_class(
|
|
||||||
tp_m,
|
|
||||||
conf,
|
|
||||||
pred_cls,
|
|
||||||
target_cls,
|
|
||||||
plot=self.plot,
|
|
||||||
save_dir=self.save_dir,
|
|
||||||
names=self.names,
|
|
||||||
prefix="Mask",
|
|
||||||
)
|
|
||||||
|
|
||||||
tp, fp, results_mask = res_mask[0], res_mask[1], res_mask[2:]
|
|
||||||
self.seg.nc = len(self.names)
|
|
||||||
self.seg.update(results_mask)
|
|
||||||
self.tp = tp
|
|
||||||
self.fp = fp
|
|
||||||
# print(self.tp, self.fp)
|
|
||||||
|
|
||||||
results_box = ap_per_class(
|
|
||||||
tp_b,
|
|
||||||
conf,
|
|
||||||
pred_cls,
|
|
||||||
target_cls,
|
|
||||||
plot=self.plot,
|
|
||||||
save_dir=self.save_dir,
|
|
||||||
names=self.names,
|
|
||||||
prefix="Box",
|
|
||||||
)[2:]
|
|
||||||
self.box.nc = len(self.names)
|
|
||||||
self.box.update(results_box)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def keys(self):
|
|
||||||
return [
|
|
||||||
"metrics/precision(B)",
|
|
||||||
"metrics/recall(B)",
|
|
||||||
"metrics/mAP50(B)",
|
|
||||||
"metrics/mAP50-95(B)",
|
|
||||||
"metrics/precision(M)",
|
|
||||||
"metrics/recall(M)",
|
|
||||||
"metrics/mAP50(M)",
|
|
||||||
"metrics/mAP50-95(M)",
|
|
||||||
]
|
|
||||||
|
|
||||||
def mean_results(self):
|
|
||||||
return self.box.mean_results() + self.seg.mean_results()
|
|
||||||
|
|
||||||
def class_result(self, i):
|
|
||||||
return self.box.class_result(i) + self.seg.class_result(i)
|
|
||||||
|
|
||||||
def custom_result(self, instances_info =None, iou_match_dict: dict = None, prob_of_classes: dict = None):
|
|
||||||
"""_summary_
|
|
||||||
|
|
||||||
Args:
|
|
||||||
instances_info (np.ndarray, optional): _description_. Defaults to None.
|
|
||||||
iou_list (list, optional): _description_. Defaults to None.
|
|
||||||
iou_match_dict (dict, optional): _description_. Defaults to None.
|
|
||||||
prob_of_classes (dict, optional): _description_. Defaults to None.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
_type_: _description_
|
|
||||||
"""
|
|
||||||
|
|
||||||
instances_info = instances_info.tolist() if isinstance(instances_info, np.ndarray) else instances_info
|
|
||||||
total_instances = sum(instances_info)
|
|
||||||
total_instances = total_instances.item() if not isinstance(total_instances, int) else total_instances
|
|
||||||
|
|
||||||
custom_res = {}
|
|
||||||
|
|
||||||
for ci, c in self.names.items():
|
|
||||||
iou_match = iou_match_dict[c]
|
|
||||||
average_iou = np.mean(iou_match).item() if len(iou_match) > 0 else 0
|
|
||||||
_tp = self.tp[ci] if len(self.tp) == len(self.names) else 0
|
|
||||||
_fp = self.fp[ci] if len(self.fp) == len(self.names) else 0
|
|
||||||
_miss = instances_info[ci] - _tp
|
|
||||||
custom_res.update(
|
|
||||||
{
|
|
||||||
self.names[ci]: {
|
|
||||||
"actual": instances_info[ci],
|
|
||||||
"correct": int(_tp),
|
|
||||||
"missed_detection": int(_miss),
|
|
||||||
"false_detection": int(_fp),
|
|
||||||
"average_iou": round(average_iou, 4),
|
|
||||||
"average_dice": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
custom_res.update({
|
|
||||||
"probability": prob_of_classes,
|
|
||||||
"average": {
|
|
||||||
"actual": int(total_instances // len(self.names)),
|
|
||||||
"correct": int(self.tp.sum() // len(self.names)) if len(self.tp) > 0 else 0,
|
|
||||||
"missed_detection": 0,
|
|
||||||
"false_detection": int(self.fp.sum() // len(self.names)) if len(self.fp) > 0 else 0,
|
|
||||||
"average_iou": round(np.mean([custom_res[cls_name]['average_iou'] for cls_name in self.names.values()]).item(), 4),
|
|
||||||
"average_dice": 0,
|
|
||||||
},
|
|
||||||
"total": {
|
|
||||||
"actual": total_instances,
|
|
||||||
"correct": int(self.tp.sum()) if len(self.tp) > 0 else 0 ,
|
|
||||||
"missed_detection": 0,
|
|
||||||
"false_detection": int(self.fp.sum()) if len(self.fp) > 0 else 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
custom_res["total"]["missed_detection"] = (
|
|
||||||
custom_res["total"]["actual"] - custom_res["total"]["correct"]
|
|
||||||
)
|
|
||||||
custom_res["average"]["missed_detection"] = custom_res["total"][
|
|
||||||
"missed_detection"
|
|
||||||
] // len(self.names)
|
|
||||||
|
|
||||||
|
|
||||||
return custom_res
|
|
||||||
|
|
||||||
@property
|
|
||||||
def maps(self):
|
|
||||||
return self.box.maps + self.seg.maps
|
|
||||||
|
|
||||||
@property
|
|
||||||
def fitness(self):
|
|
||||||
return self.seg.fitness() + self.box.fitness()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ap_class_index(self):
|
|
||||||
# boxes and masks have the same ap_class_index
|
|
||||||
return self.box.ap_class_index
|
|
||||||
|
|
||||||
@property
|
|
||||||
def results_dict(self):
|
|
||||||
return dict(zip(self.keys + ["fitness"], self.mean_results() + [self.fitness]))
|
|
||||||
|
|
||||||
|
|
||||||
class ClassifyMetrics:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.top1 = 0
|
|
||||||
self.top5 = 0
|
|
||||||
|
|
||||||
self.speed = {
|
|
||||||
"preprocess": 0.0,
|
|
||||||
"inference": 0.0,
|
|
||||||
"loss": 0.0,
|
|
||||||
"postprocess": 0.0,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def process(self, targets, pred):
|
|
||||||
# target classes and predicted classes
|
|
||||||
pred, targets = torch.cat(pred), torch.cat(targets)
|
|
||||||
correct = (targets[:, None] == pred).float()
|
|
||||||
acc = torch.stack(
|
|
||||||
(correct[:, 0], correct.max(1).values), dim=1
|
|
||||||
) # (top1, top5) accuracy
|
|
||||||
self.top1, self.top5 = acc.mean(0).tolist()
|
|
||||||
|
|
||||||
def custom_result(self ,targets, pred):
|
|
||||||
# from IPython import embed; embed()
|
|
||||||
metric_per_class = {}
|
|
||||||
pred, targets = torch.cat(pred), torch.cat(targets)
|
|
||||||
pred = pred.cpu().numpy()[:, 0]
|
|
||||||
targets = targets.cpu().numpy()
|
|
||||||
conf_mat = confusion_matrix(targets, pred)
|
|
||||||
|
|
||||||
"""{
|
|
||||||
"actual":
|
|
||||||
"correct":
|
|
||||||
"recall":
|
|
||||||
"precision":
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
k = conf_mat.shape[0]
|
|
||||||
for cls_id in range(k):
|
|
||||||
tp = conf_mat[cls_id, cls_id]
|
|
||||||
fp = np.sum(conf_mat[cls_id, :]) - tp
|
|
||||||
fn = np.sum(conf_mat[:, cls_id]) - tp
|
|
||||||
tn = np.sum(conf_mat) - tp - fp - fn
|
|
||||||
|
|
||||||
res_per_class = {
|
|
||||||
"actual": tp + fp,
|
|
||||||
"correct": tp,
|
|
||||||
"miss_detection": 0,
|
|
||||||
"false_detection": fp,
|
|
||||||
"recall": 0 if tp + fn == 0 else tp / (tp+fn),
|
|
||||||
"precision": tp / (tp + fp)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
metric_per_class[cls_id] = res_per_class
|
|
||||||
|
|
||||||
return metric_per_class
|
|
||||||
|
|
||||||
|
|
||||||
@property
|
|
||||||
def fitness(self):
|
|
||||||
return self.top5
|
|
||||||
|
|
||||||
@property
|
|
||||||
def results_dict(self):
|
|
||||||
return dict(zip(self.keys + ["fitness"], [self.top1, self.top5, self.fitness]))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def keys(self):
|
|
||||||
return ["metrics/accuracy_top1", "metrics/accuracy_top5"]
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
det_metric = DetMetrics()
|
|
||||||
|
|
@ -1,275 +0,0 @@
|
|||||||
import json
|
|
||||||
import logging
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any, Dict, List, Optional, Union
|
|
||||||
|
|
||||||
import requests
|
|
||||||
import tqdm
|
|
||||||
from sdsvkie.utils.eval_kie import eval_kie
|
|
||||||
from sdsvkie.utils.io_file import read_json, write_json
|
|
||||||
|
|
||||||
logging.basicConfig(
|
|
||||||
level=logging.INFO,
|
|
||||||
# format=""
|
|
||||||
|
|
||||||
)
|
|
||||||
logger = logging.getLogger()
|
|
||||||
|
|
||||||
|
|
||||||
HEADERS = {
|
|
||||||
'accept': 'application/json',
|
|
||||||
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTA2ODk4ODcsInVzZXJuYW1lIjoiYWRtaW4ifQ.Oybpc9tBsN35vCn3jzekkABDQKJT6yO1aBBJ4rMNln0'
|
|
||||||
}
|
|
||||||
|
|
||||||
URL = "http://107.120.133.27:8082/predict/image"
|
|
||||||
|
|
||||||
|
|
||||||
def run(
|
|
||||||
data_dir: str,
|
|
||||||
url: str,
|
|
||||||
gt_path: str,
|
|
||||||
field_pred_file: str,
|
|
||||||
samples: Union[int, None] = None,
|
|
||||||
|
|
||||||
):
|
|
||||||
|
|
||||||
files = get_files(data_dir, recursive=False, limit=samples)
|
|
||||||
preds = predict(url, files)
|
|
||||||
|
|
||||||
## process for table
|
|
||||||
# table_eval_result = {}
|
|
||||||
# table_preds = get_table_preds(preds)
|
|
||||||
# table_eval_result =
|
|
||||||
|
|
||||||
# process for seller, buyer, ...
|
|
||||||
field_eval_result = {}
|
|
||||||
# field_preds = get_field_preds_from_api(api_preds=preds)
|
|
||||||
field_preds = get_field_preds_from_file(pred_file=field_pred_file)
|
|
||||||
classes = get_classes(preds=field_preds)
|
|
||||||
if len(classes) == 0:
|
|
||||||
raise Exception("Can not get the classes list")
|
|
||||||
field_eval_result = eval(
|
|
||||||
gt=gt_path,
|
|
||||||
pred=field_preds,
|
|
||||||
classes=classes,
|
|
||||||
classes_ignore=['other', 'table']
|
|
||||||
)
|
|
||||||
print(field_eval_result)
|
|
||||||
## combine result
|
|
||||||
combine_result = {}
|
|
||||||
# combine_result = combine_result(table_res=table_eval_result, field_res=field_eval_result)
|
|
||||||
|
|
||||||
|
|
||||||
print_result(
|
|
||||||
data_path=data_dir,
|
|
||||||
num_samples=len(list(field_preds.keys())),
|
|
||||||
target_level=0.05,
|
|
||||||
result=1.0, # edit here
|
|
||||||
)
|
|
||||||
return combine_result
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def print_result(
|
|
||||||
data_path: str,
|
|
||||||
num_samples:int,
|
|
||||||
target_level: float,
|
|
||||||
result: float,
|
|
||||||
metric: str = "NLD",
|
|
||||||
avg_time: float = 1.6363
|
|
||||||
):
|
|
||||||
|
|
||||||
print(f"Path of validation dataset: {data_path}\n"
|
|
||||||
+ f"Number of validation dataset: {num_samples}\n"
|
|
||||||
+ f"Evaluation metric: {metric}\n"
|
|
||||||
+ f"Target level: {target_level}\n"
|
|
||||||
+ f"Archieved level: {result}\n"
|
|
||||||
+ f"Average time: {avg_time}\n"
|
|
||||||
+ f"Verification result: {'PASS' if result > target_level else 'FAILED'}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_field_preds_from_api(api_preds: str) -> dict:
|
|
||||||
field_preds = get_fields_preds(api_preds)
|
|
||||||
field_preds = combine_to_single_file(field_preds)
|
|
||||||
return field_preds
|
|
||||||
|
|
||||||
def get_field_preds_from_file(pred_file: str) -> dict:
|
|
||||||
"""
|
|
||||||
Get predictions from json file
|
|
||||||
"""
|
|
||||||
field_preds = read_json(pred_file)
|
|
||||||
return field_preds
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_fields_preds(preds: List[Dict]):
|
|
||||||
preds = [
|
|
||||||
{item['file_path']: format_output_api(item['response_dict'])}
|
|
||||||
for item in preds
|
|
||||||
]
|
|
||||||
return preds
|
|
||||||
|
|
||||||
def combine_result(table_res: Dict, field_res: Dict):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def _str2dict(text: str) -> Dict:
|
|
||||||
try:
|
|
||||||
data = json.loads(text)
|
|
||||||
except Exception as err:
|
|
||||||
logger.error(f"{err} - data: {text}")
|
|
||||||
data = {}
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def predict_one_file(url: str, file: Union[str, Path]) -> Dict:
|
|
||||||
"""
|
|
||||||
Output format:
|
|
||||||
{
|
|
||||||
file_path: path of file
|
|
||||||
response_dict:
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
if isinstance(file, str):
|
|
||||||
file = Path(file)
|
|
||||||
|
|
||||||
payload = {}
|
|
||||||
filename = file.name
|
|
||||||
files = [
|
|
||||||
(
|
|
||||||
'file',
|
|
||||||
(
|
|
||||||
filename,
|
|
||||||
open(str(file), 'rb'),
|
|
||||||
'application/pdf'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
# logger.info(f"Files: {file}")
|
|
||||||
response = requests.request(
|
|
||||||
"POST", url, headers=HEADERS, data=payload, files=files)
|
|
||||||
|
|
||||||
response_dict = _str2dict(response.text)
|
|
||||||
|
|
||||||
return {
|
|
||||||
"file_path": str(file),
|
|
||||||
"pred_data": response_dict
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def predict(url: str, files: List[Union[str, Path]]) -> List[Dict]:
|
|
||||||
"""
|
|
||||||
List of {'file_path', 'response_dict'}
|
|
||||||
"""
|
|
||||||
|
|
||||||
preds = []
|
|
||||||
for idx, file in tqdm.tqdm(enumerate(files)):
|
|
||||||
try:
|
|
||||||
pred = predict_one_file(url, file)
|
|
||||||
preds.append(pred)
|
|
||||||
except:
|
|
||||||
logger.info(f"Error at file: {file}")
|
|
||||||
return preds
|
|
||||||
|
|
||||||
|
|
||||||
def get_files(data_dir: str, recursive: bool = False, limit: Union[int, None] = None) -> List[Union[Path, str]]:
|
|
||||||
if recursive:
|
|
||||||
files = Path(data_dir).rglob("*")
|
|
||||||
else:
|
|
||||||
files = Path(data_dir).glob("*")
|
|
||||||
|
|
||||||
if limit:
|
|
||||||
files = list(files)[:limit]
|
|
||||||
return files
|
|
||||||
|
|
||||||
|
|
||||||
def _stem_filename(filename: str) -> str:
|
|
||||||
"""
|
|
||||||
Stem a file path: x/y.txt -> y
|
|
||||||
"""
|
|
||||||
return Path(filename).stem
|
|
||||||
|
|
||||||
|
|
||||||
def format_output_api(output_api: Dict, skip_fields=['table']) -> Dict:
|
|
||||||
if "pages" not in output_api:
|
|
||||||
return {}
|
|
||||||
pages = output_api['pages']
|
|
||||||
|
|
||||||
result = {}
|
|
||||||
for page in pages:
|
|
||||||
fields = page['fields']
|
|
||||||
for field_item in fields:
|
|
||||||
field_label, field_value = field_item['label'], field_item['value']
|
|
||||||
if field_label in result or field_label in skip_fields:
|
|
||||||
continue
|
|
||||||
result[field_label] = field_value
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def combine_to_single_file(preds: List[Dict]) -> None:
|
|
||||||
if len(preds) == 0:
|
|
||||||
return {}
|
|
||||||
combined_data = {
|
|
||||||
_stem_filename(item["filename"]): item["pred_data"]
|
|
||||||
for item in preds
|
|
||||||
}
|
|
||||||
return combined_data
|
|
||||||
|
|
||||||
|
|
||||||
def eval(
|
|
||||||
gt: Union[str, Dict],
|
|
||||||
pred: Union[str, Dict],
|
|
||||||
classes: List[str],
|
|
||||||
classes_ignore: List[str] = []
|
|
||||||
) -> Dict:
|
|
||||||
eval_res = eval_kie(
|
|
||||||
gt_e2e_path=gt,
|
|
||||||
pred_e2e_path=pred,
|
|
||||||
kie_labels=classes,
|
|
||||||
skip_labels=classes_ignore
|
|
||||||
)
|
|
||||||
return eval_res
|
|
||||||
|
|
||||||
|
|
||||||
def get_classes(preds: Dict) -> List[str]:
|
|
||||||
classes = []
|
|
||||||
for k, v in preds.items():
|
|
||||||
if v:
|
|
||||||
classes = list(v.keys())
|
|
||||||
break
|
|
||||||
return classes
|
|
||||||
|
|
||||||
|
|
||||||
def test():
|
|
||||||
import requests
|
|
||||||
|
|
||||||
url = "http://107.120.133.27:8082/predict/image"
|
|
||||||
|
|
||||||
payload = {}
|
|
||||||
files = [
|
|
||||||
('file', ('(1 of 19)_HOADON_1C23TYY_50.pdf', open(
|
|
||||||
'/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/PV2/final/all_in/(1 of 19)_HOADON_1C23TYY_50.pdf', 'rb'), 'application/pdf'))
|
|
||||||
]
|
|
||||||
headers = {
|
|
||||||
'accept': 'application/json',
|
|
||||||
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTA2ODk4ODcsInVzZXJuYW1lIjoiYWRtaW4ifQ.Oybpc9tBsN35vCn3jzekkABDQKJT6yO1aBBJ4rMNln0'
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.request(
|
|
||||||
"POST", url, headers=headers, data=payload, files=files)
|
|
||||||
|
|
||||||
print(response.text)
|
|
||||||
# print(json.loa ds(response.text))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
limit = 5
|
|
||||||
run(
|
|
||||||
data_dir="/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/PV2/final/all_in",
|
|
||||||
url=URL,
|
|
||||||
gt_path="/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/PV2/final/all_in.json",
|
|
||||||
field_pred_file="/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/invoice_all_in_final_e2e_21072023_5.json",
|
|
||||||
samples=limit
|
|
||||||
)
|
|
||||||
|
|
||||||
# test()
|
|
@ -1,15 +0,0 @@
|
|||||||
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="vi"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script nonce="zHShHBII_Chw737pdVlj6Q">(function(){window.google={kEI:'1d43ZPakBPjJ0PEPi7S6aA',kEXPI:'0,1359409,6059,206,4804,2316,383,246,5,1129120,1197734,658,380098,16115,19398,9286,22431,1361,12317,2817,14765,4998,13228,3847,6884,31560,887,1985,2891,11754,606,29842,826,30022,2614,13142,3,346,230,20573,4,1538,2304,42127,13658,4437,16786,5830,2527,4094,7596,1,39047,2,3105,2,14022,25739,5679,1021,31122,4568,6252,23423,1253,5835,14967,4333,24,4993,2467,445,2,2,1,6959,19673,8155,7381,15969,874,19632,8,1922,9779,12415,8224,751,1503,13261,6305,20199,927,4869,14,14326,14,82,12151,8055,1622,1778,669,4308,8051,11189,575,3560,988,1494,1536,426,5685,3225,6480,1804,6250,1979,2243,1757,1127,152,9329,3571,6273,147,269,1896,276,3607,671,2054,1696,562,196,1330,1697,1635,1606,4198,2,931,906,31,6,267,3417,1055,2181,386,2483,663,536,1261,958,951,492,931,355,838,278,628,444,892,3,952,1237,951,3347,84,480,72,734,862,521,117,360,18,409,966,335,1,5,84,619,679,1973,123,686,255,123,2,728,765,57,392,549,25,65,410,101,110,418,626,225,585,656,52,163,8,645,2,184,1289,3,40,7,251,161,280,5,69,716,221,596,50,520,40,1361,111,218,214,739,34,2,14,70,421,164,600,620,520,141,5206827,2,21,47,136,329,8798385,3306,141,795,19736,1,346,4808,17,1,5,1,6,1,32,106,10,2,20725522,2920861,299113,550,2773269,1268323,1964,16673,2893,6250,12560,3179,726,841,213,430,270,1412577,194320,23565287,2064,34',kBL:'gVXf',kOPI:89978449};google.sn='webhp';google.kHL='vi';})();(function(){
|
|
||||||
var e=this||self;var g,h=[];function k(a){for(var c;a&&(!a.getAttribute||!(c=a.getAttribute("eid")));)a=a.parentNode;return c||g}function l(a){for(var c=null;a&&(!a.getAttribute||!(c=a.getAttribute("leid")));)a=a.parentNode;return c}function m(a){/^http:/i.test(a)&&"https:"===window.location.protocol&&(google.ml&&google.ml(Error("a"),!1,{src:a,glmm:1}),a="");return a}
|
|
||||||
function p(a,c,b,f){var d="";-1===c.search("&ei=")&&(d="&ei="+k(b),-1===c.search("&lei=")&&(b=l(b))&&(d+="&lei="+b));b="";e._cshid&&-1===c.search("&cshid=")&&"slh"!==a&&(b="&cshid="+e._cshid);return"/"+(f||"gen_204")+"?atyp=i&ct="+String(a)+"&cad="+(c+d)+"&zx="+String(Date.now())+b};g=google.kEI;google.getEI=k;google.getLEI=l;google.ml=function(){return null};google.log=function(a,c,b,f,d){b||(b=p(a,c,f,d));if(b=m(b)){a=new Image;var n=h.length;h[n]=a;a.onerror=a.onload=a.onabort=function(){delete h[n]};a.src=b}};google.logUrl=function(a){return p("",a)};}).call(this);(function(){google.y={};google.sy=[];google.x=function(a,b){if(a)var c=a.id;else{do c=Math.random();while(google.y[c])}google.y[c]=[a,b];return!1};google.sx=function(a){google.sy.push(a)};google.lm=[];google.plm=function(a){google.lm.push.apply(google.lm,a)};google.lq=[];google.load=function(a,b,c){google.lq.push([[a],b,c])};google.loadAll=function(a,b){google.lq.push([a,b])};google.bx=!1;google.lx=function(){};}).call(this);google.f={};(function(){
|
|
||||||
document.documentElement.addEventListener("submit",function(b){var a;if(a=b.target){var c=a.getAttribute("data-submitfalse");a="1"===c||"q"===c&&!a.elements.q.value?!0:!1}else a=!1;a&&(b.preventDefault(),b.stopPropagation())},!0);document.documentElement.addEventListener("click",function(b){var a;a:{for(a=b.target;a&&a!==document.documentElement;a=a.parentElement)if("A"===a.tagName){a="1"===a.getAttribute("data-nohref");break a}a=!1}a&&b.preventDefault()},!0);}).call(this);</script><style>#gbar,#guser{font-size:13px;padding-top:1px !important;}#gbar{height:22px}#guser{padding-bottom:7px !important;text-align:right}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}@media all{.gb1{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb4{text-decoration:underline !important}a.gb1,a.gb4{color:#00c !important}.gbi .gb4{color:#dd8e27 !important}.gbf .gb4{color:#900 !important}
|
|
||||||
</style><style>body,td,a,p,.h{font-family:arial,sans-serif}body{margin:0;overflow-y:scroll}#gog{padding:3px 8px 0}td{line-height:.8em}.gac_m td{line-height:17px}form{margin-bottom:20px}.h{color:#1558d6}em{font-weight:bold;font-style:normal}.lst{height:25px;width:496px}.gsfi,.lst{font:18px arial,sans-serif}.gsfs{font:17px arial,sans-serif}.ds{display:inline-box;display:inline-block;margin:3px 0 4px;margin-left:4px}input{font-family:inherit}body{background:#fff;color:#000}a{color:#4b11a8;text-decoration:none}a:hover,a:active{text-decoration:underline}.fl a{color:#1558d6}a:visited{color:#4b11a8}.sblc{padding-top:5px}.sblc a{display:block;margin:2px 0;margin-left:13px;font-size:11px}.lsbb{background:#f8f9fa;border:solid 1px;border-color:#dadce0 #70757a #70757a #dadce0;height:30px}.lsbb{display:block}#WqQANb a{display:inline-block;margin:0 12px}.lsb{background:url(/images/nav_logo229.png) 0 -261px repeat-x;border:none;color:#000;cursor:pointer;height:30px;margin:0;outline:0;font:15px arial,sans-serif;vertical-align:top}.lsb:active{background:#dadce0}.lst:focus{outline:none}.Ucigb{width:458px}</style><script nonce="zHShHBII_Chw737pdVlj6Q">(function(){window.google.erd={jsr:1,bv:1776,de:true};
|
|
||||||
var h=this||self;var k,l=null!=(k=h.mei)?k:1,n,p=null!=(n=h.sdo)?n:!0,q=0,r,t=google.erd,v=t.jsr;google.ml=function(a,b,d,m,e){e=void 0===e?2:e;b&&(r=a&&a.message);if(google.dl)return google.dl(a,e,d),null;if(0>v){window.console&&console.error(a,d);if(-2===v)throw a;b=!1}else b=!a||!a.message||"Error loading script"===a.message||q>=l&&!m?!1:!0;if(!b)return null;q++;d=d||{};b=encodeURIComponent;var c="/gen_204?atyp=i&ei="+b(google.kEI);google.kEXPI&&(c+="&jexpid="+b(google.kEXPI));c+="&srcpg="+b(google.sn)+"&jsr="+b(t.jsr)+"&bver="+b(t.bv);var f=a.lineNumber;void 0!==f&&(c+="&line="+f);var g=
|
|
||||||
a.fileName;g&&(0<g.indexOf("-extension:/")&&(e=3),c+="&script="+b(g),f&&g===window.location.href&&(f=document.documentElement.outerHTML.split("\n")[f],c+="&cad="+b(f?f.substring(0,300):"No script found.")));c+="&jsel="+e;for(var u in d)c+="&",c+=b(u),c+="=",c+=b(d[u]);c=c+"&emsg="+b(a.name+": "+a.message);c=c+"&jsst="+b(a.stack||"N/A");12288<=c.length&&(c=c.substr(0,12288));a=c;m||google.log(0,"",a);return a};window.onerror=function(a,b,d,m,e){r!==a&&(a=e instanceof Error?e:Error(a),void 0===d||"lineNumber"in a||(a.lineNumber=d),void 0===b||"fileName"in a||(a.fileName=b),google.ml(a,!1,void 0,!1,"SyntaxError"===a.name||"SyntaxError"===a.message.substring(0,11)||-1!==a.message.indexOf("Script error")?3:0));r=null;p&&q>=l&&(window.onerror=null)};})();</script></head><body bgcolor="#fff"><script nonce="zHShHBII_Chw737pdVlj6Q">(function(){var src='/images/nav_logo229.png';var iesg=false;document.body.onload = function(){window.n && window.n();if (document.images){new Image().src=src;}
|
|
||||||
if (!iesg){document.f&&document.f.q.focus();document.gbqf&&document.gbqf.q.focus();}
|
|
||||||
}
|
|
||||||
})();</script><div id="mngb"><div id=gbar><nobr><b class=gb1>Tìm kiếm</b> <a class=gb1 href="http://www.google.com.vn/imghp?hl=vi&tab=wi">Hình ảnh</a> <a class=gb1 href="http://maps.google.com/maps?hl=vi&tab=wl">Maps</a> <a class=gb1 href="https://play.google.com/?hl=vi&tab=w8">Play</a> <a class=gb1 href="https://www.youtube.com/?tab=w1">YouTube</a> <a class=gb1 href="https://news.google.com/?tab=wn">Tin tức</a> <a class=gb1 href="https://mail.google.com/mail/?tab=wm">Gmail</a> <a class=gb1 href="https://drive.google.com/?tab=wo">Drive</a> <a class=gb1 style="text-decoration:none" href="https://www.google.com.vn/intl/vi/about/products?tab=wh"><u>Thêm</u> »</a></nobr></div><div id=guser width=100%><nobr><span id=gbn class=gbi></span><span id=gbf class=gbf></span><span id=gbe></span><a href="http://www.google.com.vn/history/optout?hl=vi" class=gb4>Lịch sử Web</a> | <a href="/preferences?hl=vi" class=gb4>Cài đặt</a> | <a target=_top id=gb_70 href="https://accounts.google.com/ServiceLogin?hl=vi&passive=true&continue=http://www.google.com/&ec=GAZAAQ" class=gb4>Đăng nhập</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div></div><center><br clear="all" id="lgpd"><div id="lga"><img alt="Google" height="92" src="/images/branding/googlelogo/1x/googlelogo_white_background_color_272x92dp.png" style="padding:28px 0 14px" width="272" id="hplogo"><br><br></div><form action="/search" name="f"><table cellpadding="0" cellspacing="0"><tr valign="top"><td width="25%"> </td><td align="center" nowrap=""><input name="ie" value="ISO-8859-1" type="hidden"><input value="vi" name="hl" type="hidden"><input name="source" type="hidden" value="hp"><input name="biw" type="hidden"><input name="bih" type="hidden"><div class="ds" style="height:32px;margin:4px 0"><div style="position:relative;zoom:1"><input class="lst Ucigb" style="margin:0;padding:5px 8px 0 6px;vertical-align:top;color:#000;padding-right:38px" autocomplete="off" value="" title="Tìm trên Google" maxlength="2048" name="q" size="57"><img src="/textinputassistant/tia.png" style="position:absolute;cursor:pointer;right:5px;top:4px;z-index:300" data-script-url="/textinputassistant/11/vi_tia.js" id="tsuid_1" alt="" height="23" width="27"><script nonce="zHShHBII_Chw737pdVlj6Q">(function(){var id='tsuid_1';document.getElementById(id).onclick = function(){var s = document.createElement('script');s.src = this.getAttribute('data-script-url');(document.getElementById('xjsc')||document.body).appendChild(s);};})();</script></div></div><br style="line-height:0"><span class="ds"><span class="lsbb"><input class="lsb" value="Tìm trên Google" name="btnG" type="submit"></span></span><span class="ds"><span class="lsbb"><input class="lsb" id="tsuid_2" value="Xem trang đầu tiên tìm được" name="btnI" type="submit"><script nonce="zHShHBII_Chw737pdVlj6Q">(function(){var id='tsuid_2';document.getElementById(id).onclick = function(){if (this.form.q.value){this.checked = 1;if (this.form.iflsig)this.form.iflsig.disabled = false;}
|
|
||||||
else top.location='/doodles/';};})();</script><input value="AOEireoAAAAAZDfs5TmWBqHzA-IR1T30Oi85AUDoQoip" name="iflsig" type="hidden"></span></span></td><td class="fl sblc" align="left" nowrap="" width="25%"><a href="/advanced_search?hl=vi&authuser=0">Tìm kiếm nâng cao</a></td></tr></table><input id="gbv" name="gbv" type="hidden" value="1"><script nonce="zHShHBII_Chw737pdVlj6Q">(function(){var a,b="1";if(document&&document.getElementById)if("undefined"!=typeof XMLHttpRequest)b="2";else if("undefined"!=typeof ActiveXObject){var c,d,e=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"];for(c=0;d=e[c++];)try{new ActiveXObject(d),b="2"}catch(h){}}a=b;if("2"==a&&-1==location.search.indexOf("&gbv=2")){var f=google.gbvu,g=document.getElementById("gbv");g&&(g.value=a);f&&window.setTimeout(function(){location.href=f},0)};}).call(this);</script></form><div id="gac_scont"></div><div style="font-size:83%;min-height:3.5em"><br><div id="gws-output-pages-elements-homepage_additional_languages__als"><style>#gws-output-pages-elements-homepage_additional_languages__als{font-size:small;margin-bottom:24px}#SIvCob{color:#3c4043;display:inline-block;line-height:28px;}#SIvCob a{padding:0 3px;}.H6sW5{display:inline-block;margin:0 2px;white-space:nowrap}.z4hgWe{display:inline-block;margin:0 2px}</style><div id="SIvCob">Google có các thứ tiếng: <a href="http://www.google.com/setprefs?sig=0_LiRsKCij61938RPrg0HatfNL9R8%3D&hl=en&source=homepage&sa=X&ved=0ahUKEwi245qf2Kb-AhX4JDQIHQuaDg0Q2ZgBCAU">English</a> <a href="http://www.google.com/setprefs?sig=0_LiRsKCij61938RPrg0HatfNL9R8%3D&hl=fr&source=homepage&sa=X&ved=0ahUKEwi245qf2Kb-AhX4JDQIHQuaDg0Q2ZgBCAY">Français</a> <a href="http://www.google.com/setprefs?sig=0_LiRsKCij61938RPrg0HatfNL9R8%3D&hl=zh-TW&source=homepage&sa=X&ved=0ahUKEwi245qf2Kb-AhX4JDQIHQuaDg0Q2ZgBCAc">繁體中文</a> </div></div></div><span id="footer"><div style="font-size:10pt"><div style="margin:19px auto;text-align:center" id="WqQANb"><a href="/intl/vi/ads/">Quảng cáo</a><a href="/services/">Giải pháp Kinh doanh</a><a href="/intl/vi/about.html">Giới thiệu về Google</a><a href="http://www.google.com/setprefdomain?prefdom=VN&prev=http://www.google.com.vn/&sig=K_USzddBar78vXxQUAlYD0s7dc7wA%3D">Google.com.vn</a></div></div><p style="font-size:8pt;color:#70757a">© 2023</p></span></center><script nonce="zHShHBII_Chw737pdVlj6Q">(function(){window.google.cdo={height:757,width:1440};(function(){var a=window.innerWidth,b=window.innerHeight;if(!a||!b){var c=window.document,d="CSS1Compat"==c.compatMode?c.documentElement:c.body;a=d.clientWidth;b=d.clientHeight}a&&b&&(a!=google.cdo.width||b!=google.cdo.height)&&google.log("","","/client_204?&atyp=i&biw="+a+"&bih="+b+"&ei="+google.kEI);}).call(this);})();</script> <script nonce="zHShHBII_Chw737pdVlj6Q">(function(){google.xjs={ck:'xjs.hp.7OK0Zk1e1VY.L.X.O',cs:'ACT90oGoTtEyU0QPoieI0SztcjxmRBMKuQ',excm:[]};})();</script> <script nonce="zHShHBII_Chw737pdVlj6Q">(function(){var u='/xjs/_/js/k\x3dxjs.hp.en.jodjsTdQot0.O/am\x3dAgAAdAIAKACw/d\x3d1/ed\x3d1/rs\x3dACT90oGMuax7_CJvh2mHTlqLp1N805IOLg/m\x3dsb_he,d';var amd=0;
|
|
||||||
var e=this||self,g=function(c){return c};var k;var n=function(c,f){this.g=f===l?c:""};n.prototype.toString=function(){return this.g+""};var l={};
|
|
||||||
function p(){var c=u,f=function(){};google.lx=google.stvsc?f:function(){google.timers&&google.timers.load&&google.tick&&google.tick("load","xjsls");var a=document;var b="SCRIPT";"application/xhtml+xml"===a.contentType&&(b=b.toLowerCase());b=a.createElement(b);b.id="base-js";a=null===c?"null":void 0===c?"undefined":c;if(void 0===k){var d=null;var m=e.trustedTypes;if(m&&m.createPolicy){try{d=m.createPolicy("goog#html",{createHTML:g,createScript:g,createScriptURL:g})}catch(r){e.console&&e.console.error(r.message)}k=
|
|
||||||
d}else k=d}a=(d=k)?d.createScriptURL(a):a;a=new n(a,l);b.src=a instanceof n&&a.constructor===n?a.g:"type_error:TrustedResourceUrl";var h,q;(h=(a=null==(q=(h=(b.ownerDocument&&b.ownerDocument.defaultView||window).document).querySelector)?void 0:q.call(h,"script[nonce]"))?a.nonce||a.getAttribute("nonce")||"":"")&&b.setAttribute("nonce",h);document.body.appendChild(b);google.psa=!0;google.lx=f};google.bx||google.lx()};google.xjsu=u;setTimeout(function(){0<amd?google.caft(function(){return p()},amd):p()},0);})();window._ = window._ || {};window._DumpException = _._DumpException = function(e){throw e;};window._s = window._s || {};_s._DumpException = _._DumpException;window._qs = window._qs || {};_qs._DumpException = _._DumpException;function _F_installCss(c){}
|
|
||||||
(function(){google.jl={blt:'none',chnk:0,dw:false,dwu:true,emtn:0,end:0,ico:false,ikb:0,ine:false,injs:'none',injt:0,injth:0,injv2:false,lls:'default',pdt:0,rep:0,snet:true,strt:0,ubm:false,uwp:true};})();(function(){var pmc='{\x22d\x22:{},\x22sb_he\x22:{\x22agen\x22:true,\x22cgen\x22:true,\x22client\x22:\x22heirloom-hp\x22,\x22dh\x22:true,\x22ds\x22:\x22\x22,\x22fl\x22:true,\x22host\x22:\x22google.com\x22,\x22jsonp\x22:true,\x22msgs\x22:{\x22cibl\x22:\x22Xóa tìm kiếm\x22,\x22dym\x22:\x22Có phải bạn muốn tìm:\x22,\x22lcky\x22:\x22Xem trang đầu tiên tìm được\x22,\x22lml\x22:\x22Tìm hiểu thêm\x22,\x22psrc\x22:\x22Đã xóa tìm kiếm này khỏi \\u003Ca href\x3d\\\x22/history\\\x22\\u003ELịch sử Web\\u003C/a\\u003E của bạn\x22,\x22psrl\x22:\x22Xóa\x22,\x22sbit\x22:\x22Tìm kiếm bằng hình ảnh\x22,\x22srch\x22:\x22Tìm trên Google\x22},\x22ovr\x22:{},\x22pq\x22:\x22\x22,\x22rfs\x22:[],\x22sbas\x22:\x220 3px 8px 0 rgba(0,0,0,0.2),0 0 0 1px rgba(0,0,0,0.08)\x22,\x22stok\x22:\x22eeOJZ_zWwu1haY9vT9tVq7xv54E\x22}}';google.pmc=JSON.parse(pmc);})();</script> </body></html>
|
|
@ -1,84 +0,0 @@
|
|||||||
# from sdsvkie.utils.io_file import read_json
|
|
||||||
import json
|
|
||||||
import Levenshtein
|
|
||||||
from pathlib import Path
|
|
||||||
import shutil
|
|
||||||
import re
|
|
||||||
from unidecode import unidecode
|
|
||||||
|
|
||||||
# from sdsvkie.utils.io_file import read_json
|
|
||||||
|
|
||||||
|
|
||||||
def normalize(text):
|
|
||||||
text = text.lower()
|
|
||||||
text = unidecode(text)
|
|
||||||
text = re.sub(r'[^a-zA-Z0-9\s]+', '', text)
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def is_match(src, str_new, thr=0.7):
|
|
||||||
src = normalize(src)
|
|
||||||
str_new = normalize(str_new)
|
|
||||||
distance = Levenshtein.ratio(src, str_new)
|
|
||||||
if distance > thr:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_store_name(gt_store, store_list):
|
|
||||||
for store in store_list:
|
|
||||||
if is_match(store, gt_store, thr=0.6):
|
|
||||||
return store.lower()
|
|
||||||
|
|
||||||
if len(gt_store) == 0:
|
|
||||||
return "other_non_title"
|
|
||||||
else:
|
|
||||||
return "other_have_title_{}".format(gt_store)
|
|
||||||
|
|
||||||
|
|
||||||
def read_json(json_path):
|
|
||||||
with open(json_path, "r", encoding="utf8") as f:
|
|
||||||
data = json.load(f)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
json_path = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_ss_receipt.json"
|
|
||||||
pred_data = read_json(json_path)
|
|
||||||
|
|
||||||
store_names = [normalize(item['Store_name_value']) for k, item in pred_data.items()]
|
|
||||||
# store_names = list(set(store_names))
|
|
||||||
from collections import Counter
|
|
||||||
my_counter = Counter(store_names)
|
|
||||||
list_tuples = my_counter.most_common()
|
|
||||||
print(list_tuples)
|
|
||||||
stores = [x[0] for x in list_tuples]
|
|
||||||
print(stores)
|
|
||||||
|
|
||||||
|
|
||||||
store_names = stores[1:]
|
|
||||||
|
|
||||||
img_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted/All"
|
|
||||||
out_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Done"
|
|
||||||
out_dir = Path(out_dir)
|
|
||||||
for img_name, item in pred_data.items():
|
|
||||||
store_name = item['Store_name_value']
|
|
||||||
store_category = get_store_name(store_name, store_list=store_names)
|
|
||||||
store_category = store_category.replace(" ", "_")
|
|
||||||
print(store_category)
|
|
||||||
out_dir_by_store = out_dir / store_category
|
|
||||||
if not out_dir_by_store.exists():
|
|
||||||
out_dir_by_store.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
img_full_name = Path(img_name).with_suffix(".jpg")
|
|
||||||
img_full_path = Path(img_dir) / img_full_name
|
|
||||||
|
|
||||||
txt_full_path = img_full_path.with_suffix(".txt")
|
|
||||||
if not img_full_path.exists():
|
|
||||||
print(str(img_full_path))
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
shutil.copy(str(img_full_path), out_dir_by_store)
|
|
||||||
shutil.copy(str(txt_full_path), out_dir_by_store)
|
|
Before Width: | Height: | Size: 490 KiB |
@ -1 +0,0 @@
|
|||||||
rsync -r --exclude='workdirs/' --exclude='notebooks/' --exclude='weights/' --exclude='wandb/' --exclude='microsoft/' /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie user@107.120.133.42:/mnt/data/kie
|
|
@ -1,194 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 1,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import os \n",
|
|
||||||
"import glob \n",
|
|
||||||
"from tqdm import tqdm \n",
|
|
||||||
"import cv2 \n",
|
|
||||||
"import shutil\n",
|
|
||||||
"from pathlib import Path"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"DATA_DIR = \"/mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/raw/IMGS\"\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def copy_only_first_page(data_dir, out_dir, skip_types=['Receipt_taxi','Receipt_food_Cam', 'Receipt_food_Scan']):\n",
|
|
||||||
" paths = sorted(glob.glob(data_dir + \"/*/*\"))\n",
|
|
||||||
" print(\"Total paths: \", len(paths))\n",
|
|
||||||
" out_dir = Path(out_dir)\n",
|
|
||||||
" for path in paths:\n",
|
|
||||||
" type_doc = Path(path).parent.name\n",
|
|
||||||
" out_dir_full = out_dir / type_doc\n",
|
|
||||||
" if not out_dir_full.exists():\n",
|
|
||||||
" out_dir_full.mkdir(parents=True)\n",
|
|
||||||
" if type_doc in skip_types:\n",
|
|
||||||
" shutil.copy(path, str(out_dir_full))\n",
|
|
||||||
" else:\n",
|
|
||||||
" if \"_1.jpg\" in path:\n",
|
|
||||||
" shutil.copy(path, out_dir_full)\n",
|
|
||||||
" prefix_name = \"_\".join(path.split(\"_\")[:-1]) + \"_1.jpg\"\n",
|
|
||||||
" print(prefix_name)\n",
|
|
||||||
" if Path(prefix_name).exists():\n",
|
|
||||||
" continue\n",
|
|
||||||
" else:\n",
|
|
||||||
" shutil.copy(path, out_dir_full)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"classes = [\n",
|
|
||||||
" # id invoice\n",
|
|
||||||
" 'No_key', # số hóa đơn\n",
|
|
||||||
" 'No_value', \n",
|
|
||||||
" 'Form_key', # mẫu số hóa đơn\n",
|
|
||||||
" 'Form_value', \n",
|
|
||||||
" 'Serial_key', # số kí hiệu hoá đơn\n",
|
|
||||||
" 'Serial_value', \n",
|
|
||||||
" 'Date_value', \n",
|
|
||||||
"\n",
|
|
||||||
" # seller info\n",
|
|
||||||
" 'Seller_company_name_key', \n",
|
|
||||||
" 'Seller_company_name_value', \n",
|
|
||||||
" 'Seller_tax_code_key', \n",
|
|
||||||
" 'Seller_tax_code_value', \n",
|
|
||||||
" 'Seller_address_value',\n",
|
|
||||||
" 'Seller_address_key', \n",
|
|
||||||
" 'Seller_tel_key',\n",
|
|
||||||
" 'Seller_tel_value', \n",
|
|
||||||
" \n",
|
|
||||||
" # buyer info\n",
|
|
||||||
" 'Buyer_personal_name_key',\n",
|
|
||||||
" 'Buyer_personal_name_value', \n",
|
|
||||||
" 'Buyer_company_name_key', \n",
|
|
||||||
" 'Buyer_company_name_value', \n",
|
|
||||||
" 'Buyer_tax_code_key', \n",
|
|
||||||
" 'Buyer_tax_code_value', \n",
|
|
||||||
" 'Buyer_address_key', \n",
|
|
||||||
" 'Buyer_address_value', \n",
|
|
||||||
" 'Buyer_address_key',\n",
|
|
||||||
" 'Buyer_address_value',\n",
|
|
||||||
"\n",
|
|
||||||
" # money info\n",
|
|
||||||
" 'Tax_amount_key', \n",
|
|
||||||
" 'Tax_amount_value', \n",
|
|
||||||
" 'Total_key', \n",
|
|
||||||
" 'Total_value', \n",
|
|
||||||
" 'Total_in_words_key', \n",
|
|
||||||
" 'Total_in_words_value',\n",
|
|
||||||
" \n",
|
|
||||||
" 'Other', \n",
|
|
||||||
"]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"classes = [x.lower() for x in classes]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"['no_key',\n",
|
|
||||||
" 'no_value',\n",
|
|
||||||
" 'form_key',\n",
|
|
||||||
" 'form_value',\n",
|
|
||||||
" 'serial_key',\n",
|
|
||||||
" 'serial_value',\n",
|
|
||||||
" 'date_value',\n",
|
|
||||||
" 'seller_company_name_key',\n",
|
|
||||||
" 'seller_company_name_value',\n",
|
|
||||||
" 'seller_tax_code_key',\n",
|
|
||||||
" 'seller_tax_code_value',\n",
|
|
||||||
" 'seller_address_value',\n",
|
|
||||||
" 'seller_address_key',\n",
|
|
||||||
" 'seller_tel_key',\n",
|
|
||||||
" 'seller_tel_value',\n",
|
|
||||||
" 'buyer_personal_name_key',\n",
|
|
||||||
" 'buyer_personal_name_value',\n",
|
|
||||||
" 'buyer_company_name_key',\n",
|
|
||||||
" 'buyer_company_name_value',\n",
|
|
||||||
" 'buyer_tax_code_key',\n",
|
|
||||||
" 'buyer_tax_code_value',\n",
|
|
||||||
" 'buyer_address_key',\n",
|
|
||||||
" 'buyer_address_value',\n",
|
|
||||||
" 'buyer_address_key',\n",
|
|
||||||
" 'buyer_address_value',\n",
|
|
||||||
" 'tax_amount_key',\n",
|
|
||||||
" 'tax_amount_value',\n",
|
|
||||||
" 'total_key',\n",
|
|
||||||
" 'total_value',\n",
|
|
||||||
" 'total_in_words_key',\n",
|
|
||||||
" 'total_in_words_value',\n",
|
|
||||||
" 'other']"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"classes"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "py38_hoanglv",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.8.16"
|
|
||||||
},
|
|
||||||
"orig_nbformat": 4
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
protobuf>=3.19.6,<4
|
|
||||||
opencv-python>=4.4.0
|
|
||||||
torch>=1.4
|
|
||||||
torchvision
|
|
||||||
transformers>=4.25.1
|
|
||||||
datasets>=2.5.2
|
|
||||||
Pillow==9.5.0
|
|
||||||
wandb
|
|
||||||
easydict==1.10
|
|
||||||
terminaltables==3.1.10
|
|
||||||
tqdm
|
|
||||||
rapidfuzz==2.13.7
|
|
||||||
PyMuPDF==1.20.2
|
|
||||||
sentencepiece
|
|
||||||
underthesea
|
|
@ -1,49 +0,0 @@
|
|||||||
%PDF-1.3
|
|
||||||
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
|
||||||
1 0 obj
|
|
||||||
<<
|
|
||||||
/F1 2 0 R
|
|
||||||
>>
|
|
||||||
endobj
|
|
||||||
2 0 obj
|
|
||||||
<<
|
|
||||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
|
||||||
>>
|
|
||||||
endobj
|
|
||||||
3 0 obj
|
|
||||||
<<
|
|
||||||
/PageMode /UseNone /Pages 5 0 R /Type /Catalog
|
|
||||||
>>
|
|
||||||
endobj
|
|
||||||
4 0 obj
|
|
||||||
<<
|
|
||||||
/Author (anonymous) /CreationDate (D:20230522134603-07'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20230522134603-07'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
|
||||||
/Subject (unspecified) /Title (untitled) /Trapped /False
|
|
||||||
>>
|
|
||||||
endobj
|
|
||||||
5 0 obj
|
|
||||||
<<
|
|
||||||
/Count 0 /Kids [ ] /Type /Pages
|
|
||||||
>>
|
|
||||||
endobj
|
|
||||||
xref
|
|
||||||
0 6
|
|
||||||
0000000000 65535 f
|
|
||||||
0000000073 00000 n
|
|
||||||
0000000104 00000 n
|
|
||||||
0000000211 00000 n
|
|
||||||
0000000279 00000 n
|
|
||||||
0000000575 00000 n
|
|
||||||
trailer
|
|
||||||
<<
|
|
||||||
/ID
|
|
||||||
[<4d2762f6f45f96a78f66af9b0251b167><4d2762f6f45f96a78f66af9b0251b167>]
|
|
||||||
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
|
||||||
|
|
||||||
/Info 4 0 R
|
|
||||||
/Root 3 0 R
|
|
||||||
/Size 6
|
|
||||||
>>
|
|
||||||
startxref
|
|
||||||
629
|
|
||||||
%%EOF
|
|
@ -1,10 +0,0 @@
|
|||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
import shutil
|
|
||||||
data_dir = "/mnt/hdd2T/AICR/Projects/2023/FI_Invoices/Data"
|
|
||||||
|
|
||||||
data_dir = Path(data_dir)
|
|
||||||
|
|
||||||
for path in data_dir.glob("*/*.pdf"):
|
|
||||||
if path.with_suffix(".xml").exists():
|
|
||||||
shutil.copy(str(path), "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/multi_page_vat/batch_2")
|
|
@ -1,117 +0,0 @@
|
|||||||
|
|
||||||
from pathlib import Path
|
|
||||||
import shutil
|
|
||||||
import json
|
|
||||||
|
|
||||||
def write_txt(txt, data, mode="w"):
|
|
||||||
with open(txt, mode, encoding="utf8") as f:
|
|
||||||
for line in data:
|
|
||||||
f.write(line + "\n")
|
|
||||||
|
|
||||||
|
|
||||||
def read_txt(txt):
|
|
||||||
with open(txt, "r", encoding="utf8") as f:
|
|
||||||
data = [line.strip() for line in f]
|
|
||||||
return data
|
|
||||||
|
|
||||||
def get_no(items):
|
|
||||||
no = "xxxx"
|
|
||||||
for item in items:
|
|
||||||
if "No_value" in item:
|
|
||||||
tmp = item.split("\t")
|
|
||||||
no = tmp[-2]
|
|
||||||
|
|
||||||
return no
|
|
||||||
|
|
||||||
def write_json(json_path, data):
|
|
||||||
with open(json_path, "w", encoding="utf8") as f:
|
|
||||||
json.dump(data, f, ensure_ascii=False, sort_keys=True)
|
|
||||||
|
|
||||||
|
|
||||||
def read_json(json_path):
|
|
||||||
with open(json_path, "r", encoding="utf8") as f:
|
|
||||||
data = json.load(f)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def check(txt_dir):
|
|
||||||
log_dict = {}
|
|
||||||
txt_dir = Path(txt_dir)
|
|
||||||
txt_paths = txt_dir.rglob("*.txt")
|
|
||||||
for txt_path in txt_paths:
|
|
||||||
items = read_txt(str(txt_path))
|
|
||||||
no_doc = get_no(items)
|
|
||||||
if no_doc not in log_dict:
|
|
||||||
log_dict[no_doc] = [str(txt_path.with_suffix(".jpg"))]
|
|
||||||
else:
|
|
||||||
log_dict[no_doc].append(str(txt_path.with_suffix(".jpg")))
|
|
||||||
|
|
||||||
not_dups = []
|
|
||||||
for no, paths in log_dict.items():
|
|
||||||
if len(paths) == 1:
|
|
||||||
not_dups.append(no)
|
|
||||||
# if "xxxx" in log_dict.keys():
|
|
||||||
# log_dict.pop("xxxx")
|
|
||||||
for _ in not_dups:
|
|
||||||
log_dict.pop(_)
|
|
||||||
|
|
||||||
print(log_dict.keys())
|
|
||||||
return log_dict
|
|
||||||
|
|
||||||
# print(check("/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/train/SS_Invoice"))
|
|
||||||
|
|
||||||
|
|
||||||
def get_leak_test(data_dir):
|
|
||||||
test_keys = []
|
|
||||||
data_dir = Path(data_dir)
|
|
||||||
test_paths = data_dir.rglob("test_*")
|
|
||||||
# print(list(test_paths))
|
|
||||||
for path in test_paths:
|
|
||||||
img_name = path.stem
|
|
||||||
img_name = img_name.replace("test_","")
|
|
||||||
test_keys.append(img_name)
|
|
||||||
|
|
||||||
|
|
||||||
# write_txt("leak.txt", test_keys)
|
|
||||||
return test_keys
|
|
||||||
|
|
||||||
|
|
||||||
def create_new_test(ori_dir, out_dir, test_keys):
|
|
||||||
ori_dir = Path(ori_dir)
|
|
||||||
out_dir = Path(out_dir)
|
|
||||||
if not out_dir.exists():
|
|
||||||
out_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
img_paths = ori_dir.rglob("*.jpg")
|
|
||||||
for img_path in img_paths:
|
|
||||||
img_key = img_path.stem
|
|
||||||
if img_key in test_keys:
|
|
||||||
continue
|
|
||||||
txt_path = img_path.with_suffix(".txt")
|
|
||||||
shutil.copy(str(img_path), str(out_dir))
|
|
||||||
shutil.copy(str(txt_path), str(out_dir))
|
|
||||||
|
|
||||||
def create_new_e2e_test(ori_json, out_json, test_keys):
|
|
||||||
ori_data = read_json(ori_json)
|
|
||||||
out_dict = {}
|
|
||||||
for k, v in ori_data.items():
|
|
||||||
if k in test_keys:
|
|
||||||
continue
|
|
||||||
out_dict[k] = v
|
|
||||||
|
|
||||||
write_json(out_json, out_dict)
|
|
||||||
|
|
||||||
|
|
||||||
test_keys = get_leak_test("/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/EXCESS")
|
|
||||||
# create_new_test(
|
|
||||||
# ori_dir="/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss",
|
|
||||||
# out_dir="/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss_rm_leak",
|
|
||||||
# test_keys=test_keys
|
|
||||||
# )
|
|
||||||
|
|
||||||
create_new_e2e_test(
|
|
||||||
ori_json="/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss_e2e.json",
|
|
||||||
out_json="/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss_e2e_rm_leak.json",
|
|
||||||
test_keys=test_keys
|
|
||||||
)
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
import argparse
|
|
||||||
from pathlib import Path
|
|
||||||
from tqdm import tqdm
|
|
||||||
from sdsvkie.utils.io_file import read_json, write_json
|
|
||||||
|
|
||||||
|
|
||||||
def clean_json(in_json, out_json, pdf_dir):
|
|
||||||
data_src = read_json(in_json)
|
|
||||||
|
|
||||||
pdf_dir = Path(pdf_dir)
|
|
||||||
pdf_paths = pdf_dir.glob("*.pdf")
|
|
||||||
pdf_keys = set([pdf_path.stem for pdf_path in pdf_paths])
|
|
||||||
|
|
||||||
data_tgt = {}
|
|
||||||
for src_pdf_key in data_src.keys():
|
|
||||||
if src_pdf_key in pdf_keys:
|
|
||||||
data_tgt[src_pdf_key] = data_src[src_pdf_key]
|
|
||||||
|
|
||||||
write_json(out_json, data_tgt, sort_keys=False)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(prog="Rename labels")
|
|
||||||
parser.add_argument("--input", type=str, required=True, help="dataset directory")
|
|
||||||
parser.add_argument("--out", type=str, required=False, help="output")
|
|
||||||
parser.add_argument("--dir", type=str, required=True, help="document type: receipt / invoice")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
clean_json(
|
|
||||||
in_json=args.input,
|
|
||||||
out_json=args.out,
|
|
||||||
pdf_dir=args.dir
|
|
||||||
)
|
|
@ -1,49 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
import json
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
def read_json(json_path):
|
|
||||||
with open(json_path, 'r') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
return data
|
|
||||||
|
|
||||||
def write_json(json_path, data):
|
|
||||||
with open(json_path, 'w') as f:
|
|
||||||
json.dump(data, f, ensure_ascii=False)
|
|
||||||
|
|
||||||
|
|
||||||
def clean_json(json_in, json_out, valid_names):
|
|
||||||
out_data = {}
|
|
||||||
data = read_json(json_in)
|
|
||||||
for name_key, items in data.items():
|
|
||||||
if name_key in valid_names:
|
|
||||||
out_data[name_key] = items
|
|
||||||
|
|
||||||
write_json(json_out, out_data)
|
|
||||||
|
|
||||||
# DIRNAMES = ['SL_HCM', 'SL_HN_batch_1', 'SL_HN_batch_2', 'Invoices_SAVINA']
|
|
||||||
# ROOT_DIR = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/PDF/multi_page"
|
|
||||||
|
|
||||||
DIRNAMES = ['test_sbt_v2']
|
|
||||||
ROOT_DIR = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed"
|
|
||||||
for dirname in DIRNAMES:
|
|
||||||
json_path = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test_end2end/sbt_validation_e2e.json"
|
|
||||||
json_out_path = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test_end2end/sbt_validation_e2e_v2.json"
|
|
||||||
valid_names = [p.stem for p in (Path(ROOT_DIR) / dirname).glob("*")]
|
|
||||||
print(valid_names)
|
|
||||||
clean_json(json_path, json_out_path, valid_names)
|
|
||||||
|
|
||||||
|
|
||||||
# def combine_json(json_paths, json_out):
|
|
||||||
# datas = [read_json(json_path) for json_path in json_paths]
|
|
||||||
# out_data = {}
|
|
||||||
# for data in datas:
|
|
||||||
# out_data.update(data)
|
|
||||||
# write_json(json_out, out_data)
|
|
||||||
|
|
||||||
|
|
||||||
# json_paths = [Path(ROOT_DIR) / (dirname + "_out.json") for dirname in DIRNAMES]
|
|
||||||
# json_out = ROOT_DIR + "/test_e2e_multi_pages.json"
|
|
||||||
# combine_json(json_paths, json_out)
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
import os
|
|
||||||
import shutil
|
|
||||||
import glob
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
src_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/train/SL_HCM_batch_2_multi_pages"
|
|
||||||
tgt_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/intermediate/key_information_extraction/"
|
|
||||||
num_files = 100
|
|
||||||
|
|
||||||
files = glob.glob(os.path.join(src_dir, "*.jpg"))
|
|
||||||
count = 0
|
|
||||||
for file in files:
|
|
||||||
src_path = os.path.join(src_dir, file)
|
|
||||||
tgt_path = os.path.join(tgt_dir, file)
|
|
||||||
if os.path.isfile(src_path):
|
|
||||||
shutil.copy(src_path, tgt_path)
|
|
||||||
count += 1
|
|
||||||
if count == num_files:
|
|
||||||
break
|
|
||||||
|
|
||||||
print(f"Copied {count} files from {src_dir} to {tgt_dir}")
|
|
@ -1,25 +0,0 @@
|
|||||||
import os
|
|
||||||
import shutil
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
SRC_DIR = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/train/sbt/batch_1"
|
|
||||||
TEST_DIR = "/mnt/ssd1T/tuanlv/06.KVUCombineStage/datasets/invoices-receipts/SS_invoices/SBT/validation_data/images"
|
|
||||||
OUT_DIR = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test_sbt"
|
|
||||||
|
|
||||||
# Get a list of all the files in the test directory
|
|
||||||
test_files = [Path(f).name for f in os.listdir(TEST_DIR) if ".txt" not in f]
|
|
||||||
|
|
||||||
# Create the output directory if it doesn't exist
|
|
||||||
os.makedirs(OUT_DIR, exist_ok=True)
|
|
||||||
|
|
||||||
# Move the matching files from the source directory to the output directory
|
|
||||||
for filename in os.listdir(SRC_DIR):
|
|
||||||
if Path(filename).name in test_files:
|
|
||||||
src_path = os.path.join(SRC_DIR, filename)
|
|
||||||
# out_path = os.path.join(OUT_DIR, filename)
|
|
||||||
shutil.move(src_path, OUT_DIR)
|
|
||||||
|
|
||||||
#move .txt
|
|
||||||
src_txt_path = Path(os.path.join(SRC_DIR, filename)).with_suffix(".txt")
|
|
||||||
shutil.move(str(src_txt_path), OUT_DIR)
|
|
@ -1,314 +0,0 @@
|
|||||||
import shutil
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
from datetime import datetime
|
|
||||||
# from sdsvkie.utils.io_file import read_json, write_json
|
|
||||||
import json
|
|
||||||
|
|
||||||
import csv
|
|
||||||
import ast
|
|
||||||
def get_xml_from_csv(csv_file):
|
|
||||||
data = {}
|
|
||||||
with open(csv_file, 'r') as file:
|
|
||||||
csv_reader = csv.DictReader(file)
|
|
||||||
for row in csv_reader:
|
|
||||||
# print(row)
|
|
||||||
pdf_path = row['file_path']
|
|
||||||
pdf_key = Path(pdf_path).stem
|
|
||||||
xml_paths = ast.literal_eval(row['xml_path'])
|
|
||||||
data[pdf_key] = xml_paths
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def get_xml_from_dirs(dir_path, pdf_keys):
|
|
||||||
dir_path = Path(dir_path)
|
|
||||||
xml_paths = dir_path.rglob("*.xml")
|
|
||||||
xml_paths = [str(path) for path in xml_paths]
|
|
||||||
xml_infos = {}
|
|
||||||
|
|
||||||
for pdf_key in pdf_keys:
|
|
||||||
xml_infos[pdf_key] = xml_paths
|
|
||||||
return xml_infos
|
|
||||||
|
|
||||||
|
|
||||||
def write_json(json_path, data, sort_keys=True):
|
|
||||||
with open(json_path, "w", encoding="utf8") as f:
|
|
||||||
json.dump(data, f, ensure_ascii=False, sort_keys=sort_keys)
|
|
||||||
|
|
||||||
|
|
||||||
def read_json(json_path):
|
|
||||||
with open(json_path, "r", encoding="utf8") as f:
|
|
||||||
data = json.load(f)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
import tqdm
|
|
||||||
import logging
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
def convert_date(date_str: str, ori_pattern: str = '%Y-%m-%d', tgt_pattern: str = '%d/%m/%Y'):
|
|
||||||
date_obj = datetime.strptime(date_str, ori_pattern)
|
|
||||||
|
|
||||||
# convert back to string in DD-MM-YY format
|
|
||||||
new_date_str = date_obj.strftime(tgt_pattern)
|
|
||||||
return new_date_str
|
|
||||||
|
|
||||||
def extract(xml_in, field_mapping):
|
|
||||||
|
|
||||||
|
|
||||||
with open(xml_in, "r") as f:
|
|
||||||
xml_string = f.read()
|
|
||||||
# parse the XML string
|
|
||||||
root = ET.fromstring(xml_string)
|
|
||||||
|
|
||||||
# extract the SHDon and NLap elements
|
|
||||||
output = {}
|
|
||||||
for key in field_mapping:
|
|
||||||
pattern = f".//{field_mapping[key]}"
|
|
||||||
value = root.find(pattern)
|
|
||||||
value = "" if value is None else value.text
|
|
||||||
if key == "date_value" and value != "":
|
|
||||||
value = convert_date(value)
|
|
||||||
|
|
||||||
if key in ["tax_amount_value", "total_value"] and value != "":
|
|
||||||
value = str(int(float(value)))
|
|
||||||
|
|
||||||
|
|
||||||
output[key] = value
|
|
||||||
return output
|
|
||||||
|
|
||||||
field_mapping = {
|
|
||||||
"no_value": "SHDon",
|
|
||||||
"form_value": "KHMSHDon",
|
|
||||||
"serial_value": "XXXXXXX",
|
|
||||||
"date_value": "NLap", # 2023-06-05 -> YY-MM-DD
|
|
||||||
"seller_company_name_value": "NBan/Ten",
|
|
||||||
"seller_address_value": "NBan/DChi",
|
|
||||||
"seller_tel_value": "XXXXXXXXX",
|
|
||||||
"seller_tax_code_value": "NBan/MST",
|
|
||||||
"buyer_personal_name_value": "NMua/HVTNMHang",
|
|
||||||
"buyer_company_name_value": "NMua/Ten",
|
|
||||||
"buyer_address_value": "NMua/DChi",
|
|
||||||
"buyer_tax_code_value": "NMua/MST",
|
|
||||||
"buyer_tel_value": "NMua/SDT",
|
|
||||||
"tax_amount_value": "TThue",
|
|
||||||
"total_value": "TgTTTBSo",
|
|
||||||
"total_in_words_value": "TgTTTBChu"
|
|
||||||
}
|
|
||||||
|
|
||||||
## fields need care: serial_value, seller_tel_value, buyer_tel_value
|
|
||||||
|
|
||||||
def get_xml_list_info(xml_dir):
|
|
||||||
xml_dir = Path(xml_dir)
|
|
||||||
xml_files = xml_dir.glob("*/*.xml")
|
|
||||||
xml_info = {}
|
|
||||||
for xml_file in xml_files:
|
|
||||||
pdf_key = xml_file.stem
|
|
||||||
xml_info[pdf_key] = str(xml_file)
|
|
||||||
return xml_info
|
|
||||||
|
|
||||||
def process(json_in, json_out, xml_dir):
|
|
||||||
assert Path(json_in).exists() == True
|
|
||||||
assert Path(xml_dir).exists() == True
|
|
||||||
data_in = read_json(json_in)
|
|
||||||
data_out = {}
|
|
||||||
if data_in is None or not data_in:
|
|
||||||
logger.error("empty file")
|
|
||||||
return
|
|
||||||
|
|
||||||
xml_info = get_xml_list_info(xml_dir)
|
|
||||||
for pdf_key in tqdm.tqdm(data_in.keys()):
|
|
||||||
|
|
||||||
xml_path = xml_info[pdf_key] if pdf_key in xml_info else None
|
|
||||||
if xml_path is None:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
output = extract(xml_path, field_mapping)
|
|
||||||
|
|
||||||
data_out[pdf_key] = output
|
|
||||||
|
|
||||||
write_json(json_out, data_out, sort_keys=False)
|
|
||||||
|
|
||||||
|
|
||||||
def get_xml_list_info_v2(xml_dir):
|
|
||||||
xml_dir = Path(xml_dir)
|
|
||||||
xml_files = xml_dir.glob("*/*.xml")
|
|
||||||
|
|
||||||
xml_info = {}
|
|
||||||
for xml_file in xml_files:
|
|
||||||
pdf_key = xml_file.stem
|
|
||||||
|
|
||||||
if pdf_key in xml_info:
|
|
||||||
xml_info[pdf_key].append(str(xml_file))
|
|
||||||
else:
|
|
||||||
xml_info[pdf_key] = [str(xml_file)]
|
|
||||||
|
|
||||||
return xml_info
|
|
||||||
|
|
||||||
def extract_v2(xml_paths, preds, field_mapping, pdf_key=None):
|
|
||||||
|
|
||||||
|
|
||||||
xml_path = None
|
|
||||||
if len(xml_paths) == 1:
|
|
||||||
xml_path = xml_paths[0]
|
|
||||||
else:
|
|
||||||
# find best xml
|
|
||||||
for xml_in in xml_paths:
|
|
||||||
try:
|
|
||||||
with open(xml_in, "r", encoding='utf8') as f:
|
|
||||||
xml_string = f.read()
|
|
||||||
root = ET.fromstring(xml_string, parser = ET.XMLParser(encoding = 'iso-8859-5'))
|
|
||||||
except Exception as err:
|
|
||||||
print("Error exception (check) ", err, xml_in)
|
|
||||||
continue
|
|
||||||
|
|
||||||
key_checks = ["no_value"]
|
|
||||||
is_exists_xml = False
|
|
||||||
for key_check in key_checks:
|
|
||||||
pattern = f".//{field_mapping[key_check]}"
|
|
||||||
value = root.find(pattern)
|
|
||||||
value = "" if value is None else value.text
|
|
||||||
|
|
||||||
if value == preds[key_check]:
|
|
||||||
is_exists_xml = True
|
|
||||||
if is_exists_xml:
|
|
||||||
xml_path = xml_in
|
|
||||||
if xml_path is None:
|
|
||||||
print("Not found best xml for ",pdf_key, xml_paths)
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
#
|
|
||||||
try:
|
|
||||||
with open(xml_path, "r") as f:
|
|
||||||
xml_string = f.read()
|
|
||||||
# parse the XML string
|
|
||||||
root = ET.fromstring(xml_string)
|
|
||||||
except Exception as err:
|
|
||||||
print("Error exception: ", err, xml_path)
|
|
||||||
return None, None
|
|
||||||
# extract the SHDon and NLap elements
|
|
||||||
output = {}
|
|
||||||
for key in field_mapping:
|
|
||||||
pattern = f".//{field_mapping[key]}"
|
|
||||||
value = root.find(pattern)
|
|
||||||
value = "" if value is None else value.text
|
|
||||||
if key == "date_value" and value != "":
|
|
||||||
value = convert_date(value)
|
|
||||||
if key in ["tax_amount_value", "total_value"] and value != "":
|
|
||||||
value = str(int(float(value)))
|
|
||||||
|
|
||||||
output[key] = value
|
|
||||||
|
|
||||||
return output, xml_path
|
|
||||||
|
|
||||||
def process_v2(json_in, json_out, csv_file, xml_dir, xml_out_dir, pdf_xml_json):
|
|
||||||
assert Path(json_in).exists() == True
|
|
||||||
assert Path(xml_dir).exists() == True
|
|
||||||
# make dir
|
|
||||||
if not Path(xml_out_dir).exists():
|
|
||||||
Path(xml_out_dir).mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
data_in = read_json(json_in)
|
|
||||||
data_out = {}
|
|
||||||
if data_in is None or not data_in:
|
|
||||||
logger.error("empty file")
|
|
||||||
return
|
|
||||||
|
|
||||||
# xml_info = get_xml_list_info_v2(xml_dir)
|
|
||||||
# xml_info = get_xml_from_csv(csv_file=csv_file)
|
|
||||||
xml_info = get_xml_from_dirs(dir_path=csv_file, pdf_keys=list(data_in.keys()))
|
|
||||||
print("Num xml: ", len(xml_info))
|
|
||||||
succes = 0
|
|
||||||
pdf_xml_info = {}
|
|
||||||
set_xml_paths = set()
|
|
||||||
for pdf_key in tqdm.tqdm(data_in.keys()):
|
|
||||||
|
|
||||||
xml_paths = xml_info[pdf_key] if pdf_key in xml_info else None
|
|
||||||
# print(xml_paths)
|
|
||||||
preds = data_in[pdf_key]
|
|
||||||
if xml_paths is None or len(xml_paths) == 0:
|
|
||||||
print("Not exist xml because xml_paths is None or len xml_paths = 0", pdf_key)
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
output, xml_path = extract_v2(xml_paths, preds, field_mapping, pdf_key=pdf_key)
|
|
||||||
|
|
||||||
if output is not None:
|
|
||||||
pdf_xml_info[pdf_key] = xml_path
|
|
||||||
shutil.copy(xml_path, xml_out_dir)
|
|
||||||
# if Path(xml_path).stem in set_xml_paths:
|
|
||||||
# print(pdf_key, xml_path)
|
|
||||||
set_xml_paths.add(Path(xml_path).stem)
|
|
||||||
succes += 1
|
|
||||||
data_out[pdf_key] = output
|
|
||||||
print("Succes: ", succes)
|
|
||||||
print(len(set_xml_paths))
|
|
||||||
write_json(pdf_xml_json, pdf_xml_info, sort_keys=False)
|
|
||||||
write_json(json_out, data_out, sort_keys=False)
|
|
||||||
|
|
||||||
|
|
||||||
def combine_xml(json_src, json_refer):
|
|
||||||
data_src = read_json(json_src)
|
|
||||||
data_refer = read_json(json_refer)
|
|
||||||
|
|
||||||
for pdf_key in data_src.keys():
|
|
||||||
for field_key in data_src[pdf_key]:
|
|
||||||
if data_src[pdf_key][field_key] == "":
|
|
||||||
data_src[pdf_key][field_key] = data_refer[pdf_key][field_key]
|
|
||||||
|
|
||||||
write_json(json_src, data=data_src, sort_keys=False)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_data_from_json(in_dir, out_dir, json_path):
|
|
||||||
in_dir = Path(in_dir)
|
|
||||||
out_dir = Path(out_dir)
|
|
||||||
|
|
||||||
if not out_dir.exists():
|
|
||||||
out_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
data = read_json(json_path)
|
|
||||||
|
|
||||||
for pdf_key in data.keys():
|
|
||||||
pdf_path = in_dir / (pdf_key + ".pdf")
|
|
||||||
shutil.copy(str(pdf_path), str(out_dir))
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
|
|
||||||
# json_in = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_multi_page.json"
|
|
||||||
# json_out = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_multi_page_from_xml.json"
|
|
||||||
# xml_dir = "/mnt/hdd2T/AICR/Projects/2023/FI_Invoices/Test"
|
|
||||||
# process(json_in=json_in, json_out=json_out, xml_dir=xml_dir)
|
|
||||||
|
|
||||||
# json_in = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_multi_page_from_xml.json"
|
|
||||||
# json_refer = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_multi_page.json"
|
|
||||||
# json_in = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_one_page_e2e_from_xml.json"
|
|
||||||
# json_refer = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_one_page_e2e.json"
|
|
||||||
|
|
||||||
# combine_xml(json_src=json_in, json_refer=json_refer)
|
|
||||||
|
|
||||||
## One page
|
|
||||||
# json_in = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_one_page_e2e.json"
|
|
||||||
# json_out = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_one_page_e2e_from_xml.json"
|
|
||||||
## Multi page
|
|
||||||
json_in = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/PV2/Invoice_v1_multi_page.json"
|
|
||||||
json_out = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/PV2/Invoice_v1_multi_page_from_xml.json"
|
|
||||||
|
|
||||||
# csv_file = "/mnt/ssd1T/tuanlv/02.KeyValueUnderstanding/inferences/e2e_outputs/FI_June_data.csv"
|
|
||||||
csv_file = "/mnt/hdd2T/AICR/Projects/2023/FI_Invoices/Data"
|
|
||||||
pdf_xml_json = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v1_multi_page_metadata.json"
|
|
||||||
|
|
||||||
xml_dir = "/mnt/hdd2T/AICR/Projects/2023/FI_Invoices/Test"
|
|
||||||
xml_out_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/Invoice_v1_multi_page_xml"
|
|
||||||
|
|
||||||
process_v2(json_in=json_in, json_out=json_out, csv_file=csv_file, xml_dir=xml_dir, xml_out_dir=xml_out_dir, pdf_xml_json=pdf_xml_json)
|
|
||||||
|
|
||||||
# in_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/Invoice_v2_multi_page"
|
|
||||||
# out_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/Invoice_v2_multi_page_clean"
|
|
||||||
# json_path = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_multi_page_from_xml.json"
|
|
||||||
# in_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/Invoice_v2_one_page"
|
|
||||||
# out_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/Invoice_v2_one_page_clean"
|
|
||||||
# json_path = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_one_page_e2e_from_xml.json"
|
|
||||||
|
|
||||||
# create_data_from_json(in_dir, out_dir, json_path)
|
|
@ -1,42 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
json_path = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/multi_page_vat/SL_HCM.json"
|
|
||||||
with open(json_path, 'r', encoding='utf8') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
print(data[list(data.keys())[0]].keys())
|
|
||||||
|
|
||||||
keys = [
|
|
||||||
'serial_value',
|
|
||||||
'no_value',
|
|
||||||
'form_value',
|
|
||||||
'date',
|
|
||||||
|
|
||||||
'seller_company_name_value',
|
|
||||||
'seller_address_value',
|
|
||||||
'seller_mobile_value',
|
|
||||||
'seller_tax_code_value',
|
|
||||||
|
|
||||||
'buyer_name_value',
|
|
||||||
'buyer_company_name_value',
|
|
||||||
'buyer_address_value',
|
|
||||||
'buyer_mobile_value',
|
|
||||||
'buyer_tax_code_value',
|
|
||||||
|
|
||||||
'VAT_amount_value',
|
|
||||||
'total_in_words_value',
|
|
||||||
'total_value'
|
|
||||||
]
|
|
||||||
new_data = {}
|
|
||||||
for file_name, items in data.items():
|
|
||||||
|
|
||||||
new_items = {}
|
|
||||||
for k in keys:
|
|
||||||
new_items[k] = items[k]
|
|
||||||
new_data[file_name] = new_items
|
|
||||||
|
|
||||||
|
|
||||||
with open(json_path, 'w', encoding='utf8') as f:
|
|
||||||
json.dump(new_data, f, ensure_ascii=False)
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
|||||||
import os
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
folder1 = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/PV2/Invoice_v2_multi_page"
|
|
||||||
folder2 = "/mnt/hdd2T/AICR/Projects/2023/FI_Invoices/Invoice_v2_multi_page"
|
|
||||||
|
|
||||||
out_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/PV2/Invoice_v2_multi_page_2"
|
|
||||||
out_dir = Path(out_dir)
|
|
||||||
if not out_dir.exists():
|
|
||||||
out_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
# Get list of files in both folders
|
|
||||||
files1 = [f for f in os.listdir(folder1) if os.path.isfile(os.path.join(folder1, f))]
|
|
||||||
files2 = [f for f in os.listdir(folder2) if os.path.isfile(os.path.join(folder2, f))]
|
|
||||||
|
|
||||||
# Get list of file names in both folders
|
|
||||||
names1 = [os.path.splitext(f)[0] for f in files1]
|
|
||||||
names2 = [os.path.splitext(f)[0] for f in files2]
|
|
||||||
|
|
||||||
# Find duplicates by comparing names
|
|
||||||
duplicates = set(names1) ^ set(names2)
|
|
||||||
print(len(duplicates))
|
|
||||||
# Print duplicate file names
|
|
||||||
for d in duplicates:
|
|
||||||
print(f"Duplicate file name found: {d}")
|
|
||||||
pdf_path = Path(folder2) / (d+".pdf")
|
|
||||||
shutil.copy(str(pdf_path), str(out_dir))
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
|||||||
200
|
|
||||||
Invoice_ho_1007_000
|
|
||||||
210
|
|
||||||
invoice_126
|
|
||||||
inv_SDV_016
|
|
||||||
invoice_108
|
|
||||||
invoice_215
|
|
||||||
invoice_135
|
|
||||||
inv_SDV_004
|
|
||||||
292
|
|
||||||
164
|
|
||||||
242
|
|
||||||
inv_SDV_240
|
|
||||||
207
|
|
||||||
invoice_0525_000
|
|
||||||
invoice_1279_000
|
|
||||||
306
|
|
||||||
d2.sc_1261_000
|
|
||||||
invoice_90
|
|
||||||
304
|
|
||||||
s1.sc_1258_000
|
|
||||||
ce_1h_0967_000
|
|
||||||
invoice_1392_000
|
|
||||||
193
|
|
||||||
invoice_109
|
|
||||||
281
|
|
||||||
354
|
|
||||||
invoice_1059_000
|
|
||||||
es_10_1043_000
|
|
||||||
257
|
|
||||||
invoice_65
|
|
||||||
invoice_1252_006
|
|
||||||
331
|
|
||||||
scan__1319_000
|
|
||||||
230
|
|
||||||
20210_1314_000
|
|
||||||
328
|
|
||||||
o1_aa_1093_000
|
|
||||||
342
|
|
||||||
invoice_149
|
|
||||||
invoice_1304_000
|
|
||||||
c2_em_0081_000
|
|
||||||
Invoice_En_1074_000
|
|
||||||
invoice_89
|
|
||||||
Invoice_Sh_0712_000
|
|
||||||
invoice_202
|
|
||||||
hotel_0209_000
|
|
||||||
invoice_0872_000
|
|
||||||
invoice_72
|
|
||||||
InvoiceofP_0648_000
|
|
||||||
invoice_133
|
|
||||||
C1_Invoice_0968_000
|
|
||||||
invoice_0803_000
|
|
||||||
invoice_50
|
|
||||||
invoice_208
|
|
||||||
253
|
|
||||||
inv_SDV_215
|
|
||||||
360
|
|
||||||
invoice_1393_000
|
|
||||||
scan__0953_000
|
|
||||||
invoice_22
|
|
||||||
O1_Invoice_1348_000
|
|
||||||
inv_SDV_231
|
|
||||||
252
|
|
||||||
273
|
|
||||||
156
|
|
||||||
330
|
|
||||||
invoice_0457_001
|
|
||||||
invoice_0180_001
|
|
||||||
invoice_182
|
|
||||||
326
|
|
||||||
14
|
|
||||||
301
|
|
||||||
334
|
|
||||||
01gtk_0199_000
|
|
||||||
343
|
|
||||||
Invoice201_0930_000
|
|
||||||
invoice_1
|
|
||||||
344
|
|
||||||
inv_SDV_021
|
|
||||||
invoice_170
|
|
||||||
E2.Invoice_0561_000
|
|
||||||
Invoice_Sh_0262_000
|
|
||||||
1.1Invoice_1431_000
|
|
||||||
invoice_0112_000
|
|
||||||
invoice_195
|
|
||||||
314
|
|
||||||
2021._0035_000
|
|
||||||
invoice_0013_000
|
|
||||||
invoice_1204_000
|
|
||||||
2021._0868_000
|
|
||||||
scan__0520_000
|
|
||||||
255
|
|
||||||
invoice_200
|
|
||||||
C3_Invoice_1359_000
|
|
||||||
invoice_49
|
|
||||||
invoice_1095_000
|
|
||||||
hq_20_0003_000
|
|
||||||
invoice_180
|
|
||||||
invoice_184
|
|
||||||
340
|
|
||||||
invoice_0447_000
|
|
||||||
invoice_6
|
|
||||||
invoice_190
|
|
||||||
invoice_105
|
|
||||||
invoice_0673_000
|
|
@ -1,24 +0,0 @@
|
|||||||
import os
|
|
||||||
import shutil
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
SRC_DIR = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/train/sbt/batch_1"
|
|
||||||
TEST_DIR = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/sbt_txt"
|
|
||||||
|
|
||||||
# Get a list of all the files in the test directory
|
|
||||||
test_files = sorted([Path(f).stem for f in os.listdir(TEST_DIR) if ".txt" in f])
|
|
||||||
print(len(test_files))
|
|
||||||
|
|
||||||
# Create the output directory if it doesn't exist
|
|
||||||
# Move the matching files from the source directory to the output directory
|
|
||||||
i = 0
|
|
||||||
src_files = sorted(os.listdir(SRC_DIR))
|
|
||||||
print(len(src_files))
|
|
||||||
for filename in src_files:
|
|
||||||
# print(Path(filename).stem )
|
|
||||||
if Path(filename).stem not in test_files:
|
|
||||||
print(Path(filename).stem)
|
|
||||||
i+=1
|
|
||||||
|
|
||||||
print(i)
|
|
@ -1,15 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
def rename_files(folder_path):
|
|
||||||
# Get a list of all the files in the folder
|
|
||||||
files = os.listdir(folder_path)
|
|
||||||
# Iterate over the files and rename them
|
|
||||||
for i, filename in enumerate(files):
|
|
||||||
# Construct the new filename
|
|
||||||
new_filename = filename.replace(" ", "_")
|
|
||||||
# Rename the file
|
|
||||||
os.rename(os.path.join(folder_path, filename), os.path.join(folder_path, new_filename))
|
|
||||||
|
|
||||||
rename_files(
|
|
||||||
folder_path="/mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/sbt/images",
|
|
||||||
)
|
|
@ -1,10 +0,0 @@
|
|||||||
python rename_labels.py \
|
|
||||||
--in_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed \
|
|
||||||
--out_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed \
|
|
||||||
--doc_type receipt
|
|
||||||
|
|
||||||
|
|
||||||
python rename_labels.py \
|
|
||||||
--in_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed \
|
|
||||||
--out_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed \
|
|
||||||
--doc_type invoice
|
|
@ -1,191 +0,0 @@
|
|||||||
import argparse
|
|
||||||
from pathlib import Path
|
|
||||||
from tqdm import tqdm
|
|
||||||
import json
|
|
||||||
|
|
||||||
INVOICE_MAPPING = {
|
|
||||||
'no_key': 'No_key', # số hóa đơn
|
|
||||||
'no_value': 'No_value',
|
|
||||||
'form_key': 'Form_key', # mẫu số hóa đơn
|
|
||||||
'form_value': 'Form_value',
|
|
||||||
'serial_key': 'Serial_key', # số kí hiệu hoá đơn
|
|
||||||
'serial_value': 'Serial_value',
|
|
||||||
'date': 'Date_value',
|
|
||||||
|
|
||||||
# seller info
|
|
||||||
'seller_company_name_key': 'Seller_company_name_key',
|
|
||||||
'seller_company_name_value': 'Seller_company_name_value',
|
|
||||||
'seller_tax_code_key': 'Seller_tax_code_key',
|
|
||||||
'seller_tax_code_value': 'Seller_tax_code_value',
|
|
||||||
'seller_address_value': 'Seller_address_value',
|
|
||||||
'seller_address_key': 'Seller_address_key',
|
|
||||||
'seller_mobile_key': 'Seller_tel_key',
|
|
||||||
'seller_mobile_value': 'Seller_tel_value',
|
|
||||||
|
|
||||||
# buyer info
|
|
||||||
'buyer_name_key': 'Buyer_personal_name_key',
|
|
||||||
'buyer_name_value': 'Buyer_personal_name_value',
|
|
||||||
'buyer_company_name_value': 'Buyer_company_name_value',
|
|
||||||
'buyer_company_name_key': 'Buyer_company_name_key',
|
|
||||||
'buyer_tax_code_key': 'Buyer_tax_code_key',
|
|
||||||
'buyer_tax_code_value': 'Buyer_tax_code_value',
|
|
||||||
'buyer_address_key': 'Buyer_address_key',
|
|
||||||
'buyer_address_value': 'Buyer_address_value',
|
|
||||||
'buyer_mobile_key': 'Buyer_tel_key',
|
|
||||||
'buyer_mobile_value': 'Buyer_tel_value',
|
|
||||||
|
|
||||||
# money info
|
|
||||||
'VAT_amount_key': 'Tax_amount_key',
|
|
||||||
'VAT_amount_value': 'Tax_amount_value',
|
|
||||||
'total_key': 'Total_key',
|
|
||||||
'total_value': 'Total_value',
|
|
||||||
'total_in_words_key': 'Total_in_words_key',
|
|
||||||
'total_in_words_value': 'Total_in_words_value',
|
|
||||||
|
|
||||||
'other': 'Other',
|
|
||||||
}
|
|
||||||
|
|
||||||
RECEIPT_MAPPING = {
|
|
||||||
"Store_name_value": "seller_company_name_value",
|
|
||||||
"Seller_company_name_value": "seller_company_name_value",
|
|
||||||
"id": "no_value",
|
|
||||||
"No_value": "no_value",
|
|
||||||
|
|
||||||
"Date_value": "date_value",
|
|
||||||
"Total_key": "total_key",
|
|
||||||
"Total_value": "total_value",
|
|
||||||
|
|
||||||
"Others": "other",
|
|
||||||
"others": "other",
|
|
||||||
"Other": "other",
|
|
||||||
}
|
|
||||||
|
|
||||||
def write_txt(txt, data, mode="w"):
|
|
||||||
with open(txt, mode, encoding="utf8") as f:
|
|
||||||
for line in data:
|
|
||||||
f.write(line + "\n")
|
|
||||||
|
|
||||||
|
|
||||||
def read_txt(txt):
|
|
||||||
with open(txt, "r", encoding="utf8") as f:
|
|
||||||
data = [line.strip() for line in f]
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def edit_file(in_txt, out_txt, mapping):
|
|
||||||
data = read_txt(in_txt)
|
|
||||||
new_items = []
|
|
||||||
not_exits_label = False
|
|
||||||
not_edit = True
|
|
||||||
for item in data:
|
|
||||||
splited_item = item.split("\t")
|
|
||||||
label = splited_item[-1]
|
|
||||||
if label in mapping.keys():
|
|
||||||
new_label = mapping[label]
|
|
||||||
splited_item[-1] = new_label
|
|
||||||
not_edit = False
|
|
||||||
else:
|
|
||||||
# print(label, "not in ", mapping.keys())
|
|
||||||
not_exits_label = True
|
|
||||||
splited_item[-1] = label.lower()
|
|
||||||
|
|
||||||
splited_item[-1] = splited_item[-1].lower()
|
|
||||||
new_item = "\t".join(splited_item)
|
|
||||||
new_items.append(new_item)
|
|
||||||
|
|
||||||
if not_exits_label:
|
|
||||||
print("Not exists label: ", in_txt)
|
|
||||||
|
|
||||||
if not not_edit:
|
|
||||||
print("Not edit: ", in_txt)
|
|
||||||
write_txt(out_txt, new_items)
|
|
||||||
|
|
||||||
def rename_labels(data_dir, out_dir, doc_type):
|
|
||||||
data_dir = Path(data_dir)
|
|
||||||
out_dir = Path(out_dir)
|
|
||||||
if not out_dir.exists():
|
|
||||||
out_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
if doc_type == "receipt":
|
|
||||||
mapping = RECEIPT_MAPPING
|
|
||||||
elif doc_type == 'invoice':
|
|
||||||
mapping = INVOICE_MAPPING
|
|
||||||
else:
|
|
||||||
raise NotImplementedError()
|
|
||||||
txt_paths = data_dir.rglob("*.txt")
|
|
||||||
for txt_path in tqdm(txt_paths):
|
|
||||||
txt_dir = str(Path(str(txt_path).replace(str(data_dir), "")).parent) # a/b/c/x.txt -> c/x.txt -> c
|
|
||||||
|
|
||||||
if txt_dir[0] == "/":
|
|
||||||
txt_dir = txt_dir[1:]
|
|
||||||
out_sub_dir = out_dir / Path(txt_dir)
|
|
||||||
|
|
||||||
if not out_sub_dir.exists():
|
|
||||||
out_sub_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
out_txt = out_sub_dir / txt_path.name
|
|
||||||
|
|
||||||
# if "failure" in str(out_txt):
|
|
||||||
# # print(out_txt)
|
|
||||||
# print(out_sub_dir)
|
|
||||||
# print(out_txt)
|
|
||||||
# print(out_txt)
|
|
||||||
edit_file(str(txt_path), out_txt=out_txt, mapping=mapping)
|
|
||||||
|
|
||||||
def write_json(json_path, data):
|
|
||||||
with open(json_path, "w", encoding="utf8") as f:
|
|
||||||
json.dump(data, f, ensure_ascii=False, sort_keys=True)
|
|
||||||
|
|
||||||
|
|
||||||
def read_json(json_path):
|
|
||||||
with open(json_path, "r", encoding="utf8") as f:
|
|
||||||
data = json.load(f)
|
|
||||||
return data
|
|
||||||
def rename_label_in_json(json_in, json_out, doc_type):
|
|
||||||
if doc_type == "invoice":
|
|
||||||
mapping = INVOICE_MAPPING
|
|
||||||
else:
|
|
||||||
mapping = RECEIPT_MAPPING
|
|
||||||
ori_data = read_json(json_in)
|
|
||||||
new_data = {}
|
|
||||||
for img_key, field_item in ori_data.items():
|
|
||||||
new_field_item = {}
|
|
||||||
for field_key, field_value in field_item.items():
|
|
||||||
if field_key in mapping:
|
|
||||||
new_field_key = mapping[field_key]
|
|
||||||
else:
|
|
||||||
new_field_key = field_key
|
|
||||||
new_field_key = new_field_key.lower()
|
|
||||||
new_field_item[new_field_key] = field_value
|
|
||||||
|
|
||||||
new_data[img_key] = new_field_item
|
|
||||||
|
|
||||||
write_json(json_out, new_data)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(prog="Rename labels")
|
|
||||||
parser.add_argument("--in_dir", type=str, required=True, help="dataset directory")
|
|
||||||
parser.add_argument("--out_dir", type=str, required=False, help="output")
|
|
||||||
parser.add_argument("--doc_type", type=str, required=True, help="document type: receipt / invoice")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
rename_labels(
|
|
||||||
data_dir=args.in_dir,
|
|
||||||
out_dir=args.out_dir,
|
|
||||||
doc_type=args.doc_type
|
|
||||||
)
|
|
||||||
|
|
||||||
# rename_label_in_json(
|
|
||||||
# json_in=args.in_dir,
|
|
||||||
# json_out=args.out_dir,
|
|
||||||
# doc_type=args.doc_type
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""
|
|
@ -1,83 +0,0 @@
|
|||||||
import argparse
|
|
||||||
from sdsvkie.utils import read_json, yaml_load, write_json
|
|
||||||
# from sdsvkie.utils.post_processing.invoice_post_processing import *
|
|
||||||
# from sdsvkie.utils.post_processing.common_post_processing import normalize_number
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
INVOICE_KEYS = [
|
|
||||||
'no_key',
|
|
||||||
'no_value',
|
|
||||||
'form_key',
|
|
||||||
'form_value',
|
|
||||||
'serial_key',
|
|
||||||
'serial_value',
|
|
||||||
|
|
||||||
'date_value',
|
|
||||||
|
|
||||||
'seller_company_name_key',
|
|
||||||
'seller_company_name_value',
|
|
||||||
'seller_address_value',
|
|
||||||
'seller_address_key',
|
|
||||||
'seller_tel_key',
|
|
||||||
'seller_tel_value',
|
|
||||||
'seller_tax_code_key',
|
|
||||||
'seller_tax_code_value',
|
|
||||||
|
|
||||||
'buyer_personal_name_key',
|
|
||||||
'buyer_personal_name_value',
|
|
||||||
'buyer_company_name_value',
|
|
||||||
'buyer_company_name_key',
|
|
||||||
|
|
||||||
'buyer_address_key',
|
|
||||||
'buyer_address_value',
|
|
||||||
'buyer_tax_code_key',
|
|
||||||
'buyer_tax_code_value',
|
|
||||||
'buyer_tel_key',
|
|
||||||
'buyer_tel_value',
|
|
||||||
|
|
||||||
'tax_amount_key',
|
|
||||||
'tax_amount_value',
|
|
||||||
'total_key',
|
|
||||||
'total_value',
|
|
||||||
'total_in_words_key',
|
|
||||||
'total_in_words_value',
|
|
||||||
'other'
|
|
||||||
]
|
|
||||||
|
|
||||||
def sort_invoice(data):
|
|
||||||
|
|
||||||
sorted_data = {}
|
|
||||||
for img_key, img_data in tqdm(data.items()):
|
|
||||||
sorted_img_data = {}
|
|
||||||
for field_key in INVOICE_KEYS:
|
|
||||||
if "_key" in field_key or "other" in field_key:
|
|
||||||
continue
|
|
||||||
sorted_img_data[field_key] = img_data.get(field_key, "")
|
|
||||||
|
|
||||||
sorted_data[img_key] = sorted_img_data
|
|
||||||
|
|
||||||
return sorted_data
|
|
||||||
|
|
||||||
|
|
||||||
def sort_receipt(data):
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--input", type=str, help="e2e label file path")
|
|
||||||
parser.add_argument("--out", type=str, help='postprocess e2e label')
|
|
||||||
parser.add_argument("--doc_type", default="invoice")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
data = read_json(args.input)
|
|
||||||
if args.doc_type:
|
|
||||||
|
|
||||||
sorted_data = sort_invoice(data)
|
|
||||||
else:
|
|
||||||
sorted_data = sort_receipt(data)
|
|
||||||
|
|
||||||
write_json(args.out, sorted_data, sort_keys=False)
|
|
||||||
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
|||||||
import os
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
def split_folder_into_batches(input_folder, output_folder, n):
|
|
||||||
# Get the list of image files in the input folder
|
|
||||||
image_files = [f for f in os.listdir(input_folder) if f.lower().endswith(('.jpg', '.jpeg', '.png'))]
|
|
||||||
# Sort the list of image files
|
|
||||||
image_files.sort()
|
|
||||||
print("len: ", len(image_files))
|
|
||||||
# Calculate the number of images per batch
|
|
||||||
batch_size = len(image_files) // n
|
|
||||||
# Create the output directories
|
|
||||||
for i in range(n):
|
|
||||||
batch_dir = os.path.join(output_folder, f"batch_{i+1}")
|
|
||||||
os.makedirs(batch_dir, exist_ok=True)
|
|
||||||
# Split the images into batches
|
|
||||||
for i, image_file in enumerate(image_files):
|
|
||||||
# print(i, image_file)
|
|
||||||
batch_index = i // batch_size
|
|
||||||
batch_dir = os.path.join(output_folder, f"batch_{batch_index+1}")
|
|
||||||
if not os.path.exists(batch_dir):
|
|
||||||
os.makedirs(batch_dir, exist_ok=True)
|
|
||||||
# print(batch_dir)
|
|
||||||
# Find the corresponding label file
|
|
||||||
image_name, image_ext = os.path.splitext(image_file)
|
|
||||||
label_file = f"{image_name}.txt"
|
|
||||||
label_path = os.path.join(input_folder, label_file)
|
|
||||||
# Copy the image and label files into the appropriate batch directory
|
|
||||||
print(label_path, os.path.join(input_folder, image_file), batch_dir)
|
|
||||||
shutil.copy(os.path.join(input_folder, image_file), batch_dir)
|
|
||||||
shutil.copy(label_path, batch_dir)
|
|
||||||
|
|
||||||
# Example usage:
|
|
||||||
split_folder_into_batches("/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/pseudo_ocr/invoice_receipt_sbt", "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/pseudo_ocr/invoice_receipt_sbt_split", 3)
|
|
@ -1,31 +0,0 @@
|
|||||||
# import xml.etree.ElementTree as ET
|
|
||||||
# from reportlab.pdfgen import canvas
|
|
||||||
# from reportlab.lib.pagesizes import letter
|
|
||||||
|
|
||||||
# # Load XML file
|
|
||||||
# tree = ET.parse('/mnt/hdd2T/AICR/Projects/2023/Xml_SAVINA/2023-04-20_0101803564_0300741922_1C23TYY_714.xml')
|
|
||||||
# root = tree.getroot()
|
|
||||||
|
|
||||||
# # Create PDF canvas
|
|
||||||
# pdf_canvas = canvas.Canvas('./2023-04-20_0101803564_0300741922_1C23TYY_714.pdf', pagesize=letter)
|
|
||||||
|
|
||||||
# # Iterate over XML elements and draw on PDF canvas
|
|
||||||
# for element in root.iter():
|
|
||||||
# if element.tag == 'paragraph':
|
|
||||||
# pdf_canvas.drawString(int(element.get('x')), int(element.get('y')), element.text)
|
|
||||||
# elif element.tag == 'image':
|
|
||||||
# pdf_canvas.drawImage(element.get('src'), int(element.get('x')), int(element.get('y')), int(element.get('width')), int(element.get('height')))
|
|
||||||
|
|
||||||
# # Save PDF file
|
|
||||||
# pdf_canvas.save()
|
|
||||||
|
|
||||||
import pyxml2pdf
|
|
||||||
|
|
||||||
# Create an XML file
|
|
||||||
|
|
||||||
|
|
||||||
# Create a new xml2pdf object
|
|
||||||
xml2pdf = pyxml2pdf.("/mnt/hdd2T/AICR/Projects/2023/Xml_SAVINA/2023-04-20_0101803564_0300741922_1C23TYY_714.xml")
|
|
||||||
|
|
||||||
# Save the output PDF file
|
|
||||||
xml2pdf.save("my_pdf_file.pdf")
|
|
@ -1,256 +0,0 @@
|
|||||||
python tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/batch_1_taxi_sub_1_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/batch_1_taxi_sub_1_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo_OCR/Batch_1_Good/Taxi_sub_1
|
|
||||||
|
|
||||||
python tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/batch_1_taxi_sub_2_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/batch_1_taxi_sub_2_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/Taxi_sub_2
|
|
||||||
|
|
||||||
python rename_labels.py \
|
|
||||||
--in_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed \
|
|
||||||
--out_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed \
|
|
||||||
--doc_type receipt
|
|
||||||
|
|
||||||
|
|
||||||
python rename_labels.py \
|
|
||||||
--in_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed \
|
|
||||||
--out_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed \
|
|
||||||
--doc_type receipt
|
|
||||||
# text detect
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/batch_1_taxi_sub_1_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/batch_1_taxi_sub_1_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/taxi_sub_1
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/batch_1_food.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/batch_1_food_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/food
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/labeling/train_vnpt_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/labeling/train_vnpt_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/train_with_vnpt
|
|
||||||
|
|
||||||
##########
|
|
||||||
python tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo_OCR/Batch_1_Good/Taxi_sub_1 \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/batch_1_taxi_sub_1_done.xml \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_1/Good/Taxi_sub_1 \
|
|
||||||
--line_to_word \
|
|
||||||
--other_class Others
|
|
||||||
|
|
||||||
python tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/Taxi_sub_2 \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/batch_1_taxi_sub_2_done.xml \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_1/Good/Taxi_sub_2 \
|
|
||||||
--other_class Others
|
|
||||||
|
|
||||||
python tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/Food \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/batch_1_food_done.xml \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_1/Good/Food \
|
|
||||||
--other_class Others
|
|
||||||
|
|
||||||
python tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_2/Good/Food \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_2/batch_2_food_done.xml \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_2/Good/Food \
|
|
||||||
--other_class Others
|
|
||||||
|
|
||||||
# WILD RECEIPT
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/WildReceipt/re_labeling/batches/batch_1 \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/WildReceipt/re_labeling/batches/batch_1 \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/WildReceipt/re_labeling/wild_batch_1_done.xml \
|
|
||||||
--other_class Others
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# SS RECEIPT
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted/ss_receipt_batch_1_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted/ss_receipt_batch_1_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted_txt/batch_1 \
|
|
||||||
--other_class Others
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_txt/mc_ocr_batch_3_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_txt/mc_ocr_batch_3_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_v2/batch_3 \
|
|
||||||
--other_class Others \
|
|
||||||
--resever_parent_dir
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/ss_receipt_all_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/ss_receipt_all_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Done \
|
|
||||||
--other_class Others \
|
|
||||||
--resever_parent_dir
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/pseudo_label/mcocr_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/pseudo_label/mcocr_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/train/mc_ocr \
|
|
||||||
--other_class Others \
|
|
||||||
--resever_parent_dir
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/pseudo_label/sdsap_receipt_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/pseudo_label/sdsap_receipt_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/train/sdsap_receipt \
|
|
||||||
--other_class Others \
|
|
||||||
--resever_parent_dir
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/pseudo_label/ss_receipt_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/pseudo_label/ss_receipt_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/train/ss_receipt \
|
|
||||||
--other_class Others \
|
|
||||||
--resever_parent_dir
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/pseudo_label/wildreceipt_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/pseudo_label/wildreceipt_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/train/wildreceipt \
|
|
||||||
--other_class Others \
|
|
||||||
--resever_parent_dir
|
|
||||||
|
|
||||||
# INVOICE
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/Labeling/invoice_sl_hn_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/Labeling/invoice_sl_hn_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/SL_HN_Invoice_txt \
|
|
||||||
--other_class other
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/Labeling/invoice_sl_hcm_tmp_done.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/Labeling/invoice_sl_hcm_tmp_done_2.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/invoice_add_sl_hcm_finetuning/SL_HCM_Invoice_wg_txt_need_review \
|
|
||||||
--other_class other
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/Labeling/invoice_ss_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/Labeling/invoice_ss_wg_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/intermediate/parse_wg/SS_Invoice \
|
|
||||||
--other_class other
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/intermediate/multi_pages/labels/ss_hcm_batch_2_multi_pages_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/intermediate/multi_pages/labels/ss_hcm_batch_2_multi_pages_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/SL_HCM_batch_2_first_last_page_txt \
|
|
||||||
--other_class other
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/sbt/sbt_craw_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/sbt/sbt_craw_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/Crawled_invoices_SBT \
|
|
||||||
--other_class other
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_6/sbt_test_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_6/sbt_test_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test_sbt_wg \
|
|
||||||
--other_class other
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/viettinbank_pocr_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/viettinbank_pocr_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/invoice_viettinbank_poc_txt \
|
|
||||||
--other_class other
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# UPDATE TXT
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_txt/batch_1 \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted/batch_1 \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_txt/mc_ocr_batch_1_done.xml \
|
|
||||||
--other_class Others
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_txt/batch_2 \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted/batch_2 \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_txt/mc_ocr_batch_2_done.xml \
|
|
||||||
--other_class Others
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_v2/batch_3 \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_v2/batch_3_2 \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_txt/mc_ocr_batch_3_done.xml \
|
|
||||||
--other_class Others \
|
|
||||||
--resever_parent_dir
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Done \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Done \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/ss_receipt_by_store_done.xml \
|
|
||||||
--other_class Others \
|
|
||||||
--resever_parent_dir
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted_txt/batch_1 \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted/batch_1 \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted/ss_receipt_batch_1_done.xml \
|
|
||||||
--other_class Others
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted_txt/batch_2 \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted/batch_2 \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted/ss_receipt_batch_2_done.xml \
|
|
||||||
--other_class Others
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/JPG/SL_HN_Invoice \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/JPG/SL_HN_Invoice \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/Labeling/invoice_sl_hn_done.xml \
|
|
||||||
--other_class other \
|
|
||||||
--line_to_word
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/train/SS_Invoice \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/train/SS_Invoice \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/Labeling/ss_invoice_done.xml \
|
|
||||||
--other_class other \
|
|
||||||
--line_to_word
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/intermediate/multi_pages/SL_HCM_batch_2_first_last_page \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/intermediate/multi_pages/SL_HCM_batch_2_first_last_page \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/intermediate/multi_pages/labels/sl_hcm_batch_2_multi_pages_done.xml \
|
|
||||||
--other_class other \
|
|
||||||
--line_to_word
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/Crawled_invoices_SBT_no_wg_txt \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/Crawled_invoices_SBT_no_wg_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/intermediate/sbt/sbt_craw_done.xml \
|
|
||||||
--other_class other \
|
|
||||||
--line_to_word
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test_sbt \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test_sbt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_6/sbt_test_done.xml \
|
|
||||||
--other_class other \
|
|
||||||
--line_to_word
|
|
||||||
|
|
||||||
python sdsvkie/tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/invoice_viettinbank_poc_txt \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/invoice_viettinbank_poc_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/viettinbank_poc_done.xml \
|
|
||||||
--other_class other \
|
|
||||||
--line_to_word
|
|
@ -1,96 +0,0 @@
|
|||||||
#SDSAP
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/test_end2end/food_e2e.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_end2end_food_pred_v1.json \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/test_end2end/all_e2e.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_all_end2end_w0.1_h0.3_thr5.json \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_all_end2end_w0.1_h0.3_thr5.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/test_end2end/taxi_e2e.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_taxi_end2end_text_det_20230425.json \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_taxi_end2end_text_det_20230425_fail.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/test_end2end/taxi_e2e.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_taxi_end2end_w0.2_h0.2_thr5.json \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_taxi_end2end_w0.2_h0.2_thr5_fail.json
|
|
||||||
|
|
||||||
|
|
||||||
# 10/5/2023
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_8_lr9e_6/config.yaml \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/test_end2end/all_e2e.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_8_lr9e_6/receipt_e2e.json \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_8_lr9e_6/receipt_e2e_fail.json
|
|
||||||
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/config.yaml \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test_end2end/all_e2e.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/receipt_e2e_best.json \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/receipt_e2e_best_fail.json
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
=============================== INVOICE ====================================================================
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/test_end2end/test_e2e.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/e2e/test_vnpt_epx_4_best_not_ocr_merge_use_label.json \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/failure_of_test_vnpt_epx_4_best_not_ocr_merge_use_label.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/test_end2end/test_e2e.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/pred_test_end2end.json \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/vnpt_epx_falures_v2.json
|
|
||||||
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss_e2e_rm_leak.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/test_ss_rm_leak.json \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/test_ss_e2e_rm_leak_fail.json
|
|
||||||
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/PDF/multi_page/test_e2e_multi_pages.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/test_e2e_multi_page.json \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/config.yaml \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/test_e2e_multi_page_fail.json
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss_e2e_rm_leak.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/test_ss_rm_leak.json \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/config.yaml \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/test_ss_rm_leak_fail.json
|
|
||||||
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/PDF/multi_page/test_e2e_multi_pages.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/test_e2e_multi_page.json \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/config.yaml \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/test_e2e_multi_page_fail.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/utils/eval_kie.py \
|
|
||||||
--gt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test_end2end/sbt_validation_e2e.json \
|
|
||||||
--pred /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_6/sbt_validation_e2e_ep50.json \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_6/config.yaml \
|
|
||||||
--log_failure_case /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_6/sbt_validation_e2e_ep50_fail.json
|
|
@ -1,199 +0,0 @@
|
|||||||
python sdsvkie/tools/infer.py --cfg workdirs/invoice/exp1/config.yaml --inference_weights workdirs/invoice/exp1/best --device cuda --img ../TokenClassification_invoice/DATA/test/01067_0452_000.jpg
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py --cfg workdirs/invoice/exp1/config.yaml --inference_weights workdirs/invoice/exp1/best --device "cuda:1" \
|
|
||||||
--img ../craw_data/output/synth_template_4/one_line --txt_out workdirs/visualize/vnpt_one_line_txt --kie_wordgroup_out
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py --cfg workdirs/invoice/exp1/config.yaml --inference_weights workdirs/invoice/exp1/best --device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/craw_data/output/synth_vnpt_r20/one_line --txt_out workdirs/visualize/vnpt_one_line_r20_txt --kie_wordgroup_out
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py --cfg workdirs/invoice/exp_add_vnpt_template/config.yaml --inference_weights workdirs/invoice/exp_add_vnpt_r2/best --device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/craw_data/output/synth_vnpt_r2_2/one_line \
|
|
||||||
--vis_out workdirs/visualize/vnpt_r2_phase_2 \
|
|
||||||
--txt_out workdirs/visualize/vnpt_r2_phase_2_txt --kie_wordgroup_out
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py --cfg workdirs/invoice/exp_add_vnpt_template/config.yaml --inference_weights workdirs/invoice/exp_add_vnpt_r2/best --device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/craw_data/output/synth_vnpt_r2_2/one_line \
|
|
||||||
--vis_out workdirs/visualize/vnpt_r2_phase_2 \
|
|
||||||
--txt_out workdirs/visualize/vnpt_r2_phase_2_txt --kie_wordgroup_out
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py --cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoiceadd_vnpt_final/config.yaml --inference_weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoiceadd_vnpt_final/epoch_60 --device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/test \
|
|
||||||
--vis_out workdirs/visualize/test_sorted
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoiceadd_vnpt_final/config.yaml \
|
|
||||||
--inference_weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoiceadd_vnpt_final/epoch_60 \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/test \
|
|
||||||
--vis_out workdirs/visualize/test_sorted
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoiceadd_vnpt_final/config.yaml \
|
|
||||||
--inference_weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoiceadd_vnpt_final/epoch_60 \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/test \
|
|
||||||
|
|
||||||
|
|
||||||
# test e2e
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/exp_wild_1/config.yaml \
|
|
||||||
--inference_weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/exp_wild_1/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/intermediate/labeling/phase_1/batch_1 \
|
|
||||||
--vis_out workdirs/visualize/SDSAP_Invoice_exp_wild_1
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--inference_weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/test \
|
|
||||||
--e2e workdirs/e2e/test_sampling_sortword_exp4_best.json
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--inference_weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/last \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Dataset/common_tools/JPG/one_page/vat \
|
|
||||||
--e2e workdirs/e2e/test_invoice_vnpt_exp4_sdsv_invoice.json \
|
|
||||||
--vis workdirs/e2e/test_invoice_vnpt_exp4_sdsv_invoice_visualize
|
|
||||||
|
|
||||||
# sdsAP
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_1/config.yaml \
|
|
||||||
--inference_weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_1/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_1/Good/Taxi_sub_2 \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/infer/visualize/exp_1_batch_1_taxi_sub_2
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_2/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_2/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_2/Noise \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/infer/visualize/exp_2_batch_2_noise
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_2/Good/Taxi \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/infer/visualize/exp_3_batch_2_good_taxi
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/test_end2end/Taxi \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/infer/visualize/exp_3_batch_2_good_taxi
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/food \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/infer/visualize/exp_3_batch_1_food
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/test_end2end/Taxi \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/infer/visualize/exp_3_test_end2end_taxi_2
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/test_end2end/All \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/receipt_e2e_infer_best
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/last \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test_sbt \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/test_sbt_infer
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# MCOCR
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted/batch_1 \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images_aligned/train_splitted_txt/batch_1
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted/batch_1 \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/SS_Receipt/Images_splitted_txt/batch_1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/02062023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/02062023/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/JPG/multi_pages/sl_hcm_hn_savina \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/02062023/multi_pages_sl_hcm_hn_savina_wg_txt \
|
|
||||||
--kie_wordgroup_out
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/last \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/raw/Crawled_invoices_SBT \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/Crawled_invoices_SBT \
|
|
||||||
--kie_wordgroup_out
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/last \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/raw/Crawled_invoices_SBT \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/Crawled_invoices_SBT_no_wg_txt
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_6/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_6/epoch_50 \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/tuanlv/06.KVUCombineStage/datasets/invoices-receipts/SS_invoices/SBT/validation_data/valid_images \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_6/sbt_validation_e2e_ep50_old_textdet_infer
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/PDF/Viettinbank_POC/POC_OCR/invoice_JPG \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/visualize/vietinbank
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/intermediate/1000416613 \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/visualize/intermediate_1000416613
|
|
@ -1,210 +0,0 @@
|
|||||||
# SDSAP_Receipt
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/test_end2end/All \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_all_end2end.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_all_end2end
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/OTHER_DATA/MC-OCR/raw/Images/train \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/train_mcocr_end2end.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/train_mcocr_end2end
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--text_det /mnt/ssd500/datnt/mmdetection/logs/textdet-fwd-table-receipt-20230425/best_bbox_mAP_epoch_15_lite.pth \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/test_end2end/Taxi \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_taxi_end2end_text_det_20230425.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_taxi_end2end_text_det_20230425
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/v1/train \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_end2end.json
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/test_end2end/Taxi \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_taxi_end2end_w0.2_h0.2_thr5.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_taxi_end2end_w0.2_h0.2_thr5
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/test_end2end/All \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_all_end2end_w0.1_h0.3_thr5_v2.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/test_taxi_end2end_w0.1_h0.3_thr5_v2
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_8_lr9e_6/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_8_lr9e_6/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/test_end2end/All \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_8_lr9e_6/receipt_e2e.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_8_lr9e_6/receipt_e2e
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/test_end2end/All \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/receipt_e2e_best.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/sdsap_receipt/exp_9_lr5e_6_no_scheduler/receipt_e2e_best
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/Webcash/testing \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/pred_webcash_testing.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_3/pred_webcash_testing
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#invoice
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/last \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/test \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/invoice_end2end_last.json
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/last \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Dataset/common_tools/Split_by_pages/multi_page/vat \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/pred_vat_multi_page_v2.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/last \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Dataset/common_tools/Split_by_pages/multi_page/vat \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/pred_vat_multi_page_v2.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/last \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/multi_page_vat/SL_HCM \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/multi_page_vat/SL_HCM.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/last \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss_rm_leak \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/test_ss_rm_leak.json
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/last \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/test_ss.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/last \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/JPG/SL_HCM_Invoice \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/SL_HCM_Invoice.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/SL_HCM_Invoice
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss_rm_leak \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/test_ss_rm_leak.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/test_ss_rm_leak
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/JPG/multi_pages/SL_HCM_batch_2 \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/test_ss_sl_hcm_batch_2_multi_page_jpg.json \
|
|
||||||
--vis /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/test_ss_sl_hcm_batch_2_multi_page_jpg
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/PDF/multi_page/SL_HN_batch_2 \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/multi_page_SL_HN_batch_2.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/PDF/multi_page/test_e2e_multi_page \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/26052023/test_e2e_multi_page.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/02062023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/02062023/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/PDF/multi_page/SL_HN_batch_2 \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/02062023/multi_page_SL_HN_batch_2.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/hdd2T/AICR/Projects/2023/Vietinbank_POC/Invoice_JPG/ \
|
|
||||||
--e2e /mnt/hdd2T/AICR/Projects/2023/Vietinbank_POC/Invoice_KIE_Results/result.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/hdd2T/AICR/Projects/2023/FI_Invoices/Invoice_v2_multi_page \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/Invoice_v2_multi_page.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/19072023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/19072023/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/PDF/Viettinbank_POC/POC_OCR/invoice_JPG/ \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/19072023/vietinbank_poc_infer.json \
|
|
||||||
--vis workdirs/invoice/19072023/visualize/vietinbank_infer
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/hdd2T/AICR/Projects/2023/FI_Invoices/Test/1000416613/1000416613_0102310385_26062023163233062_001.pdf \
|
|
||||||
--e2e /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/1000416613_0102310385_26062023163233062_001.json
|
|
||||||
|
|
@ -1,226 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"name": "total_in_words_key",
|
|
||||||
"id": 92,
|
|
||||||
"color": "#33ddff",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "no_value",
|
|
||||||
"id": 93,
|
|
||||||
"color": "#fa3253",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "form_key",
|
|
||||||
"id": 94,
|
|
||||||
"color": "#34d1b7",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "no_key",
|
|
||||||
"id": 95,
|
|
||||||
"color": "#ff007c",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "form_value",
|
|
||||||
"id": 96,
|
|
||||||
"color": "#ddff33",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "serial_key",
|
|
||||||
"id": 97,
|
|
||||||
"color": "#24b353",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "serial_value",
|
|
||||||
"id": 98,
|
|
||||||
"color": "#b83df5",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "date_value",
|
|
||||||
"id": 99,
|
|
||||||
"color": "#66ff66",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_company_name_key",
|
|
||||||
"id": 100,
|
|
||||||
"color": "#32b7fa",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_company_name_value",
|
|
||||||
"id": 101,
|
|
||||||
"color": "#ffcc33",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_tax_code_key",
|
|
||||||
"id": 102,
|
|
||||||
"color": "#83e070",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_tax_code_value",
|
|
||||||
"id": 103,
|
|
||||||
"color": "#fafa37",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_address_value",
|
|
||||||
"id": 104,
|
|
||||||
"color": "#5986b3",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_address_key",
|
|
||||||
"id": 105,
|
|
||||||
"color": "#8c78f0",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_tel_key",
|
|
||||||
"id": 106,
|
|
||||||
"color": "#ff6a4d",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_tel_value",
|
|
||||||
"id": 107,
|
|
||||||
"color": "#f078f0",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_personal_name_key",
|
|
||||||
"id": 108,
|
|
||||||
"color": "#2a7dd1",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_personal_name_value",
|
|
||||||
"id": 109,
|
|
||||||
"color": "#83e070",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_company_name_value",
|
|
||||||
"id": 110,
|
|
||||||
"color": "#5986b3",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_company_name_key",
|
|
||||||
"id": 111,
|
|
||||||
"color": "#8c78f0",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_tax_code_key",
|
|
||||||
"id": 112,
|
|
||||||
"color": "#ff6a4d",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_tax_code_value",
|
|
||||||
"id": 113,
|
|
||||||
"color": "#f078f0",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_address_key",
|
|
||||||
"id": 114,
|
|
||||||
"color": "#2a7dd1",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_address_value",
|
|
||||||
"id": 115,
|
|
||||||
"color": "#b25050",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_tel_key",
|
|
||||||
"id": 116,
|
|
||||||
"color": "#cc3366",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_tel_value",
|
|
||||||
"id": 117,
|
|
||||||
"color": "#cc9933",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "tax_amount_key",
|
|
||||||
"id": 118,
|
|
||||||
"color": "#aaf0d1",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "tax_amount_value",
|
|
||||||
"id": 119,
|
|
||||||
"color": "#ff00cc",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "total_key",
|
|
||||||
"id": 120,
|
|
||||||
"color": "#3df53d",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "total_value",
|
|
||||||
"id": 121,
|
|
||||||
"color": "#fa32b7",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "total_in_words_value",
|
|
||||||
"id": 122,
|
|
||||||
"color": "#3d3df5",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "other",
|
|
||||||
"id": 123,
|
|
||||||
"color": "#733380",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,10 +0,0 @@
|
|||||||
python sdsvkie/tools/postprocess_e2e_label.py \
|
|
||||||
--cfg workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--input /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/test_end2end/test_e2e.json \
|
|
||||||
--out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SS_Invoice/test_end2end/test_e2e_post.json
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/postprocess_e2e_label.py \
|
|
||||||
--cfg workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--input /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/invoice_exp4/test_end2end_post.json \
|
|
||||||
--out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/invoice_exp4/test_end2end_post.json
|
|
@ -1,36 +0,0 @@
|
|||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/exp_wild_1/config.yaml \
|
|
||||||
--inference_weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/exp_wild_1/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_2/Good/Food \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_2/Good/Food
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_2/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/training/sdsap_receipt/exp_2/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_1/Good/Taxi_sub_2 \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_1/Good/Taxi_sub_2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/intermediate/multi_pages/SL_HCM_batch_2_first_last_page \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/SL_HCM_batch_2_first_last_page_vis \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/SL_HCM_batch_2_first_last_page_txt \
|
|
||||||
--kie_wordgroup_out
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/infer.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/best \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/JPG/invoice_viettinbank_poc \
|
|
||||||
--vis_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/invoice_viettinbank_poc_vis \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/invoice_viettinbank_poc_txt \
|
|
||||||
--kie_wordgroup_out
|
|
@ -1,19 +0,0 @@
|
|||||||
python sdsvkie/tools/run_ocr.py \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/raw/IMGS \
|
|
||||||
--out_dir /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/SDSAP_Invoice/visualize_ocr \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--reserve_parent_dir
|
|
||||||
|
|
||||||
|
|
||||||
# python sdsvkie/tools/run_ocr.py \
|
|
||||||
# --img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/raw/IMGS \
|
|
||||||
# --out_dir /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/SDSAP_Invoice/visualize_ocr \
|
|
||||||
# --device "cuda:1" \
|
|
||||||
# --reserve_parent_dir
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/run_ocr.py \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/test_end2end/Taxi \
|
|
||||||
--device "cuda:1" \
|
|
||||||
--out_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/test_v2/taxi \
|
|
||||||
--text_det "/mnt/ssd500/datnt/mmdetection/logs/textdet-fwd-table-receipt-20230425/best_bbox_mAP_epoch_15_lite.pth"
|
|
@ -1,35 +0,0 @@
|
|||||||
python sdsvkie/tools/run_ocr.py \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/WildReceipt/pseudo_ocr \
|
|
||||||
--out_dir ./workdirs/visualize/WildReceipt \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--out_txt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/WildReceipt/pseudo_ocr
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/run_ocr.py \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_1/Good/Taxi_sub_1 \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--out_txt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo_OCR/Batch_1_Good/Taxi_sub_1
|
|
||||||
|
|
||||||
|
|
||||||
# pseudo for edit text detect boxes
|
|
||||||
python sdsvkie/tools/run_ocr.py \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/taxi_sub_1 \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--out_txt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/taxi_sub_1
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/run_ocr.py \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/taxi_sub_1 \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--out_txt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/taxi_sub_1
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/run_ocr.py \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/food \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--out_txt /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/label_ocr/all/batch_1/food
|
|
||||||
|
|
||||||
python sdsvkie/tools/run_ocr.py \
|
|
||||||
--img /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/demos/invoice \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--out_txt /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/demos/invoice
|
|
@ -1,15 +0,0 @@
|
|||||||
python sdsvkie/utils/pdf2image.py \
|
|
||||||
--pdf_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/raw/batch_1/PDF \
|
|
||||||
--out_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/raw/batch_1/IMGS_dpi_300 \
|
|
||||||
--reserve_parent_dir
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/utils/pdf2image.py \
|
|
||||||
--pdf_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/PDF/multi_page/Invoices_SL_HCM \
|
|
||||||
--out_dir /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/raw/JPG/Invoices_SL_HCM
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/utils/pdf2image.py \
|
|
||||||
--pdf_dir /mnt/hdd2T/AICR/Projects/2023/Invoice_SDSV/SDSV_Invoice_2023/All \
|
|
||||||
--out_dir /mnt/hdd2T/AICR/Projects/2023/Invoice_SDSV/SDSV_Invoice_2023/JPG
|
|
@ -1,25 +0,0 @@
|
|||||||
python sdsvkie/utils/split_data.py \
|
|
||||||
--path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_1/Good/Food \
|
|
||||||
--out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/v2/ \
|
|
||||||
--test_ratio 0.05
|
|
||||||
|
|
||||||
python sdsvkie/utils/split_data.py \
|
|
||||||
--path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_1/Good/Taxi_sub_1 \
|
|
||||||
--out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/v2/ \
|
|
||||||
--test_ratio 0.05
|
|
||||||
|
|
||||||
python sdsvkie/utils/split_data.py \
|
|
||||||
--path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_1/Good/Taxi_sub_2 \
|
|
||||||
--out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/v2/ \
|
|
||||||
--test_ratio 0.05
|
|
||||||
|
|
||||||
python sdsvkie/utils/split_data.py \
|
|
||||||
--path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_2/Good/Food \
|
|
||||||
--out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/v2/ \
|
|
||||||
--test_ratio 0.05
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/utils/split_data.py \
|
|
||||||
--path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/WildReceipt/re_labeling/batches/batch_1 \
|
|
||||||
--out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/done/v2/ \
|
|
||||||
--test_ratio 0.0
|
|
@ -1,7 +0,0 @@
|
|||||||
python sdsvkie/tools/train.py --cfg sdsvkie/cfg/wildreciept.yaml --device cuda:0 --save_dir workdirs/invoice/exp_wild_1
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/train.py --cfg sdsvkie/cfg/sdsap_receipt_scheduler_linear.yaml --device cuda:0 --save_dir workdirs/sdsap_receipt/exp_4_scheduler_linear
|
|
||||||
|
|
||||||
|
|
||||||
python sdsvkie/tools/train.py --cfg sdsvkie/cfg/sdsap_receipt.yaml --device cuda:1 --save_dir workdirs/sdsap_receipt/exp_5
|
|
@ -1,5 +0,0 @@
|
|||||||
import os
|
|
||||||
import sys
|
|
||||||
sys.path.append(__file__)
|
|
||||||
|
|
||||||
from .engine.predictor import Predictor
|
|
@ -1,33 +0,0 @@
|
|||||||
from types import SimpleNamespace
|
|
||||||
from sdsvkie.utils.io_file import yaml_load
|
|
||||||
from pathlib import Path
|
|
||||||
from copy import copy, deepcopy
|
|
||||||
|
|
||||||
def load_cfg(cfg, args=None):
|
|
||||||
"""
|
|
||||||
Convert a configuration object to a dictionary, whether it is a file path, a string, or a SimpleNamespace object.
|
|
||||||
Inputs:
|
|
||||||
cfg (str) or (Path) or (SimpleNamespace): Configuration object to be converted to a dictionary.
|
|
||||||
Returns:
|
|
||||||
cfg (dict): Configuration object in dictionary format.
|
|
||||||
"""
|
|
||||||
if isinstance(cfg, (str, Path)):
|
|
||||||
cfg = yaml_load(cfg) # load dict
|
|
||||||
elif isinstance(cfg, SimpleNamespace):
|
|
||||||
cfg = vars(cfg) # convert to dict
|
|
||||||
|
|
||||||
|
|
||||||
if args is not None:
|
|
||||||
_args = deepcopy(args)
|
|
||||||
for k, v in args.items():
|
|
||||||
if v is None or v == "cfg" :
|
|
||||||
_args.pop(k)
|
|
||||||
|
|
||||||
if v is not None and k == "weights":
|
|
||||||
_args['inference_weights'] = v
|
|
||||||
_args.pop(k)
|
|
||||||
|
|
||||||
cfg.update(_args)
|
|
||||||
return cfg
|
|
||||||
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
no_key
|
|
||||||
no_value
|
|
||||||
form_key
|
|
||||||
form_value
|
|
||||||
serial_key
|
|
||||||
serial_value
|
|
||||||
date_key
|
|
||||||
date_value
|
|
||||||
subtotal_key
|
|
||||||
subtotal_value
|
|
||||||
tax_rate_key
|
|
||||||
tax_rate_value
|
|
||||||
tax_amount_key
|
|
||||||
tax_amount_value
|
|
||||||
tips_key
|
|
||||||
tips_value
|
|
||||||
total_key
|
|
||||||
total_value
|
|
||||||
total_in_words_key
|
|
||||||
total_in_words_value
|
|
||||||
seller_company_name_key
|
|
||||||
seller_company_name_value
|
|
||||||
seller_address_key
|
|
||||||
seller_address_value
|
|
||||||
seller_tel_key
|
|
||||||
seller_tel_value
|
|
||||||
seller_tax_code_key
|
|
||||||
seller_tax_code_value
|
|
||||||
buyer_company_name_key
|
|
||||||
buyer_company_name_value
|
|
||||||
buyer_personal_name_key
|
|
||||||
buyer_personal_name_value
|
|
||||||
buyer_tax_code_key
|
|
||||||
buyer_tax_code_value
|
|
||||||
buyer_address_key
|
|
||||||
buyer_address_value
|
|
||||||
buyer_tel_key
|
|
||||||
buyer_tel_value
|
|
||||||
other
|
|
@ -1,79 +0,0 @@
|
|||||||
|
|
||||||
debug: False
|
|
||||||
v3: False
|
|
||||||
# common
|
|
||||||
device: 'cpu' # 'cpu' / 'cuda:0' / 'cuda:1' / 'cuda'
|
|
||||||
|
|
||||||
#dataset
|
|
||||||
train_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/train_with_vnpt
|
|
||||||
val_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/test
|
|
||||||
slice_interval: 75
|
|
||||||
postprocess_type: invoice_postprocess
|
|
||||||
classes: [
|
|
||||||
# id invoice
|
|
||||||
'no_key', # số hóa đơn
|
|
||||||
'no_value',
|
|
||||||
'form_key', # mẫu số hóa đơn
|
|
||||||
'form_value',
|
|
||||||
'serial_key', # số kí hiệu hoá đơn
|
|
||||||
'serial_value',
|
|
||||||
'date',
|
|
||||||
|
|
||||||
# seller info
|
|
||||||
'seller_company_name_key',
|
|
||||||
'seller_company_name_value',
|
|
||||||
'seller_tax_code_key',
|
|
||||||
'seller_tax_code_value',
|
|
||||||
'seller_address_value',
|
|
||||||
'seller_address_key',
|
|
||||||
'seller_mobile_key',
|
|
||||||
'seller_mobile_value',
|
|
||||||
|
|
||||||
# buyer info
|
|
||||||
'buyer_name_key',
|
|
||||||
'buyer_name_value',
|
|
||||||
'buyer_company_name_value',
|
|
||||||
'buyer_company_name_key',
|
|
||||||
'buyer_tax_code_key',
|
|
||||||
'buyer_tax_code_value',
|
|
||||||
'buyer_address_key',
|
|
||||||
'buyer_address_value',
|
|
||||||
'buyer_mobile_key',
|
|
||||||
'buyer_mobile_value',
|
|
||||||
|
|
||||||
# money info
|
|
||||||
'VAT_amount_key',
|
|
||||||
'VAT_amount_value',
|
|
||||||
'total_key',
|
|
||||||
'total_value',
|
|
||||||
'total_in_words_key',
|
|
||||||
'total_in_words_value',
|
|
||||||
|
|
||||||
'other',
|
|
||||||
]
|
|
||||||
sampling: true # sampling window - fix long document (larger than 512 token)
|
|
||||||
|
|
||||||
#model
|
|
||||||
img_size: 224 # fixed
|
|
||||||
max_seq_length: 512 # fixed
|
|
||||||
max_num_words: 150
|
|
||||||
tokenizer_weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base" # fixed
|
|
||||||
weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base"
|
|
||||||
|
|
||||||
# opt + scheduler
|
|
||||||
batch_size: 8
|
|
||||||
epochs: 100
|
|
||||||
lr: 5.0e-6
|
|
||||||
shuffle: True
|
|
||||||
num_workers: 4
|
|
||||||
scheduler: False # False or "linear" / "cosine" / "cosine_with_restarts" / "polynomial" / "constant" / "constant_with_warmup" / "inverse_sqrt"
|
|
||||||
save_dir: workdirs/invoice/exp1
|
|
||||||
save_weight_interval: 10
|
|
||||||
eval_delay: 0
|
|
||||||
wandb: null
|
|
||||||
|
|
||||||
# inference
|
|
||||||
inference_weights: null
|
|
||||||
text_det: yolox-s-general-text-pretrain-20221226
|
|
||||||
text_reg: satrn-lite-general-pretrain-20230106
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
|||||||
|
|
||||||
debug: False
|
|
||||||
v3: False
|
|
||||||
# common
|
|
||||||
device: 'cpu' # 'cpu' / 'cuda:0' / 'cuda:1' / 'cuda'
|
|
||||||
|
|
||||||
#dataset
|
|
||||||
train_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/train
|
|
||||||
val_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss
|
|
||||||
slice_interval: 75
|
|
||||||
postprocess_type: invoice_postprocess
|
|
||||||
classes: [
|
|
||||||
'no_key',
|
|
||||||
'no_value',
|
|
||||||
'form_key',
|
|
||||||
'form_value',
|
|
||||||
'serial_key',
|
|
||||||
'serial_value',
|
|
||||||
'date_value',
|
|
||||||
|
|
||||||
'seller_company_name_key',
|
|
||||||
'seller_company_name_value',
|
|
||||||
'seller_tax_code_key',
|
|
||||||
'seller_tax_code_value',
|
|
||||||
'seller_address_value',
|
|
||||||
'seller_address_key',
|
|
||||||
'seller_tel_key',
|
|
||||||
'seller_tel_value',
|
|
||||||
|
|
||||||
'buyer_personal_name_key',
|
|
||||||
'buyer_personal_name_value',
|
|
||||||
'buyer_company_name_value',
|
|
||||||
'buyer_company_name_key',
|
|
||||||
'buyer_tax_code_key',
|
|
||||||
'buyer_tax_code_value',
|
|
||||||
'buyer_address_key',
|
|
||||||
'buyer_address_value',
|
|
||||||
'buyer_tel_key',
|
|
||||||
'buyer_tel_value',
|
|
||||||
'tax_amount_key',
|
|
||||||
'tax_amount_value',
|
|
||||||
'total_key',
|
|
||||||
'total_value',
|
|
||||||
'total_in_words_key',
|
|
||||||
'total_in_words_value',
|
|
||||||
'other'
|
|
||||||
]
|
|
||||||
|
|
||||||
sampling: true # sampling window - fix long document (larger than 512 token)
|
|
||||||
|
|
||||||
#model
|
|
||||||
img_size: 224 # fixed
|
|
||||||
max_seq_length: 512 # fixed
|
|
||||||
max_num_words: 145
|
|
||||||
tokenizer_weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base" # fixed
|
|
||||||
weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base"
|
|
||||||
|
|
||||||
# opt + scheduler
|
|
||||||
batch_size: 8
|
|
||||||
epochs: 100
|
|
||||||
lr: 5.0e-6
|
|
||||||
shuffle: True
|
|
||||||
num_workers: 4
|
|
||||||
scheduler: "linear" # False or "linear" / "cosine" / "cosine_with_restarts" / "polynomial" / "constant" / "constant_with_warmup" / "inverse_sqrt"
|
|
||||||
save_dir: workdirs/invoice/19072023
|
|
||||||
save_weight_interval: 10
|
|
||||||
eval_delay: 50
|
|
||||||
wandb: null
|
|
||||||
|
|
||||||
# inference
|
|
||||||
inference_weights: null
|
|
||||||
text_det: yolox-s-general-text-pretrain-20221226
|
|
||||||
text_reg: satrn-lite-general-pretrain-20230106
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
|||||||
|
|
||||||
debug: False
|
|
||||||
v3: False
|
|
||||||
# common
|
|
||||||
device: 'cpu' # 'cpu' / 'cuda:0' / 'cuda:1' / 'cuda'
|
|
||||||
|
|
||||||
#dataset
|
|
||||||
train_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/train
|
|
||||||
val_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss
|
|
||||||
slice_interval: 75
|
|
||||||
postprocess_type: invoice_postprocess
|
|
||||||
classes: [
|
|
||||||
'no_key',
|
|
||||||
'no_value',
|
|
||||||
'form_key',
|
|
||||||
'form_value',
|
|
||||||
'serial_key',
|
|
||||||
'serial_value',
|
|
||||||
'date_value',
|
|
||||||
|
|
||||||
'seller_company_name_key',
|
|
||||||
'seller_company_name_value',
|
|
||||||
'seller_tax_code_key',
|
|
||||||
'seller_tax_code_value',
|
|
||||||
'seller_address_value',
|
|
||||||
'seller_address_key',
|
|
||||||
'seller_tel_key',
|
|
||||||
'seller_tel_value',
|
|
||||||
|
|
||||||
'buyer_personal_name_key',
|
|
||||||
'buyer_personal_name_value',
|
|
||||||
'buyer_company_name_value',
|
|
||||||
'buyer_company_name_key',
|
|
||||||
'buyer_tax_code_key',
|
|
||||||
'buyer_tax_code_value',
|
|
||||||
'buyer_address_key',
|
|
||||||
'buyer_address_value',
|
|
||||||
'buyer_tel_key',
|
|
||||||
'buyer_tel_value',
|
|
||||||
'tax_amount_key',
|
|
||||||
'tax_amount_value',
|
|
||||||
'total_key',
|
|
||||||
'total_value',
|
|
||||||
'total_in_words_key',
|
|
||||||
'total_in_words_value',
|
|
||||||
'other'
|
|
||||||
]
|
|
||||||
|
|
||||||
sampling: true # sampling window - fix long document (larger than 512 token)
|
|
||||||
|
|
||||||
#model
|
|
||||||
img_size: 224 # fixed
|
|
||||||
max_seq_length: 512 # fixed
|
|
||||||
max_num_words: 145
|
|
||||||
tokenizer_weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base" # fixed
|
|
||||||
weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base"
|
|
||||||
|
|
||||||
# opt + scheduler
|
|
||||||
batch_size: 8
|
|
||||||
epochs: 100
|
|
||||||
lr: 5.0e-6
|
|
||||||
shuffle: True
|
|
||||||
num_workers: 4
|
|
||||||
scheduler: "cosine" # False or "linear" / "cosine" / "cosine_with_restarts" / "polynomial" / "constant" / "constant_with_warmup" / "inverse_sqrt"
|
|
||||||
save_dir: workdirs/invoice/26052023
|
|
||||||
save_weight_interval: 10
|
|
||||||
eval_delay: 50
|
|
||||||
wandb: null
|
|
||||||
|
|
||||||
# inference
|
|
||||||
inference_weights: null
|
|
||||||
text_det: yolox-s-general-text-pretrain-20221226
|
|
||||||
text_reg: satrn-lite-general-pretrain-20230106
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
|||||||
|
|
||||||
debug: False
|
|
||||||
v3: False
|
|
||||||
# common
|
|
||||||
device: 'cpu' # 'cpu' / 'cuda:0' / 'cuda:1' / 'cuda'
|
|
||||||
|
|
||||||
#dataset
|
|
||||||
train_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/train
|
|
||||||
val_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/test_ss
|
|
||||||
slice_interval: 75
|
|
||||||
postprocess_type: invoice_postprocess
|
|
||||||
classes: [
|
|
||||||
'no_key',
|
|
||||||
'no_value',
|
|
||||||
'form_key',
|
|
||||||
'form_value',
|
|
||||||
'serial_key',
|
|
||||||
'serial_value',
|
|
||||||
'date_value',
|
|
||||||
|
|
||||||
'seller_company_name_key',
|
|
||||||
'seller_company_name_value',
|
|
||||||
'seller_tax_code_key',
|
|
||||||
'seller_tax_code_value',
|
|
||||||
'seller_address_value',
|
|
||||||
'seller_address_key',
|
|
||||||
'seller_tel_key',
|
|
||||||
'seller_tel_value',
|
|
||||||
|
|
||||||
'buyer_personal_name_key',
|
|
||||||
'buyer_personal_name_value',
|
|
||||||
'buyer_company_name_value',
|
|
||||||
'buyer_company_name_key',
|
|
||||||
'buyer_tax_code_key',
|
|
||||||
'buyer_tax_code_value',
|
|
||||||
'buyer_address_key',
|
|
||||||
'buyer_address_value',
|
|
||||||
'buyer_tel_key',
|
|
||||||
'buyer_tel_value',
|
|
||||||
'tax_amount_key',
|
|
||||||
'tax_amount_value',
|
|
||||||
'total_key',
|
|
||||||
'total_value',
|
|
||||||
'total_in_words_key',
|
|
||||||
'total_in_words_value',
|
|
||||||
'other'
|
|
||||||
]
|
|
||||||
|
|
||||||
sampling: true # sampling window - fix long document (larger than 512 token)
|
|
||||||
|
|
||||||
#model
|
|
||||||
img_size: 224 # fixed
|
|
||||||
max_seq_length: 512 # fixed
|
|
||||||
max_num_words: 150
|
|
||||||
tokenizer_weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base" # fixed
|
|
||||||
weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/vnpt_exp_4/last"
|
|
||||||
|
|
||||||
# opt + scheduler
|
|
||||||
batch_size: 8
|
|
||||||
epochs: 100
|
|
||||||
lr: 1.0e-5
|
|
||||||
shuffle: True
|
|
||||||
num_workers: 4
|
|
||||||
scheduler: "cosine" # False or "linear" / "cosine" / "cosine_with_restarts" / "polynomial" / "constant" / "constant_with_warmup" / "inverse_sqrt"
|
|
||||||
save_dir: workdirs/invoice/add_sl_hcm
|
|
||||||
save_weight_interval: 1
|
|
||||||
eval_delay: 1
|
|
||||||
wandb: null
|
|
||||||
|
|
||||||
# inference
|
|
||||||
inference_weights: null
|
|
||||||
text_det: yolox-s-general-text-pretrain-20221226
|
|
||||||
text_reg: satrn-lite-general-pretrain-20230106
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
|
|
||||||
debug: False
|
|
||||||
v3: False
|
|
||||||
|
|
||||||
# common
|
|
||||||
device: 'cpu' # 'cpu' / 'cuda:0' / 'cuda:1' / 'cuda'
|
|
||||||
|
|
||||||
#dataset
|
|
||||||
train_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/train
|
|
||||||
val_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test
|
|
||||||
slice_interval: 75
|
|
||||||
postprocess_type: receipt_postprocess
|
|
||||||
|
|
||||||
classes: [
|
|
||||||
"seller_company_name_value",
|
|
||||||
"no_value",
|
|
||||||
"date_value",
|
|
||||||
"total_key",
|
|
||||||
"total_value",
|
|
||||||
"other"
|
|
||||||
]
|
|
||||||
sampling: true # sampling window - fix long document (larger than 512 token)
|
|
||||||
|
|
||||||
#model
|
|
||||||
img_size: 224 # fixed
|
|
||||||
max_seq_length: 512 # fixed
|
|
||||||
max_num_words: 150
|
|
||||||
tokenizer_weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base" # fixed
|
|
||||||
weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base"
|
|
||||||
|
|
||||||
# opt + scheduler
|
|
||||||
batch_size: 8
|
|
||||||
epochs: 100
|
|
||||||
lr: 5.0e-6
|
|
||||||
scheduler: False
|
|
||||||
shuffle: True
|
|
||||||
num_workers: 4
|
|
||||||
save_dir: workdirs/receipt/13062023
|
|
||||||
save_weight_interval: 10
|
|
||||||
eval_delay: 0
|
|
||||||
wandb: null
|
|
||||||
|
|
||||||
# inference
|
|
||||||
inference_weights: null
|
|
||||||
text_det: yolox-s-general-text-pretrain-20221226
|
|
||||||
text_reg: satrn-lite-general-pretrain-20230106
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
|
|
||||||
debug: False
|
|
||||||
v3: False
|
|
||||||
|
|
||||||
# common
|
|
||||||
device: 'cpu' # 'cpu' / 'cuda:0' / 'cuda:1' / 'cuda'
|
|
||||||
|
|
||||||
#dataset
|
|
||||||
train_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/train
|
|
||||||
val_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/processed/test
|
|
||||||
slice_interval: 75
|
|
||||||
postprocess_type: receipt_postprocess
|
|
||||||
|
|
||||||
classes: [
|
|
||||||
"seller_company_name_value",
|
|
||||||
"no_value",
|
|
||||||
"date_value",
|
|
||||||
"total_key",
|
|
||||||
"total_value",
|
|
||||||
"other"
|
|
||||||
]
|
|
||||||
sampling: true # sampling window - fix long document (larger than 512 token)
|
|
||||||
|
|
||||||
#model
|
|
||||||
img_size: 224 # fixed
|
|
||||||
max_seq_length: 512 # fixed
|
|
||||||
max_num_words: 150
|
|
||||||
tokenizer_weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base" # fixed
|
|
||||||
weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/receipt/13062023_4/last"
|
|
||||||
|
|
||||||
# opt + scheduler
|
|
||||||
batch_size: 8
|
|
||||||
epochs: 30
|
|
||||||
lr: 3.0e-6
|
|
||||||
scheduler: False
|
|
||||||
shuffle: True
|
|
||||||
num_workers: 4
|
|
||||||
save_dir: workdirs/receipt/13062023
|
|
||||||
save_weight_interval: 10
|
|
||||||
eval_delay: 0
|
|
||||||
wandb: null
|
|
||||||
|
|
||||||
# inference
|
|
||||||
inference_weights: null
|
|
||||||
text_det: yolox-s-general-text-pretrain-20221226
|
|
||||||
text_reg: satrn-lite-general-pretrain-20230106
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
|
|
||||||
debug: False
|
|
||||||
v3: False
|
|
||||||
|
|
||||||
# common
|
|
||||||
device: 'cpu' # 'cpu' / 'cuda:0' / 'cuda:1' / 'cuda'
|
|
||||||
|
|
||||||
#dataset
|
|
||||||
train_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/train
|
|
||||||
val_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/test
|
|
||||||
slice_interval: 75
|
|
||||||
postprocess_type: receipt_postprocess
|
|
||||||
|
|
||||||
classes: [
|
|
||||||
"Seller_company_name_value",
|
|
||||||
"ID_value",
|
|
||||||
"Date_value",
|
|
||||||
"Total_key",
|
|
||||||
"Total_value",
|
|
||||||
"Other"
|
|
||||||
]
|
|
||||||
sampling: true # sampling window - fix long document (larger than 512 token)
|
|
||||||
|
|
||||||
#model
|
|
||||||
img_size: 224 # fixed
|
|
||||||
max_seq_length: 512 # fixed
|
|
||||||
max_num_words: 150
|
|
||||||
tokenizer_weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base" # fixed
|
|
||||||
weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base"
|
|
||||||
|
|
||||||
# opt + scheduler
|
|
||||||
batch_size: 8
|
|
||||||
epochs: 100
|
|
||||||
lr: 9.0e-6
|
|
||||||
scheduler: "linear"
|
|
||||||
shuffle: True
|
|
||||||
num_workers: 4
|
|
||||||
save_dir: workdirs/invoice/exp1
|
|
||||||
save_weight_interval: 10
|
|
||||||
eval_delay: 50
|
|
||||||
wandb: null
|
|
||||||
|
|
||||||
# inference
|
|
||||||
inference_weights: null
|
|
||||||
text_det: yolox-s-general-text-pretrain-20221226
|
|
||||||
text_reg: satrn-lite-general-pretrain-20230106
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
|
|
||||||
debug: False
|
|
||||||
v3: False
|
|
||||||
|
|
||||||
# common
|
|
||||||
device: 'cpu' # 'cpu' / 'cuda:0' / 'cuda:1' / 'cuda'
|
|
||||||
|
|
||||||
#dataset
|
|
||||||
train_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/train
|
|
||||||
val_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Receipt/test
|
|
||||||
slice_interval: 75
|
|
||||||
postprocess_type: receipt_postprocess
|
|
||||||
|
|
||||||
classes: [
|
|
||||||
"Store_name_value",
|
|
||||||
"id",
|
|
||||||
"Date_value",
|
|
||||||
"Total_key",
|
|
||||||
"Total_value",
|
|
||||||
"Others"
|
|
||||||
]
|
|
||||||
sampling: true # sampling window - fix long document (larger than 512 token)
|
|
||||||
|
|
||||||
#model
|
|
||||||
img_size: 224 # fixed
|
|
||||||
max_seq_length: 512 # fixed
|
|
||||||
max_num_words: 150
|
|
||||||
tokenizer_weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base" # fixed
|
|
||||||
weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base"
|
|
||||||
|
|
||||||
# opt + scheduler
|
|
||||||
batch_size: 8
|
|
||||||
epochs: 100
|
|
||||||
lr: 9.0e-6
|
|
||||||
scheduler: "linear"
|
|
||||||
shuffle: True
|
|
||||||
num_workers: 4
|
|
||||||
save_dir: workdirs/invoice/exp1
|
|
||||||
save_weight_interval: 10
|
|
||||||
eval_delay: 50
|
|
||||||
wandb: null
|
|
||||||
|
|
||||||
# inference
|
|
||||||
inference_weights: null
|
|
||||||
text_det: yolox-s-general-text-pretrain-20221226
|
|
||||||
text_reg: satrn-lite-general-pretrain-20230106
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
debug: False
|
|
||||||
v3: False
|
|
||||||
scheduler: False
|
|
||||||
# common
|
|
||||||
device: 'cpu' # 'cpu' / 'cuda:0' / 'cuda:1' / 'cuda'
|
|
||||||
|
|
||||||
#dataset
|
|
||||||
train_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/WildReceipt/v1/train
|
|
||||||
val_dir: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/WildReceipt/v1/test
|
|
||||||
slice_interval: 75
|
|
||||||
postprocess_type: receipt_postprocess
|
|
||||||
|
|
||||||
classes: [
|
|
||||||
"Store_name_value",
|
|
||||||
"Date_value",
|
|
||||||
"Total_key",
|
|
||||||
"Total_value",
|
|
||||||
"Others"
|
|
||||||
]
|
|
||||||
sampling: True # sampling window - fix long document (larger than 512 token)
|
|
||||||
|
|
||||||
#model
|
|
||||||
img_size: 224 # fixed
|
|
||||||
max_seq_length: 512 # fixed
|
|
||||||
max_num_words: 150
|
|
||||||
|
|
||||||
# tokenizer_weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/layoutlmv3-base" # fixed
|
|
||||||
# weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/layoutlmv3-base"
|
|
||||||
tokenizer_weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base" # fixed
|
|
||||||
weights: "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/microsoft/microsoft/layoutxlm-base"
|
|
||||||
|
|
||||||
# opt + scheduler
|
|
||||||
batch_size: 8
|
|
||||||
epochs: 100
|
|
||||||
lr: 5.0e-6
|
|
||||||
shuffle: True
|
|
||||||
num_workers: 4
|
|
||||||
save_dir: workdirs/invoice/exp1
|
|
||||||
save_weight_interval: 10
|
|
||||||
eval_delay: 0
|
|
||||||
wandb: null
|
|
||||||
|
|
||||||
# inference
|
|
||||||
inference_weights: null
|
|
||||||
text_det: yolox-s-general-text-pretrain-20221226
|
|
||||||
text_reg: satrn-lite-general-pretrain-20230106
|
|
||||||
|
|
@ -1,314 +0,0 @@
|
|||||||
import logging
|
|
||||||
import os
|
|
||||||
import pickle
|
|
||||||
import random
|
|
||||||
from copy import deepcopy
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import cv2
|
|
||||||
import pandas as pd
|
|
||||||
import torch
|
|
||||||
from datasets import (Array2D, Array3D, ClassLabel, Dataset, Features,
|
|
||||||
Sequence, Value, concatenate_datasets)
|
|
||||||
from easydict import EasyDict
|
|
||||||
from PIL import Image
|
|
||||||
from tqdm import tqdm
|
|
||||||
from sdsvkie.utils.io_file import read_txt
|
|
||||||
|
|
||||||
from sdsvkie.utils import normalize_box, visualize_kie
|
|
||||||
from sdsvkie.utils.augmentation import perturbate_character, sampling_data
|
|
||||||
from sdsvkie.utils.word_formation import sliding_windows, sort_words
|
|
||||||
import glob
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
|
||||||
|
|
||||||
|
|
||||||
IMG_EXTENSION = [".jpg", ".jpeg", ".png"]
|
|
||||||
|
|
||||||
class BaseDataset:
|
|
||||||
def __init__(self, cfg):
|
|
||||||
|
|
||||||
self.cfg = cfg
|
|
||||||
self.feature_format = Features(
|
|
||||||
{
|
|
||||||
"image": Array3D(
|
|
||||||
dtype="int64", shape=(3, self.cfg.img_size, self.cfg.img_size)
|
|
||||||
),
|
|
||||||
"input_ids": Sequence(feature=Value(dtype="int64")),
|
|
||||||
"attention_mask": Sequence(Value(dtype="int64")),
|
|
||||||
"bbox": Array2D(dtype="int64", shape=(self.cfg.max_seq_length, 4)),
|
|
||||||
"labels": Sequence(ClassLabel(names=self.cfg.classes)),
|
|
||||||
}
|
|
||||||
) if not self.cfg.v3 else \
|
|
||||||
Features(
|
|
||||||
{
|
|
||||||
"pixel_values": Array3D(
|
|
||||||
dtype="float32", shape=(3, self.cfg.img_size, self.cfg.img_size)
|
|
||||||
),
|
|
||||||
"input_ids": Sequence(feature=Value(dtype="int64")),
|
|
||||||
"attention_mask": Sequence(Value(dtype="int64")),
|
|
||||||
"bbox": Array2D(dtype="int64", shape=(self.cfg.max_seq_length, 4)),
|
|
||||||
"labels": Sequence(ClassLabel(names=self.cfg.classes)),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info("Feature format: {}".format(self.feature_format.keys()))
|
|
||||||
|
|
||||||
|
|
||||||
def _build_df(self, data_dir):
|
|
||||||
"""Build dataframe from data directory
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data_dir (str): structure data folder
|
|
||||||
- data_dir
|
|
||||||
- img1.jpg
|
|
||||||
- img1.txt
|
|
||||||
- ...
|
|
||||||
"""
|
|
||||||
data_dir = Path(data_dir)
|
|
||||||
|
|
||||||
# img_paths = glob.glob("*") + glob.glob("*/*")
|
|
||||||
|
|
||||||
img_paths = [
|
|
||||||
path for path in list(data_dir.rglob("*"))
|
|
||||||
|
|
||||||
if ".txt" not in str(path) and path.with_suffix(".txt").exists() and path.suffix.lower() in IMG_EXTENSION
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
label_paths = [str(path.with_suffix(".txt")) for path in img_paths]
|
|
||||||
|
|
||||||
|
|
||||||
img_paths = [str(path) for path in img_paths]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
assert len(label_paths) == len(img_paths)
|
|
||||||
# remove empty txt
|
|
||||||
ids = [id for id in range(len(label_paths)) if len(read_txt(label_paths[id])) > 0]
|
|
||||||
label_paths = [label_paths[id] for id in ids]
|
|
||||||
img_paths = [img_paths[id] for id in ids]
|
|
||||||
|
|
||||||
dataframe = pd.DataFrame.from_dict(
|
|
||||||
{"image_path": img_paths, "label": label_paths}
|
|
||||||
)
|
|
||||||
return dataframe
|
|
||||||
|
|
||||||
def build_dataloader_from_dataset(
|
|
||||||
self,
|
|
||||||
dataset,
|
|
||||||
processor,
|
|
||||||
device,
|
|
||||||
batch_size,
|
|
||||||
shuffle=True,
|
|
||||||
num_workers=4,
|
|
||||||
cache_file="./cache.pkl",
|
|
||||||
use_sampling=False,
|
|
||||||
):
|
|
||||||
|
|
||||||
if not os.path.exists(cache_file):
|
|
||||||
self._build_cache(
|
|
||||||
dataset,
|
|
||||||
processor,
|
|
||||||
cache_file=cache_file,
|
|
||||||
max_seq_length=self.cfg.max_seq_length,
|
|
||||||
)
|
|
||||||
cache = self._load_cache(cache_file)
|
|
||||||
dataset = dataset.map(
|
|
||||||
self._prepare_data,
|
|
||||||
fn_kwargs={"cache": cache, "sampling": use_sampling},
|
|
||||||
remove_columns=dataset.column_names,
|
|
||||||
features=self.feature_format,
|
|
||||||
batched=False,
|
|
||||||
batch_size=self.cfg.batch_size,
|
|
||||||
)
|
|
||||||
|
|
||||||
dataset.set_format(type="torch", device=device)
|
|
||||||
dataloader = torch.utils.data.DataLoader(
|
|
||||||
dataset, batch_size=batch_size, shuffle=shuffle, num_workers=num_workers
|
|
||||||
)
|
|
||||||
return dataloader
|
|
||||||
|
|
||||||
def build_dataloader_from_dir(
|
|
||||||
self,
|
|
||||||
data_dir,
|
|
||||||
processor,
|
|
||||||
device,
|
|
||||||
batch_size,
|
|
||||||
shuffle=True,
|
|
||||||
num_workers=4,
|
|
||||||
cache_file="./cache.pkl",
|
|
||||||
use_sampling=False,
|
|
||||||
):
|
|
||||||
|
|
||||||
dataset = self._build_dataset(data_dir)
|
|
||||||
dataloader = self.build_dataloader_from_dataset(
|
|
||||||
dataset,
|
|
||||||
processor,
|
|
||||||
device,
|
|
||||||
batch_size,
|
|
||||||
shuffle,
|
|
||||||
num_workers,
|
|
||||||
cache_file,
|
|
||||||
use_sampling,
|
|
||||||
)
|
|
||||||
return dataloader
|
|
||||||
|
|
||||||
def _build_dataset(self, data_dir):
|
|
||||||
df = self._build_df(data_dir)
|
|
||||||
dataset = Dataset.from_pandas(df)
|
|
||||||
logger.info(f"Load example for {data_dir}")
|
|
||||||
dataset = dataset.map(lambda example: self._load_example_info(example))
|
|
||||||
return dataset
|
|
||||||
|
|
||||||
def _build_cache(self, dataset, processor, max_seq_length, cache_file=""):
|
|
||||||
logger.info(f"Caching {cache_file}...")
|
|
||||||
cache = {}
|
|
||||||
for examples in tqdm(dataset):
|
|
||||||
encoding_inputs = self._cache_feature(examples, processor, max_seq_length)
|
|
||||||
cache[examples["image_path"]] = encoding_inputs
|
|
||||||
|
|
||||||
with open(cache_file, "wb") as f:
|
|
||||||
pickle.dump(cache, f)
|
|
||||||
|
|
||||||
def _load_cache(self, cache_file):
|
|
||||||
with open(cache_file, "rb") as f:
|
|
||||||
cache = pickle.load(f)
|
|
||||||
return cache
|
|
||||||
|
|
||||||
def _prepare_data(self, example, cache, sampling):
|
|
||||||
encoded_inputs_windows = cache[example["image_path"]]
|
|
||||||
if len(encoded_inputs_windows) == 0:
|
|
||||||
raise Exception("Empty encoded_inputs_windows")
|
|
||||||
if sampling:
|
|
||||||
if random.random() < 0.6:
|
|
||||||
encoded_inputs = encoded_inputs_windows[-1]
|
|
||||||
else:
|
|
||||||
encoded_inputs = random.choice(encoded_inputs_windows)
|
|
||||||
else:
|
|
||||||
encoded_inputs = encoded_inputs_windows[-1]
|
|
||||||
for k, v in encoded_inputs.items():
|
|
||||||
if k in ["image", "pixel_values"]:
|
|
||||||
encoded_inputs[k] = encoded_inputs[k][0]
|
|
||||||
return encoded_inputs
|
|
||||||
|
|
||||||
def _cache_feature(self, example, processor, max_seq_length=512):
|
|
||||||
"""Sampling (optional) + apply LayoutLMProcessor
|
|
||||||
|
|
||||||
Args:
|
|
||||||
examples (dict): dict {'image_path', 'words', 'bbox', 'word_labels'}
|
|
||||||
max_seq_length (int, optional): _description_. Defaults to 512.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list[dict]: list encoding inputs
|
|
||||||
"""
|
|
||||||
|
|
||||||
image = Image.open(example["image_path"]).convert("RGB")
|
|
||||||
batch_words = example["words"]
|
|
||||||
batch_boxes = example["bbox"]
|
|
||||||
batch_labels = example["word_labels"]
|
|
||||||
|
|
||||||
window_size = self.cfg.max_num_words
|
|
||||||
slice_interval = self.cfg.slice_interval
|
|
||||||
|
|
||||||
word_windows = sliding_windows(batch_words, window_size, slice_interval)
|
|
||||||
box_windows = sliding_windows(batch_boxes, window_size, slice_interval)
|
|
||||||
label_windows = sliding_windows(batch_labels, window_size, slice_interval)
|
|
||||||
|
|
||||||
encoded_inputs = []
|
|
||||||
for words, boxes, labels in zip(word_windows, box_windows, label_windows):
|
|
||||||
# Process examples
|
|
||||||
encoded_input = processor(
|
|
||||||
image,
|
|
||||||
padding="max_length",
|
|
||||||
truncation=True,
|
|
||||||
text=words,
|
|
||||||
boxes=boxes,
|
|
||||||
word_labels=labels,
|
|
||||||
max_length=max_seq_length,
|
|
||||||
)
|
|
||||||
|
|
||||||
encoded_inputs.append(encoded_input)
|
|
||||||
|
|
||||||
# full page
|
|
||||||
encoded_input = processor(
|
|
||||||
image,
|
|
||||||
padding="max_length",
|
|
||||||
truncation=True,
|
|
||||||
text=batch_words,
|
|
||||||
boxes=batch_boxes,
|
|
||||||
word_labels=batch_labels,
|
|
||||||
max_length=max_seq_length,
|
|
||||||
)
|
|
||||||
encoded_inputs.append(encoded_input)
|
|
||||||
|
|
||||||
return encoded_inputs
|
|
||||||
|
|
||||||
def _load_example_info(self, example, aug_prob=0.0):
|
|
||||||
"""_summary_
|
|
||||||
|
|
||||||
Args:
|
|
||||||
example (_type_): _description_
|
|
||||||
aug_prob (float, optional): _description_. Defaults to 0.0.
|
|
||||||
"""
|
|
||||||
|
|
||||||
image_path = example["image_path"]
|
|
||||||
label_path = example["label"]
|
|
||||||
assert os.path.exists(image_path)
|
|
||||||
assert os.path.exists(label_path)
|
|
||||||
# try:
|
|
||||||
image = cv2.imread(image_path)
|
|
||||||
h, w, _ = image.shape
|
|
||||||
with open(label_path) as f:
|
|
||||||
lines = [line.replace("\n", "").replace("\r", "") for line in f.readlines()]
|
|
||||||
|
|
||||||
words, boxes, labels = [], [], []
|
|
||||||
# print(label_path)
|
|
||||||
for i, line in enumerate(lines):
|
|
||||||
x1, y1, x2, y2, text, label = line.split("\t")
|
|
||||||
box = [int(x1), int(y1), int(x2), int(y2)]
|
|
||||||
if text != " ":
|
|
||||||
words.append(text)
|
|
||||||
boxes.append(box)
|
|
||||||
labels.append(label)
|
|
||||||
|
|
||||||
if aug_prob > 0:
|
|
||||||
p_words = perturbate_character(words, aug_prob)
|
|
||||||
logging.info("{} - {}".format(len(p_words), len(words)))
|
|
||||||
|
|
||||||
# custom for sort boxes
|
|
||||||
items = {
|
|
||||||
'boxes': boxes,
|
|
||||||
'texts': words,
|
|
||||||
'labels': labels
|
|
||||||
}
|
|
||||||
# boxes, words, labels = sort_words(boxes, words, labels)
|
|
||||||
sorted_items = sort_words(items)
|
|
||||||
boxes, words, labels = sorted_items['boxes'], sorted_items['texts'], sorted_items['labels']
|
|
||||||
|
|
||||||
# print(image_path)
|
|
||||||
# print(image_path)
|
|
||||||
labels = [self.cfg.classes.index(label) for label in labels]
|
|
||||||
if self.cfg.debug:
|
|
||||||
visualize_kie(
|
|
||||||
img=image,
|
|
||||||
boxes=boxes,
|
|
||||||
pred_labels=labels,
|
|
||||||
outdir="wordirs/debug_{}".format(
|
|
||||||
"val" if "train" not in image_path else "train"
|
|
||||||
),
|
|
||||||
image_name=os.path.basename(image_path),
|
|
||||||
)
|
|
||||||
|
|
||||||
boxes = [normalize_box(box, width=w, height=h) for box in boxes]
|
|
||||||
|
|
||||||
example["words"] = words
|
|
||||||
example["bbox"] = boxes # TODO: Check this
|
|
||||||
example["word_labels"] = labels
|
|
||||||
# except Exception as err:
|
|
||||||
# logger.info(f"Exception: {err} at image path: {example['image_path']}")
|
|
||||||
# example["words"] = []
|
|
||||||
# example["bbox"] = [] # TODO: Check this
|
|
||||||
# example["word_labels"] = []
|
|
||||||
return example
|
|
@ -1 +0,0 @@
|
|||||||
from .predictor import Predictor
|
|
@ -1,457 +0,0 @@
|
|||||||
import logging
|
|
||||||
import time
|
|
||||||
|
|
||||||
import cv2
|
|
||||||
import numpy as np
|
|
||||||
from sdsvkie.utils.word_formation import merge_boxes
|
|
||||||
import torch
|
|
||||||
from easydict import EasyDict
|
|
||||||
from PIL import Image
|
|
||||||
|
|
||||||
from sdsvkie.cfg import load_cfg
|
|
||||||
# from sdsvkie.models.layoutlm import LayoutLM
|
|
||||||
from sdsvkie.models.layoutlmv2 import LayoutLMv2
|
|
||||||
from sdsvkie.models.ocr import OCREngine
|
|
||||||
from sdsvkie.utils import invoice_postprocess # invoice
|
|
||||||
from sdsvkie.utils import receipt_postprocess # receipt
|
|
||||||
from sdsvkie.utils import POSTPROCESS_FUNC
|
|
||||||
from sdsvkie.utils import (Word, construct_word_groups_to_kie_label,
|
|
||||||
normalize_box, sliding_windows, sort_words,
|
|
||||||
unnormalize_box, words_to_lines,
|
|
||||||
pdf_to_image)
|
|
||||||
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class Predictor:
|
|
||||||
def __init__(self, cfg, **kwargs) -> None:
|
|
||||||
"""
|
|
||||||
|
|
||||||
Args:
|
|
||||||
cfg (dict / str): config
|
|
||||||
**kwargs: device=..., weights=..., text_det=..., text_reg=...
|
|
||||||
"""
|
|
||||||
|
|
||||||
if isinstance(cfg, str):
|
|
||||||
cfg = load_cfg(cfg, kwargs)
|
|
||||||
self.cfg = EasyDict(cfg)
|
|
||||||
print(self.cfg)
|
|
||||||
|
|
||||||
self.model = None
|
|
||||||
self.processor = None
|
|
||||||
self.ocr_engine = None
|
|
||||||
self.classes = self.cfg["classes"]
|
|
||||||
|
|
||||||
self.max_num_words = self.cfg.max_num_words
|
|
||||||
self.model = None
|
|
||||||
self.processor = None
|
|
||||||
self.ocr_engine = None
|
|
||||||
|
|
||||||
def _init_predictor(self, model=None, proccessor=None, ocr_engine=None):
|
|
||||||
|
|
||||||
if self.cfg.device != "cpu" and not torch.cuda.is_available():
|
|
||||||
logger.info("Can not found cuda, training with CPU!!!")
|
|
||||||
self.cfg.device = "cpu"
|
|
||||||
|
|
||||||
if self.cfg["inference_weights"] is None:
|
|
||||||
logger.info(
|
|
||||||
"Not yet set value for inference weights, use weights instead!!!"
|
|
||||||
)
|
|
||||||
if model is None:
|
|
||||||
self.model = LayoutLMv2._load_model(self.cfg)
|
|
||||||
if proccessor is None:
|
|
||||||
self.processor = LayoutLMv2._load_processor(self.cfg)
|
|
||||||
|
|
||||||
if ocr_engine is None:
|
|
||||||
self.ocr_engine = OCREngine(
|
|
||||||
text_det=self.cfg["text_det"],
|
|
||||||
text_recog=self.cfg["text_reg"],
|
|
||||||
device=self.cfg["device"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def __call__(self, input , ocr_output=None, return_raw=False):
|
|
||||||
"""Inference KIE -
|
|
||||||
Pipeline: Img -> OCR -> box + text (word-level) -> sort by x, y-axis -> LayoutLM -> Word formation -> result
|
|
||||||
|
|
||||||
Args:
|
|
||||||
input (np.ndarray / str / pdf path): BGR image (cv2)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(dict): {
|
|
||||||
'kie_raw_output':
|
|
||||||
'kie_post_output':
|
|
||||||
'end2end_results': (dict) : {kie_label : value}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
if self.model is None:
|
|
||||||
self._init_predictor()
|
|
||||||
#check single or multi images
|
|
||||||
if isinstance(input, np.ndarray):
|
|
||||||
final_out= self.predict_single_image(input, ocr_output=ocr_output, return_raw=return_raw)
|
|
||||||
elif isinstance(input, list):
|
|
||||||
items = [self.predict_single_image(im, ocr_output=ocr_output, return_raw=return_raw) for im in input]
|
|
||||||
final_out = self.aggregate_outputs(items)
|
|
||||||
else: #pdf
|
|
||||||
import time
|
|
||||||
t1 = time.time()
|
|
||||||
imgs = pdf_to_image(input)
|
|
||||||
print("1. pdf2img: ", round(time.time() - t1, 4))
|
|
||||||
t2 = time.time()
|
|
||||||
items = [self.predict_single_image(im, ocr_output=ocr_output, return_raw=return_raw) for im in imgs]
|
|
||||||
final_out = self.aggregate_outputs(items)
|
|
||||||
print("2. kie: ", round(time.time() - t2, 4))
|
|
||||||
print(f"3. full pipeline for {len(imgs)} pages: {round(time.time() - t1, 4)}")
|
|
||||||
return final_out
|
|
||||||
|
|
||||||
def predict_single_image(self, img, ocr_output=None, return_raw=False):
|
|
||||||
|
|
||||||
if ocr_output is None:
|
|
||||||
ocr_output = self.ocr_engine(img, extend_ratio=[0.1, 0.3], ratio_thr=5) # solve long box
|
|
||||||
# ocr_output = self.ocr_engine(img)
|
|
||||||
kie_input = self.prepare_inputs(img, ocr_output)
|
|
||||||
kie_output = self.predict(kie_input)
|
|
||||||
kie_post_output = self.postprocessing(kie_output)
|
|
||||||
formated_output = self.format_output(kie_post_output)
|
|
||||||
output = {
|
|
||||||
"kie_raw_output": kie_output if return_raw else None, # raw output from layoutlm model
|
|
||||||
"kie_post_output": kie_post_output if return_raw else None, # wordgroup
|
|
||||||
"end2end_results": formated_output, # field_key + field_value
|
|
||||||
}
|
|
||||||
return output
|
|
||||||
|
|
||||||
def predict(self, inputs: dict):
|
|
||||||
"""predict
|
|
||||||
|
|
||||||
Args:
|
|
||||||
inputs (dict): format
|
|
||||||
{
|
|
||||||
'image": PIL RGB,
|
|
||||||
'boxes': list[],
|
|
||||||
'texts'
|
|
||||||
}
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list[Word]: list of Word object
|
|
||||||
"""
|
|
||||||
window_size = self.cfg.max_num_words
|
|
||||||
slice_interval = self.cfg.slice_interval
|
|
||||||
|
|
||||||
image, batch_boxes, batch_words = (
|
|
||||||
inputs["img"],
|
|
||||||
inputs["boxes"],
|
|
||||||
inputs["texts"],
|
|
||||||
)
|
|
||||||
results = []
|
|
||||||
non_norm_boxes = inputs['non_norm_boxes']
|
|
||||||
if len(batch_boxes) == 0:
|
|
||||||
logger.info("Not found any words in image!!! Continue...")
|
|
||||||
return results
|
|
||||||
|
|
||||||
text_windows = sliding_windows(batch_words, window_size, slice_interval)
|
|
||||||
box_windows = sliding_windows(batch_boxes, window_size, slice_interval)
|
|
||||||
# print([len(t) for t in text_windows])
|
|
||||||
|
|
||||||
out_boxes_windows = []
|
|
||||||
# out_labels_windows = []
|
|
||||||
out_logits_windows = []
|
|
||||||
|
|
||||||
for i in range(len(text_windows)):
|
|
||||||
words = text_windows[i] # len: MAX_N_WORDS
|
|
||||||
boxes = box_windows[i]
|
|
||||||
|
|
||||||
# Preprocess
|
|
||||||
dummy_word_labels = [0] * len(words)
|
|
||||||
encoding = self.processor(
|
|
||||||
image,
|
|
||||||
text=words,
|
|
||||||
boxes=boxes,
|
|
||||||
word_labels=dummy_word_labels,
|
|
||||||
return_tensors="pt",
|
|
||||||
padding="max_length",
|
|
||||||
truncation=True,
|
|
||||||
max_length=self.cfg.max_seq_length,
|
|
||||||
)
|
|
||||||
|
|
||||||
label_ = encoding.pop('labels')
|
|
||||||
# Run model
|
|
||||||
for k, v in encoding.items():
|
|
||||||
encoding[k] = v.to(self.cfg.device)
|
|
||||||
with torch.no_grad():
|
|
||||||
output = self.model(**encoding)
|
|
||||||
|
|
||||||
|
|
||||||
logits = output.logits.squeeze() # seq_len * classes
|
|
||||||
predictions = output.logits.argmax(-1).squeeze().tolist()
|
|
||||||
token_boxes = encoding.bbox.squeeze().tolist()
|
|
||||||
|
|
||||||
# Postprocess
|
|
||||||
# is_subword = (encoding["labels"] == -100).detach().cpu()[0]
|
|
||||||
is_subword = (label_ == -100).detach().cpu()[0]
|
|
||||||
logit_predictions = logits[torch.logical_not(is_subword), :]
|
|
||||||
true_boxes = torch.Tensor(
|
|
||||||
[
|
|
||||||
unnormalize_box(box, image.size[0], image.size[1])
|
|
||||||
for idx, box in enumerate(token_boxes)
|
|
||||||
if not is_subword[idx]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
# print("logit shape: ", logit_predictions.shape)
|
|
||||||
# print("box shape: ", true_boxes.shape)
|
|
||||||
# true_boxes = torch.Tensor(
|
|
||||||
# [
|
|
||||||
# unnormalize_box(box, image.size[0], image.size[1])
|
|
||||||
# for idx, box in enumerate(boxes)
|
|
||||||
# ]
|
|
||||||
# )
|
|
||||||
out_boxes_windows.append(true_boxes)
|
|
||||||
out_logits_windows.append(logit_predictions)
|
|
||||||
|
|
||||||
# merge output by average logits between overlap window
|
|
||||||
merged_out_boxes = out_boxes_windows[0]
|
|
||||||
merged_out_logit = out_logits_windows[0]
|
|
||||||
overlap = window_size - slice_interval
|
|
||||||
for i in range(1, len(out_boxes_windows)):
|
|
||||||
if overlap != 0:
|
|
||||||
prev_overlap_logits = merged_out_logit[-overlap:, :]
|
|
||||||
curr_overlap_logits = out_logits_windows[i][:overlap, :]
|
|
||||||
avg_overlap_logits = (
|
|
||||||
prev_overlap_logits + curr_overlap_logits
|
|
||||||
) / 2
|
|
||||||
curr_logits = torch.cat(
|
|
||||||
[avg_overlap_logits, out_logits_windows[i][overlap:, :]], dim=0
|
|
||||||
)
|
|
||||||
merged_out_logit = torch.cat(
|
|
||||||
[merged_out_logit[:-overlap, :], curr_logits], dim=0
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
merged_out_logit = torch.cat(
|
|
||||||
[merged_out_logit, out_logits_windows[i]], dim=0
|
|
||||||
)
|
|
||||||
|
|
||||||
merged_out_boxes = torch.cat(
|
|
||||||
[merged_out_boxes, out_boxes_windows[i][overlap:, :]], dim=0
|
|
||||||
)
|
|
||||||
|
|
||||||
# print(f"merged_out_logit={len(merged_out_logit)} - merged_out_boxes={len(merged_out_boxes)}")
|
|
||||||
# from IPython import embed; embed()
|
|
||||||
assert len(merged_out_logit) == len(
|
|
||||||
merged_out_boxes
|
|
||||||
), f"{len(merged_out_logit)} # {len(merged_out_boxes)}"
|
|
||||||
predictions = merged_out_logit.argmax(-1).squeeze().tolist()
|
|
||||||
if not isinstance(predictions, list):
|
|
||||||
predictions = [predictions]
|
|
||||||
|
|
||||||
|
|
||||||
assert len(predictions) == len(batch_words), f"{len(predictions)} # {len(batch_words)}"
|
|
||||||
# for word_index in range(len(batch_words)):
|
|
||||||
for word_index, word in enumerate(batch_words):
|
|
||||||
word = batch_words[word_index]
|
|
||||||
# bndbox = [int(coord) for coord in merged_out_boxes[word_index]]
|
|
||||||
bndbox = non_norm_boxes[word_index]
|
|
||||||
kie_label = self.cfg.classes[predictions[word_index]]
|
|
||||||
results.append(
|
|
||||||
Word(
|
|
||||||
text=word,
|
|
||||||
bndbox=bndbox,
|
|
||||||
kie_label=kie_label,
|
|
||||||
conf_cls=inputs["recog_confs"][word_index]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
def postprocessing(self, words):
|
|
||||||
"""Post processing for output of kie
|
|
||||||
- Merge wordgroup list for each field
|
|
||||||
|
|
||||||
Args:
|
|
||||||
items (dict): _description_
|
|
||||||
"""
|
|
||||||
list_lines, _ = words_to_lines(words)
|
|
||||||
list_word_group = []
|
|
||||||
for line in list_lines:
|
|
||||||
for word_group in line.list_word_groups:
|
|
||||||
word_group.update_kie_label()
|
|
||||||
word_group.update_conf()
|
|
||||||
list_word_group.append(word_group)
|
|
||||||
|
|
||||||
kie_dict = construct_word_groups_to_kie_label(list_word_group)
|
|
||||||
#receipt postprocess
|
|
||||||
if 'postprocess_type' in self.cfg and self.cfg.postprocess_type == "receipt_postprocess":
|
|
||||||
kie_dict = receipt_postprocess(kie_dict, words)
|
|
||||||
else: #invoice_postprocess
|
|
||||||
# kie_dict = invoice_postprocess(kie_dict)
|
|
||||||
kie_dict = self._postprocess_kie_wordgroups(kie_dict, doc_type=self.cfg.postprocess_type)
|
|
||||||
return kie_dict
|
|
||||||
|
|
||||||
def format_output(self, kie_dict):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
kie_dict (dict) : format
|
|
||||||
{
|
|
||||||
'field_name': list[Wordgroup]
|
|
||||||
}
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(dict): format
|
|
||||||
{
|
|
||||||
'field_name': {
|
|
||||||
'box': list,
|
|
||||||
'value': str,
|
|
||||||
'conf': float
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
end2end_results = {}
|
|
||||||
filtered_dict = {k:v for k,v in kie_dict.items() if "key" not in k}
|
|
||||||
for field_name, wg_list in filtered_dict.items():
|
|
||||||
wg_list = [wg_list] if not isinstance(wg_list, list) else wg_list
|
|
||||||
|
|
||||||
if len(wg_list) == 0:
|
|
||||||
text, conf, box = "", 0.0, []
|
|
||||||
else:
|
|
||||||
text = " ".join([wg.text for wg in wg_list]).strip().replace("✪", " ")
|
|
||||||
conf = sum(wg.conf for wg in wg_list) / len(wg_list)
|
|
||||||
box = merge_boxes([wg.boundingbox for wg in wg_list])
|
|
||||||
|
|
||||||
end2end_results[field_name] = {
|
|
||||||
"box": box,
|
|
||||||
"value": text,
|
|
||||||
"conf": conf
|
|
||||||
}
|
|
||||||
|
|
||||||
# add empty values for missing fields
|
|
||||||
for class_name in self.classes:
|
|
||||||
if "key" not in class_name and class_name not in end2end_results and class_name.lower() not in ['other', 'others']:
|
|
||||||
end2end_results[class_name] = {
|
|
||||||
"box": [],
|
|
||||||
"value": "",
|
|
||||||
"conf": 0.0
|
|
||||||
}
|
|
||||||
|
|
||||||
end2end_results = self._postprocess_recognized_text(end2end_results, doc_type=self.cfg.postprocess_type)
|
|
||||||
# sort by keys
|
|
||||||
end2end_results = dict(sorted(end2end_results.items()))
|
|
||||||
return end2end_results
|
|
||||||
|
|
||||||
|
|
||||||
def _postprocess_kie_wordgroups(self, result, doc_type, metadata=None):
|
|
||||||
"""post process for wordgroup outputs
|
|
||||||
|
|
||||||
Args:
|
|
||||||
result (dict): {'field_name': list[Wordgroup]}
|
|
||||||
doc_type (str): invoice / receipt
|
|
||||||
metadata (_type_, optional): _description_. Defaults to None.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
_type_: _description_
|
|
||||||
"""
|
|
||||||
for field_name in result.keys():
|
|
||||||
if field_name not in POSTPROCESS_FUNC[doc_type]:
|
|
||||||
continue
|
|
||||||
postprocess_func = POSTPROCESS_FUNC[doc_type][field_name].get("wordgroup", None)
|
|
||||||
if postprocess_func is None:
|
|
||||||
continue
|
|
||||||
result[field_name] = postprocess_func(result[field_name], metadata={"field_name": field_name, "wg_res": result})
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _postprocess_recognized_text(self, result, doc_type, metadata=None):
|
|
||||||
for field_name in result.keys():
|
|
||||||
if field_name not in POSTPROCESS_FUNC[doc_type]:
|
|
||||||
continue
|
|
||||||
postprocess_func = POSTPROCESS_FUNC[doc_type][field_name].get("text", None)
|
|
||||||
if postprocess_func is None:
|
|
||||||
continue
|
|
||||||
result[field_name]["value"] = postprocess_func(result[field_name]['value'], metadata)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def prepare_inputs(self, img, ocr_output):
|
|
||||||
"""Prepare input for KIE model
|
|
||||||
|
|
||||||
Args:
|
|
||||||
img (np.ndarray): BGR image
|
|
||||||
ocr_output (dict): format
|
|
||||||
{
|
|
||||||
"img_path": img_path,
|
|
||||||
"img": image,
|
|
||||||
"boxes": boxes,
|
|
||||||
"texts": words,
|
|
||||||
"kie_labels": word_labels
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
assert "boxes" in ocr_output, "boxes not exists in ocr_output"
|
|
||||||
assert "texts" in ocr_output, "texts not exists in ocr_output"
|
|
||||||
|
|
||||||
# cv2 to PIL (RGB)
|
|
||||||
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
|
|
||||||
w, h = img.size
|
|
||||||
texts = ocr_output["texts"]
|
|
||||||
boxes = ocr_output["boxes"]
|
|
||||||
recog_confs = ocr_output['recog_confs']
|
|
||||||
det_confs = ocr_output['det_confs']
|
|
||||||
texts = [text.replace(" ", "✪") for text in texts] # layoutlm will throw an error if the input has space characters
|
|
||||||
word_items = {
|
|
||||||
'boxes': boxes,
|
|
||||||
'texts': texts,
|
|
||||||
'det_confs': det_confs,
|
|
||||||
'recog_confs': recog_confs
|
|
||||||
}
|
|
||||||
sorted_word_items = sort_words(word_items)
|
|
||||||
(boxes, texts, det_confs, recog_confs) = (
|
|
||||||
sorted_word_items['boxes'],
|
|
||||||
sorted_word_items['texts'],
|
|
||||||
sorted_word_items['det_confs'],
|
|
||||||
sorted_word_items['recog_confs']
|
|
||||||
)
|
|
||||||
non_norm_boxes = sorted_word_items['boxes']
|
|
||||||
boxes = [normalize_box(box, width=w, height=h) for box in boxes]
|
|
||||||
out_item = {
|
|
||||||
"img": img,
|
|
||||||
"boxes": np.array(boxes),
|
|
||||||
"texts": texts,
|
|
||||||
"det_confs": det_confs,
|
|
||||||
"recog_confs": recog_confs,
|
|
||||||
"non_norm_boxes": non_norm_boxes
|
|
||||||
}
|
|
||||||
return out_item
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def aggregate_outputs(self, outs):
|
|
||||||
f"""Postprocess the outputs of the muliple pages
|
|
||||||
|
|
||||||
Args:
|
|
||||||
outs (_type_): _description_
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
output: (dict): final output
|
|
||||||
|
|
||||||
"""
|
|
||||||
combine_out = {
|
|
||||||
'kie_raw_output': [],
|
|
||||||
'kie_post_output': [],
|
|
||||||
'end2end_result_each_page': [],
|
|
||||||
'end2end_results': None
|
|
||||||
}
|
|
||||||
|
|
||||||
for idx, out in enumerate(outs):
|
|
||||||
combine_out['kie_raw_output'].append(out['kie_raw_output'])
|
|
||||||
combine_out['kie_post_output'].append(out['kie_post_output'])
|
|
||||||
combine_out['end2end_result_each_page'].append(out['end2end_results'])
|
|
||||||
|
|
||||||
#merge end2end result
|
|
||||||
end2end_results = combine_out['end2end_result_each_page'][0]
|
|
||||||
|
|
||||||
for page_id, end2end_results_page in enumerate(combine_out['end2end_result_each_page'][1:]):
|
|
||||||
for field_key, field_value in end2end_results_page.items():
|
|
||||||
if "value" in end2end_results[field_key] \
|
|
||||||
and (end2end_results[field_key]['value'] == "" or end2end_results[field_key]['value'] == "0"):
|
|
||||||
end2end_results[field_key] = field_value
|
|
||||||
combine_out['end2end_results'] = end2end_results
|
|
||||||
|
|
||||||
return combine_out
|
|
||||||
|
|
@ -1,260 +0,0 @@
|
|||||||
import logging
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
|
|
||||||
import torch
|
|
||||||
import wandb
|
|
||||||
from easydict import EasyDict
|
|
||||||
from sklearn.metrics import precision_recall_fscore_support
|
|
||||||
from terminaltables import AsciiTable
|
|
||||||
from torch.optim import AdamW
|
|
||||||
from torch.optim.lr_scheduler import LinearLR
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
from sdsvkie.datasets.base_dataset import BaseDataset
|
|
||||||
from sdsvkie.models.layoutlmv2 import LayoutLMv2
|
|
||||||
from sdsvkie.models.layoutlm import LayoutLM
|
|
||||||
from sdsvkie.utils import yaml_save, get_info_env, get_logger
|
|
||||||
from transformers import get_scheduler
|
|
||||||
|
|
||||||
# logging = logging.getlogging(__name__)
|
|
||||||
# logging.basicConfig(level=logging.INFO)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Trainer:
|
|
||||||
def __init__(self, cfg: dict):
|
|
||||||
self.cfg = EasyDict(cfg)
|
|
||||||
self.model = None
|
|
||||||
self.processor = None
|
|
||||||
self._init_trainer()
|
|
||||||
|
|
||||||
def _init_trainer(self):
|
|
||||||
|
|
||||||
if self.cfg.v3:
|
|
||||||
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
|
||||||
|
|
||||||
if not os.path.exists(self.cfg.save_dir):
|
|
||||||
os.makedirs(self.cfg.save_dir, exist_ok=True)
|
|
||||||
|
|
||||||
timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime())
|
|
||||||
log_file = "{}/{}.log".format(self.cfg.save_dir, str(timestamp))
|
|
||||||
self.logger = get_logger(log_file=log_file, log_level='INFO')
|
|
||||||
self.logger.info(self.cfg)
|
|
||||||
# self.logger.info(get_info_env())
|
|
||||||
|
|
||||||
if not torch.cuda.is_available():
|
|
||||||
self.logger.info("Can not found cuda, training with CPU!!!")
|
|
||||||
self.cfg.device = "cpu"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.model = LayoutLMv2._load_model(self.cfg)
|
|
||||||
self.processor = LayoutLMv2._load_processor(self.cfg)
|
|
||||||
|
|
||||||
self.model.to(self.cfg.device)
|
|
||||||
|
|
||||||
if self.cfg.wandb:
|
|
||||||
wandb.init(
|
|
||||||
project=self.cfg.wandb,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _build_dataloader(self, data_dir, cache_file, use_sampling=False):
|
|
||||||
base_dataset = BaseDataset(self.cfg)
|
|
||||||
dataloader = base_dataset.build_dataloader_from_dir(
|
|
||||||
data_dir=data_dir,
|
|
||||||
processor=self.processor,
|
|
||||||
device="cpu",
|
|
||||||
batch_size=self.cfg.batch_size,
|
|
||||||
num_workers=self.cfg.num_workers,
|
|
||||||
shuffle=False,
|
|
||||||
cache_file=cache_file,
|
|
||||||
use_sampling=use_sampling,
|
|
||||||
)
|
|
||||||
return dataloader
|
|
||||||
|
|
||||||
def val(self, val_dir=None):
|
|
||||||
val_dir = val_dir if val_dir is not None else self.cfg.val_dir
|
|
||||||
val_cache_file = os.path.splitext(val_dir)[0] + ".pkl"
|
|
||||||
val_dataloader = self._build_dataloader(
|
|
||||||
val_dir if val_dir is not None else self.cfg.val_dir,
|
|
||||||
cache_file=val_cache_file
|
|
||||||
)
|
|
||||||
acc = self.val_on_dataloader(val_dataloader)
|
|
||||||
return acc
|
|
||||||
|
|
||||||
def train(self, train_dir=None, val_dir=None):
|
|
||||||
self.logger.info("Building train dataloader...")
|
|
||||||
base_dataset = BaseDataset(self.cfg)
|
|
||||||
train_dir = train_dir if train_dir is not None else self.cfg.train_dir
|
|
||||||
val_dir = val_dir if val_dir is not None else self.cfg.val_dir
|
|
||||||
train_cache_file = os.path.splitext(train_dir)[0] + ".pkl"
|
|
||||||
val_cache_file = os.path.splitext(val_dir)[0] + ".pkl"
|
|
||||||
if self.cfg.sampling:
|
|
||||||
train_dataset = base_dataset._build_dataset(data_dir=train_dir)
|
|
||||||
train_dataloader = base_dataset.build_dataloader_from_dataset(
|
|
||||||
train_dataset,
|
|
||||||
batch_size=self.cfg.batch_size,
|
|
||||||
processor=self.processor,
|
|
||||||
device="cpu",
|
|
||||||
shuffle=True,
|
|
||||||
num_workers=self.cfg.num_workers,
|
|
||||||
cache_file=train_cache_file,
|
|
||||||
use_sampling=True,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
train_dataloader = self._build_dataloader(
|
|
||||||
train_dir if train_dir is not None else self.cfg.train_dir,
|
|
||||||
cache_file=train_cache_file,
|
|
||||||
use_sampling=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.logger.info("Building valid dataloader...")
|
|
||||||
val_dataloader = self._build_dataloader(
|
|
||||||
val_dir if val_dir is not None else self.cfg.val_dir,
|
|
||||||
cache_file= val_cache_file,
|
|
||||||
use_sampling=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.logger.info(
|
|
||||||
f"Info dataset: train = {len(train_dataloader)}, test = {len(val_dataloader)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
optimizer = AdamW(self.model.parameters(), lr=self.cfg.lr)
|
|
||||||
if self.cfg.scheduler:
|
|
||||||
# scheduler = torch.optim.lr_scheduler.OneCycleLR(
|
|
||||||
# optimizer,
|
|
||||||
# max_lr=self.cfg.lr,
|
|
||||||
# steps_per_epoch=len(train_dataloader),
|
|
||||||
# epochs=self.cfg.epochs,
|
|
||||||
# anneal_strategy='cos',
|
|
||||||
# pct_start=0.1,
|
|
||||||
# div_factor=25, #init lr = max_lr / div_factor
|
|
||||||
# final_div_factor=1e4, # min lr = init_lr / final_dev_factor
|
|
||||||
# )
|
|
||||||
num_training_steps = self.cfg.epochs * len(train_dataloader)
|
|
||||||
scheduler = get_scheduler(
|
|
||||||
name=self.cfg.scheduler,
|
|
||||||
optimizer=optimizer,
|
|
||||||
num_warmup_steps=0,
|
|
||||||
num_training_steps=num_training_steps,
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.cfg.wandb:
|
|
||||||
wandb.config = dict(self.cfg)
|
|
||||||
|
|
||||||
best_acc = 0.0
|
|
||||||
best_epoch = 0
|
|
||||||
yaml_save(os.path.join(self.cfg.save_dir, "config.yaml"), dict(self.cfg))
|
|
||||||
for epoch in range(self.cfg.epochs):
|
|
||||||
|
|
||||||
# sampling slice window
|
|
||||||
if (
|
|
||||||
self.cfg.sampling and epoch != 0 and epoch % self.cfg.sampling == 0
|
|
||||||
): # sampling each cfg.sampling epochs
|
|
||||||
train_dataloader = base_dataset.build_dataloader_from_dataset(
|
|
||||||
train_dataset,
|
|
||||||
batch_size=self.cfg.batch_size,
|
|
||||||
processor=self.processor,
|
|
||||||
device="cpu",
|
|
||||||
shuffle=True,
|
|
||||||
num_workers=self.cfg.num_workers,
|
|
||||||
cache_file=train_cache_file,
|
|
||||||
use_sampling=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.model.train()
|
|
||||||
self.logger.info(f"Epoch: {epoch}:")
|
|
||||||
|
|
||||||
running_loss = 0.0
|
|
||||||
|
|
||||||
for batch in tqdm(train_dataloader):
|
|
||||||
# forward pass
|
|
||||||
batch = self._to_device(batch, self.cfg.device)
|
|
||||||
|
|
||||||
outputs = self.model(**batch)
|
|
||||||
loss = outputs.loss
|
|
||||||
running_loss += loss.item()
|
|
||||||
# backward pass to get the gradients
|
|
||||||
loss.backward()
|
|
||||||
|
|
||||||
# update
|
|
||||||
optimizer.step()
|
|
||||||
if self.cfg.scheduler:
|
|
||||||
scheduler.step()
|
|
||||||
optimizer.zero_grad()
|
|
||||||
|
|
||||||
loss_avg = running_loss / len(train_dataloader)
|
|
||||||
self.logger.info(f"Epoch[{epoch}/{self.cfg.epochs}] - lr: {round(scheduler.get_last_lr()[0], 9) if self.cfg.scheduler else self.cfg.lr} - loss: {loss_avg}")
|
|
||||||
if self.cfg.wandb:
|
|
||||||
wandb.log({"train_loss": loss_avg})
|
|
||||||
|
|
||||||
# valid
|
|
||||||
if epoch >= self.cfg.eval_delay:
|
|
||||||
acc = self.val_on_dataloader(val_dataloader)
|
|
||||||
|
|
||||||
if acc > best_acc:
|
|
||||||
self.model.save_pretrained(os.path.join(self.cfg.save_dir, "best"))
|
|
||||||
self.logger.info(f"Update best acc, prev best acc = {best_acc}, current best acc = {acc}")
|
|
||||||
best_acc = acc
|
|
||||||
best_epoch = epoch
|
|
||||||
|
|
||||||
if epoch % self.cfg.save_weight_interval == 0:
|
|
||||||
self.model.save_pretrained(
|
|
||||||
os.path.join(self.cfg.save_dir, "epoch_{}".format(epoch))
|
|
||||||
)
|
|
||||||
|
|
||||||
self.model.save_pretrained(os.path.join(self.cfg.save_dir, "last"))
|
|
||||||
self.logger.info(f"Best accuracy = {best_acc} at epoch {best_epoch}")
|
|
||||||
|
|
||||||
def _to_device(self, batch, device):
|
|
||||||
batch = {k: v.to(device) for k, v in batch.items()}
|
|
||||||
return batch
|
|
||||||
|
|
||||||
def val_on_dataloader(self, dataloader):
|
|
||||||
self.model.eval()
|
|
||||||
total, correct = 0, 0
|
|
||||||
preds, truths = [], []
|
|
||||||
|
|
||||||
running_loss = 0.0
|
|
||||||
for batch in tqdm(dataloader):
|
|
||||||
with torch.no_grad():
|
|
||||||
batch = self._to_device(batch, self.cfg.device)
|
|
||||||
outputs = self.model(**batch)
|
|
||||||
|
|
||||||
loss = outputs.loss
|
|
||||||
running_loss += loss.item()
|
|
||||||
predictions = outputs.logits.argmax(dim=2)
|
|
||||||
valid_samples = batch["labels"] != -100
|
|
||||||
predictions = predictions[valid_samples]
|
|
||||||
batch_labels = batch["labels"][valid_samples]
|
|
||||||
|
|
||||||
preds.extend(predictions.detach().cpu().numpy().tolist())
|
|
||||||
truths.extend(batch_labels.detach().cpu().numpy().tolist())
|
|
||||||
correct += (predictions == batch_labels).float().sum()
|
|
||||||
total += predictions.numel()
|
|
||||||
|
|
||||||
loss_avg = running_loss / len(dataloader)
|
|
||||||
|
|
||||||
p, r, f1, support = precision_recall_fscore_support(truths, preds)
|
|
||||||
# self.logger.info("shapeeee", p.shape)
|
|
||||||
table_data = [["Class", "P", "R", "F1", "#samples"]]
|
|
||||||
for c in range(len(self.cfg.classes)):
|
|
||||||
if c < p.shape[0]:
|
|
||||||
table_data.append([self.cfg.classes[c], p[c], r[c], f1[c], support[c]])
|
|
||||||
continue
|
|
||||||
|
|
||||||
f1_avg = sum(f1) / len(f1)
|
|
||||||
table = AsciiTable(table_data)
|
|
||||||
self.logger.info(table.table)
|
|
||||||
self.logger.info(
|
|
||||||
"Validation F1: {} - #samples: {} - #corrects: {}".format(
|
|
||||||
f1_avg, total, correct
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.cfg.wandb:
|
|
||||||
wandb.log({"val_loss": loss_avg, "f1": f1_avg})
|
|
||||||
|
|
||||||
return f1_avg
|
|
@ -1,671 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import glob
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import tqdm
|
|
||||||
from sdsvkie.utils.word_formation import Box, check_iou
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
def read_txt(txt):
|
|
||||||
with open(txt, 'r', encoding='utf8') as f:
|
|
||||||
data = [line.strip() for line in f]
|
|
||||||
return data
|
|
||||||
|
|
||||||
def write_txt(txt, data):
|
|
||||||
with open(txt, 'w', encoding='utf8') as f:
|
|
||||||
for line in data:
|
|
||||||
f.write(line + "\n")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
general json format:
|
|
||||||
|
|
||||||
|
|
||||||
python cvat.py --task pseudo --xml sample_cvat/annotations.xml --xml_out sample_cvat/annotations_out.xml --pseudo_path sample_cvat/pseudo.json
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
config for fwd
|
|
||||||
{
|
|
||||||
"id": "OCR005_2",
|
|
||||||
"name": "Số Hợp đồng",
|
|
||||||
"type": "text",
|
|
||||||
"value": "33252663",
|
|
||||||
"page_num": 0,
|
|
||||||
"box": [192, 168, 220, 250]
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
"""
|
|
||||||
# CONFIG = {
|
|
||||||
# "label": "field",
|
|
||||||
|
|
||||||
# #edit here
|
|
||||||
# "attribute_names": ["type", "value", "id", "name"] # name of attribute in cvat label: text / checkbox
|
|
||||||
# }
|
|
||||||
|
|
||||||
|
|
||||||
CONFIG = {
|
|
||||||
"label": "word",
|
|
||||||
# "attribute_names": ["text", "kie_label"] # name of attribute in cvat label: text / checkbox
|
|
||||||
"attribute_names": []
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CVAT:
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def create_xml_from_json(self, json_path, xml_in, xml_out):
|
|
||||||
"""
|
|
||||||
json data format:
|
|
||||||
{
|
|
||||||
"img_1.jpg": [
|
|
||||||
{
|
|
||||||
"box": [x1, y1, x2, y2]
|
|
||||||
"label": str # (not required)
|
|
||||||
"attrib1": str,
|
|
||||||
"attrib2": str,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"box": [x1, y1, x2, y2]
|
|
||||||
"label": str # (not required)
|
|
||||||
"attrib1": str,
|
|
||||||
"attrib2": str,
|
|
||||||
}
|
|
||||||
...
|
|
||||||
],
|
|
||||||
"img_2.jpg": [...]
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
data = self.read_json(json_path)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tree = ET.parse(xml_in)
|
|
||||||
root = tree.getroot()
|
|
||||||
for img_item in root.iter("image"):
|
|
||||||
img_path = img_item.attrib['name']
|
|
||||||
|
|
||||||
img_data = data[img_path]
|
|
||||||
|
|
||||||
for item in img_data:
|
|
||||||
et = ET.Element('box')
|
|
||||||
#default values
|
|
||||||
et.attrib['occluded']="0"
|
|
||||||
et.attrib['source']="manual"
|
|
||||||
et.attrib['z_order'] = "0"
|
|
||||||
|
|
||||||
#overwrite values
|
|
||||||
if 'label' in item:
|
|
||||||
et.attrib['label'] = item['label']
|
|
||||||
else:
|
|
||||||
et.attrib['label'] = CONFIG['label']
|
|
||||||
|
|
||||||
xmin, ymin, xmax, ymax = item['box']
|
|
||||||
(
|
|
||||||
et.attrib['xtl'], et.attrib['ytl'],
|
|
||||||
et.attrib['xbr'], et.attrib['ybr']
|
|
||||||
) = (
|
|
||||||
str(xmin), str(ymin),
|
|
||||||
str(xmax), str(ymax)
|
|
||||||
)
|
|
||||||
|
|
||||||
for att_name in CONFIG['attribute_names']:
|
|
||||||
if att_name not in item:
|
|
||||||
continue
|
|
||||||
|
|
||||||
att_et = ET.Element('atrribute')
|
|
||||||
att_et.attrib['name'] = att_name
|
|
||||||
att_et.text = item[att_name]
|
|
||||||
et.append(att_et)
|
|
||||||
|
|
||||||
|
|
||||||
img_item.append(et)
|
|
||||||
|
|
||||||
tree.write(xml_out, encoding='utf8')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_data_from_txt_dir(self, txt_dir, resever_parent_dir=False):
|
|
||||||
if resever_parent_dir:
|
|
||||||
txt_paths = glob.glob(txt_dir + "/*/*.txt")
|
|
||||||
else:
|
|
||||||
txt_paths = glob.glob(txt_dir + "/*.txt")
|
|
||||||
data = {}
|
|
||||||
for txt_path in txt_paths:
|
|
||||||
if resever_parent_dir:
|
|
||||||
txt_name = "/".join(txt_path.split("/")[-2:])
|
|
||||||
else:
|
|
||||||
txt_name = os.path.basename(txt_path)
|
|
||||||
|
|
||||||
|
|
||||||
txt_data = read_txt(txt_path)
|
|
||||||
format_data = []
|
|
||||||
for line in txt_data:
|
|
||||||
items = line.split("\t")
|
|
||||||
# assert len(items) == 6, "error get len = {} - {}".format(len(items), items)
|
|
||||||
|
|
||||||
box = [int(float(x)) for x in items[:4]]
|
|
||||||
text = items[4]
|
|
||||||
|
|
||||||
if len(items) == 6:
|
|
||||||
kie_label = items[5]
|
|
||||||
else:
|
|
||||||
kie_label = "word"
|
|
||||||
format_data.append(
|
|
||||||
{
|
|
||||||
'box': box,
|
|
||||||
'text': text,
|
|
||||||
'label': kie_label
|
|
||||||
}
|
|
||||||
)
|
|
||||||
data[txt_name] = format_data
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def get_data_from_txt_path(self, txt_path):
|
|
||||||
|
|
||||||
txt_data = read_txt(txt_path)
|
|
||||||
format_data = []
|
|
||||||
for line in txt_data:
|
|
||||||
items = line.split("\t")
|
|
||||||
assert len(items) == 6, "error get len = {} - {}".format(len(items), items)
|
|
||||||
box = [int(float(x)) for x in items[:4]]
|
|
||||||
text = items[4]
|
|
||||||
kie_label = items[5]
|
|
||||||
format_data.append(
|
|
||||||
{
|
|
||||||
'box': box,
|
|
||||||
'text': text,
|
|
||||||
'label': kie_label
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return format_data
|
|
||||||
|
|
||||||
def format_data_invoice(self, data):
|
|
||||||
|
|
||||||
new_data = {}
|
|
||||||
for txt_name, value in data.items():
|
|
||||||
items = []
|
|
||||||
for item in value:
|
|
||||||
text = item['text']
|
|
||||||
if "____kie_wordgroup" in text:
|
|
||||||
new_item = {
|
|
||||||
'box': item['box'],
|
|
||||||
'label': item['label']
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
|
|
||||||
new_item = {
|
|
||||||
"box": item['box'],
|
|
||||||
'text': "xxxxxx",
|
|
||||||
'kie_label': item['label'],
|
|
||||||
'label': "word"
|
|
||||||
}
|
|
||||||
|
|
||||||
items.append(new_item)
|
|
||||||
new_data[txt_name] = items
|
|
||||||
return new_data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_xml_from_txt(self, txt_dir, xml_in, xml_out, skip_labels=[], resever_parent_dir=False):
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""
|
|
||||||
data = self.get_data_from_txt_dir(txt_dir, resever_parent_dir)
|
|
||||||
print(list(data.keys()))
|
|
||||||
|
|
||||||
# for invoice
|
|
||||||
if len(skip_labels) > 0 and "word" in skip_labels:
|
|
||||||
data = self.format_data_invoice(data)
|
|
||||||
tree = ET.parse(xml_in)
|
|
||||||
root = tree.getroot()
|
|
||||||
count = 0
|
|
||||||
for img_item in tqdm.tqdm(root.iter("image")):
|
|
||||||
count += 1
|
|
||||||
img_path = img_item.attrib['name']
|
|
||||||
|
|
||||||
|
|
||||||
txt_name = os.path.splitext(img_path)[0] + ".txt"
|
|
||||||
|
|
||||||
img_data = data.get(txt_name, [])
|
|
||||||
# from IPython import embed; embed()
|
|
||||||
# break
|
|
||||||
if len(img_data) > 0:
|
|
||||||
# img_item.clear()
|
|
||||||
for child in img_item:
|
|
||||||
img_item.remove(child)
|
|
||||||
|
|
||||||
for item in img_data:
|
|
||||||
et = ET.Element('box')
|
|
||||||
#default values
|
|
||||||
et.attrib['occluded']="0"
|
|
||||||
et.attrib['source']="manual"
|
|
||||||
et.attrib['z_order'] = "0"
|
|
||||||
|
|
||||||
#overwrite values
|
|
||||||
|
|
||||||
if 'label' in item:
|
|
||||||
if item['label'] in skip_labels:
|
|
||||||
continue
|
|
||||||
et.attrib['label'] = item['label']
|
|
||||||
else:
|
|
||||||
et.attrib['label'] = CONFIG['label']
|
|
||||||
|
|
||||||
xmin, ymin, xmax, ymax = item['box']
|
|
||||||
(
|
|
||||||
et.attrib['xtl'], et.attrib['ytl'],
|
|
||||||
et.attrib['xbr'], et.attrib['ybr']
|
|
||||||
) = (
|
|
||||||
str(xmin), str(ymin),
|
|
||||||
str(xmax), str(ymax)
|
|
||||||
)
|
|
||||||
|
|
||||||
for att_name in CONFIG['attribute_names']:
|
|
||||||
if att_name not in item:
|
|
||||||
continue
|
|
||||||
|
|
||||||
att_et = ET.Element('atrribute')
|
|
||||||
att_et.attrib['name'] = att_name
|
|
||||||
att_et.text = item[att_name]
|
|
||||||
et.append(att_et)
|
|
||||||
|
|
||||||
|
|
||||||
img_item.append(et)
|
|
||||||
print("Num imgs: ", count)
|
|
||||||
tree.write(xml_out, encoding='utf8')
|
|
||||||
|
|
||||||
def get_data_from_xml(self, xml, skip_labels=[]):
|
|
||||||
""" parse xml to dict
|
|
||||||
|
|
||||||
|
|
||||||
Args:
|
|
||||||
xml (str): cvat anno xml path
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(dict): {
|
|
||||||
'img_1.jpg': [
|
|
||||||
'kie_label': [xyxy]
|
|
||||||
...
|
|
||||||
],
|
|
||||||
'img_2.jpg': ...
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
anno_data = open(xml, encoding='utf8')
|
|
||||||
tree = ET.parse(anno_data)
|
|
||||||
root = tree.getroot()
|
|
||||||
data = {}
|
|
||||||
|
|
||||||
for obj in tqdm.tqdm(root.iter("image")):
|
|
||||||
img_path = obj.attrib['name']
|
|
||||||
img_data = []
|
|
||||||
for box in obj.iter("box"):
|
|
||||||
box_label = box.attrib['label']
|
|
||||||
if box_label in skip_labels:
|
|
||||||
continue
|
|
||||||
|
|
||||||
#get coordinate
|
|
||||||
xmin, ymin, xmax, ymax = box.attrib['xtl'], box.attrib['ytl'], box.attrib['xbr'], box.attrib['ybr']
|
|
||||||
xmin, ymin, xmax, ymax = int(float(xmin)), int(float(ymin)), int(float(xmax)), int(float(ymax))
|
|
||||||
|
|
||||||
item = {
|
|
||||||
box_label: [xmin, ymin, xmax, ymax]
|
|
||||||
}
|
|
||||||
img_data.append(item)
|
|
||||||
|
|
||||||
data[img_path] = img_data
|
|
||||||
|
|
||||||
return data
|
|
||||||
@staticmethod
|
|
||||||
def write_json(json_path, data):
|
|
||||||
with open(json_path, 'w', encoding='utf8') as f:
|
|
||||||
json.dump(data, f, ensure_ascii=False)
|
|
||||||
|
|
||||||
|
|
||||||
def read_json(self, json_path):
|
|
||||||
with open(json_path, 'r', encoding='utf8') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def update_label_kie(self, txt_dir, json_path, out_dir):
|
|
||||||
if not os.path.exists(out_dir):
|
|
||||||
os.makedirs(out_dir, exist_ok=True)
|
|
||||||
data = self.read_json(json_path)
|
|
||||||
txt_paths = glob.glob(txt_dir + "/*.txt")
|
|
||||||
for txt_path in tqdm.tqdm(txt_paths):
|
|
||||||
ori_data = read_txt(txt_path)
|
|
||||||
|
|
||||||
boxes = []
|
|
||||||
|
|
||||||
img_name = os.path.splitext(os.path.basename(txt_path))[0]
|
|
||||||
img_name = "_".join(img_name.split("_")[:-1]) + "_1" + ".jpg"
|
|
||||||
# img_name = os.path.splitext(os.path.basename(txt_path))[0] + ".jpg"
|
|
||||||
new_img_data = data[img_name]
|
|
||||||
for line in ori_data:
|
|
||||||
xmin, ymin, xmax, ymax, text, kie_label = line.strip().split("\t")
|
|
||||||
if "____kie_wordgroup" in text:
|
|
||||||
continue
|
|
||||||
xmin, ymin, xmax, ymax = int(xmin), int(ymin), int(xmax), int(ymax)
|
|
||||||
# box_word = [xmin, ymin, xmax, ymax]
|
|
||||||
new_kie_label = "other"
|
|
||||||
for label_info in new_img_data:
|
|
||||||
for label, box_wordgroup in label_info.items():
|
|
||||||
# print(label, box_wordgroup)
|
|
||||||
box_word = Box(
|
|
||||||
xmin, ymin, xmax, ymax
|
|
||||||
)
|
|
||||||
box_wordgroup = Box(
|
|
||||||
box_wordgroup[0], box_wordgroup[1], box_wordgroup[2],box_wordgroup[3]
|
|
||||||
)
|
|
||||||
if check_iou(box1=box_word, box2=box_wordgroup, threshold=0.85):
|
|
||||||
new_kie_label = label
|
|
||||||
break
|
|
||||||
|
|
||||||
if new_kie_label != "other":
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
new_box = Box(
|
|
||||||
xmin=xmin,
|
|
||||||
ymin=ymin,
|
|
||||||
xmax=xmax,
|
|
||||||
ymax=ymax,
|
|
||||||
label=text,
|
|
||||||
kie_label=new_kie_label
|
|
||||||
|
|
||||||
)
|
|
||||||
boxes.append(new_box)
|
|
||||||
|
|
||||||
boxes = sorted(boxes, key=lambda box: [box.ymin, xmin])
|
|
||||||
new_data = [
|
|
||||||
"\t".join([str(box.xmin), str(box.ymin), str(box.xmax), str(box.ymax), box.label, box.kie_label])
|
|
||||||
for box in boxes
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
write_txt(os.path.join(out_dir, os.path.basename(txt_path)), new_data)
|
|
||||||
def _check_iou(self, box1, box2, threshold=0.9):
|
|
||||||
"""_summary_
|
|
||||||
|
|
||||||
Args:
|
|
||||||
box1 (_type_): word box
|
|
||||||
box2 (_type_): line box
|
|
||||||
threshold (float, optional): _description_. Defaults to 0.9.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
_type_: _description_
|
|
||||||
"""
|
|
||||||
area1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
|
|
||||||
area2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
|
|
||||||
xmin_intersect = max(box1[0], box2[0])
|
|
||||||
ymin_intersect = max(box1[1], box2[1])
|
|
||||||
xmax_intersect = min(box1[2], box2[2])
|
|
||||||
ymax_intersect = min(box1[3], box2[3])
|
|
||||||
|
|
||||||
|
|
||||||
if xmax_intersect < xmin_intersect or ymax_intersect < ymin_intersect:
|
|
||||||
area_intersect = 0
|
|
||||||
else:
|
|
||||||
area_intersect = (xmax_intersect - xmin_intersect) * (
|
|
||||||
ymax_intersect - ymin_intersect
|
|
||||||
)
|
|
||||||
# union = area1 + area2 - area_intersect
|
|
||||||
iou = area_intersect / area1
|
|
||||||
return iou
|
|
||||||
# if iou > threshold:
|
|
||||||
# return True
|
|
||||||
# return False
|
|
||||||
|
|
||||||
def _update_label_for_word(self, box, line_items, threshold=0.75, other_class='others'):
|
|
||||||
have_label = False
|
|
||||||
max_iou = -1
|
|
||||||
for line_item in line_items:
|
|
||||||
# 465 901 664 940
|
|
||||||
|
|
||||||
curr_iou = self._check_iou(box, line_item['box'], threshold=threshold)
|
|
||||||
if curr_iou > threshold and curr_iou > max_iou:
|
|
||||||
|
|
||||||
max_iou = curr_iou
|
|
||||||
kie_label = line_item['label']
|
|
||||||
have_label = True
|
|
||||||
|
|
||||||
# if box[0] == 465 and box[-1] == 940:
|
|
||||||
# print(box, curr_iou, kie_label, line_item)
|
|
||||||
# break
|
|
||||||
|
|
||||||
if not have_label:
|
|
||||||
kie_label = other_class
|
|
||||||
return kie_label
|
|
||||||
|
|
||||||
def update_label_kie_from_xml(self, txt_dir, xml, out_dir, skip_labels = [], line_to_word=False, other_class="others", resever_parent_dir=False):
|
|
||||||
if not os.path.exists(out_dir):
|
|
||||||
os.makedirs(out_dir, exist_ok=True)
|
|
||||||
|
|
||||||
#read xml
|
|
||||||
xml_data = {}
|
|
||||||
anno_data = open(xml, encoding='utf8')
|
|
||||||
tree = ET.parse(anno_data)
|
|
||||||
root = tree.getroot()
|
|
||||||
# data = {}
|
|
||||||
|
|
||||||
for obj in tqdm.tqdm(root.iter("image")):
|
|
||||||
img_path = obj.attrib['name']
|
|
||||||
# img_data = []
|
|
||||||
if not line_to_word:
|
|
||||||
img_data = {}
|
|
||||||
for box in obj.iter("box"):
|
|
||||||
box_label = box.attrib['label']
|
|
||||||
if box_label in skip_labels:
|
|
||||||
continue
|
|
||||||
|
|
||||||
#get coordinate
|
|
||||||
xmin, ymin, xmax, ymax = box.attrib['xtl'], box.attrib['ytl'], box.attrib['xbr'], box.attrib['ybr']
|
|
||||||
box_int = int(float(xmin)), int(float(ymin)), int(float(xmax)), int(float(ymax))
|
|
||||||
box_key = ",".join([str(x) for x in box_int])
|
|
||||||
img_data[box_key] = box_label
|
|
||||||
|
|
||||||
else:
|
|
||||||
img_data = []
|
|
||||||
for box in obj.iter("box"):
|
|
||||||
box_label = box.attrib['label']
|
|
||||||
if box_label in skip_labels:
|
|
||||||
continue
|
|
||||||
|
|
||||||
#get coordinate
|
|
||||||
xmin, ymin, xmax, ymax = box.attrib['xtl'], box.attrib['ytl'], box.attrib['xbr'], box.attrib['ybr']
|
|
||||||
box_int = int(float(xmin)), int(float(ymin)), int(float(xmax)), int(float(ymax))
|
|
||||||
box_key = ",".join([str(x) for x in box_int])
|
|
||||||
img_data.append(
|
|
||||||
{
|
|
||||||
'box': box_int,
|
|
||||||
'label': box_label
|
|
||||||
}
|
|
||||||
)
|
|
||||||
xml_data[os.path.splitext(img_path)[0]] = img_data
|
|
||||||
|
|
||||||
# print(xml_data)
|
|
||||||
if resever_parent_dir:
|
|
||||||
txt_paths = glob.glob(txt_dir + "/*/*.txt")
|
|
||||||
else:
|
|
||||||
txt_paths = glob.glob(txt_dir + "/*.txt")
|
|
||||||
updated_imgs = []
|
|
||||||
for txt_path in tqdm.tqdm(txt_paths):
|
|
||||||
is_update = False
|
|
||||||
# print(txt_path)
|
|
||||||
ori_data = read_txt(txt_path)
|
|
||||||
# print(ori_data)
|
|
||||||
img_new_data = []
|
|
||||||
if resever_parent_dir:
|
|
||||||
img_key = str(Path(txt_path).with_suffix('').relative_to(Path(txt_path).parent.parent)) # a/xyz
|
|
||||||
else:
|
|
||||||
img_key = os.path.splitext(os.path.basename(txt_path))[0] # xyz
|
|
||||||
if img_key not in xml_data:
|
|
||||||
print(txt_path)
|
|
||||||
continue
|
|
||||||
img_annoted_data = xml_data[img_key]
|
|
||||||
# print(img_key, img_annoted_data)
|
|
||||||
if not line_to_word:
|
|
||||||
|
|
||||||
for line in ori_data:
|
|
||||||
xmin, ymin, xmax, ymax, text, kie_label = line.strip().split("\t")
|
|
||||||
if "____kie_wordgroup" in text:
|
|
||||||
continue
|
|
||||||
box_int = int(xmin), int(ymin), int(xmax), int(ymax)
|
|
||||||
box_key = ",".join([str(x) for x in box_int])
|
|
||||||
|
|
||||||
if box_key in img_annoted_data:
|
|
||||||
if kie_label != img_annoted_data[box_key]:
|
|
||||||
is_update.append(txt_path)
|
|
||||||
# print(kie_label, img_annoted_data[box_key])
|
|
||||||
kie_label = img_annoted_data[box_key]
|
|
||||||
else:
|
|
||||||
kie_label = other_class
|
|
||||||
img_new_data.append("\t".join([xmin, ymin, xmax, ymax, text, kie_label]))
|
|
||||||
else:
|
|
||||||
|
|
||||||
# print("ori_data: ", ori_data)
|
|
||||||
for line in ori_data:
|
|
||||||
# print(line)
|
|
||||||
items = line.strip().split("\t")
|
|
||||||
if len(items) == 5:
|
|
||||||
xmin, ymin, xmax, ymax, text = items
|
|
||||||
else:
|
|
||||||
xmin, ymin, xmax, ymax, text, label = items
|
|
||||||
|
|
||||||
box_int = int(xmin), int(ymin), int(xmax), int(ymax)
|
|
||||||
kie_label = self._update_label_for_word(box_int, img_annoted_data, threshold=0.75, other_class=other_class)
|
|
||||||
|
|
||||||
if label != kie_label:
|
|
||||||
print(kie_label, label)
|
|
||||||
is_update = True
|
|
||||||
img_new_data.append("\t".join([xmin, ymin, xmax, ymax, text, kie_label]))
|
|
||||||
if resever_parent_dir:
|
|
||||||
out_sub_dir = Path(out_dir) / Path(img_key).parts[-2]
|
|
||||||
if not out_sub_dir.exists():
|
|
||||||
out_sub_dir.mkdir(parents=True)
|
|
||||||
# else:
|
|
||||||
# out_sub_dir = out_dir
|
|
||||||
# out_sub_dir = str(out_sub_dir)
|
|
||||||
write_txt(os.path.join(out_dir, img_key + ".txt"), img_new_data)
|
|
||||||
|
|
||||||
if is_update:
|
|
||||||
updated_imgs.append(txt_path)
|
|
||||||
else:
|
|
||||||
print("No update: ", txt_path)
|
|
||||||
print("updated_imgs: ", list(set(updated_imgs)))
|
|
||||||
print("num updated_imgs: ", len(list(set(updated_imgs))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--xml", type=str, default='annotations.xml')
|
|
||||||
parser.add_argument("--pseudo_path", type=str, default="pseudolabel.json")
|
|
||||||
parser.add_argument("--xml_out", type=str, default="annotations_out.xml")
|
|
||||||
parser.add_argument("--task", type=str, default='pseudo', help='pseudo / parse_data / update_txt / update_txt_from_xml')
|
|
||||||
parser.add_argument("--txt_in", type=str, default='txt_dir_in')
|
|
||||||
parser.add_argument("--txt_out", type=str, default='txt_dir_out')
|
|
||||||
parser.add_argument("--line_to_word", action='store_true')
|
|
||||||
parser.add_argument("--other_class", type=str, default='other')
|
|
||||||
parser.add_argument("--resever_parent_dir", action="store_true")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
cvat = CVAT()
|
|
||||||
|
|
||||||
if args.task == 'parse_data':
|
|
||||||
data = cvat.get_data_from_xml(
|
|
||||||
xml=args.xml
|
|
||||||
)
|
|
||||||
CVAT.write_json(args.xml_out, data)
|
|
||||||
|
|
||||||
elif args.task == 'pseudo_from_json':
|
|
||||||
|
|
||||||
cvat.create_xml_from_json(
|
|
||||||
xml_in=args.xml,
|
|
||||||
xml_out=args.xml_out,
|
|
||||||
json_path=args.pseudo_path
|
|
||||||
)
|
|
||||||
|
|
||||||
elif args.task == 'pseudo_from_txt':
|
|
||||||
|
|
||||||
cvat.create_xml_from_txt(
|
|
||||||
xml_in=args.xml,
|
|
||||||
xml_out=args.xml_out,
|
|
||||||
txt_dir=args.pseudo_path,
|
|
||||||
# skip_labels=['word']
|
|
||||||
# skip_labels=[args.other_class],
|
|
||||||
resever_parent_dir=args.resever_parent_dir
|
|
||||||
)
|
|
||||||
elif args.task == 'update_txt':
|
|
||||||
cvat.update_label_kie(
|
|
||||||
txt_dir=args.txt_in,
|
|
||||||
json_path=args.pseudo_path,
|
|
||||||
out_dir=args.txt_out
|
|
||||||
)
|
|
||||||
|
|
||||||
elif args.task == 'update_txt_from_xml':
|
|
||||||
cvat.update_label_kie_from_xml(
|
|
||||||
txt_dir=args.txt_in,
|
|
||||||
xml=args.xml,
|
|
||||||
out_dir=args.txt_out,
|
|
||||||
skip_labels = ['word'],
|
|
||||||
line_to_word=args.line_to_word,
|
|
||||||
other_class=args.other_class,
|
|
||||||
resever_parent_dir=args.resever_parent_dir
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise NotImplementedError(f"{args.task} not yet implemented")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
python tools/cvat.py --task update_txt --txt_in /mnt/ssd1T/hoanglv/Projects/KIE/craw_data/output/synth_vnpt_r20/one_line_filtered --txt_out /mnt/ssd1T/hoanglv/Projects/KIE/craw_data/output/synth_vnpt_r20/one_line_filtered --pseudo_path ../workdirs/data/vnpt_oneline/annotations.json
|
|
||||||
|
|
||||||
python tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/visualize/xml/vnpt_r2/annotations.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/visualize/xml/vnpt_r2/annotations_out.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/visualize/vnpt_r2_txt
|
|
||||||
|
|
||||||
python tools/cvat.py --task pseudo_from_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/WildReceipt/re_labeling/wild_batch_1_raw.xml \
|
|
||||||
--xml_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/WildReceipt/re_labeling/wild_batch_1_pseudo.xml \
|
|
||||||
--pseudo_path /mnt/ssd1T/hoanglv/Projects/KIE/DATA/WildReceipt/re_labeling/batches/batch_1
|
|
||||||
|
|
||||||
|
|
||||||
python tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/visualize/vnpt_r2_txt \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/visualize/vnpt_r2.xml \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/visualize/vnpt_r2_done_txt
|
|
||||||
|
|
||||||
python tools/cvat.py --task update_txt_from_xml \
|
|
||||||
--txt_in /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_2/Good/Food \
|
|
||||||
--xml /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/labeling/Pseudo/batch_2/batch_2_food_done.xml \
|
|
||||||
--txt_out /mnt/ssd1T/hoanglv/Projects/KIE/DATA/SDSAP_Invoice/processed/batch_2/Good/Food \
|
|
||||||
--other_class Others
|
|
||||||
"""
|
|
@ -1,137 +0,0 @@
|
|||||||
import cv2
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import fitz
|
|
||||||
import json
|
|
||||||
import numpy as np
|
|
||||||
import pandas as pd
|
|
||||||
from time import time
|
|
||||||
import yaml
|
|
||||||
from tqdm.auto import tqdm
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
from sklearn.model_selection import StratifiedKFold
|
|
||||||
|
|
||||||
# from textdetection.src.serve_model import Predictor as TextDetector
|
|
||||||
|
|
||||||
FOLDER = "/mnt/ssd1T/tuanlv/06.KVUCombineStage/preprocess/data/invoices-receipts/SBT/nttmai_renamed/"
|
|
||||||
TXT_DIR = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/pseudo_ocr/invoice_receipt_sbt"
|
|
||||||
OUT_FOLDER = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/pseudo_ocr/sbt_batches"
|
|
||||||
ANN_OUT = "processed_textdet_batch%d.json"
|
|
||||||
N_BATCHES = 3
|
|
||||||
|
|
||||||
os.makedirs(OUT_FOLDER, exist_ok=True)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
all_files = []
|
|
||||||
doc_types = []
|
|
||||||
for file_name in tqdm(sorted(os.listdir(FOLDER))):
|
|
||||||
try:
|
|
||||||
file_name_no_ext = file_name.split('.')[0]
|
|
||||||
all_files.append(file_name)
|
|
||||||
doc_type = "1"
|
|
||||||
doc_types.append(doc_type)
|
|
||||||
file_path = os.path.join(FOLDER, file_name)
|
|
||||||
|
|
||||||
except Exception as ex:
|
|
||||||
print('image:', file_name, '. Error:', ex)
|
|
||||||
|
|
||||||
df = pd.DataFrame({'file_name': all_files, 'doc_type': doc_types})
|
|
||||||
|
|
||||||
df = df[df.doc_type.isin(['1'])].reset_index(drop=True)
|
|
||||||
|
|
||||||
kfold = StratifiedKFold(n_splits=N_BATCHES)
|
|
||||||
fold_num = 0
|
|
||||||
for train_inds, val_inds in kfold.split(df, df['doc_type']):
|
|
||||||
df.loc[val_inds, 'fold'] = fold_num
|
|
||||||
fold_num+=1
|
|
||||||
|
|
||||||
df.to_csv(f'{OUT_FOLDER}/tmp.csv', index=False)
|
|
||||||
|
|
||||||
text_detector = TextDetector(setting['text_detection']['setting'], "textdetection")
|
|
||||||
|
|
||||||
for batch in range(N_BATCHES):
|
|
||||||
print(f"================== Batch {batch} ================")
|
|
||||||
fold_df = df.loc[df.fold == batch]
|
|
||||||
# tree = ET.parse(XML_IN)
|
|
||||||
# root = tree.getroot()
|
|
||||||
|
|
||||||
# for image in root.findall('image'):
|
|
||||||
# root.remove(image)
|
|
||||||
with open('/home/sds/namnt/FWD_Data/coco_template.json', 'r') as f:
|
|
||||||
coco_annotations = json.load(f)
|
|
||||||
|
|
||||||
count = 2
|
|
||||||
img_id = 1
|
|
||||||
ann_id = 1
|
|
||||||
|
|
||||||
all_images = []
|
|
||||||
all_annotations = []
|
|
||||||
|
|
||||||
for row_num, row in tqdm(fold_df.iterrows(), total=len(fold_df)):
|
|
||||||
# try:
|
|
||||||
file_name = row['file_name']
|
|
||||||
file_name_no_ext = file_name.split('.')[0]
|
|
||||||
doc_type = row['doc_type']
|
|
||||||
file_path = os.path.join(FOLDER, file_name)
|
|
||||||
images = pdf2np_fitz(file_path, _type='fname')
|
|
||||||
|
|
||||||
images, batch_boxes = text_detector(images)
|
|
||||||
for page_num, (img, boxes) in enumerate(zip(images, batch_boxes)):
|
|
||||||
os.makedirs(os.path.join(OUT_FOLDER, f"batch{batch}"), exist_ok=True)
|
|
||||||
out_img_path = os.path.join(OUT_FOLDER, f"batch{batch}", f"batch{batch}_{img_id:04d}_{file_name_no_ext}_{page_num}.jpg")
|
|
||||||
cv2.imwrite(out_img_path, img[:,:,::-1])
|
|
||||||
H, W = img.shape[:2]
|
|
||||||
c_img = {
|
|
||||||
"id": int(img_id),
|
|
||||||
"width": W,
|
|
||||||
"height": H,
|
|
||||||
"file_name": os.path.join(f"batch{batch}", f"batch{batch}_{img_id:04d}_{file_name_no_ext}_{page_num}.jpg"),
|
|
||||||
"license": 0,
|
|
||||||
"flickr_url": "",
|
|
||||||
"coco_url": "",
|
|
||||||
"date_captured": 0
|
|
||||||
}
|
|
||||||
all_images.append(c_img)
|
|
||||||
|
|
||||||
for box in boxes:
|
|
||||||
x1,y1,x2,y2 = box
|
|
||||||
w, h = x2-x1, y2-y1
|
|
||||||
c_ann = {
|
|
||||||
"id": int(ann_id),
|
|
||||||
"image_id": int(img_id),
|
|
||||||
"category_id": 1,
|
|
||||||
"segmentation": [],
|
|
||||||
"area": w*h,
|
|
||||||
"bbox": [x1,y1,w,h],
|
|
||||||
"iscrowd": 0,
|
|
||||||
"attributes": {
|
|
||||||
"occluded": False,
|
|
||||||
"rotation": 0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
all_annotations.append(c_ann)
|
|
||||||
ann_id += 1
|
|
||||||
|
|
||||||
img_id += 1
|
|
||||||
# if count == 1:
|
|
||||||
# break
|
|
||||||
# else:
|
|
||||||
# count -= 1
|
|
||||||
# except Exception as ex:
|
|
||||||
# print('image:', file_name, '. Error:', ex)
|
|
||||||
|
|
||||||
coco_annotations['categories'] = [{
|
|
||||||
"id": 1,
|
|
||||||
"name": "text",
|
|
||||||
"supercategory": ""
|
|
||||||
}]
|
|
||||||
coco_annotations['images'] = all_images
|
|
||||||
coco_annotations['annotations'] = all_annotations
|
|
||||||
with open(os.path.join(OUT_FOLDER, ANN_OUT%(batch)), 'w') as f:
|
|
||||||
json.dump(coco_annotations, f)
|
|
||||||
|
|
||||||
# break
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,144 +0,0 @@
|
|||||||
"""
|
|
||||||
Use for eval, debug
|
|
||||||
"""
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
from copy import copy
|
|
||||||
from glob import glob
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import cv2
|
|
||||||
import tqdm
|
|
||||||
|
|
||||||
from sdsvkie.cfg import load_cfg
|
|
||||||
from sdsvkie.engine import Predictor
|
|
||||||
from sdsvkie.utils import visualize_kie
|
|
||||||
from sdsvkie.utils.io_file import load_ocr_output, write_json, write_txt
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--cfg", type=str, default="sdsvkie/cfg/default.yaml")
|
|
||||||
parser.add_argument(
|
|
||||||
"--img", type=str, default="img.jpg", help="image path or directory"
|
|
||||||
)
|
|
||||||
|
|
||||||
# optional
|
|
||||||
parser.add_argument("--weights", type=str, default=None, required=False)
|
|
||||||
|
|
||||||
parser.add_argument("--device", type=str, default=None, required=False)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"--text_det", type=str, default=None, required=False, help="image path or directory"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--text_reg", type=str, default=None, required=False, help="image path or directory"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--vis_out", type=str, default=None, required=False, help="visualize output directory"
|
|
||||||
)
|
|
||||||
parser.add_argument("--txt_out", type=str, required=False, default=None)
|
|
||||||
parser.add_argument("--kie_wordgroup_out", required=False, action="store_true")
|
|
||||||
parser.add_argument("--e2e", type=str, required=False, default=None)
|
|
||||||
parser.add_argument("--not_use_ocr", required=False, action="store_true")
|
|
||||||
parser.add_argument("--parse_e2e", action='store_true', help="Parse end2end result from word label")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
# print(cfg)
|
|
||||||
|
|
||||||
predictor = Predictor(**vars(args))
|
|
||||||
|
|
||||||
|
|
||||||
# cfg = load_cfg(args.cfg, vars(args))
|
|
||||||
# predictor = Predictor(cfg)
|
|
||||||
|
|
||||||
if args.txt_out:
|
|
||||||
if not os.path.exists(args.txt_out):
|
|
||||||
os.makedirs(args.txt_out, exist_ok=True)
|
|
||||||
|
|
||||||
if args.e2e:
|
|
||||||
outdir_e2e = os.path.dirname(args.e2e)
|
|
||||||
if not os.path.exists(outdir_e2e):
|
|
||||||
os.makedirs(outdir_e2e, exist_ok=True)
|
|
||||||
|
|
||||||
if os.path.isdir(args.img):
|
|
||||||
img_paths = glob(args.img + "/*")
|
|
||||||
print("Infence image dir, total imgs: {}".format(len(img_paths)))
|
|
||||||
else:
|
|
||||||
img_paths = [args.img]
|
|
||||||
|
|
||||||
out_dict = {}
|
|
||||||
for img_path in tqdm.tqdm(img_paths):
|
|
||||||
|
|
||||||
img = cv2.imread(img_path)
|
|
||||||
if img is None:
|
|
||||||
print("img is None: ", img_path)
|
|
||||||
continue
|
|
||||||
if args.not_use_ocr:
|
|
||||||
txt_path = str(Path(img_path).with_suffix(".txt"))
|
|
||||||
ocr_output = load_ocr_output(txt_path)
|
|
||||||
# print(len(ocr_output["boxes"]))
|
|
||||||
out = predictor(img, ocr_output=ocr_output, return_raw=True)
|
|
||||||
else:
|
|
||||||
out = predictor(img, return_raw=True)
|
|
||||||
|
|
||||||
# visualize
|
|
||||||
if args.vis_out:
|
|
||||||
# from IPython import embed; embed()
|
|
||||||
out_kie = out["kie_raw_output"]
|
|
||||||
visualize_kie(
|
|
||||||
img,
|
|
||||||
boxes=[word.boundingbox for word in out_kie],
|
|
||||||
pred_labels=[word.kie_label for word in out_kie],
|
|
||||||
image_name=os.path.basename(img_path),
|
|
||||||
outdir=args.vis_out,
|
|
||||||
skip_classes=["other---"]
|
|
||||||
)
|
|
||||||
|
|
||||||
if args.txt_out:
|
|
||||||
txt_out_path = os.path.join(
|
|
||||||
args.txt_out, os.path.splitext(os.path.basename(img_path))[0] + ".txt"
|
|
||||||
)
|
|
||||||
|
|
||||||
out_kie = out["kie_raw_output"]
|
|
||||||
boxes = [word.boundingbox for word in out_kie]
|
|
||||||
pred_labels = [word.kie_label for word in out_kie]
|
|
||||||
texts = [word.text for word in out_kie]
|
|
||||||
|
|
||||||
data = []
|
|
||||||
|
|
||||||
|
|
||||||
if args.kie_wordgroup_out:
|
|
||||||
output = out["kie_post_output"]
|
|
||||||
# print(output)
|
|
||||||
# from IPython import embed; embed()
|
|
||||||
wordgroup_all_list = []
|
|
||||||
for kie_label, wordgroup_list in output.items():
|
|
||||||
if isinstance(wordgroup_list, list):
|
|
||||||
wordgroup_all_list.extend(wordgroup_list)
|
|
||||||
else:
|
|
||||||
wordgroup_all_list.append(wordgroup_list)
|
|
||||||
boxes = [word.boundingbox for word in wordgroup_all_list]
|
|
||||||
pred_labels = [word.kie_label for word in wordgroup_all_list]
|
|
||||||
texts = [word.text + "____kie_wordgroup" for word in wordgroup_all_list]
|
|
||||||
|
|
||||||
for box, text, kie_label in zip(boxes, texts, pred_labels):
|
|
||||||
item = "\t".join([str(int(x)) for x in box])
|
|
||||||
item = "\t".join([item, text, kie_label])
|
|
||||||
data.append(item)
|
|
||||||
else:
|
|
||||||
for box, text, kie_label in zip(boxes, texts, pred_labels):
|
|
||||||
item = "\t".join([str(int(x)) for x in box])
|
|
||||||
item = "\t".join([item, text, kie_label])
|
|
||||||
data.append(item)
|
|
||||||
|
|
||||||
write_txt(txt_out_path, data)
|
|
||||||
|
|
||||||
if args.e2e:
|
|
||||||
|
|
||||||
img_id = os.path.splitext(os.path.basename(img_path))[0]
|
|
||||||
out_dict[img_id] = out['end2end_results']
|
|
||||||
|
|
||||||
if args.e2e:
|
|
||||||
write_json(os.path.join(args.e2e), out_dict)
|
|
@ -1,122 +0,0 @@
|
|||||||
"""
|
|
||||||
Use for deploy
|
|
||||||
"""
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
from glob import glob
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import cv2
|
|
||||||
import tqdm
|
|
||||||
|
|
||||||
from sdsvkie.cfg import load_cfg
|
|
||||||
from sdsvkie.engine.predictor import Predictor
|
|
||||||
from sdsvkie.utils.io_file import write_json
|
|
||||||
from sdsvkie.utils import visualize_kie, IMG_EXT, PDF_EXT
|
|
||||||
import random
|
|
||||||
"""
|
|
||||||
python sdsvkie/tools/infer_e2e.py \
|
|
||||||
--cfg /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/config.yaml \
|
|
||||||
--weights /mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/invoice/06062023/best \
|
|
||||||
--device "cuda:0" \
|
|
||||||
--img /mnt/hdd2T/AICR/Projects/2023/Vietinbank_POC/Invoice_JPG/ \
|
|
||||||
--e2e /mnt/hdd2T/AICR/Projects/2023/Vietinbank_POC/Invoice_KIE_Results/result.json
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--cfg", type=str, default="sdsvkie/cfg/default.yaml")
|
|
||||||
parser.add_argument("--img", type=str, default="img.jpg", help="image path or directory")
|
|
||||||
parser.add_argument("--weights", type=str, default=None)
|
|
||||||
parser.add_argument("--text_det", type=str, default=None)
|
|
||||||
parser.add_argument("--device", type=str, default=None)
|
|
||||||
parser.add_argument("--e2e", type=str, default=None)
|
|
||||||
parser.add_argument("--vis", type=str, default=None)
|
|
||||||
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# predictor = Predictor(cfg=cfg)
|
|
||||||
predictor = Predictor(**vars(args))
|
|
||||||
|
|
||||||
if args.e2e:
|
|
||||||
outdir_e2e = os.path.dirname(args.e2e)
|
|
||||||
if not os.path.exists(outdir_e2e):
|
|
||||||
os.makedirs(outdir_e2e, exist_ok=True)
|
|
||||||
|
|
||||||
if os.path.isdir(args.img):
|
|
||||||
img_paths = sorted(glob(args.img + "/*"))
|
|
||||||
print("Infence image dir, total imgs: {}".format(len(img_paths)))
|
|
||||||
else:
|
|
||||||
img_paths = [args.img]
|
|
||||||
|
|
||||||
out_dict = {}
|
|
||||||
|
|
||||||
if "Others" in predictor.classes:
|
|
||||||
colors = {
|
|
||||||
"Store_name_value": (30,97,235),
|
|
||||||
"id": (28,175,6),
|
|
||||||
"Date_value": (241,26,242),
|
|
||||||
"Total_value": (255,0,0),
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
colors = [
|
|
||||||
(
|
|
||||||
random.randint(0, 255),
|
|
||||||
random.randint(0, 255),
|
|
||||||
random.randint(0, 255),
|
|
||||||
)
|
|
||||||
for _ in range(len(predictor.classes))
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
for img_path in tqdm.tqdm(img_paths):
|
|
||||||
print(img_path)
|
|
||||||
if Path(img_path).suffix.lower() in IMG_EXT:
|
|
||||||
img = cv2.imread(img_path)
|
|
||||||
if img is None:
|
|
||||||
print("img is None: ", img_path)
|
|
||||||
continue
|
|
||||||
elif Path(img_path).suffix.lower() in PDF_EXT:
|
|
||||||
img = img_path #pdf
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
# try:
|
|
||||||
out = predictor(img)
|
|
||||||
# except Exception as err:
|
|
||||||
# print(err, img_path)
|
|
||||||
# continue
|
|
||||||
|
|
||||||
out_api = out['end2end_results']
|
|
||||||
|
|
||||||
if not args.e2e:
|
|
||||||
print(out_api)
|
|
||||||
else:
|
|
||||||
|
|
||||||
img_id = os.path.splitext(os.path.basename(img_path))[0]
|
|
||||||
out_dict[img_id] = {
|
|
||||||
field_name: field_item['value'] for field_name, field_item in out_api.items()
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.vis:
|
|
||||||
|
|
||||||
visualize_kie(
|
|
||||||
img,
|
|
||||||
boxes=[field_item['box'] for field_name, field_item in out_api.items() if len(field_item['box']) > 0],
|
|
||||||
pred_labels=[field_name for field_name, field_item in out_api.items() if len(field_item['box']) > 0],
|
|
||||||
image_name=os.path.basename(img_path),
|
|
||||||
outdir=args.vis,
|
|
||||||
colors=colors,
|
|
||||||
texts = [field_item['value'] for field_name, field_item in out_api.items() if len(field_item['box']) > 0]
|
|
||||||
)
|
|
||||||
|
|
||||||
if args.e2e:
|
|
||||||
write_json(os.path.join(args.e2e), out_dict)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
|||||||
"""
|
|
||||||
Use for eval, debug
|
|
||||||
"""
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
from glob import glob
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from sdsvkie.utils.word_formation import Word
|
|
||||||
import tqdm
|
|
||||||
|
|
||||||
from sdsvkie.engine import Predictor
|
|
||||||
from sdsvkie.utils.io_file import load_ocr_output, write_txt
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--cfg", type=str, default="sdsvkie/cfg/default.yaml")
|
|
||||||
parser.add_argument(
|
|
||||||
"--src", type=str, default="img.jpg / img_dir", help="image path or directory"
|
|
||||||
)
|
|
||||||
parser.add_argument("--tgt", type=str, required=True, default=None)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
predictor = Predictor(args.cfg)
|
|
||||||
|
|
||||||
|
|
||||||
if not os.path.exists(args.tgt):
|
|
||||||
os.makedirs(args.tgt, exist_ok=True)
|
|
||||||
|
|
||||||
txt_paths = glob(args.src + "/*.txt")
|
|
||||||
print("Total txt: {}".format(len(txt_paths)))
|
|
||||||
|
|
||||||
|
|
||||||
for txt_path in tqdm.tqdm(txt_paths):
|
|
||||||
ocr_output = load_ocr_output(txt_path)
|
|
||||||
|
|
||||||
boxes, texts, labels = ocr_output['boxes'], ocr_output['texts'], ocr_output['labels']
|
|
||||||
words = []
|
|
||||||
for box, text, label in zip(boxes, texts, labels):
|
|
||||||
words.append(
|
|
||||||
Word(
|
|
||||||
text=text,
|
|
||||||
bndbox=box,
|
|
||||||
kie_label=label,
|
|
||||||
conf_cls=0.0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
kie_output = predictor.postprocessing(words)
|
|
||||||
|
|
||||||
|
|
||||||
txt_out_path = str(Path(args.tgt) / Path(txt_path).name)
|
|
||||||
|
|
||||||
|
|
||||||
data = []
|
|
||||||
|
|
||||||
# print(output)
|
|
||||||
wordgroup_all_list = []
|
|
||||||
for kie_label, wordgroup_list in kie_output.items():
|
|
||||||
wordgroup_all_list.extend(wordgroup_list)
|
|
||||||
boxes = [word.boundingbox for word in wordgroup_all_list]
|
|
||||||
pred_labels = [word.kie_label for word in wordgroup_all_list]
|
|
||||||
texts = [word.text + "____kie_wordgroup" for word in wordgroup_all_list]
|
|
||||||
|
|
||||||
for box, text, kie_label in zip(boxes, texts, pred_labels):
|
|
||||||
item = "\t".join([str(int(x)) for x in box])
|
|
||||||
item = "\t".join([item, text, kie_label])
|
|
||||||
data.append(item)
|
|
||||||
|
|
||||||
|
|
||||||
write_txt(txt_out_path, data)
|
|
@ -1,72 +0,0 @@
|
|||||||
import argparse
|
|
||||||
from sdsvkie.utils import read_json, yaml_load, write_json
|
|
||||||
from sdsvkie.utils.post_processing.invoice_post_processing import *
|
|
||||||
from sdsvkie.utils.post_processing.common_post_processing import normalize_number
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def postprocess_invoice(invoice_data):
|
|
||||||
if 'date' in invoice_data:
|
|
||||||
invoice_data['date'] = post_processing_datetime(invoice_data['date'])
|
|
||||||
|
|
||||||
#### normalize number
|
|
||||||
number_fields = ['total_value', 'VAT_amount_value']
|
|
||||||
for number_field in number_fields:
|
|
||||||
if number_field not in invoice_data:
|
|
||||||
continue
|
|
||||||
invoice_data[number_field] = normalize_number(invoice_data[number_field])
|
|
||||||
if 'buyer_tax_code_value' in invoice_data:
|
|
||||||
invoice_data['buyer_tax_code_value'] = normalize_number(invoice_data['buyer_tax_code_value'], rerserve_minus=True)
|
|
||||||
if 'seller_tax_code_value' in invoice_data:
|
|
||||||
invoice_data['seller_tax_code_value'] = normalize_number(invoice_data['seller_tax_code_value'], rerserve_minus=True)
|
|
||||||
if "seller_mobile_value" in invoice_data:
|
|
||||||
invoice_data['seller_mobile_value'] = normalize_number(invoice_data['seller_mobile_value'], rerserve_minus=False, reserve_plus=True)
|
|
||||||
|
|
||||||
|
|
||||||
for field_name in invoice_data.keys():
|
|
||||||
field_value = invoice_data[field_name]
|
|
||||||
field_value = field_value.replace("✪", " ")
|
|
||||||
field_value = field_value.replace("\t", " ")
|
|
||||||
field_value = re.sub(r"\s+", " ", field_value)
|
|
||||||
invoice_data[field_name] = field_value
|
|
||||||
|
|
||||||
return invoice_data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def format_e2e_data(input_json, output_json, cfg):
|
|
||||||
cfg = yaml_load(cfg)
|
|
||||||
classes = cfg['classes']
|
|
||||||
value_classes = [cls_name for cls_name in classes if "_key" not in cls_name and "other" not in cls_name]
|
|
||||||
print(value_classes)
|
|
||||||
in_data = read_json(input_json)
|
|
||||||
|
|
||||||
out_data = {}
|
|
||||||
for img_id, img_data in in_data.items():
|
|
||||||
|
|
||||||
new_img_data = postprocess_invoice(img_data)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for cls_value in value_classes:
|
|
||||||
if cls_value not in new_img_data:
|
|
||||||
new_img_data[cls_value] = ""
|
|
||||||
|
|
||||||
|
|
||||||
out_data[img_id] = new_img_data
|
|
||||||
|
|
||||||
|
|
||||||
write_json(data=out_data, json_path=output_json)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--cfg", type=str)
|
|
||||||
parser.add_argument("--input", type=str, help="e2e label file path")
|
|
||||||
parser.add_argument("--out", type=str, help='postprocess e2e label')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
format_e2e_data(args.input, args.out, args.cfg)
|
|
||||||
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
|||||||
import argparse
|
|
||||||
import glob
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import cv2
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
from sdsvkie.models.ocr import OCREngine
|
|
||||||
from sdsvkie.utils.visualize import visualize_ocr
|
|
||||||
from sdsvkie.utils.io_file import write_txt
|
|
||||||
from sdsvkie.utils.word_formation import sort_words
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
|
|
||||||
parser.add_argument("--img", type=str)
|
|
||||||
parser.add_argument("--out_dir", type=str, default=None)
|
|
||||||
parser.add_argument("--device", type=str, default='cpu')
|
|
||||||
parser.add_argument("--reserve_parent_dir", action='store_true')
|
|
||||||
parser.add_argument("--only_text", action='store_true')
|
|
||||||
parser.add_argument("--out_txt", type=str, default=None)
|
|
||||||
parser.add_argument("--text_det", default="yolox-s-general-text-pretrain-20221226")
|
|
||||||
parser.add_argument("--text_recog", default="satrn-lite-general-pretrain-20230106")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
ocr_engine = OCREngine(text_det=args.text_det, text_recog=args.text_recog, device=args.device)
|
|
||||||
|
|
||||||
|
|
||||||
if args.reserve_parent_dir:
|
|
||||||
paths = glob.glob(args.img + "/*/*")
|
|
||||||
else:
|
|
||||||
paths = glob.glob(args.img + "/*")
|
|
||||||
for path in tqdm(paths):
|
|
||||||
img = cv2.imread(path)
|
|
||||||
if img is None:
|
|
||||||
print(path)
|
|
||||||
continue
|
|
||||||
ocr_output = ocr_engine(img, extend_ratio=[0.1, 0.3], ratio_thr=5)
|
|
||||||
|
|
||||||
if args.out_dir:
|
|
||||||
if args.reserve_parent_dir:
|
|
||||||
out_dir_img = Path(args.out_dir) / Path(path).parent.name
|
|
||||||
else:
|
|
||||||
out_dir_img = Path(args.out_dir)
|
|
||||||
if not out_dir_img.exists():
|
|
||||||
out_dir_img.mkdir(parents=True)
|
|
||||||
|
|
||||||
|
|
||||||
visualize_ocr(
|
|
||||||
img = img,
|
|
||||||
boxes=ocr_output['boxes'],
|
|
||||||
texts=ocr_output['texts'],
|
|
||||||
image_name=str(Path(path).name),
|
|
||||||
outdir=str(out_dir_img)
|
|
||||||
)
|
|
||||||
|
|
||||||
if args.out_txt:
|
|
||||||
|
|
||||||
|
|
||||||
if args.reserve_parent_dir:
|
|
||||||
out_dir_txt = Path(args.out_txt) / Path(path).parent.name
|
|
||||||
else:
|
|
||||||
out_dir_txt = Path(args.out_txt)
|
|
||||||
if not out_dir_txt.exists():
|
|
||||||
out_dir_txt.mkdir(parents=True)
|
|
||||||
|
|
||||||
out_txt_path = out_dir_txt / Path(path).with_suffix(".txt").name
|
|
||||||
data = []
|
|
||||||
if args.only_text:
|
|
||||||
out = sort_words(ocr_output)
|
|
||||||
text = " ".join(out['texts'])
|
|
||||||
data.append(text)
|
|
||||||
else:
|
|
||||||
|
|
||||||
for box, text in zip(ocr_output['boxes'], ocr_output['texts']):
|
|
||||||
item = "\t".join([str(int(x)) for x in box])
|
|
||||||
item = "\t".join([item, text])
|
|
||||||
data.append(item)
|
|
||||||
write_txt(str(out_txt_path), data)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
|||||||
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
from sdsvkie.cfg import load_cfg
|
|
||||||
from sdsvkie.engine.trainer import Trainer
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--cfg", type=str, default="sdsvkie/cfg/default.yaml")
|
|
||||||
parser.add_argument("--device", type=str, default="cuda")
|
|
||||||
parser.add_argument("--save_dir", type=str, default="./workdirs/exp")
|
|
||||||
parser.add_argument("--wandb", action="store_true")
|
|
||||||
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
# cfg = cfg2dict(args.cfg)
|
|
||||||
# cfg['device'] = args.device
|
|
||||||
# cfg['save_dir'] = args.save_dir
|
|
||||||
cfg = load_cfg(args.cfg, vars(args))
|
|
||||||
print(cfg)
|
|
||||||
|
|
||||||
if args.wandb:
|
|
||||||
cfg['wandb'] = "invoice"
|
|
||||||
|
|
||||||
trainer = Trainer(cfg)
|
|
||||||
trainer.train()
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
from sdsvkie.cfg import load_cfg
|
|
||||||
from sdsvkie.engine.trainer import Trainer
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--cfg", type=str, default="sdsvkie/cfg/default.yaml")
|
|
||||||
parser.add_argument("--device", type=str, default="cuda")
|
|
||||||
parser.add_argument("--weights", type=str, default=None)
|
|
||||||
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
cfg = load_cfg(args.cfg, vars(args))
|
|
||||||
|
|
||||||
trainer = Trainer(cfg)
|
|
||||||
metric = trainer.val()
|
|
||||||
print(metric)
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
|||||||
from .transform import normalize_box, unnormalize_box
|
|
||||||
from .augmentation import perturbate_character, sampling_data
|
|
||||||
from .io_file import yaml_load, yaml_save, read_json,write_json
|
|
||||||
from .visualize import visualize_kie, visualize_ocr
|
|
||||||
from .word_formation import (
|
|
||||||
sliding_windows, Word_group, words_to_lines,
|
|
||||||
sort_words, Word, merge_boxes, merge_wordgroups,
|
|
||||||
distance_of_boxes, y_distance
|
|
||||||
)
|
|
||||||
from .post_processing import *
|
|
||||||
from .logger import get_logger
|
|
||||||
from .common import get_info_env
|
|
||||||
from .convert_pdf2image import pdf_to_image
|
|
||||||
|
|
||||||
|
|
||||||
IMG_EXT = ['.jpg', ".png", ".jpeg"]
|
|
||||||
PDF_EXT = [".pdf"]
|
|
@ -1,112 +0,0 @@
|
|||||||
import math
|
|
||||||
import random
|
|
||||||
|
|
||||||
VN_list_char = "aAàÀảẢãÃáÁạẠăĂằẰẳẲẵẴắẮặẶâÂầẦẩẨẫẪấẤậẬbBcCdDđĐeEèÈẻẺẽẼéÉẹẸêÊềỀểỂễỄếẾệỆfFgGhHiIìÌỉỈĩĨíÍịỊjJkKlLmMnNoOòÒỏỎõÕóÓọỌôÔồỒổỔỗỖốỐộỘơƠờỜởỞỡỠớỚợỢpPqQrRsStTuUùÙủỦũŨúÚụỤưƯừỪửỬữỮứỨựỰvVwWxXyYỳỲỷỶỹỸýÝỵỴzZ0123456789!#$%&()*+,-./:;<=>?@[\]^_`{|}~"
|
|
||||||
|
|
||||||
|
|
||||||
def perturbate_character(words: list, ratio=0.01):
|
|
||||||
# Algorithm
|
|
||||||
# Step 1: couting number of characters is words and sample the postion we want to perturbation
|
|
||||||
# ( words = ["abc", "lkdhf", "lfhdlsa", "akdjhf"] =>> total_char = 21, pertubation_position = [15,13,7]), these are the positions of perturbating chars in the concatenating string of words "abclkdhflfhdlsaakdjhf"
|
|
||||||
# start_pos = 0, ending_pos = 0
|
|
||||||
# Step 2: with each word in words, calculate the start_position and ending_pos of word in the concatenating string
|
|
||||||
# if ending pos > pertubation_position[-1] => conduct perturbation and plus 1 to perturbation index, else => continue
|
|
||||||
# Loop 1: words[0], start_pos = 0 ,ending_pos= 3 <= pertubation_position[-1] =7 => continue
|
|
||||||
# Loop 2:
|
|
||||||
|
|
||||||
total_char = sum(len(i) for i in words)
|
|
||||||
pertubation_positions = sorted(
|
|
||||||
random.sample(range(total_char), int(ratio * total_char))
|
|
||||||
)
|
|
||||||
# logging.info(pertubation_positions)
|
|
||||||
pos = 0
|
|
||||||
start_pos = 0
|
|
||||||
j = 0
|
|
||||||
for i, word in enumerate(words):
|
|
||||||
if j == len(pertubation_positions):
|
|
||||||
break
|
|
||||||
start_pos = pos
|
|
||||||
pos += len(word)
|
|
||||||
# logging.info(start_pos,pos)
|
|
||||||
while pos > pertubation_positions[j]:
|
|
||||||
x = random.randint(0, 3)
|
|
||||||
fixing_pos = pertubation_positions[j] - start_pos
|
|
||||||
if x == 0: # append random char to the left
|
|
||||||
word = (
|
|
||||||
word[:fixing_pos]
|
|
||||||
+ VN_list_char[random.randint(0, len(VN_list_char) - 1)]
|
|
||||||
+ word[fixing_pos:]
|
|
||||||
)
|
|
||||||
|
|
||||||
if x == 1: # append random char to the right
|
|
||||||
word = (
|
|
||||||
word[: fixing_pos + 1]
|
|
||||||
+ VN_list_char[random.randint(0, len(VN_list_char) - 1)]
|
|
||||||
+ word[fixing_pos + 1 :]
|
|
||||||
)
|
|
||||||
|
|
||||||
if x == 2: # adjust to another random char at current position
|
|
||||||
word = (
|
|
||||||
word[:fixing_pos]
|
|
||||||
+ VN_list_char[random.randint(0, len(VN_list_char) - 1)]
|
|
||||||
+ word[fixing_pos + 1 :]
|
|
||||||
)
|
|
||||||
|
|
||||||
if x == 3 and len(word) > 1: # delete char at current position
|
|
||||||
|
|
||||||
word = word[:fixing_pos] + word[fixing_pos + 1 :]
|
|
||||||
|
|
||||||
j += 1
|
|
||||||
# logging.info(words[i], word)
|
|
||||||
words[i] = word
|
|
||||||
if j == len(pertubation_positions):
|
|
||||||
break
|
|
||||||
|
|
||||||
return words
|
|
||||||
|
|
||||||
|
|
||||||
def sampling_data(words, boxes, labels, max_num_words=150, slice_interval=50):
|
|
||||||
# num_boxes = len(words)
|
|
||||||
# if num_boxes > max_num_words:
|
|
||||||
# slide = max_num_words // 2
|
|
||||||
# num_batches = math.ceil(num_boxes / slide)
|
|
||||||
|
|
||||||
# idx_batches = [i for i in range(num_batches)]
|
|
||||||
# idx_batch = random.choice(idx_batches)
|
|
||||||
# start_idx = slide * idx_batch
|
|
||||||
# words = words[start_idx:]
|
|
||||||
# normalized_word_boxes = normalized_word_boxes[start_idx:]
|
|
||||||
# word_labels = normalized_word_boxes[start_idx:]
|
|
||||||
|
|
||||||
total_word = len(words)
|
|
||||||
window_size = max_num_words
|
|
||||||
text_windows = [
|
|
||||||
words[i : i + window_size] for i in range(0, total_word, slice_interval)
|
|
||||||
]
|
|
||||||
box_windows = [
|
|
||||||
boxes[i : i + window_size] for i in range(0, total_word, slice_interval)
|
|
||||||
]
|
|
||||||
label_windown = [
|
|
||||||
labels[i : i + window_size] for i in range(0, total_word, slice_interval)
|
|
||||||
]
|
|
||||||
|
|
||||||
# assert all(
|
|
||||||
# [
|
|
||||||
# len(_words) == len(boxes)
|
|
||||||
# for _words, boxes in zip(words, normalized_word_boxes)
|
|
||||||
# ]
|
|
||||||
# )
|
|
||||||
# assert all(
|
|
||||||
# [
|
|
||||||
# len(_words) == len(_word_labels)
|
|
||||||
# for _words, _word_labels in zip(words, word_labels)
|
|
||||||
# ]
|
|
||||||
# )
|
|
||||||
sampling_idx = random.choice([i for i in range(len(text_windows))])
|
|
||||||
sampling_words, sampling_boxes, sampling_labels = (
|
|
||||||
text_windows[sampling_idx],
|
|
||||||
box_windows[sampling_idx],
|
|
||||||
label_windown[sampling_idx],
|
|
||||||
)
|
|
||||||
|
|
||||||
return sampling_idx, sampling_words, sampling_boxes, sampling_labels
|
|
@ -1,8 +0,0 @@
|
|||||||
from torch.utils import collect_env
|
|
||||||
|
|
||||||
|
|
||||||
def get_info_env():
|
|
||||||
return collect_env.get_pretty_env_info()
|
|
||||||
|
|
||||||
def count_parameters(model):
|
|
||||||
return sum(p.numel() for p in model.parameters() if p.requires_grad)
|
|
@ -1,166 +0,0 @@
|
|||||||
import argparse
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import fitz # PyMuPDF, imported as fitz for backward compatibility reasons
|
|
||||||
import numpy as np
|
|
||||||
from tqdm import tqdm
|
|
||||||
import cv2
|
|
||||||
from pdf2image import convert_from_path
|
|
||||||
|
|
||||||
|
|
||||||
def convert_pdf2image(filename, out_dir, dpi=300, reserve_parent_dir=False, is_get_first_page=False):
|
|
||||||
"""Convert and save to disk
|
|
||||||
|
|
||||||
Args:
|
|
||||||
filename (_type_): _description_
|
|
||||||
out_dir (_type_): _description_
|
|
||||||
dpi (int, optional): _description_. Defaults to 300.
|
|
||||||
reserve_parent_dir (bool, optional): _description_. Defaults to False.
|
|
||||||
"""
|
|
||||||
out_dir = Path(out_dir)
|
|
||||||
filename = Path(filename)
|
|
||||||
filename_str = str(filename)
|
|
||||||
|
|
||||||
if reserve_parent_dir:
|
|
||||||
parent_dir = filename.parent.name
|
|
||||||
out_dir = out_dir / parent_dir
|
|
||||||
|
|
||||||
if not out_dir.exists():
|
|
||||||
out_dir.mkdir(parents=True)
|
|
||||||
if ".txt" in str(filename).lower():
|
|
||||||
return
|
|
||||||
if ".pdf" not in str(filename).lower():
|
|
||||||
shutil.copy(filename, out_dir)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# doc = fitz.open(filename_str) # open document
|
|
||||||
# # zoom = 2 # zoom factor, standard: 72 dpi
|
|
||||||
|
|
||||||
# # dpi = 300
|
|
||||||
# zoom = dpi // 72
|
|
||||||
# magnify = fitz.Matrix(zoom, zoom)
|
|
||||||
# for idx, page in enumerate(doc):
|
|
||||||
# pix = page.get_pixmap(matrix=magnify) # render page to an image
|
|
||||||
|
|
||||||
# outpath = out_dir / Path(os.path.splitext(os.path.basename(filename))[0] + "_" + str(idx+1) + ".jpg")
|
|
||||||
# pix.pil_save(outpath)
|
|
||||||
try:
|
|
||||||
imgs = pdf_to_image(pdf=filename_str, is_get_first_page=is_get_first_page, dpi=dpi)
|
|
||||||
except:
|
|
||||||
print("Use v2: ", filename_str)
|
|
||||||
imgs = pdf_to_image_v2(pdf=filename_str, is_get_first_page=is_get_first_page, dpi=dpi)
|
|
||||||
print("Len img: ", len(imgs))
|
|
||||||
for idx, img in enumerate(imgs):
|
|
||||||
outpath = str(out_dir / Path(os.path.splitext(os.path.basename(filename))[0] + "_" + str(idx+1) + ".jpg"))
|
|
||||||
|
|
||||||
cv2.imwrite(img=img, filename=outpath)
|
|
||||||
|
|
||||||
|
|
||||||
def pdf_to_image_v2(pdf, dpi=300, is_get_first_page=False, max_page=1000):
|
|
||||||
"""_summary_
|
|
||||||
|
|
||||||
Args:
|
|
||||||
pdf (_type_): _description_
|
|
||||||
dpi (int, optional): _description_. Defaults to 300.
|
|
||||||
is_get_first_page (bool, optional): _description_. Defaults to False.
|
|
||||||
max_page (int, optional): _description_. Defaults to 1000.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
NotImplementedError: _description_
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
_type_: _description_
|
|
||||||
"""
|
|
||||||
if isinstance(pdf, str):
|
|
||||||
if not os.path.exists(pdf):
|
|
||||||
print(f"Not found pdf path at {pdf}")
|
|
||||||
return []
|
|
||||||
imgs = convert_from_path(pdf, dpi=dpi) # PILLOW
|
|
||||||
else:
|
|
||||||
raise NotImplementedError(f"Not yet implement for {type(pdf)} type !!!")
|
|
||||||
|
|
||||||
|
|
||||||
# zoom = dpi // 72
|
|
||||||
# magnify = fitz.Matrix(zoom, zoom)
|
|
||||||
cv_imgs = []
|
|
||||||
|
|
||||||
for idx, img in enumerate(imgs):
|
|
||||||
img = img.convert("RGB")
|
|
||||||
cv_img = np.array(img)
|
|
||||||
cv_img = cv_img[:, :, ::-1].copy()
|
|
||||||
cv_imgs.append(cv_img)
|
|
||||||
if is_get_first_page or idx >= max_page:
|
|
||||||
break
|
|
||||||
return cv_imgs
|
|
||||||
|
|
||||||
|
|
||||||
def pdf_to_image(pdf, dpi=300, is_get_first_page=False, max_page=1000):
|
|
||||||
"""_summary_
|
|
||||||
|
|
||||||
Args:
|
|
||||||
pdf (_type_): _description_
|
|
||||||
dpi (int, optional): _description_. Defaults to 300.
|
|
||||||
is_get_first_page (bool, optional): _description_. Defaults to False.
|
|
||||||
max_page (int, optional): _description_. Defaults to 1000.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
NotImplementedError: _description_
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
_type_: _description_
|
|
||||||
"""
|
|
||||||
if isinstance(pdf, str):
|
|
||||||
if not os.path.exists(pdf):
|
|
||||||
print(f"Not found pdf path at {pdf}")
|
|
||||||
return []
|
|
||||||
doc = fitz.open(pdf) # open document
|
|
||||||
elif isinstance(pdf, bytes):
|
|
||||||
doc = fitz.open(stream=pdf, filetype='pdf')
|
|
||||||
else:
|
|
||||||
raise NotImplementedError(f"Not yet implement for {type(pdf)} type !!!")
|
|
||||||
|
|
||||||
|
|
||||||
zoom = dpi // 72
|
|
||||||
magnify = fitz.Matrix(zoom, zoom)
|
|
||||||
imgs = []
|
|
||||||
|
|
||||||
for idx, page in enumerate(doc):
|
|
||||||
pix = page.get_pixmap(matrix=magnify) # render page to an image
|
|
||||||
|
|
||||||
im = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.h, pix.w, pix.n)
|
|
||||||
im = np.ascontiguousarray(im[..., [2, 1, 0]]) # rgb to bgr
|
|
||||||
imgs.append(im)
|
|
||||||
if is_get_first_page or idx >= max_page:
|
|
||||||
break
|
|
||||||
return imgs
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--pdf_dir", type=str)
|
|
||||||
parser.add_argument("--out_dir", type=str)
|
|
||||||
parser.add_argument("--reserve_parent_dir", action='store_true')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
paths = glob.glob(args.pdf_dir + "/*") \
|
|
||||||
+ glob.glob(args.pdf_dir + "/*/*") \
|
|
||||||
+ glob.glob(args.pdf_dir + "/*/*/*")
|
|
||||||
# + glob.glob(args.pdf_dir + "/*")
|
|
||||||
print(f"Total pdf paths in {args.pdf_dir}: {len(paths)} ")
|
|
||||||
|
|
||||||
error_pdfs = []
|
|
||||||
for path in tqdm(paths):
|
|
||||||
path = str(path)
|
|
||||||
try:
|
|
||||||
convert_pdf2image(path, args.out_dir, reserve_parent_dir=args.reserve_parent_dir)
|
|
||||||
except Exception as err:
|
|
||||||
print(err, path)
|
|
||||||
error_pdfs.append(path)
|
|
||||||
continue
|
|
||||||
print("Total error pdfs: ", len(error_pdfs))
|
|
||||||
print(error_pdfs)
|
|
@ -1,90 +0,0 @@
|
|||||||
from typing import List
|
|
||||||
import random
|
|
||||||
|
|
||||||
def gen_random_color():
|
|
||||||
red = random.randint(0, 255)
|
|
||||||
green = random.randint(0, 255)
|
|
||||||
blue = random.randint(0, 255)
|
|
||||||
|
|
||||||
# combine the values into a hexadecimal color code
|
|
||||||
color_code = "#{:02x}{:02x}{:02x}".format(red, green, blue)
|
|
||||||
return color_code
|
|
||||||
|
|
||||||
def gen_raw_label(labels: List[str]):
|
|
||||||
"""gen raw label for cvat tool
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "no_key",
|
|
||||||
"color": "#33ddff",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
|
|
||||||
Args:
|
|
||||||
labels (List[str]): _description_
|
|
||||||
"""
|
|
||||||
raw_label = []
|
|
||||||
for label in labels:
|
|
||||||
item = {
|
|
||||||
"name": label,
|
|
||||||
"color": gen_random_color(),
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
}
|
|
||||||
raw_label.append(item)
|
|
||||||
|
|
||||||
return raw_label
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
labels = [
|
|
||||||
# id invoice
|
|
||||||
'no_key', # số hóa đơn
|
|
||||||
'no_value',
|
|
||||||
'form_key', # mẫu số hóa đơn
|
|
||||||
'form_value',
|
|
||||||
'serial_key', # số kí hiệu hoá đơn
|
|
||||||
'serial_value',
|
|
||||||
'date',
|
|
||||||
|
|
||||||
# seller info
|
|
||||||
'seller_company_name_key',
|
|
||||||
'seller_company_name_value',
|
|
||||||
'seller_tax_code_key',
|
|
||||||
'seller_tax_code_value',
|
|
||||||
'seller_address_value',
|
|
||||||
'seller_address_key',
|
|
||||||
'seller_mobile_key',
|
|
||||||
'seller_mobile_value',
|
|
||||||
|
|
||||||
# Not yet support seller_bank_no, seller_bank_name
|
|
||||||
# 'seller_name_key',
|
|
||||||
# 'seller_name_value',
|
|
||||||
# 'seller_company_name_value', -> seller_name_value
|
|
||||||
|
|
||||||
# buyer info
|
|
||||||
'buyer_name_key',
|
|
||||||
'buyer_name_value',
|
|
||||||
'buyer_company_name_value',
|
|
||||||
'buyer_company_name_key',
|
|
||||||
'buyer_tax_code_key',
|
|
||||||
'buyer_tax_code_value',
|
|
||||||
'buyer_address_key',
|
|
||||||
'buyer_address_value',
|
|
||||||
'buyer_mobile_key',
|
|
||||||
'buyer_mobile_value',
|
|
||||||
|
|
||||||
# money info
|
|
||||||
'VAT_amount_key',
|
|
||||||
'VAT_amount_value',
|
|
||||||
'total_key',
|
|
||||||
'total_value',
|
|
||||||
'total_in_words_key',
|
|
||||||
'total_in_words_value',
|
|
||||||
|
|
||||||
'other',
|
|
||||||
]
|
|
||||||
|
|
||||||
raw_label = gen_raw_label(labels)
|
|
||||||
print(raw_label)
|
|
@ -1,87 +0,0 @@
|
|||||||
|
|
||||||
import os
|
|
||||||
import glob
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
def read_txt(txt):
|
|
||||||
with open(txt, 'r', encoding='utf8') as f:
|
|
||||||
data = [line.strip() for line in f]
|
|
||||||
return data
|
|
||||||
|
|
||||||
def write_txt(txt, data):
|
|
||||||
with open(txt, 'w', encoding='utf8') as f:
|
|
||||||
for line in data:
|
|
||||||
f.write(line + "\n")
|
|
||||||
|
|
||||||
def write_json(json_path, data):
|
|
||||||
with open(json_path, 'w', encoding='utf8') as f:
|
|
||||||
json.dump(data, f, ensure_ascii=False)
|
|
||||||
|
|
||||||
|
|
||||||
def read_json(json_path):
|
|
||||||
with open(json_path, 'r', encoding='utf8') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def create_template_info(data_dir, json_out):
|
|
||||||
outputs ={}
|
|
||||||
txt_paths = sorted(glob.glob(data_dir + "/*.txt"))
|
|
||||||
|
|
||||||
for txt_path in txt_paths:
|
|
||||||
txt_name = os.path.basename(txt_path)
|
|
||||||
txt_data = read_txt(txt_path)
|
|
||||||
wordgroups = [item for item in txt_data if "____kie_wordgroup seller_company_name_value" in item]
|
|
||||||
num_line_company = len(wordgroups)
|
|
||||||
outputs[txt_name] = num_line_company
|
|
||||||
write_json(json_out, outputs)
|
|
||||||
|
|
||||||
|
|
||||||
def filter_data(template_file, data_file, img_dir, txt_dir, output):
|
|
||||||
template_data = read_json(template_file)
|
|
||||||
data = read_json(data_file)
|
|
||||||
|
|
||||||
new_data = []
|
|
||||||
for txt_name, num_wordgroup_line in template_data.items():
|
|
||||||
id = txt_name.split("_type99_")[0]
|
|
||||||
for txt_name_target, num_wordgroup_target_line in data.items():
|
|
||||||
id_target = txt_name_target.split("_type99_")[0]
|
|
||||||
# print(id, id_target, id_target != id)
|
|
||||||
if id_target != id:
|
|
||||||
# print(id_target, id)
|
|
||||||
continue
|
|
||||||
if num_wordgroup_line != num_wordgroup_target_line:
|
|
||||||
continue
|
|
||||||
|
|
||||||
new_data.append(txt_name_target)
|
|
||||||
|
|
||||||
new_data = sorted(list(set(new_data)))
|
|
||||||
print(new_data[:5])
|
|
||||||
# return new_data
|
|
||||||
|
|
||||||
if not os.path.exists(output):
|
|
||||||
os.makedirs(output, exist_ok=True)
|
|
||||||
|
|
||||||
for txt_name in new_data:
|
|
||||||
img_path = os.path.join(img_dir, txt_name.replace(".txt", ".jpg"))
|
|
||||||
shutil.copy(img_path, output)
|
|
||||||
shutil.copy(os.path.join(txt_dir, txt_name), output)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
target_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/visualize/vnpt_one_line_r20_txt"
|
|
||||||
template_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/visualize/vnpt_one_line_txt"
|
|
||||||
output_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/craw_data/output/synth_vnpt_r20/one_line_filtered"
|
|
||||||
img_target_dir = "/mnt/ssd1T/hoanglv/Projects/KIE/craw_data/output/synth_vnpt_r20/one_line"
|
|
||||||
out_template_json = "vnpt_template.json"
|
|
||||||
out_target_json = "vnpt_r20.json"
|
|
||||||
create_template_info(template_dir, out_template_json)
|
|
||||||
create_template_info(target_dir, out_target_json)
|
|
||||||
|
|
||||||
new_data = filter_data(out_template_json, out_target_json,img_target_dir, target_dir, output_dir)
|
|
||||||
print("Total after filter: ", len(new_data))
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"invoice_vnpt_id10_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id11_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id12_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id13_type99_1.txt": 2,
|
|
||||||
"invoice_vnpt_id14_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id15_type99_1.txt": 0,
|
|
||||||
"invoice_vnpt_id16_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id17_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id18_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id19_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id20_type99_1.txt": 2,
|
|
||||||
"invoice_vnpt_id21_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id22_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id23_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id24_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id25_type99_1.txt": 2,
|
|
||||||
"invoice_vnpt_id26_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id27_type99_1.txt": 4,
|
|
||||||
"invoice_vnpt_id28_type99_1.txt": 0,
|
|
||||||
"invoice_vnpt_id29_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id30_type99_1.txt": 3,
|
|
||||||
"invoice_vnpt_id31_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id32_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id33_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id34_type99_1.txt": 3,
|
|
||||||
"invoice_vnpt_id35_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id36_type99_1.txt": 2,
|
|
||||||
"invoice_vnpt_id37_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id39_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id40_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id43_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id44_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id45_type99_1.txt": 0,
|
|
||||||
"invoice_vnpt_id46_type99_1.txt": 2,
|
|
||||||
"invoice_vnpt_id47_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id48_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id49_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id50_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id52_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id53_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id54_type99_1.txt": 0,
|
|
||||||
"invoice_vnpt_id55_type99_1.txt": 0,
|
|
||||||
"invoice_vnpt_id56_type99_1.txt": 2,
|
|
||||||
"invoice_vnpt_id57_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id8_type99_1.txt": 1,
|
|
||||||
"invoice_vnpt_id9_type99_1.txt": 1
|
|
||||||
}
|
|
@ -1,213 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"name": "word",
|
|
||||||
"color": "#83e070",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": [
|
|
||||||
{
|
|
||||||
"name": "text",
|
|
||||||
"input_type": "text",
|
|
||||||
"mutable": false,
|
|
||||||
"values": ["x"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kie_label",
|
|
||||||
"input_type": "text",
|
|
||||||
"mutable": false,
|
|
||||||
"values": ["x"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "no_key",
|
|
||||||
"color": "#cf04f1",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "no_value",
|
|
||||||
"color": "#0a01ce",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "form_key",
|
|
||||||
"color": "#bfe920",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "form_value",
|
|
||||||
"color": "#ac3436",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "serial_key",
|
|
||||||
"color": "#706724",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "serial_value",
|
|
||||||
"color": "#7a9b4b",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "date",
|
|
||||||
"color": "#23f0e9",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_company_name_key",
|
|
||||||
"color": "#f47ccc",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_company_name_value",
|
|
||||||
"color": "#9c9c73",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_tax_code_key",
|
|
||||||
"color": "#afa0fa",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_tax_code_value",
|
|
||||||
"color": "#6e7352",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_address_value",
|
|
||||||
"color": "#121512",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_address_key",
|
|
||||||
"color": "#188735",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_mobile_key",
|
|
||||||
"color": "#7387fd",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seller_mobile_value",
|
|
||||||
"color": "#325bf1",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_name_key",
|
|
||||||
"color": "#a5b431",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_name_value",
|
|
||||||
"color": "#e63dcc",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_company_name_value",
|
|
||||||
"color": "#e9bf0b",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_company_name_key",
|
|
||||||
"color": "#a8d921",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_tax_code_key",
|
|
||||||
"color": "#1d8f4f",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_tax_code_value",
|
|
||||||
"color": "#e638c6",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_address_key",
|
|
||||||
"color": "#74afe5",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_address_value",
|
|
||||||
"color": "#1518dc",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_mobile_key",
|
|
||||||
"color": "#13b1cd",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buyer_mobile_value",
|
|
||||||
"color": "#c49d59",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "VAT_amount_key",
|
|
||||||
"color": "#69c945",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "VAT_amount_value",
|
|
||||||
"color": "#77c3be",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "total_key",
|
|
||||||
"color": "#d1353a",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "total_value",
|
|
||||||
"color": "#246976",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "total_in_words_key",
|
|
||||||
"color": "#45a8b5",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "total_in_words_value",
|
|
||||||
"color": "#d800df",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "other",
|
|
||||||
"color": "#ba0fbd",
|
|
||||||
"type": "any",
|
|
||||||
"attributes": []
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,479 +0,0 @@
|
|||||||
import argparse
|
|
||||||
import re
|
|
||||||
from difflib import SequenceMatcher
|
|
||||||
|
|
||||||
from rapidfuzz.distance import Levenshtein
|
|
||||||
from terminaltables import AsciiTable
|
|
||||||
|
|
||||||
from sdsvkie.cfg import load_cfg
|
|
||||||
from sdsvkie.utils.io_file import read_json, write_json
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
def is_type_list(x, type):
|
|
||||||
|
|
||||||
if not isinstance(x, list):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return all(isinstance(item, type) for item in x)
|
|
||||||
|
|
||||||
|
|
||||||
def cal_true_positive_char(pred, gt):
|
|
||||||
"""Calculate correct character number in prediction.
|
|
||||||
Args:
|
|
||||||
pred (str): Prediction text.
|
|
||||||
gt (str): Ground truth text.
|
|
||||||
Returns:
|
|
||||||
true_positive_char_num (int): The true positive number.
|
|
||||||
"""
|
|
||||||
|
|
||||||
all_opt = SequenceMatcher(None, pred, gt)
|
|
||||||
true_positive_char_num = 0
|
|
||||||
for opt, _, _, s2, e2 in all_opt.get_opcodes():
|
|
||||||
if opt == "equal":
|
|
||||||
true_positive_char_num += e2 - s2
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
return true_positive_char_num
|
|
||||||
|
|
||||||
|
|
||||||
def post_processing(text, lowercase=False):
|
|
||||||
"""
|
|
||||||
- Remove special characters and extra spaces
|
|
||||||
"""
|
|
||||||
|
|
||||||
text = re.sub(
|
|
||||||
r"[^aAàÀảẢãÃáÁạẠăĂằẰẳẲẵẴắẮặẶâÂầẦẩẨẫẪấẤậẬbBcCdDđĐeEèÈẻẺẽẼéÉẹẸêÊềỀểỂễỄếẾệỆfFgGhHiIìÌỉỈĩĨíÍịỊjJkKlLmMnNoOòÒỏỎõÕóÓọỌôÔồỒổỔỗỖốỐộỘơƠờỜởỞỡỠớỚợỢpPqQrRsStTuUùÙủỦũŨúÚụỤưƯừỪửỬữỮứỨựỰvVwWxXyYỳỲỷỶỹỸýÝỵỴzZ0123456789 ]",
|
|
||||||
" ",
|
|
||||||
text,
|
|
||||||
)
|
|
||||||
text = re.sub(r"\s\s+", " ", text)
|
|
||||||
text = text.strip()
|
|
||||||
|
|
||||||
if lowercase:
|
|
||||||
text = text.lower()
|
|
||||||
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
def count_matches(pred_texts, gt_texts, use_ignore=True):
|
|
||||||
"""Count the various match number for metric calculation.
|
|
||||||
Args:
|
|
||||||
pred_texts (list[str]): Predicted text string.
|
|
||||||
gt_texts (list[str]): Ground truth text string.
|
|
||||||
Returns:
|
|
||||||
match_res: (dict[str: int]): Match number used for
|
|
||||||
metric calculation.
|
|
||||||
"""
|
|
||||||
match_res = {
|
|
||||||
"gt_char_num": 0,
|
|
||||||
"pred_char_num": 0,
|
|
||||||
"true_positive_char_num": 0,
|
|
||||||
"gt_word_num": 0,
|
|
||||||
"match_word_num": 0,
|
|
||||||
"match_word_ignore_case": 0,
|
|
||||||
"match_word_ignore_case_symbol": 0,
|
|
||||||
"match_kie": 0,
|
|
||||||
"match_kie_ignore_case": 0,
|
|
||||||
}
|
|
||||||
# comp = re.compile('[^A-Z^a-z^0-9^\u4e00-\u9fa5]')
|
|
||||||
# comp = re.compile('[]')
|
|
||||||
norm_ed_sum = 0.0
|
|
||||||
|
|
||||||
gt_texts_for_ned_word = []
|
|
||||||
pred_texts_for_ned_word = []
|
|
||||||
for pred_text, gt_text in zip(pred_texts, gt_texts):
|
|
||||||
if gt_text == pred_text:
|
|
||||||
match_res["match_word_num"] += 1
|
|
||||||
match_res["match_kie"] += 1
|
|
||||||
gt_text_lower = gt_text.lower()
|
|
||||||
pred_text_lower = pred_text.lower()
|
|
||||||
if gt_text_lower == pred_text_lower:
|
|
||||||
match_res["match_word_ignore_case"] += 1
|
|
||||||
|
|
||||||
# gt_text_lower_ignore = comp.sub('', gt_text_lower)
|
|
||||||
# pred_text_lower_ignore = comp.sub('', pred_text_lower)
|
|
||||||
if use_ignore:
|
|
||||||
gt_text_lower_ignore = post_processing(gt_text_lower)
|
|
||||||
pred_text_lower_ignore = post_processing(pred_text_lower)
|
|
||||||
else:
|
|
||||||
gt_text_lower_ignore = gt_text_lower
|
|
||||||
pred_text_lower_ignore = pred_text_lower
|
|
||||||
|
|
||||||
if gt_text_lower_ignore == pred_text_lower_ignore:
|
|
||||||
match_res["match_kie_ignore_case"] += 1
|
|
||||||
|
|
||||||
gt_texts_for_ned_word.append(gt_text_lower_ignore.split(" "))
|
|
||||||
pred_texts_for_ned_word.append(pred_text_lower_ignore.split(" "))
|
|
||||||
|
|
||||||
match_res["gt_word_num"] += 1
|
|
||||||
|
|
||||||
norm_ed = Levenshtein.normalized_distance(
|
|
||||||
pred_text_lower_ignore, gt_text_lower_ignore
|
|
||||||
)
|
|
||||||
# if norm_ed > 0.1:
|
|
||||||
# print(gt_text_lower_ignore, pred_text_lower_ignore, sep='\n')
|
|
||||||
# print("-"*20)
|
|
||||||
norm_ed_sum += norm_ed
|
|
||||||
|
|
||||||
# number to calculate char level recall & precision
|
|
||||||
match_res["gt_char_num"] += len(gt_text_lower_ignore)
|
|
||||||
match_res["pred_char_num"] += len(pred_text_lower_ignore)
|
|
||||||
true_positive_char_num = cal_true_positive_char(
|
|
||||||
pred_text_lower_ignore, gt_text_lower_ignore
|
|
||||||
)
|
|
||||||
match_res["true_positive_char_num"] += true_positive_char_num
|
|
||||||
|
|
||||||
normalized_edit_distance = norm_ed_sum / max(1, len(gt_texts))
|
|
||||||
match_res["ned"] = normalized_edit_distance
|
|
||||||
|
|
||||||
# NED for word-level
|
|
||||||
norm_ed_word_sum = 0.0
|
|
||||||
# print(pred_texts_for_ned_word[0])
|
|
||||||
unique_words = list(
|
|
||||||
set(
|
|
||||||
[x for line in pred_texts_for_ned_word for x in line]
|
|
||||||
+ [x for line in gt_texts_for_ned_word for x in line]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
preds = [
|
|
||||||
[unique_words.index(w) for w in pred_text_for_ned_word]
|
|
||||||
for pred_text_for_ned_word in pred_texts_for_ned_word
|
|
||||||
]
|
|
||||||
truths = [
|
|
||||||
[unique_words.index(w) for w in gt_text_for_ned_word]
|
|
||||||
for gt_text_for_ned_word in gt_texts_for_ned_word
|
|
||||||
]
|
|
||||||
for pred_text, gt_text in zip(preds, truths):
|
|
||||||
norm_ed_word = Levenshtein.normalized_distance(pred_text, gt_text)
|
|
||||||
# if norm_ed_word < 0.2:
|
|
||||||
# print(pred_text, gt_text)
|
|
||||||
norm_ed_word_sum += norm_ed_word
|
|
||||||
|
|
||||||
normalized_edit_distance_word = norm_ed_word_sum / max(1, len(gt_texts))
|
|
||||||
match_res["ned_word"] = normalized_edit_distance_word
|
|
||||||
|
|
||||||
return match_res
|
|
||||||
|
|
||||||
|
|
||||||
def eval_ocr_metric(pred_texts, gt_texts, metric="acc"):
|
|
||||||
"""Evaluate the text recognition performance with metric: word accuracy and
|
|
||||||
1-N.E.D. See https://rrc.cvc.uab.es/?ch=14&com=tasks for details.
|
|
||||||
Args:
|
|
||||||
pred_texts (list[str]): Text strings of prediction.
|
|
||||||
gt_texts (list[str]): Text strings of ground truth.
|
|
||||||
metric (str | list[str]): Metric(s) to be evaluated. Options are:
|
|
||||||
- 'word_acc': Accuracy at word level.
|
|
||||||
- 'word_acc_ignore_case': Accuracy at word level, ignoring letter
|
|
||||||
case.
|
|
||||||
- 'word_acc_ignore_case_symbol': Accuracy at word level, ignoring
|
|
||||||
letter case and symbol. (Default metric for academic evaluation)
|
|
||||||
- 'char_recall': Recall at character level, ignoring
|
|
||||||
letter case and symbol.
|
|
||||||
- 'char_precision': Precision at character level, ignoring
|
|
||||||
letter case and symbol.
|
|
||||||
- 'one_minus_ned': 1 - normalized_edit_distance
|
|
||||||
In particular, if ``metric == 'acc'``, results on all metrics above
|
|
||||||
will be reported.
|
|
||||||
Returns:
|
|
||||||
dict{str: float}: Result dict for text recognition, keys could be some
|
|
||||||
of the following: ['word_acc', 'word_acc_ignore_case',
|
|
||||||
'word_acc_ignore_case_symbol', 'char_recall', 'char_precision',
|
|
||||||
'1-N.E.D'].
|
|
||||||
"""
|
|
||||||
assert isinstance(pred_texts, list)
|
|
||||||
assert isinstance(gt_texts, list)
|
|
||||||
assert len(pred_texts) == len(gt_texts)
|
|
||||||
|
|
||||||
assert isinstance(metric, str) or is_type_list(metric, str)
|
|
||||||
if metric == "acc" or metric == ["acc"]:
|
|
||||||
metric = [
|
|
||||||
"word_acc",
|
|
||||||
"word_acc_ignore_case",
|
|
||||||
"word_acc_ignore_case_symbol",
|
|
||||||
"char_recall",
|
|
||||||
"char_precision",
|
|
||||||
"one_minus_ned",
|
|
||||||
]
|
|
||||||
metric = set([metric]) if isinstance(metric, str) else set(metric)
|
|
||||||
|
|
||||||
# supported_metrics = set([
|
|
||||||
# 'word_acc', 'word_acc_ignore_case', 'word_acc_ignore_case_symbol',
|
|
||||||
# 'char_recall', 'char_precision', 'one_minus_ned', 'one_minust_ned_word'
|
|
||||||
# ])
|
|
||||||
# assert metric.issubset(supported_metrics)
|
|
||||||
|
|
||||||
match_res = count_matches(pred_texts, gt_texts)
|
|
||||||
eps = 1e-8
|
|
||||||
eval_res = {}
|
|
||||||
|
|
||||||
if "char_recall" in metric:
|
|
||||||
char_recall = (
|
|
||||||
1.0 * match_res["true_positive_char_num"] / (eps + match_res["gt_char_num"])
|
|
||||||
)
|
|
||||||
eval_res["char_recall"] = char_recall
|
|
||||||
|
|
||||||
if "char_precision" in metric:
|
|
||||||
char_precision = (
|
|
||||||
1.0
|
|
||||||
* match_res["true_positive_char_num"]
|
|
||||||
/ (eps + match_res["pred_char_num"])
|
|
||||||
)
|
|
||||||
eval_res["char_precision"] = char_precision
|
|
||||||
|
|
||||||
if "word_acc" in metric:
|
|
||||||
word_acc = 1.0 * match_res["match_word_num"] / (eps + match_res["gt_word_num"])
|
|
||||||
eval_res["word_acc"] = word_acc
|
|
||||||
|
|
||||||
if "word_acc_ignore_case" in metric:
|
|
||||||
word_acc_ignore_case = (
|
|
||||||
1.0 * match_res["match_word_ignore_case"] / (eps + match_res["gt_word_num"])
|
|
||||||
)
|
|
||||||
eval_res["word_acc_ignore_case"] = word_acc_ignore_case
|
|
||||||
|
|
||||||
if "word_acc_ignore_case_symbol" in metric:
|
|
||||||
word_acc_ignore_case_symbol = (
|
|
||||||
1.0
|
|
||||||
* match_res["match_word_ignore_case_symbol"]
|
|
||||||
/ (eps + match_res["gt_word_num"])
|
|
||||||
)
|
|
||||||
eval_res["word_acc_ignore_case_symbol"] = word_acc_ignore_case_symbol
|
|
||||||
|
|
||||||
if "one_minus_ned" in metric:
|
|
||||||
|
|
||||||
eval_res["1-N.E.D"] = 1.0 - match_res["ned"]
|
|
||||||
|
|
||||||
if "one_minus_ned_word" in metric:
|
|
||||||
|
|
||||||
eval_res["1-N.E.D_word"] = 1.0 - match_res["ned_word"]
|
|
||||||
|
|
||||||
if "line_acc_ignore_case_symbol" in metric:
|
|
||||||
line_acc_ignore_case_symbol = (
|
|
||||||
1.0 * match_res["match_kie_ignore_case"] / (eps + match_res["gt_word_num"])
|
|
||||||
)
|
|
||||||
eval_res["line_acc_ignore_case_symbol"] = line_acc_ignore_case_symbol
|
|
||||||
|
|
||||||
if "line_acc" in metric:
|
|
||||||
word_acc_ignore_case_symbol = (
|
|
||||||
1.0 * match_res["match_kie"] / (eps + match_res["gt_word_num"])
|
|
||||||
)
|
|
||||||
eval_res["line_acc"] = word_acc_ignore_case_symbol
|
|
||||||
|
|
||||||
for key, value in eval_res.items():
|
|
||||||
eval_res[key] = float("{:.4f}".format(value))
|
|
||||||
|
|
||||||
return eval_res
|
|
||||||
|
|
||||||
|
|
||||||
def eval_kie(pred_e2e_path, gt_e2e_path, kie_labels=[], skip_labels=[], log_failure_case=None, norm_failcase=False):
|
|
||||||
# assert ".json" in pred_e2e_path and ".json" in gt_e2e_path, "only support json type"
|
|
||||||
|
|
||||||
f = None
|
|
||||||
if log_failure_case:
|
|
||||||
log_failure_case = Path(log_failure_case)
|
|
||||||
log_failure_case_dir = log_failure_case.parent
|
|
||||||
if not log_failure_case_dir.exists():
|
|
||||||
log_failure_case_dir.mkdir(parents=True)
|
|
||||||
|
|
||||||
if isinstance(gt_e2e_path, str):
|
|
||||||
gt_e2e = read_json(gt_e2e_path)
|
|
||||||
else:
|
|
||||||
gt_e2e = gt_e2e_path
|
|
||||||
if isinstance(pred_e2e_path, str):
|
|
||||||
preds_e2e = read_json(pred_e2e_path)
|
|
||||||
else:
|
|
||||||
preds_e2e = pred_e2e_path
|
|
||||||
|
|
||||||
KIE_LABELS_WITH_ONLY_VALUES = [
|
|
||||||
class_name
|
|
||||||
for class_name in kie_labels
|
|
||||||
if "_key" not in class_name
|
|
||||||
and "other" not in class_name
|
|
||||||
and class_name not in skip_labels
|
|
||||||
]
|
|
||||||
|
|
||||||
pred_texts_dict = {label: [] for label in KIE_LABELS_WITH_ONLY_VALUES}
|
|
||||||
gt_texts_dict = {label: [] for label in KIE_LABELS_WITH_ONLY_VALUES}
|
|
||||||
|
|
||||||
results = {label: 1 for label in KIE_LABELS_WITH_ONLY_VALUES}
|
|
||||||
# print(KIE_LABELS_WITH_ONLY_VALUES)
|
|
||||||
|
|
||||||
fail_cases = {}
|
|
||||||
for img_id in preds_e2e.keys():
|
|
||||||
fail_cases[img_id] = {}
|
|
||||||
pred_items = preds_e2e[img_id]
|
|
||||||
gt_items = gt_e2e[img_id]
|
|
||||||
|
|
||||||
if not pred_items:
|
|
||||||
pred_items = {
|
|
||||||
class_name: "" for class_name in KIE_LABELS_WITH_ONLY_VALUES
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for class_name, text_gt in gt_items.items():
|
|
||||||
if class_name in skip_labels:
|
|
||||||
continue
|
|
||||||
# if class_name == 'seller_name_value':
|
|
||||||
# print(gt_items)
|
|
||||||
if class_name not in pred_items:
|
|
||||||
text_pred = ""
|
|
||||||
else:
|
|
||||||
text_pred = pred_items[class_name]
|
|
||||||
|
|
||||||
if norm_failcase:
|
|
||||||
_text_pred = post_processing(text_pred, lowercase=True)
|
|
||||||
_text_gt = post_processing(text_gt, lowercase=True)
|
|
||||||
|
|
||||||
else:
|
|
||||||
_text_pred = text_pred
|
|
||||||
_text_gt = text_gt
|
|
||||||
|
|
||||||
if _text_pred != _text_gt:
|
|
||||||
fail_cases[img_id][class_name] = {
|
|
||||||
'pred': _text_pred,
|
|
||||||
'gt': _text_gt
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pred_texts_dict[class_name].append(text_pred)
|
|
||||||
gt_texts_dict[class_name].append(text_gt)
|
|
||||||
|
|
||||||
if log_failure_case:
|
|
||||||
with open(log_failure_case, 'w', encoding='utf8') as f:
|
|
||||||
write_json(log_failure_case, fail_cases)
|
|
||||||
|
|
||||||
for class_name in KIE_LABELS_WITH_ONLY_VALUES:
|
|
||||||
pred_texts = pred_texts_dict[class_name]
|
|
||||||
gt_texts = gt_texts_dict[class_name]
|
|
||||||
result = eval_ocr_metric(
|
|
||||||
pred_texts,
|
|
||||||
gt_texts,
|
|
||||||
metric=[
|
|
||||||
"one_minus_ned",
|
|
||||||
"line_acc_ignore_case_symbol",
|
|
||||||
"line_acc",
|
|
||||||
"one_minus_ned_word",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
results[class_name] = {
|
|
||||||
"1-ned": result["1-N.E.D"],
|
|
||||||
"1-ned-word": result["1-N.E.D_word"],
|
|
||||||
"line_acc": result["line_acc"],
|
|
||||||
"line_acc_ignore_case_symbol": result["line_acc_ignore_case_symbol"],
|
|
||||||
"samples": len(pred_texts),
|
|
||||||
}
|
|
||||||
|
|
||||||
# avg reusults
|
|
||||||
sum_1_ned = sum(
|
|
||||||
[
|
|
||||||
results[class_name]["1-ned"] * results[class_name]["samples"]
|
|
||||||
for class_name in KIE_LABELS_WITH_ONLY_VALUES
|
|
||||||
]
|
|
||||||
)
|
|
||||||
sum_1_ned_word = sum(
|
|
||||||
[
|
|
||||||
results[class_name]["1-ned-word"] * results[class_name]["samples"]
|
|
||||||
for class_name in KIE_LABELS_WITH_ONLY_VALUES
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
sum_line_acc = sum(
|
|
||||||
[
|
|
||||||
results[class_name]["line_acc"] * results[class_name]["samples"]
|
|
||||||
for class_name in KIE_LABELS_WITH_ONLY_VALUES
|
|
||||||
]
|
|
||||||
)
|
|
||||||
sum_line_acc_ignore_case_symbol = sum(
|
|
||||||
[
|
|
||||||
results[class_name]["line_acc_ignore_case_symbol"]
|
|
||||||
* results[class_name]["samples"]
|
|
||||||
for class_name in KIE_LABELS_WITH_ONLY_VALUES
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
total_samples = sum(
|
|
||||||
[results[class_name]["samples"] for class_name in KIE_LABELS_WITH_ONLY_VALUES]
|
|
||||||
)
|
|
||||||
results["avg_all"] = {
|
|
||||||
"1-ned": round(sum_1_ned / total_samples, 4),
|
|
||||||
"1-ned-word": round(sum_1_ned_word / total_samples, 4),
|
|
||||||
"line_acc": round(sum_line_acc / total_samples, 4),
|
|
||||||
"line_acc_ignore_case_symbol": round(
|
|
||||||
sum_line_acc_ignore_case_symbol / total_samples, 4
|
|
||||||
),
|
|
||||||
"samples": total_samples,
|
|
||||||
}
|
|
||||||
|
|
||||||
table_data = [
|
|
||||||
[
|
|
||||||
"class_name",
|
|
||||||
"1-NED",
|
|
||||||
"1-N.E.D_word",
|
|
||||||
"line-acc",
|
|
||||||
"line_acc_ignore_case_symbol",
|
|
||||||
"#samples",
|
|
||||||
]
|
|
||||||
]
|
|
||||||
for class_name in results.keys():
|
|
||||||
# if c < p.shape[0]:
|
|
||||||
table_data.append(
|
|
||||||
[
|
|
||||||
class_name,
|
|
||||||
results[class_name]["1-ned"],
|
|
||||||
results[class_name]["1-ned-word"],
|
|
||||||
results[class_name]["line_acc"],
|
|
||||||
results[class_name]["line_acc_ignore_case_symbol"],
|
|
||||||
results[class_name]["samples"],
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
table = AsciiTable(table_data)
|
|
||||||
print(table.table)
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
# gt_e2e = "/mnt/ssd1T/hoanglv/Projects/KIE/DATA/test_end2end/test_e2e.json"
|
|
||||||
|
|
||||||
# # pred_e2e = "/mnt/ssd1T/hoanglv/Projects/KIE/TokenClassification_invoice/workdirs/runs/pred_e2e.json"
|
|
||||||
# # pred_e2e = "/mnt/ssd1T/hoanglv/Projects/KIE/TokenClassification_invoice/workdirs/runs/infer/layoutxlm-base-31-03-2023-maxwords150_samplingv2/pred_e2e.json"
|
|
||||||
# # pred_e2e = "/mnt/ssd1T/hoanglv/Projects/KIE/TokenClassification_invoice/workdirs/runs/infer/kie_e2e_pred_17-10-2022-maxwords150_samplingv2_rm_dup_boxes/pred_e2e.json"
|
|
||||||
# # pred_e2e = "/mnt/ssd1T/hoanglv/Projects/KIE/TokenClassification_invoice/workdirs/runs/infer/kie_e2e_pred_17-10-2022-maxwords150_samplingv2/pred_e2e.json"
|
|
||||||
|
|
||||||
# # pred_e2e = "/home/sds/hoanglv/Projects/TokenClassification_invoice/runs/infer/kie_e2e_pred_14-10-2022_2/pred_e2e.json"
|
|
||||||
# pred_e2e = "/mnt/ssd1T/hoanglv/Projects/KIE/sdsvkie/workdirs/e2e/test_17_10_2022_last_use_ocr_merge_use_label.json"
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--cfg", type=str)
|
|
||||||
parser.add_argument("--pred", type=str, help="predict json file path")
|
|
||||||
parser.add_argument("--gt", type=str, help="ground truth json file path")
|
|
||||||
parser.add_argument("--log_failure_case", type=str, default=None, help="log_failure_case path")
|
|
||||||
parser.add_argument("--norm_failcase", action='store_true')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
cfg = load_cfg(args.cfg)
|
|
||||||
kie_labels = cfg['classes']
|
|
||||||
|
|
||||||
# res = eval_kie(pred_e2e, gt_e2e, skip_labels=["buyer_mobile_value"])
|
|
||||||
# print(res)
|
|
||||||
result = eval_kie(
|
|
||||||
pred_e2e_path=args.pred,
|
|
||||||
gt_e2e_path=args.gt,
|
|
||||||
kie_labels=kie_labels,
|
|
||||||
skip_labels=["Others", "other"],
|
|
||||||
log_failure_case=args.log_failure_case,
|
|
||||||
norm_failcase=args.norm_failcase
|
|
||||||
)
|
|
||||||
|
|
||||||
print("Path of validation dataset: /mnt/ssd1T/hoanglv/Projects/KIE/DATA/dev_model/Invoice/processed/test/PV2/invoice_kie_validation")
|
|
||||||
print("Number of validation dataset: ", result[list(result.keys())[0]]['samples'])
|
|
||||||
print("Evaluation metric: NLD")
|
|
||||||
print("Target level: ")
|
|
||||||
print("Archieved level: ")
|
|
||||||
print("Verification result: PASS")
|
|
||||||
|
|
||||||
""""
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
@ -1,102 +0,0 @@
|
|||||||
import json
|
|
||||||
import re
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
|
|
||||||
def yaml_load(file="data.yaml", append_filename=False):
|
|
||||||
"""
|
|
||||||
Load YAML data from a file.
|
|
||||||
Args:
|
|
||||||
file (str, optional): File name. Default is 'data.yaml'.
|
|
||||||
append_filename (bool): Add the YAML filename to the YAML dictionary. Default is False.
|
|
||||||
Returns:
|
|
||||||
dict: YAML data and file name.
|
|
||||||
"""
|
|
||||||
with open(file, errors="ignore", encoding="utf-8") as f:
|
|
||||||
s = f.read() # string
|
|
||||||
|
|
||||||
# Remove special characters
|
|
||||||
if not s.isprintable():
|
|
||||||
s = re.sub(
|
|
||||||
r"[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010ffff]+",
|
|
||||||
"",
|
|
||||||
s,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add YAML filename to dict and return
|
|
||||||
return (
|
|
||||||
{**yaml.safe_load(s), "yaml_file": str(file)}
|
|
||||||
if append_filename
|
|
||||||
else yaml.safe_load(s)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def yaml_save(file="data.yaml", data=None):
|
|
||||||
"""
|
|
||||||
Save YAML data to a file.
|
|
||||||
Args:
|
|
||||||
file (str, optional): File name. Default is 'data.yaml'.
|
|
||||||
data (dict, optional): Data to save in YAML format. Default is None.
|
|
||||||
Returns:
|
|
||||||
None: Data is saved to the specified file.
|
|
||||||
"""
|
|
||||||
file = Path(file)
|
|
||||||
if not file.parent.exists():
|
|
||||||
# Create parent directories if they don't exist
|
|
||||||
file.parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
with open(file, "w") as f:
|
|
||||||
# Dump data to file in YAML format, converting Path objects to strings
|
|
||||||
yaml.safe_dump(
|
|
||||||
{k: str(v) if isinstance(v, Path) else v for k, v in data.items()},
|
|
||||||
f,
|
|
||||||
sort_keys=False,
|
|
||||||
allow_unicode=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def write_txt(txt, data, mode="w"):
|
|
||||||
with open(txt, mode, encoding="utf8") as f:
|
|
||||||
for line in data:
|
|
||||||
f.write(line + "\n")
|
|
||||||
|
|
||||||
|
|
||||||
def read_txt(txt):
|
|
||||||
with open(txt, "r", encoding="utf8") as f:
|
|
||||||
data = [line.strip() for line in f]
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def write_json(json_path, data, sort_keys=True):
|
|
||||||
with open(json_path, "w", encoding="utf8") as f:
|
|
||||||
json.dump(data, f, ensure_ascii=False, sort_keys=sort_keys)
|
|
||||||
|
|
||||||
|
|
||||||
def read_json(json_path):
|
|
||||||
with open(json_path, "r", encoding="utf8") as f:
|
|
||||||
data = json.load(f)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def load_ocr_output(txt_path):
|
|
||||||
with open(txt_path) as f:
|
|
||||||
lines = [line.replace("\n", "").replace("\r", "") for line in f.readlines()]
|
|
||||||
words, boxes, labels = [], [], []
|
|
||||||
for i, line in enumerate(lines):
|
|
||||||
if len(line.split("\t")) == 6:
|
|
||||||
x1, y1, x2, y2, text, label = line.split("\t")
|
|
||||||
else:
|
|
||||||
x1, y1, x2, y2, text = line.split("\t")
|
|
||||||
label = None
|
|
||||||
|
|
||||||
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
|
|
||||||
box = [x1, y1, x2, y2]
|
|
||||||
if text != " ":
|
|
||||||
words.append(text)
|
|
||||||
boxes.append(box)
|
|
||||||
labels.append(label)
|
|
||||||
|
|
||||||
return {"boxes": boxes, "texts": words, 'labels': labels}
|
|
@ -1,48 +0,0 @@
|
|||||||
import os
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
import functools
|
|
||||||
|
|
||||||
logger_initialized = {}
|
|
||||||
|
|
||||||
@functools.lru_cache()
|
|
||||||
def get_logger(name='root', log_file=None, log_level=logging.DEBUG):
|
|
||||||
"""Initialize and get a logger by name.
|
|
||||||
If the logger has not been initialized, this method will initialize the
|
|
||||||
logger by adding one or two handlers, otherwise the initialized logger will
|
|
||||||
be directly returned. During initialization, a StreamHandler will always be
|
|
||||||
added. If `log_file` is specified a FileHandler will also be added.
|
|
||||||
Args:
|
|
||||||
name (str): Logger name.
|
|
||||||
log_file (str | None): The log filename. If specified, a FileHandler
|
|
||||||
will be added to the logger.
|
|
||||||
log_level (int): The logger level. Note that only the process of
|
|
||||||
rank 0 is affected, and other processes will set the level to
|
|
||||||
"Error" thus be silent most of the time.
|
|
||||||
Returns:
|
|
||||||
logging.Logger: The expected logger.
|
|
||||||
"""
|
|
||||||
logger = logging.getLogger(name)
|
|
||||||
if name in logger_initialized:
|
|
||||||
return logger
|
|
||||||
for logger_name in logger_initialized:
|
|
||||||
if name.startswith(logger_name):
|
|
||||||
return logger
|
|
||||||
|
|
||||||
formatter = logging.Formatter(
|
|
||||||
'[%(asctime)s] %(name)s %(levelname)s: %(message)s',
|
|
||||||
datefmt="%Y/%m/%d %H:%M:%S")
|
|
||||||
|
|
||||||
stream_handler = logging.StreamHandler(stream=sys.stdout)
|
|
||||||
stream_handler.setFormatter(formatter)
|
|
||||||
logger.addHandler(stream_handler)
|
|
||||||
if log_file is not None:
|
|
||||||
log_file_folder = os.path.split(log_file)[0]
|
|
||||||
os.makedirs(log_file_folder, exist_ok=True)
|
|
||||||
file_handler = logging.FileHandler(log_file, 'a', encoding='utf8')
|
|
||||||
file_handler.setFormatter(formatter)
|
|
||||||
logger.addHandler(file_handler)
|
|
||||||
|
|
||||||
logger.setLevel(log_level)
|
|
||||||
logger_initialized[name] = True
|
|
||||||
return logger
|
|
@ -1,4 +0,0 @@
|
|||||||
from .common_post_processing import *
|
|
||||||
from .invoice_post_processing import *
|
|
||||||
from .receipt_post_processing import *
|
|
||||||
from .hardcoded_postprocess_funcs import *
|
|
@ -1,129 +0,0 @@
|
|||||||
|
|
||||||
import re
|
|
||||||
from datetime import datetime
|
|
||||||
from sdsvkie.utils import Word_group
|
|
||||||
|
|
||||||
|
|
||||||
YEAR_START = 2000
|
|
||||||
def construct_word_groups_to_kie_label(list_word_groups: list):
|
|
||||||
kie_dict = dict()
|
|
||||||
|
|
||||||
for wg in list_word_groups:
|
|
||||||
if wg.kie_label.lower() in ['other', 'others']:
|
|
||||||
continue
|
|
||||||
if wg.kie_label not in kie_dict:
|
|
||||||
kie_dict[wg.kie_label] = [wg]
|
|
||||||
else:
|
|
||||||
kie_dict[wg.kie_label].append(wg)
|
|
||||||
|
|
||||||
return kie_dict
|
|
||||||
|
|
||||||
|
|
||||||
def near(word_group1: Word_group, word_group2: Word_group):
|
|
||||||
min_height = min(
|
|
||||||
word_group1.boundingbox[3] - word_group1.boundingbox[1],
|
|
||||||
word_group2.boundingbox[3] - word_group2.boundingbox[1],
|
|
||||||
)
|
|
||||||
overlap = min(word_group1.boundingbox[3], word_group2.boundingbox[3]) - max(
|
|
||||||
word_group1.boundingbox[1], word_group2.boundingbox[1]
|
|
||||||
)
|
|
||||||
|
|
||||||
if overlap > 0:
|
|
||||||
return True
|
|
||||||
if abs(overlap / min_height) < 1.5:
|
|
||||||
print("near enough", abs(overlap / min_height), overlap, min_height)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def normalize_number(text_str: str, reserve_dot=False, reserve_plus=False, reserve_minus=False):
|
|
||||||
"""
|
|
||||||
Normalize a string of numbers by removing non-numeric characters
|
|
||||||
|
|
||||||
"""
|
|
||||||
assert isinstance(text_str, str), "input must be str"
|
|
||||||
reserver_chars = ""
|
|
||||||
if reserve_dot:
|
|
||||||
reserver_chars += ".,"
|
|
||||||
if reserve_plus:
|
|
||||||
reserver_chars += "+"
|
|
||||||
if reserve_minus:
|
|
||||||
reserver_chars += "-"
|
|
||||||
regex_fomula = "[^0-9{}]".format(reserver_chars)
|
|
||||||
normalized_text_str = re.sub(r"{}".format(regex_fomula), "", text_str)
|
|
||||||
return normalized_text_str
|
|
||||||
|
|
||||||
|
|
||||||
def normalize_number_wordgroup(word_group, reserve_dot=False, reserve_plus=False, reserve_minus=False):
|
|
||||||
word_group.text = normalize_number(word_group.text, reserve_dot=reserve_dot, reserve_plus=reserve_plus, reserve_minus=reserve_minus)
|
|
||||||
return word_group
|
|
||||||
|
|
||||||
def tax_code_processing(tax_code_raw: str):
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""
|
|
||||||
if len(tax_code_raw.replace(' ', '')) != 13 or (len(tax_code_raw.replace(' ', '')) != 14 and "-" not in tax_code_raw): # to remove the first/last number dupicated
|
|
||||||
tax_code_raw = tax_code_raw.split(' ')
|
|
||||||
tax_code_raw = sorted(tax_code_raw, key=lambda x: len(x), reverse=True)[0]
|
|
||||||
return tax_code_raw.replace(' ', '')
|
|
||||||
|
|
||||||
def normalize_tax_wordgroup(word_group, reserve_dot=False, reserve_plus=False, reserve_minus=False):
|
|
||||||
print("before: ", word_group.text)
|
|
||||||
word_group.text = tax_code_processing(word_group.text)
|
|
||||||
print("after: ", word_group.text)
|
|
||||||
word_group.text = normalize_number(word_group.text, reserve_dot=reserve_dot, reserve_plus=reserve_plus, reserve_minus=reserve_minus)
|
|
||||||
return word_group
|
|
||||||
|
|
||||||
|
|
||||||
def _date_format(date_string):
|
|
||||||
"""Format date string according format dd/MM/yyyy"""
|
|
||||||
date_string = (
|
|
||||||
date_string.replace("ngay ", "")
|
|
||||||
.replace(" thang ", "/")
|
|
||||||
.replace(" nam ", "/")
|
|
||||||
)
|
|
||||||
day, month, year = date_string.split("/")
|
|
||||||
day = day.rjust(2, "0")
|
|
||||||
month = month.rjust(2, "0")
|
|
||||||
year = f"20{year}" if len(year) == 2 else year
|
|
||||||
|
|
||||||
# Check valid year
|
|
||||||
try:
|
|
||||||
_ = datetime(year=int(year), month=int(month), day=int(day))
|
|
||||||
if int(year) > YEAR_START:
|
|
||||||
return "/".join([day, month, year])
|
|
||||||
except:
|
|
||||||
print("Date is invalid", date_string)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_date(list_date):
|
|
||||||
"""Regex get date"""
|
|
||||||
|
|
||||||
list_date = [
|
|
||||||
_date_format(date.group(0))
|
|
||||||
for date in list_date
|
|
||||||
# if _date_format(date.group(0)) is not None
|
|
||||||
]
|
|
||||||
list_date = [
|
|
||||||
date for date in list_date if date is not None
|
|
||||||
]
|
|
||||||
return list_date
|
|
||||||
|
|
||||||
|
|
||||||
def merge_multi_page_results(result_pages):
|
|
||||||
"""Merge the result of the multiple pages
|
|
||||||
|
|
||||||
Args:
|
|
||||||
results (list[dict]): list of result dict of each page
|
|
||||||
"""
|
|
||||||
if len(result_pages) == 0:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
result = result_pages[0]
|
|
||||||
for result_page in result_pages[1:]:
|
|
||||||
for field_name, field_value in result_page.items():
|
|
||||||
if field_name not in result:
|
|
||||||
result[field_name] = field_value
|
|
||||||
|
|
||||||
return result
|
|