所有代碼以上傳至github:garbage_classify
已修改成本地可以運行。
修改方法:
1.save_model.py|train.py|eval.py|run.py|
中moxing.framework.file
函數全部換成os.path
和shutil.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.py
和data_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
——保存爲pdpython 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%左右