
مرة أخرى ، عندما كنت أقود سيارة حول مدينتي وأتجول في حفرة أخرى ، اعتقدت: هل توجد مثل هذه الطرق "الجيدة" في كل مكان في بلدنا وقررت أنه ينبغي لنا تقييم الوضع بموضوعية بجودة الطرق في بلدنا.
إضفاء الطابع الرسمي على المهمة
في روسيا ، تم توضيح متطلبات جودة الطرق في GOST R 50597-2017 "الطرق والطرق. متطلبات الحالة التشغيلية مقبولة بموجب شروط ضمان السلامة على الطرق. طرق التحكم. " تحدد هذه الوثيقة متطلبات تغطية الطريق ، جوانب الطرق ، شرائط التقسيم ، الأرصفة ، ممرات المشاة ، وما إلى ذلك ، كما تحدد أنواع الضرر.
نظرًا لأن مهمة تحديد جميع معالم الطرق مهمة للغاية ، فقد قررت تضييقها بنفسي والتركيز فقط على مشكلة تحديد العيوب في تغطية الطريق. في GOST R 50597-2017 ، يتم تمييز العيوب التالية في طلاء الطريق:
- الحفر
- فواصل
- السحب
- التحولات
- أمشاط
- المسار
- التعرق الموثق
قررت معالجة هذه العيوب.
جمع البيانات
أين يمكنني الحصول على صور توضح أجزاء كبيرة بما يكفي من الطريق ، وحتى بالإشارة إلى تحديد الموقع الجغرافي؟ جاءت الإجابة في أحجار الراين - صور بانورامية على خرائط Yandex (أو Google) ، ومع ذلك ، بعد قليل من البحث ، وجدت العديد من الخيارات البديلة:
- إصدار محركات البحث عن الصور للطلبات ذات الصلة ؛
- الصور على مواقع لتلقي الشكاوى (Rosyama ، المواطن الغاضب ، الفضيلة ، إلخ.)
- دفع Opendatascience مشروعًا لاكتشاف عيوب الطرق باستخدام مجموعة بيانات ملحوظة - github.com/sekilab/RoadDamageDetector
لسوء الحظ ، أظهر تحليل لهذه الخيارات أنها ليست مناسبة جدًا بالنسبة لي: إصدار محركات البحث لديه الكثير من الضوضاء (العديد من الصور التي ليست طرقًا أو عروض مختلفة أو ما إلى ذلك) ، والصور من مواقع تلقي الشكاوى تحتوي فقط على صور بها انتهاكات كبيرة لسطح الأسفلت ، هناك عدد غير قليل من الصور مع انتهاكات صغيرة للتغطية وبدون انتهاكات على هذه المواقع ، يتم جمع مجموعة البيانات من مشروع RoadDamageDetector في اليابان ولا تحتوي على عينات ذات انتهاكات كبيرة للتغطية ، وكذلك الطرق دون تغطية على الإطلاق.
نظرًا لأن الخيارات البديلة غير مناسبة ، فسنستخدم بانوراما Yandex (لقد استبعدت خيار بانوراما Google ، نظرًا لأن الخدمة مقدمة في عدد أقل من المدن في روسيا ويتم تحديثها بشكل أقل تكرارًا). قرر جمع البيانات في المدن التي يبلغ عدد سكانها أكثر من 100 ألف شخص ، وكذلك في المراكز الفيدرالية. لقد قدمت قائمة بأسماء المدن - كان هناك 176 منهم ، فيما بعد تبين أن 149 منهم فقط لديهم صور بانورامية. لن أتطرق إلى ميزات تحليل البلاط ، سأقول أنه في النهاية حصلت على 149 مجلدًا (مجلد لكل مدينة) بلغ إجمالي عدد الصور بها 1.7 مليون صورة. على سبيل المثال ، بالنسبة إلى Novokuznetsk ، بدا المجلد كما يلي:

بعدد الصور التي تم تنزيلها ، تم توزيع المدن على النحو التالي:
الجدول| المدينة 
 | عدد الصور ، أجهزة الكمبيوتر 
 | 
|---|
| موسكو 
 
 | 86048 
 
 | 
| سانت بطرسبرغ 
 
 | 41376 
 
 | 
| سارانسك 
 
 | 18880 
 
 | 
| بودولسك 
 
 | 18560 
 
 | 
