iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
AI & Data

手寫中文字之影像辨識系列 第 28

【第28天】探討與改善-資料不平衡(一)

摘要

  1. 說明
    1.1 資料類別不平衡
    1.2 示例
    1.3 多元分類

  2. 前置作業
    2.1 分類中文字
    2.2 計算每個類別的樣本數量

  3. 改善方法
    3.1 模型訓練時調整類別權重
    3.2 擴大資料集
    3.3 其他方法


內容

  1. 說明

    1.1 資料類別不平衡:即分類任務中,不同類別的樣本數量差異大。
    1.2 示例

    • 在3元分類中,A有98個、B有1個、C有1個,模型預測時,只要將分類器預設答案為A,準確率即98%。
    • 若現在待預測資料集中,A有333個、B有333個、C有333個,則預測的準確率只剩下33.3%。

    1.3 多元分類:通常會假設不同類別的樣本數目相同,避免影響模型效能。

  2. 前置作業

    2.1 分類中文字:相同類別的中文字,移動到同一資料夾。

    • 程式碼
    def word_classfier():
        # 讀取資料夾,儲存中文字的類別(800類)
        word_list_dir = []
        for i in os.listdir(src_dir_name):
            if i.endswith('.jpg'):
                word_list_dir.append(i.split('.')[0][-1])
        word_list_dir = set(word_list_dir)
        print(word_list_dir)
    
        # 將圖檔移動到對應類別的資料夾
        for i in os.listdir(src_dir_name):
            if i.endswith('.jpg'):
                if i.split('.')[0][-1] in word_list_dir:
                    try:
                        os.mkdir(src_dir_name+i.split('.')[0][-1])
                    except FileExistsError:
                        pass
                    shutil.move(src_dir_name+i,src_dir_name+i.split('.')[0][-1]+'/'+i)
    
    • 執行結果
      • 執行前

      • 執行後

    2.2 計算每個類別的樣本數量(權重表)

    • 每個類別的權重表,做為模型訓練時調整類別權重的依據。
    • 每個類別的樣本數量,供擴大資料集(OpenCV影像合成)參考。
    • 程式碼
    def class_sample_count():
        index = 0
        try:
            os.mkdir(src_dir_name)
        except FileExistsError:
            pass
        class_weights = {}
        list_class_num = []
        for i in os.listdir(src_dir_name):
            dir_length = len(os.listdir(src_dir_name+i))
            # 每個字的權重表
            class_weights[index] = dir_length
            # 每個字的數量
            list_class_num.append(dir_length)
            index += 1
        return class_weights, list_class_num
    
    if __name__ == '__main__':
        src_dir_name = './train/'
        class_weights, list_class_num = class_sample_count()
        # 每個字的權重表
        print(class_weights)
    
        list_class_add_num = [max(list_class_num)-i for i in list_class_num]
        # 每個字有幾個樣本
        print(list_class_num)
        # 每個字要再擴增幾個樣本
        print(list_class_add_num)
    
    • 執行結果

      • 每個字的權重表:key值0~799代表800個中文字;value值代表樣本數量。

      • 每個字需要增加的樣本數量

  3. 改善方法

    3.1 模型訓練時調整類別權重

    • 我們透過Keras class_weight傳遞權重。模型訓練時,樣本較多的類別,權重低;樣本較少的類別,權重高。
    • 模型訓練過程中給予權重,可調節損失函數對不同類別的敏感度,更加關注代表性不足的類別。
    • 特點:
      • 透過調節損失函數敏感度,消彌資料類別不平衡的影響。
      • 資料集樣本數量不變。
    • 程式碼
    class_weights = {0: 164, 1: 244, 2: 248, 3: 212, 4: 264, 5: 248, 6: 260, 7: 108, 8: 212, 9: 200, 10: 272, 11: 172, 12: 252, 13: 264, 14: 248, 15: 136, 16: 248, 17: 260, 18: 192, 19: 240, 20: 248, 21: 212, 22: 48, 23: 232, 24: 256, 25: 176, 26: 268, 27: 304, 28: 148, 29: 108, 30: 136, 31: 240, 32: 240, 33: 260, 34: 252, 35: 268, 36: 180, 37: 236, 38: 232, 39: 248, 40: 132, 41: 256, 42: 256, 43: 248, 44: 236, 45: 244, 46: 164, 47: 240, 48: 260, 49: 236, 50: 192, 51: 260, 52: 220, 53: 232, 54: 92, 55: 256, 56: 236, 57: 272, 58: 232, 59: 200, 60: 256, 61: 264, 62: 132, 63: 252, 64: 248, 65: 260, 66: 232, 67: 276, 68: 300, 69: 124, 70: 236, 71: 204, 72: 248, 73: 236, 74: 116, 75: 160, 76: 264, 77: 180, 78: 236, 79: 180, 80: 236, 81: 192, 82: 232, 83: 280, 84: 184, 85: 96, 86: 56, 87: 268, 88: 236, 89: 264, 90: 268, 91: 248, 92: 188, 93: 256, 94: 220, 95: 236, 96: 60, 97: 116, 98: 248, 99: 240, 100: 192, 101: 80, 102: 244, 103: 236, 104: 248, 105: 256, 106: 220, 107: 176, 108: 60, 109: 268, 110: 248, 111: 188, 112: 228, 113: 248, 114: 352, 115: 236, 116: 260, 117: 164, 118: 260, 119: 272, 120: 124, 121: 264, 122: 256, 123: 184, 124: 216, 125: 272, 126: 248, 127: 276, 128: 224, 129: 272, 130: 248, 131: 252, 132: 216, 133: 276, 134: 180, 135: 176, 136: 268, 137: 256, 138: 256, 139: 340, 140: 276, 141: 208, 142: 52, 143: 220, 144: 252, 145: 248, 146: 204, 147: 268, 148: 256, 149: 116, 150: 232, 151: 256, 152: 136, 153: 92, 154: 152, 155: 248, 156: 144, 157: 240, 158: 168, 159: 256, 160: 156, 161: 180, 162: 256, 163: 252, 164: 256, 165: 60, 166: 248, 167: 256, 168: 104, 169: 248, 170: 256, 171: 232, 172: 144, 173: 104, 174: 256, 175: 68, 176: 176, 177: 264, 178: 264, 179: 256, 180: 192, 181: 180, 182: 144, 183: 256, 184: 200, 185: 188, 186: 128, 187: 236, 188: 240, 189: 256, 190: 248, 191: 236, 192: 108, 193: 276, 194: 264, 195: 276, 196: 268, 197: 168, 198: 268, 199: 248, 200: 132, 201: 276, 202: 268, 203: 276, 204: 256, 205: 252, 206: 240, 207: 272, 208: 228, 209: 268, 210: 164, 211: 256, 212: 248, 213: 236, 214: 192, 215: 256, 216: 264, 217: 184, 218: 204, 219: 268, 220: 228, 221: 212, 222: 224, 223: 236, 224: 212, 225: 256, 226: 208, 227: 292, 228: 172, 229: 240, 230: 116, 231: 220, 232: 84, 233: 108, 234: 248, 235: 88, 236: 268, 237: 160, 238: 204, 239: 236, 240: 248, 241: 256, 242: 256, 243: 236, 244: 276, 245: 260, 246: 256, 247: 260, 248: 280, 249: 256, 250: 276, 251: 240, 252: 268, 253: 236, 254: 144, 255: 260, 256: 136, 257: 224, 258: 256, 259: 268, 260: 252, 261: 156, 262: 68, 263: 252, 264: 216, 265: 260, 266: 260, 267: 100, 268: 256, 269: 248, 270: 164, 271: 256, 272: 232, 273: 256, 274: 260, 275: 268, 276: 80, 277: 276, 278: 280, 279: 252, 280: 264, 281: 172, 282: 68, 283: 268, 284: 276, 285: 244, 286: 128, 287: 276, 288: 196, 289: 248, 290: 256, 291: 256, 292: 120, 293: 116, 294: 264, 295: 248, 296: 256, 297: 268, 298: 256, 299: 232, 300: 120, 301: 144, 302: 168, 303: 240, 304: 284, 305: 212, 306: 232, 307: 248, 308: 260, 309: 268, 310: 276, 311: 252, 312: 276, 313: 268, 314: 256, 315: 200, 316: 136, 317: 256, 318: 244, 319: 268, 320: 264, 321: 216, 322: 256, 323: 172, 324: 268, 325: 264, 326: 256, 327: 252, 328: 232, 329: 268, 330: 268, 331: 268, 332: 236, 333: 260, 334: 248, 335: 228, 336: 264, 337: 208, 338: 172, 339: 256, 340: 204, 341: 272, 342: 212, 343: 264, 344: 324, 345: 276, 346: 500, 347: 232, 348: 260, 349: 100, 350: 292, 351: 156, 352: 264, 353: 272, 354: 256, 355: 160, 356: 220, 357: 256, 358: 272, 359: 248, 360: 304, 361: 220, 362: 268, 363: 264, 364: 164, 365: 256, 366: 192, 367: 276, 368: 192, 369: 268, 370: 268, 371: 252, 372: 168, 373: 264, 374: 256, 375: 328, 376: 124, 377: 256, 378: 260, 379: 248, 380: 204, 381: 256, 382: 152, 383: 248, 384: 200, 385: 256, 386: 248, 387: 156, 388: 244, 389: 268, 390: 268, 391: 204, 392: 164, 393: 256, 394: 236, 395: 252, 396: 256, 397: 264, 398: 64, 399: 268, 400: 248, 401: 68, 402: 256, 403: 164, 404: 172, 405: 252, 406: 208, 407: 252, 408: 256, 409: 244, 410: 144, 411: 276, 412: 228, 413: 224, 414: 232, 415: 260, 416: 232, 417: 212, 418: 260, 419: 228, 420: 100, 421: 148, 422: 236, 423: 248, 424: 184, 425: 260, 426: 160, 427: 248, 428: 256, 429: 240, 430: 132, 431: 116, 432: 240, 433: 192, 434: 220, 435: 80, 436: 268, 437: 92, 438: 192, 439: 180, 440: 272, 441: 260, 442: 64, 443: 60, 444: 268, 445: 236, 446: 236, 447: 256, 448: 228, 449: 276, 450: 148, 451: 272, 452: 160, 453: 232, 454: 268, 455: 268, 456: 52, 457: 192, 458: 136, 459: 256, 460: 128, 461: 180, 462: 272, 463: 212, 464: 276, 465: 180, 466: 248, 467: 180, 468: 268, 469: 260, 470: 268, 471: 148, 472: 196, 473: 272, 474: 248, 475: 256, 476: 268, 477: 248, 478: 268, 479: 136, 480: 156, 481: 152, 482: 268, 483: 260, 484: 248, 485: 244, 486: 200, 487: 136, 488: 268, 489: 264, 490: 260, 491: 248, 492: 248, 493: 268, 494: 176, 495: 244, 496: 264, 497: 232, 498: 268, 499: 248, 500: 76, 501: 332, 502: 260, 503: 108, 504: 268, 505: 116, 506: 196, 507: 236, 508: 228, 509: 268, 510: 268, 511: 164, 512: 264, 513: 272, 514: 284, 515: 188, 516: 152, 517: 244, 518: 260, 519: 260, 520: 272, 521: 96, 522: 252, 523: 128, 524: 240, 525: 148, 526: 176, 527: 284, 528: 248, 529: 260, 530: 60, 531: 248, 532: 228, 533: 172, 534: 228, 535: 128, 536: 72, 537: 164, 538: 160, 539: 236, 540: 248, 541: 84, 542: 252, 543: 80, 544: 252, 545: 204, 546: 256, 547: 160, 548: 108, 549: 196, 550: 252, 551: 228, 552: 112, 553: 88, 554: 272, 555: 256, 556: 240, 557: 256, 558: 248, 559: 248, 560: 216, 561: 244, 562: 220, 563: 264, 564: 264, 565: 252, 566: 212, 567: 256, 568: 256, 569: 152, 570: 104, 571: 436, 572: 260, 573: 248, 574: 252, 575: 68, 576: 252, 577: 160, 578: 164, 579: 232, 580: 244, 581: 256, 582: 144, 583: 236, 584: 220, 585: 248, 586: 64, 587: 208, 588: 116, 589: 272, 590: 248, 591: 260, 592: 124, 593: 228, 594: 172, 595: 64, 596: 120, 597: 264, 598: 252, 599: 268, 600: 168, 601: 192, 602: 256, 603: 252, 604: 256, 605: 180, 606: 256, 607: 192, 608: 264, 609: 260, 610: 196, 611: 268, 612: 140, 613: 112, 614: 248, 615: 244, 616: 260, 617: 276, 618: 124, 619: 164, 620: 248, 621: 168, 622: 176, 623: 216, 624: 248, 625: 248, 626: 256, 627: 276, 628: 120, 629: 224, 630: 180, 631: 340, 632: 160, 633: 80, 634: 64, 635: 244, 636: 260, 637: 176, 638: 176, 639: 156, 640: 64, 641: 248, 642: 144, 643: 228, 644: 220, 645: 116, 646: 248, 647: 276, 648: 268, 649: 236, 650: 276, 651: 156, 652: 180, 653: 252, 654: 108, 655: 244, 656: 136, 657: 168, 658: 204, 659: 232, 660: 220, 661: 216, 662: 156, 663: 260, 664: 264, 665: 132, 666: 256, 667: 256, 668: 232, 669: 268, 670: 52, 671: 260, 672: 128, 673: 160, 674: 268, 675: 108, 676: 72, 677: 276, 678: 268, 679: 256, 680: 272, 681: 284, 682: 256, 683: 252, 684: 260, 685: 260, 686: 236, 687: 48, 688: 160, 689: 244, 690: 248, 691: 256, 692: 268, 693: 260, 694: 256, 695: 156, 696: 292, 697: 248, 698: 252, 699: 248, 700: 228, 701: 104, 702: 132, 703: 260, 704: 164, 705: 232, 706: 108, 707: 296, 708: 280, 709: 192, 710: 240, 711: 372, 712: 268, 713: 100, 714: 168, 715: 240, 716: 256, 717: 240, 718: 256, 719: 268, 720: 208, 721: 116, 722: 192, 723: 264, 724: 232, 725: 248, 726: 248, 727: 76, 728: 192, 729: 152, 730: 112, 731: 228, 732: 264, 733: 48, 734: 268, 735: 164, 736: 264, 737: 116, 738: 128, 739: 232, 740: 256, 741: 208, 742: 288, 743: 256, 744: 248, 745: 280, 746: 240, 747: 244, 748: 228, 749: 156, 750: 256, 751: 252, 752: 104, 753: 144, 754: 264, 755: 276, 756: 268, 757: 292, 758: 196, 759: 260, 760: 244, 761: 256, 762: 256, 763: 256, 764: 280, 765: 156, 766: 156, 767: 112, 768: 236, 769: 268, 770: 236, 771: 112, 772: 260, 773: 180, 774: 276, 775: 188, 776: 148, 777: 220, 778: 248, 779: 60, 780: 256, 781: 268, 782: 268, 783: 152, 784: 248, 785: 260, 786: 236, 787: 252, 788: 268, 789: 260, 790: 248, 791: 220, 792: 164, 793: 276, 794: 168, 795: 268, 796: 160, 797: 256, 798: 144, 799: 256}
    
    history = model.fit_generator(train_generator,
                       epochs=50, verbose=1,
                       steps_per_epoch=train_generator.samples//batch_size,
                       validation_data=valid_generator,
                       validation_steps=valid_generator.samples//batch_size,
                       callbacks=[checkpoint, estop, reduce_lr],
                       class_weight=class_weights)   
    

    3.2 擴大資料集

    • 統計各個字的樣本數量後,為了讓所有類別的樣本數量一致,小類別資料以OpenCV合成新訓練集,補足欠缺的訓練樣本。
    • 合成新樣本方法:中文字+空白背景疊加。
    • 程式碼
    if __name__ == '__main__':
        target_size = (80, 80)
        font_path = 'C:/Users/88691/Desktop/unofficial_in_800/'
        back_path = 'C:/Users/88691/Desktop/03_no_word/'
        result_path = 'C:/Users/88691/Desktop/result/'
        # 文字清單
        total_font = []
        for i in os.listdir(font_path):
            font_name = os.listdir(font_path+i)
            for j in font_name:
                total_font.append(font_path+i+'/'+j)
    
        # 背景清單
        total_back = []
        for i in os.listdir(back_path):
            total_back.append(back_path + i)
    
        # 合成新樣本
        n = 1
        for i in total_back:    
            for j in total_font:
                img1 = back(i, target_size)
                img2 = font(j, target_size)
                img2_rotaion = rotation(img2, target_size, (-10, 10), 1)
                result = font_and_back(img1, img2)
                word = j.split('/')[-1][0]
                try:
                    os.mkdir(result_path + word)
                except FileExistsError:
                    pass
                cv2.imencode('.jpg', result)[1].tofile(result_path + word + '/' + str(n) + '_' + j.split('/')[-1])
                print('成功儲存:{}'.format(str(n) + '_' + j.split('/')[-1]))
            n += 1
    
    • 結果

    • 特點

      • 透過影像合成補足小類別的樣本,達成實質上的資料類別平衡。
      • 資料集樣本數量增加。
      • 模型訓練時間增加。

    3.3 其他方法(迫於時間有限,僅列舉)

    • 過採樣(Oversampling)
    • 欠採樣(Undersampling)
    • 選擇合適的評價指標:如以F1 score代替accuracy

小結

下一章的目標是:「透過實際訓練DenseNet201模型,驗證兩個改善方法的效果」。

讓我們繼續看下去...


參考資料

  1. Train the model with class_weight argument

上一篇
【第27天】探討與改善-增加訓練樣本(二)
下一篇
【第29天】探討與改善-資料不平衡(二)
系列文
手寫中文字之影像辨識31

1 則留言

0
juck30808
iT邦新手 3 級 ‧ 2021-10-14 12:07:33

恭喜即將邁入完賽啦~

感謝你的祝福,最後衝刺,GOGO。

我要留言

立即登入留言