華爲雲人工智能大賽·垃圾分類挑戰杯

所有代碼以上傳至github:garbage_classify
已修改成本地可以運行。
修改方法:

1.save_model.py|train.py|eval.py|run.py|moxing.framework.file函數全部換成os.pathshutil.copy函數。因爲python裏面暫時沒有moxing框架。

2.註釋掉run.py文件裏面的下面幾行代碼:

# FLAGS.tmp = os.path.join(FLAGS.local_data_root, 'tmp/')
# print(FLAGS.tmp)
# if not os.path.exists(FLAGS.tmp):
#     os.mkdir(FLAGS.tmp)

運行環境

python3.6

tensorflow 1.13.1

keras 2.24

garbage_classify

賽題背景

比賽鏈接:華爲雲人工智能大賽·垃圾分類挑戰杯

如今,垃圾分類已成爲社會熱點話題。其實在2019年4月26日,我國住房和城鄉建設部等部門就發佈了《關於在全國地級及以上城市全面開展生活垃圾分類工作的通知》,決定自2019年起在全國地級及以上城市全面啓動生活垃圾分類工作。到2020年底,46個重點城市基本建成生活垃圾分類處理系統。

人工垃圾分類投放是垃圾處理的第一環節,但能夠處理海量垃圾的環節是垃圾處理廠。然而,目前國內的垃圾處理廠基本都是採用人工流水線分揀的方式進行垃圾分揀,存在工作環境惡劣、勞動強度大、分揀效率低等缺點。在海量垃圾面前,人工分揀只能分揀出極有限的一部分可回收垃圾和有害垃圾,絕大多數垃圾只能進行填埋,帶來了極大的資源浪費和環境污染危險。

隨着深度學習技術在視覺領域的應用和發展,讓我們看到了利用AI來自動進行垃圾分類的可能,通過攝像頭拍攝垃圾圖片,檢測圖片中垃圾的類別,從而可以讓機器自動進行垃圾分揀,極大地提高垃圾分揀效率。

因此,華爲雲面向社會各界精英人士舉辦了本次垃圾分類競賽,希望共同探索垃圾分類的AI技術,爲垃圾分類這個利國利民的國家大計貢獻自己的一份智慧。

賽題說明

本賽題採用深圳市垃圾分類標準,賽題任務是對垃圾圖片進行分類,即首先識別出垃圾圖片中物品的類別(比如易拉罐、果皮等),然後查詢垃圾分類規則,輸出該垃圾圖片中物品屬於可回收物、廚餘垃圾、有害垃圾和其他垃圾中的哪一種。
模型輸出格式示例:

{

    " result ": "可回收物/易拉罐"

}

垃圾種類40類

{
    "0": "其他垃圾/一次性快餐盒",
    "1": "其他垃圾/污損塑料",
    "2": "其他垃圾/菸蒂",
    "3": "其他垃圾/牙籤",
    "4": "其他垃圾/破碎花盆及碟碗",
    "5": "其他垃圾/竹筷",
    "6": "廚餘垃圾/剩飯剩菜",
    "7": "廚餘垃圾/大骨頭",
    "8": "廚餘垃圾/水果果皮",
    "9": "廚餘垃圾/水果果肉",
    "10": "廚餘垃圾/茶葉渣",
    "11": "廚餘垃圾/菜葉菜根",
    "12": "廚餘垃圾/蛋殼",
    "13": "廚餘垃圾/魚骨",
    "14": "可回收物/充電寶",
    "15": "可回收物/包",
    "16": "可回收物/化妝品瓶",
    "17": "可回收物/塑料玩具",
    "18": "可回收物/塑料碗盆",
    "19": "可回收物/塑料衣架",
    "20": "可回收物/快遞紙袋",
    "21": "可回收物/插頭電線",
    "22": "可回收物/舊衣服",
    "23": "可回收物/易拉罐",
    "24": "可回收物/枕頭",
    "25": "可回收物/毛絨玩具",
    "26": "可回收物/洗髮水瓶",
    "27": "可回收物/玻璃杯",
    "28": "可回收物/皮鞋",
    "29": "可回收物/砧板",
    "30": "可回收物/紙板箱",
    "31": "可回收物/調料瓶",
    "32": "可回收物/酒瓶",
    "33": "可回收物/金屬食品罐",
    "34": "可回收物/鍋",
    "35": "可回收物/食用油桶",
    "36": "可回收物/飲料瓶",
    "37": "有害垃圾/乾電池",
    "38": "有害垃圾/軟膏",
    "39": "有害垃圾/過期藥物"
}