| كراسنوجورسك 
 
 | 18208 
 
 | 
| ليوبرتسي 
 
 | 17760 
 
 | 
| كالينينجراد 
 
 | 16928 
 
 | 
| Kolomna 
 
 | 16832 
 
 | 
| ميتيشتشي 
 
 | 16192 
 
 | 
| فلاديفوستوك 
 
 | 16096 
 
 | 
| بالشيخة 
 
 | 15968 
 
 | 
| بتروزافودسك 
 
 | 15968 
 
 | 
| ايكاترينبرغ 
 
 | 15808 
 
 | 
| فيليكي نوفغورود 
 
 | 15744 
 
 | 
| نابريجني تشلني 
 
 | 15680 
 
 | 
| كراسنودار 
 
 | 15520 
 
 | 
| نيجني نوفغورود 
 
 | 15488 
 
 | 
| خيمكي 
 
 | 15296 
 
 | 
| تولا 
 
 | 15296 
 
 | 
| نوفوسيبيرسك 
 
 | 15264 
 
 | 
| تفير 
 
 | 15200 
 
 | 
| مياس 
 
 | 15104 
 
 | 
| إيفانوفو 
 
 | 15072 
 
 | 
| فولوغدا 
 
 | 15008 
 
 | 
| جوكوفسكي 
 
 | 14976 
 
 | 
| كوستروما 
 
 | 14912 
 
 | 
| سمارة 
 
 | 14880 
 
 | 
| كوروليف 
 
 | 14784 
 
 | 
| كالوغا 
 
 | 14720 
 
 | 
| تشيريبوفيتس 
 
 | 14720 
 
 | 
| سيفاستوبول 
 
 | 14688 
 
 | 
| بوشكينو 
 
 | 14528 
 
 | 
| ياروسلافل 
 
 | 14464 
 
 | 
| أوليانوفسك 
 
 | 14400 
 
 | 
| روستوف نا دون 
 
 | 14368 
 
 | 
| دوموديدوفو 
 
 | 14304 
 
 | 
| كامينسك-أورالسكي 
 
 | 14208 
 
 | 
| بسكوف 
 
 | 14144 
 
 | 
| يوشكار علا 
 
 | 14080 
 
 | 
| كيرتش 
 
 | 14080 
 
 | 
| مورمانسك 
 
 | 13920 
 
 | 
| توجلياتي 
 
 | 13920 
 
 | 
| فلاديمير 
 
 | 13792 
 
 | 
| النسر 
 
 | 13792 
 
 | 
| سيكتيفكار 
 
 | 13728 
 
 | 
| دولجوبرودني 
 
 | 13696 
 
 | 
| خانتي مانسيسك 
 
 | 13664 
 
 | 
| قازان 
 
 | 13600 
 
 | 
| إنجلز 
 
 | 13440 
 
 | 
| أرخانجيلسك 
 
 | 13280 
 
 | 
| بريانسك 
 
 | 13216 
 
 | 
| أومسك 
 
 | 13120 
 
 | 
| سيزران 
 
 | 13088 
 
 | 
| كراسنويارسك 
 
 | 13056 
 
 | 
| شيلكوفو 
 
 | 12928 
 
 | 
| بينزا 
 
 | 12864 
 
 | 
| تشيليابينسك 
 
 | 12768 
 
 | 
| تشيبوكساري 
 
 | 12768 
 
 | 
| نيجني تاجيل 
 
 | 12672 
 
 | 
| ستافروبول 
 
 | 12672 
 
 | 
| رامينسكوي 
 
 | 12640 
 
 | 
| ايركوتسك 
 
 | 12608 
 
 | 
| أنجارسك 
 
 | 12608 
 
 | 
| تيومين 
 
 | 12512 
 
 | 
| أودينتسوفو 
 
 | 12512 
 
 | 
| أوفا 
 
 | 12512 
 
 | 
| ماجادان 
 
 | 12512 
 
 | 
| بيرم 
 
 | 12448 
 
 | 
| كيروف 
 
 | 12256 
 
 | 
| نيجنكامسك 
 
 | 12224 
 
 | 
| مخاشكالا 
 
 | 12096 
 
 | 
| نيجنفارتوفسك 
 
 | 11936 
 
 | 
| كورسك 
 
 | 11904 
 
 | 
| سوتشي 
 
 | 11872 
 
 | 
| تامبوف 
 
 | 11840 
 
 | 
| بياتيغورسك 
 
 | 11808 
 
 | 
| فولجودونسك 
 
 | 11712 
 
 | 
| ريازان 
 
 | 11680 
 
 | 
| ساراتوف 
 
 | 11616 
 
 | 
| دزيرنسك 
 
 | 11456 
 
 | 
| أورينبورغ 
 
 | 11456 
 
 | 
| تل 
 
 | 11424 
 
 | 
| فولجوجراد 
 
 | 11264 
 
 | 
| إيجيفسك 
 
 | 11168 
 
 | 
| كريسوستوم 
 
 | 11136 
 
 | 
| ليبيتسك 
 
 | 11072 
 
 | 
| كيسلوفودسك 
 
 | 11072 
 
 | 
| سورجوت 
 
 | 11040 
 
 | 
| ماغنيتيوغورسك 
 
 | 10912 
 
 | 
| سمولينسك 
 
 | 10784 
 
 | 
| خاباروفسك 
 
 | 10752 
 
 | 
| كوبيسك 
 
 | 10688 
 
 | 
| مايكوب 
 
 | 10656 
 
 | 
| بيتروبافلوفسك كامتشاتسكي 
 
 | 10624 
 
 | 
| تاغونروغ 
 
 | 10560 
 
 | 
| بارناول 
 
 | 10528 
 
 | 
| سيرجيف بوساد 
 
 | 10368 
 
 | 
| إليستا 
 
 | 10304 
 
 | 
| سترليتاماك 
 
 | 9920 
 
 | 
| سيمفيروبول 
 
 | 9824 
 
 | 
| تومسك 
 
 | 9760 
 
 | 
| أوريخوفو زويفو 
 
 | 9728 
 
 | 
| استراخان 
 
 | 9664 
 
 | 
| يوباتوريا 
 
 | 9568 
 
 | 
| نوجينسك 
 
 | 9344 
 
 | 
| تشيتا 
 
 | 9216 
 
 | 
| بيلغورود 
 
 | 9120 
 
 | 
| Biysk 
 
 | 8928 
 
 | 
| ريبينسك 
 
 | 8896 
 
 | 
| سيفيرودفينسك 
 
 | 8832 
 
 | 
| فورونيج 
 
 | 8768 
 
 | 
| بلاغوفيشتشينسك 
 
 | 8672 
 
 | 
| نوفوروسيسك 
 
 | 8608 
 
 | 
| أولان أودي 
 
 | 8576 
 
 | 
| سيربوخوف 
 
 | 8320 
 
 | 
| كومسومولسك أون أمور 
 
 | 8192 
 
 | 
| أباكان 
 
 | 8128 
 
 | 
| نوريلسك 
 
 | 8096 
 
 | 
| يوجنو ساخالينسك 
 
 | 8032 
 
 | 
| أوبينسك 
 
 | 7904 
 
 | 
| إسنتوكي 
 
 | 7712 
 
 | 
| باتايسك 
 
 | 7648 
 
 | 
| فولجسكي 
 
 | 7584 
 
 | 
| نوفوتشركاسك 
 
 | 7488 
 
 | 
| بيردسك 
 
 | 7456 
 
 | 
| أرزاماس 
 
 | 7424 
 
 | 
| بيرفورالسك 
 
 | 7392 
 
 | 
| كيميروفو 
 
 | 7104 
 
 | 
| إلكتروستال 
 
 | 6720 
 
 | 
| ديربنت 
 
 | 6592 
 
 | 
| ياكوتسك 
 
 | 6528 
 
 | 
| موروم 
 
 | 6240 
 
 | 
| نفتيوجانسك 
 
 | 5792 
 
 | 
| ريوتوف 
 
 | 5696 
 
 | 
| بيروبيجان 
 
 | 5440 
 
 | 
| نوفوكويبيشيفسك 
 
 | 5248 
 
 | 
| سالخارد 
 
 | 5184 
 
 | 
| نوفوكوزنيتسك 
 
 | 5152 
 
 | 
| نوفي يورنغوي 
 
 | 4736 
 
 | 
| نويابرسك 
 
 | 4416 
 
 | 
| نوفوتشيبوكسارسك 
 
 | 4352 
 
 | 
| الصراصير 
 
 | 3968 
 
 | 
| كاسبييسك 
 
 | 3936 
 
 | 