efficientNet默認參數

    (width_coefficient, depth_coefficient, resolution, dropout_rate)
    'efficientnet-b0': (1.0, 1.0, 224, 0.2),
    'efficientnet-b1': (1.0, 1.1, 240, 0.2),
    'efficientnet-b2': (1.1, 1.2, 260, 0.3),
    'efficientnet-b3': (1.2, 1.4, 300, 0.3),
    'efficientnet-b4': (1.4, 1.8, 380, 0.4),
    'efficientnet-b5': (1.6, 2.2, 456, 0.4),
    'efficientnet-b6': (1.8, 2.6, 528, 0.5),
    'efficientnet-b7': (2.0, 3.1, 600, 0.5),

代碼解析

BaseLine改進

1.使用多種模型進行對比實驗,ResNet50, SE-ResNet50, Xeception, SE-Xeception, efficientNetB5

2.使用組歸一化(GroupNormalization)代替批量歸一化(batch_normalization)-解決當Batch_size過小導致的準確率下降。當batch_size小於16時,BN的error率
逐漸上升,train.py

for i, layer in enumerate(model.layers):
    if "batch_normalization" in layer.name:
        model.layers[i] = GroupNormalization(groups=32, axis=-1, epsilon=0.00001)

3.NAdam優化器

optimizer = Nadam(lr=FLAGS.learning_rate, beta_1=0.9, beta_2=0.999, epsilon=1e-08, schedule_decay=0.004)

4.自定義學習率-SGDR餘弦退火學習率

sample_count = len(train_sequence) * FLAGS.batch_size
epochs = FLAGS.max_epochs
warmup_epoch = 5
batch_size = FLAGS.batch_size
learning_rate_base = FLAGS.learning_rate
total_steps = int(epochs * sample_count / batch_size)
warmup_steps = int(warmup_epoch * sample_count / batch_size)

warm_up_lr = WarmUpCosineDecayScheduler(learning_rate_base=learning_rate_base,
                                        total_steps=total_steps,
                                        warmup_learning_rate=0,
                                        warmup_steps=warmup_steps,
                                        hold_base_rate_steps=0,
                                        )

5.數據增強:隨機水平翻轉、隨機垂直翻轉、以一定概率隨機旋轉90°、180°、270°、隨機crop(0-10%)等(詳細代碼請看aug.pydata_gen.py)

def img_aug(self, img):
    data_gen = ImageDataGenerator()
    dic_parameter = {'flip_horizontal': random.choice([True, False]),
                     'flip_vertical': random.choice([True, False]),
                     'theta': random.choice([0, 0, 0, 90, 180, 270])
                    }


    img_aug = data_gen.apply_transform(img, transform_parameters=dic_parameter)
    return img_aug


from imgaug import augmenters as iaa
import imgaug as ia

def augumentor(image):
    sometimes = lambda aug: iaa.Sometimes(0.5, aug)
    seq = iaa.Sequential(
        [
            iaa.Fliplr(0.5),
            iaa.Flipud(0.5),
            iaa.Affine(rotate=(-10, 10)),
            sometimes(iaa.Crop(percent=(0, 0.1), keep_size=True)),
        ],
        random_order=True
    )


    image_aug = seq.augment_image(image)

    return image_aug

6.標籤平滑data_gen.py

def smooth_labels(y, smooth_factor=0.1):
    assert len(y.shape) == 2
    if 0 <= smooth_factor <= 1:
        # label smoothing ref: https://www.robots.ox.ac.uk/~vgg/rg/papers/reinception.pdf
        y *= 1 - smooth_factor
        y += smooth_factor / y.shape[1]
    else:
        raise Exception(
            'Invalid label smoothing factor: ' + str(smooth_factor))
    return y