| ستاري اوسكول 
 
 | 3840 
 
 | 
| أرتيوم 
 
 | 3744 
 
 | 
| زيليزنوغورسك 
 
 | 3584 
 
 | 
| Salavat 
 
 | 3584 
 
 | 
| بروكوبيفسك 
 
 | 2816 
 
 | 
| غورنو التايسك 
 
 | 2464 
 
 | 
 إعداد مجموعة بيانات للتدريب
وهكذا ، يتم تجميع مجموعة البيانات ، فكيف الآن ، وبعد الحصول على صورة لقسم الطريق والأشياء المجاورة ، اكتشف نوعية الإسفلت المبين عليها؟ قررت قطع جزء من الصورة بقياس 350 * 244 بكسل في وسط الصورة الأصلية أسفل الوسط مباشرة. ثم قم بتقليل القطعة المقطوعة أفقياً إلى حجم 244 بكسل. ستكون الصورة الناتجة (244 * 244 في الحجم) هي مدخلات المشفر التلافيفي:

من أجل فهم أفضل للبيانات التي أتعامل معها ، أول 2000 صورة قمت بتمييزها بنفسي ، تم تمييز بقية الصور بواسطة موظفي Yandex.Tolki. أمامهم طرحت سؤالا في الصياغة التالية.
أشر إلى سطح الطريق الذي تراه في الصورة:
- التربة / الأنقاض
- رصف الحجارة والبلاط والرصيف
- القضبان ، مسارات السكك الحديدية
- المياه ، برك كبيرة
- الأسفلت
- لا يوجد طريق في الصورة / أشياء غريبة / التغطية غير مرئية بسبب السيارات
إذا اختار المؤدي "Asphalt" ، فقد ظهرت قائمة تقدم لتقييم جودتها:
- تغطية ممتازة
- طفيف الشقوق واحد / الحفر واحد الضحلة
- الشقوق الكبيرة / الشقوق الشبكة / الحفر الصغيرة
- الحفر الكبيرة / الحفر العميقة / الطلاء المدمر
كما أظهر اختبار المهام ، فإن فناني Y. Toloki لا يختلفون في سلامة العمل - فهم ينقرون عن طريق الخطأ على الحقول باستخدام الماوس وينظرون في المهمة المكتملة. اضطررت إلى إضافة أسئلة تحكم (في المهمة كانت هناك 46 صورة ، منها 12 كانت مراقبة) وتمكين التأخير في القبول. بصفتي أسئلة تحكم ، استخدمت تلك الصور التي حددتها بنفسي. قمت تلقائيًا بالتأخير في القبول - Y. Toloka يسمح لك بتحميل نتائج العمل إلى ملف CSV ، وتحميل نتائج التحقق من الردود. تم التحقق من الإجابات على النحو التالي - إذا كانت المهمة تحتوي على أكثر من 5٪ إجابات غير صحيحة للتحكم في الأسئلة ، فسيتم اعتبارها غير مستوفاة. علاوة على ذلك ، إذا أشار المقاول إلى إجابة قريبة منطقياً من true ، فإن إجابته تعتبر صحيحة.
نتيجةً لذلك ، حصلت على حوالي 30 ألف صورة تحمل علامات ، والتي قررت توزيعها في ثلاثة فصول للتدريب:
- "جيد" - الصور المصنفة "الإسفلت: طلاء ممتاز" و "الأسفلت: الشقوق المفردة الصغيرة"
- "الأوسط" - صور تحمل علامات "حجارة الرصف ، والبلاط ، والرصيف" ، و "القضبان ، ومسارات السكك الحديدية" و "الأسفلت: شقوق كبيرة / شقوق الشبكة / الحفر الصغيرة المفردة"
- "كبير" - الصور التي تحمل علامات "التربة / الأحجار المكسرة" و "المياه والبرك الكبيرة" و "الأسفلت: عدد كبير من الحفر / الحفر العميقة / الرصيف المدمر"
- الصور الموسومة "لا يوجد طريق في الصورة / الأجسام الغريبة / التغطية غير مرئية بسبب السيارات" كان هناك عدد قليل جدًا (22 قطعة). لقد استثنيتهم من العمل الإضافي
تطوير المصنف والتدريب
لذلك ، يتم جمع البيانات وتصنيفها ، نواصل تطوير المصنف. عادة ، بالنسبة لمهام تصنيف الصور ، خاصة عند التدريب على مجموعات البيانات الصغيرة ، يتم استخدام برنامج تشفير تلافيفي جاهز ، لإخراج مصنف جديد متصل به. قررت استخدام مصنف بسيط بدون طبقة مخفية ، وطبقة إدخال بحجم 128 وطبقة إخراج بحجم 3. قررت استخدام خيارات متعددة جاهزة على الفور تم تدريبها على ImageNet كمشفرات:
- Xception
- Resnet
- التأسيس
- Vgg16
- Densenet121
- Mobilenet
فيما يلي الوظيفة التي تنشئ نموذج Keras باستخدام المشفر المحدد:
def createModel(typeModel): conv_base = None if(typeModel == "nasnet"): conv_base = keras.applications.nasnet.NASNetMobile(include_top=False, input_shape=(224,224,3), weights='imagenet') if(typeModel == "xception"): conv_base = keras.applications.xception.Xception(include_top=False, input_shape=(224,224,3), weights='imagenet') if(typeModel == "resnet"): conv_base = keras.applications.resnet50.ResNet50(include_top=False, input_shape=(224,224,3), weights='imagenet') if(typeModel == "inception"): conv_base = keras.applications.inception_v3.InceptionV3(include_top=False, input_shape=(224,224,3), weights='imagenet') if(typeModel == "densenet121"): conv_base = keras.applications.densenet.DenseNet121(include_top=False, input_shape=(224,224,3), weights='imagenet') if(typeModel == "mobilenet"): conv_base = keras.applications.mobilenet_v2.MobileNetV2(include_top=False, input_shape=(224,224,3), weights='imagenet') if(typeModel == "vgg16"): conv_base = keras.applications.vgg16.VGG16(include_top=False, input_shape=(224,224,3), weights='imagenet') conv_base.trainable = False model = Sequential() model.add(conv_base) model.add(Flatten()) model.add(Dense(128, activation='relu', kernel_regularizer=regularizers.l2(0.0002))) model.add(Dropout(0.3)) model.add(Dense(3, activation='softmax')) model.compile(optimizer=keras.optimizers.Adam(lr=1e-4), loss='binary_crossentropy', metrics=['accuracy']) return model 
للتدريب ، استخدمت مولدًا مع زيادة (نظرًا لأن إمكانيات التعزيز المدمجة في Keras بدت لي غير كافية ، ثم استخدمت مكتبة 
Augmentor ):
- المنحدرات
- تشويه عشوائي
- يتحول
- مبادلة اللون
- التحولات
- تغيير التباين والسطوع
- مضيفا ضوضاء عشوائية
- المحاصيل
بعد التكبير ، تبدو الصور كما يلي:

رمز المولد:
 def get_datagen(): train_dir='~/data/train_img' test_dir='~/data/test_img' testDataGen = ImageDataGenerator(rescale=1. / 255) train_generator = datagen.flow_from_directory( train_dir, target_size=img_size, batch_size=16, class_mode='categorical') p = Augmentor.Pipeline(train_dir) p.skew(probability=0.9) p.random_distortion(probability=0.9,grid_width=3,grid_height=3,magnitude=8) p.rotate(probability=0.9, max_left_rotation=5, max_right_rotation=5) p.random_color(probability=0.7, min_factor=0.8, max_factor=1) p.flip_left_right(probability=0.7) p.random_brightness(probability=0.7, min_factor=0.8, max_factor=1.2) p.random_contrast(probability=0.5, min_factor=0.9, max_factor=1) p.random_erasing(probability=1,rectangle_area=0.2) p.crop_by_size(probability=1, width=244, height=244, centre=True) train_generator = keras_generator(p,batch_size=16) test_generator = testDataGen.flow_from_directory( test_dir, target_size=img_size, batch_size=32, class_mode='categorical') return (train_generator, test_generator) 
يُظهر الرمز أن التعزيز لا يستخدم لبيانات الاختبار.
بوجود مولد مُولِّف ، يمكنك البدء في تدريب النموذج ، وسوف نقوم بتنفيذه على مرحلتين: أولاً ، قم بتدريب المصنف الخاص بنا فقط ، ثم النموذج بالكامل بالكامل.
 def evalModelstep1(typeModel): K.clear_session() gc.collect() model=createModel(typeModel) traiGen,testGen=getDatagen() model.fit_generator(generator=traiGen, epochs=4, steps_per_epoch=30000/16, validation_steps=len(testGen), validation_data=testGen, ) return model def evalModelstep2(model): early_stopping_callback = EarlyStopping(monitor='val_loss', patience=3) model.layers[0].trainable=True model.trainable=True model.compile(optimizer=keras.optimizers.Adam(lr=1e-5), loss='binary_crossentropy', metrics=['accuracy']) traiGen,testGen=getDatagen() model.fit_generator(generator=traiGen, epochs=25, steps_per_epoch=30000/16, validation_steps=len(testGen), validation_data=testGen, callbacks=[early_stopping_callback] ) return model def full_fit(): model_names=[ "xception", "resnet", "inception", "vgg16", "densenet121", "mobilenet" ] for model_name in model_names: print("#########################################") print("#########################################") print("#########################################") print(model_name) print("#########################################") print("#########################################") print("#########################################") model = evalModelstep1(model_name) model = evalModelstep2(model) model.save("~/data/models/model_new_"+str(model_name)+".h5") 