7.數據歸一化:得到所有圖像的位置信息Save_path.py並計算所有圖像的均值和方差mead_std.py

normMean = [0.56719673 0.5293289  0.48351972]
normStd = [0.20874391 0.21455203 0.22451781]


img = np.asarray(img, np.float32) / 255.0
mean = [0.56719673, 0.5293289, 0.48351972]
std = [0.20874391, 0.21455203, 0.22451781]
img[..., 0] -= mean[0]
img[..., 1] -= mean[1]
img[..., 2] -= mean[2]
img[..., 0] /= std[0]
img[..., 1] /= std[1]
img[..., 2] /= std[2]

各部分代碼解析

  • deploy_scripts——推理文件,需要修改

    1.self.input_size = 456 
    
    
    2. def _inference(self, data):
    """
    model inference function
    Here are a inference example of resnet, if you use another model, please modify this function
    """
    img = data[self.input_key_1]
    img = img[np.newaxis, :, :, :]  # the input tensor shape of resnet is [?, 224, 224, 3]
    img = np.asarray(img, np.float32) / 255.0
    mean = [0.56719673, 0.5293289, 0.48351972]
    std = [0.20874391, 0.21455203, 0.22451781]
    img[..., 0] -= mean[0]
    img[..., 1] -= mean[1]
    img[..., 2] -= mean[2]
    img[..., 0] /= std[0]
    img[..., 1] /= std[1]
    img[..., 2] /= std[2]
    pred_score = self.sess.run([self.output_score], feed_dict={self.input_images: img})
    if pred_score is not None:
        pred_label = np.argmax(pred_score[0], axis=1)[0]
        result = {'result': self.label_id_name_dict[str(pred_label)]}
    else:
        result = {'result': 'predict score is None'}
    return result
    
  • aug.py——圖像增強代碼(imgaug函數)

  • data_gen.py——數據預處理代碼,包括數據增強、標籤平滑以及train和val的劃分

  • eval.py——估值函數

  • Groupnormalization.py——組歸一化

  • mean_std.py——圖像均值和方差

  • Network.py——ResNet50, SE-ResNet50, Xeception, SE-Xeception, efficientNetB5

  • run.py——運行代碼

  • save_model.py——保存模型

  • Save_path.py——圖像位置信息

  • train.py——訓練網絡部分,包括網絡,loss, optimizer等

  • warmup_cosine_decay_scheduler.py——餘弦退火學習率

使用

前期準備

  • 克隆此存儲庫

    git clone https://github.com/wusaifei/garbage_classify.git
    
  • 垃圾分類數據集下載地址

  • 擴充數據集:鏈接:https://pan.baidu.com/s/1SulD2MqZx_U891JXeI2-2g
    提取碼:epgs

運行

  • 運行Save_path.py得到圖像的位置信息

  • 運行mean_std.py得到圖像的均值和方差

  • run.py——訓練

    python run.py --data_url='./garbage_classify/train_data' --train_url='./model_snapshots' --deploy_script_path='./deploy_scripts'
    
  • run.py——保存爲pd

      python run.py --mode=save_pb --deploy_script_path='./deploy_scripts' --freeze_weights_file_path='./model_snapshots/weights_024_0.9470.h5' --num_classes=40
    
  • run.py——估值

    python run.py --mode=eval --eval_pb_path='./model_snapshots/model' --test_data_url='./garbage_classify/train_data'
    

實驗結果

  • 網絡的改進:ResNet50-0.689704,SE-ResNet50-0.0.83259,Xception-0.879003,EfficientNetB5-0.924113(無數據增強)

  • 數據增強:由0.924113提升到0.934721

  • 標籤平滑和數據歸一化處理、TTA、學習率策略的調整ReduceLROnPlateau換成WarmUpCosineDecayScheduler,最終準確率在95%左右

發佈了113 篇原創文章 · 獲贊 107 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章