استدعاء full_fit () وانتظر. نحن ننتظر لفترة طويلة.
نتيجة لذلك ، سيكون لدينا ستة نماذج مدربة ، وسوف نتحقق من دقة هذه النماذج في جزء منفصل من البيانات ذات العلامات ؛ تلقيت ما يلي:
| اسم النموذج 
 | دقة ٪ 
 | 
| Xception 
 | 87.3 
 | 
| Resnet 
 | 90.8 
 | 
| التأسيس 
 | 90.2 
 | 
| Vgg16 
 | 89.2 
 | 
| Densenet121 
 | 90.6 
 | 
| Mobilenet 
 | 86.5 
 | 
بشكل عام ، ليس كثيرًا ، ولكن مع مثل هذه العينة التدريبية الصغيرة ، لا يمكن للمرء أن يتوقع المزيد. لزيادة الدقة بشكل طفيف ، قمت بدمج مخرجات النماذج عن طريق حساب المتوسط:
 def create_meta_model(): model_names=[ "xception", "resnet", "inception", "vgg16", "densenet121", "mobilenet" ] model_input = Input(shape=(244,244,3)) submodels=[] i=0; for model_name in model_names: filename= "~/data/models/model_new_"+str(model_name)+".h5" submodel = keras.models.load_model(filename) submodel.name = model_name+"_"+str(i) i+=1 submodels.append(submodel(model_input)) out=average(submodels) model = Model(inputs = model_input,outputs=out) model.compile(optimizer=keras.optimizers.Adam(lr=1e-4), loss='binary_crossentropy', metrics=['accuracy']) return model 
كانت الدقة الناتجة 91.3 ٪. في هذه النتيجة ، قررت التوقف.
باستخدام المصنف
أخيرا المصنف جاهز ويمكن وضعه موضع التنفيذ! أقوم بإعداد بيانات الإدخال وأدير المصنف - أكثر من يوم بقليل وتم معالجة 1.7 مليون صورة. الآن الجزء الممتع هو النتائج. قم على الفور بإحضار أول عشر مدن في آخر عدد من الطرق مع تغطية جيدة:

الجدول الكامل (صورة قابلة للنقر) وهنا هو تصنيف جودة الطريق من قبل الموضوعات الفيدرالية:

التصنيف حسب المناطق الفيدرالية:

توزيع جودة الطرق في روسيا ككل:

حسنًا ، هذا كل شيء ، يمكن للجميع استخلاص النتائج بنفسه.
أخيرًا ، سأقدم أفضل الصور في كل فئة (والتي حصلت على الحد الأقصى للقيمة في فئتها):
ملاحظة: في التعليقات ، أشار بحق إلى عدم وجود إحصاءات عن سنوات استلام الصور. أصحح وأعطي طاولة:
| سنة 
 | عدد الصور ، أجهزة الكمبيوتر 
 | 
| 2008 | 37 | 
| 2009 | 13 | 
| 2010 | 157030 | 
| 2011 | 60724 | 
| 2012 | 42387 | 
| 2013 | 12148 
 
 | 
| 2014 | 141021 
 
 | 
| 2015 | 46143 
 
 | 
| 2016 | 410385 
 
 | 
| 2017 | 324279 
 
 | 
| 2018 | 581961 
 
 |