timm documentation
استخراج الميزات
استخراج الميزات
جميع النماذج في timm تملك آليات متسقة للحصول على أنواع مختلفة من الميزات من النموذج للمهام غير التصنيف.
ميزات الطبقة شبه الأخيرة (ميزات ما قبل المصنّف)
يمكن الحصول على الميزات من طبقة النموذج ما قبل الأخيرة بعدة طرق دون الحاجة إلى إجراء تعديلات على النموذج (على الرغم من أنه يمكنك إجراء التعديلات بحرية). يجب أولاً تحديد ما إذا كنت ترغب في الحصول على ميزات مجمّعة (pooled) أو غير مجمّعة (un-pooled).
غير مجمّع
هناك ثلاث طرق للحصول على الميزات غير المجمّعة. تُشار الميزات النهائية غير المجمّعة أحياناً باسم الحالة المخفية الأخيرة. في timm، يشمل ذلك حتى طبقة التطبيع النهائية (في نماذج نمط ViT على سبيل المثال) لكنه لا يشمل اختيار رمز الفئة/التجميع والطبقات ما بعد التجميع النهائية.
بدون تعديل الشبكة، يمكن استدعاء model.forward_features(input) على أي نموذج بدلاً من model(input) المعتاد. سيؤدي هذا إلى تجاوز مصنف الرأس والتجميع الشامل للشبكات.
إذا أراد المرء تعديل الشبكة بشكل صريح لتُعيد ميزات غير مجمّعة، فيمكنه إما إنشاء النموذج دون مصنّف أو تجميع، أو إزالتهما لاحقًا. كلا المسارين يُزيلان المعلمات المرتبطة بالمصنّف من الشبكة.
forward_features()
>>> import torch
>>> import timm
>>> m = timm.create_model('xception41', pretrained=True)
>>> o = m(torch.randn(2, 3, 299, 299))
>>> print(f'Original shape: {o.shape}')
>>> o = m.forward_features(torch.randn(2, 3, 299, 299))
>>> print(f'Unpooled shape: {o.shape}')المخرجات:
Original shape: torch.Size([2, 1000]) Unpooled shape: torch.Size([2, 2048, 10, 10])
إنشاء بدون مصنّف أو تجميع
>>> import torch
>>> import timm
>>> m = timm.create_model('resnet50', pretrained=True, num_classes=0, global_pool='')
>>> o = m(torch.randn(2, 3, 224, 224))
>>> print(f'Unpooled shape: {o.shape}')المخرجات:
Unpooled shape: torch.Size([2, 2048, 7, 7])
إزالته لاحقًا
>>> import torch
>>> import timm
>>> m = timm.create_model('densenet121', pretrained=True)
>>> o = m(torch.randn(2, 3, 224, 224))
>>> print(f'Original shape: {o.shape}')
>>> m.reset_classifier(0, '')
>>> o = m(torch.randn(2, 3, 224, 224))
>>> print(f'Unpooled shape: {o.shape}')المخرجات:
Original shape: torch.Size([2, 1000]) Unpooled shape: torch.Size([2, 1024, 7, 7])
ربط المخرجات غير المجمعة بتصنيف
يمكن إعادة تغذية الحالة المخفية الأخيرة إلى رأس النموذج باستخدام الدالة forward_head().
>>> model = timm.create_model('vit_medium_patch16_reg1_gap_256', pretrained=True)
>>> output = model.forward_features(torch.randn(2,3,256,256))
>>> print('Unpooled output shape:', output.shape)
>>> classified = model.forward_head(output)
>>> print('Classification output shape:', classified.shape)المخرجات:
Unpooled output shape: torch.Size([2, 257, 512]) Classification output shape: torch.Size([2, 1000])
مجمّعة
لتعديل الشبكة بحيث تُعيد ميزات مجمّعة، يمكن استخدام forward_features() ثم تجميع/تسطيح النتيجة بأنفسهم، أو تعديل الشبكة كما هو موضح أعلاه مع الإبقاء على التجميع كما هو.
إنشاء بدون مصنّف
>>> import torch
>>> import timm
>>> m = timm.create_model('resnet50', pretrained=True, num_classes=0)
>>> o = m(torch.randn(2, 3, 224, 224))
>>> print(f'Pooled shape: {o.shape}')المخرجات:
Pooled shape: torch.Size([2, 2048])
إزالته لاحقًا
>>> import torch
>>> import timm
>>> m = timm.create_model('ese_vovnet19b_dw', pretrained=True)
>>> o = m(torch.randn(2, 3, 224, 224))
>>> print(f'Original shape: {o.shape}')
>>> m.reset_classifier(0)
>>> o = m(torch.randn(2, 3, 224, 224))
>>> print(f'Pooled shape: {o.shape}')المخرجات:
Original shape: torch.Size([2, 1000]) Pooled shape: torch.Size([2, 1024])
خرائط الميزات متعددة المقاييس (هرم الميزات)
يتطلب كلٌّ من كشف الكائنات، والتجزئة، ونقاط المفاتيح، ومجموعة متنوعة من المهام الكثيفة على مستوى البكسل الوصول إلى خرائط الميزات من الشبكة العظمية على مستويات متعددة. وغالبًا ما يتم ذلك عن طريق تعديل شبكة التصنيف الأصلية. وبما أن كل شبكة تختلف إلى حد كبير في بنيتها، فلا يُعد من النادر أن تدعم مكتبة كشف الكائنات أو التجزئة المحددة عددًا قليلًا فقط من الشبكات العظمية.
يتيح timm واجهة متسقة لإنشاء أي من النماذج المضمنة كعظام هيكلية للميزات (feature backbones) تُخرج خرائط الميزات للمستويات المحددة.
يمكن إنشاء هيكل ميزات (feature backbone) عن طريق إضافة الحجة features_only=True إلى أي استدعاء لـ create_model. بشكل افتراضي، ستُخرج معظم النماذج التي تحتوي على تسلسل هرمي للميزات حتى 5 ميزات حتى مستوى اختزال قدره 32. ومع ذلك، يختلف هذا الأمر من نموذج لآخر؛ فبعض النماذج لديها مستويات هرمية أقل، وبعضها (مثل ViT) يحتوي على عدد أكبر من خرائط الميزات غير الهرمية، ويُخرج افتراضيًا آخر 3 ميزات. يمكن تمرير الحجة out_indices إلى create_model لتحديد الميزات التي تريد الحصول عليها.
إنشاء نموذج لاستخراج خرائط الميزات
>>> import torch
>>> import timm
>>> m = timm.create_model('resnest26d', features_only=True, pretrained=True)
>>> o = m(torch.randn(2, 3, 224, 224))
>>> for x in o:
... print(x.shape)المخرجات:
torch.Size([2, 64, 112, 112]) torch.Size([2, 256, 56, 56]) torch.Size([2, 512, 28, 28]) torch.Size([2, 1024, 14, 14]) torch.Size([2, 2048, 7, 7])
استعلام عن معلومات الميزات
بعد إنشاء العمود الفقري للميزات، يمكن الاستعلام منه لتوفير معلومات عن تقليل القنوات أو الدقة للرؤوس التالية دون الحاجة إلى تكوين ثابت أو ثوابت مبرمجة مسبقًا. يُعدّ السمة .feature_info فئةً تحيط بمعلومات حول نقاط استخراج الميزات.
>>> import torch
>>> import timm
>>> m = timm.create_model('regnety_032', features_only=True, pretrained=True)
>>> print(f'Feature channels: {m.feature_info.channels()}')
>>> o = m(torch.randn(2, 3, 224, 224))
>>> for x in o:
... print(x.shape)المخرجات:
Feature channels: [32, 72, 216, 576, 1512] torch.Size([2, 32, 112, 112]) torch.Size([2, 72, 56, 56]) torch.Size([2, 216, 28, 28]) torch.Size([2, 576, 14, 14]) torch.Size([2, 1512, 7, 7])
اختر مستويات ميزات محددة أو حدّ الخطوة
هناك حججان إضافيان للتأثير على مخرجات الميزات.
out_indicesيختار الفهارس التي يجب إخراجهاoutput_strideيحدّ من خطوة إخراج الميزات للشبكة (يعمل أيضًا في وضع التصنيف بالمناسبة)
اختيار فهرس المخرجات
يُؤيَّد الحُجّة out_indices في جميع النماذج، لكن ليس جميع النماذج لديها نفس التخصيص بين الفهرس وخطوة الميزة. راجع الكود أو تحقق من feature_info للمقارنة. تتوافق الفهارس الخارجة بشكل عام مع مستوى الميزة C(i+1)th (اختزال 2^(i+1)). لمعظم نماذج الشبكات التلافيفية، يكون الفهرس 0 هو ميزات الخطوة 2، والفهرس 4 هو ميزات الخطوة 32. في العديد من نماذج ViT أو الهجينة ViT-Conv، قد تكون هناك خرائط ميزات كثيرة أو جميعها بنفس الشكل، أو مزيج من خرائط الميزات الهرمية وغير الهرمية. من الأفضل النظر في خاصية feature_info لمعرفة عدد الميزات، وعدد القنوات المقابلة لكل منها، ومستوى الاختزال.
يدعم out_indices الفهرسة السالبة، مما يسهّل الحصول على خريطة الميزات الأخيرة، وقبل الأخيرة، وما إلى ذلك. فاستخدام out_indices=(-2,) سيعيد خريطة الميزات قبل الأخيرة لأي نموذج.
خطوة الإخراج (تمدد خريطة الميزات)
يُحقَّق output_stride عن طريق تحويل الطبقات لاستخدام الالتفاف المتباعد. ولا يكون هذا الأمر دائمًا مباشرًا، فبعض الشبكات تدعم output_stride=32 فقط.
>>> import torch
>>> import timm
>>> m = timm.create_model('ecaresnet101d', features_only=True, output_stride=8, out_indices=(2, 4), pretrained=True)
>>> print(f'Feature channels: {m.feature_info.channels()}')
>>> print(f'Feature reduction: {m.feature_info.reduction()}')
>>> o = m(torch.randn(2, 3, 320, 320))
>>> for x in o:
... print(x.shape)المخرجات:
Feature channels: [512, 2048] Feature reduction: [8, 8] torch.Size([2, 512, 40, 40]) torch.Size([2, 2048, 40, 40])
استخراج ميزات وسيطة مرنة
بالإضافة إلى استخدام features_only مع مصنع النماذج، تدعم جميع النماذج طريقة forward_intermediates() التي توفر آلية مرنة لاستخراج خرائط الميزات الوسيطة وحالة الإخفاء الأخيرة (والتي يمكن ربطها بالرأس). كما تدعم هذه الطريقة بعض الميزات الخاصة بالنماذج، مثل إرجاع رموز الفئة أو بادئات التقطير لبعض النماذج.
ترافق دالة forward_intermediates دالة prune_intermediate_layers تتيح إزالة طبقات من النموذج، بما في ذلك الرأس، والتطبيع النهائي، و/أو الكتل/المراحل الختامية غير الضرورية.
يُستخدم حجة indices لكل من forward_intermediates() وprune_intermediate_layers() لاختيار الميزات التي يجب إرجاعها أو الطبقات التي يجب إزالتها. وكما هو الحال مع out_indices الخاص بواجهة features_only، فإن indices يعتمد على النموذج ويحدد أي من القيم الوسيطة هي التي ستُرجع.
في النماذج غير الهرمية القائمة على الكتل مثل ViT، تتوافق الفهارس مع الكتل، أما في النماذج ذات المراحل الهرمية فتتوافق عادةً مع مخرج الجذع + كل مرحلة هرمية. ويعمل كل من الفهرسة الموجبة (من البداية) والفهرسة السالبة (نسبةً إلى النهاية)، ويُستخدم None لإرجاع جميع القيم الوسيطة.
تعيد الاستدعاء prune_intermediate_layers() متغيّر الفهارس، إذ يجب تحويل الفهارس السالبة إلى فهارس مطلقة (موجبة) عند تقليص النموذج.
model = timm.create_model('vit_medium_patch16_reg1_gap_256', pretrained=True)
output, intermediates = model.forward_intermediates(torch.randn(2,3,256,256))
for i, o in enumerate(intermediates):
print(f'Feat index: {i}, shape: {o.shape}')Feat index: 0, shape: torch.Size([2, 512, 16, 16]) Feat index: 1, shape: torch.Size([2, 512, 16, 16]) Feat index: 2, shape: torch.Size([2, 512, 16, 16]) Feat index: 3, shape: torch.Size([2, 512, 16, 16]) Feat index: 4, shape: torch.Size([2, 512, 16, 16]) Feat index: 5, shape: torch.Size([2, 512, 16, 16]) Feat index: 6, shape: torch.Size([2, 512, 16, 16]) Feat index: 7, shape: torch.Size([2, 512, 16, 16]) Feat index: 8, shape: torch.Size([2, 512, 16, 16]) Feat index: 9, shape: torch.Size([2, 512, 16, 16]) Feat index: 10, shape: torch.Size([2, 512, 16, 16]) Feat index: 11, shape: torch.Size([2, 512, 16, 16])
model = timm.create_model('vit_medium_patch16_reg1_gap_256', pretrained=True)
print('Original params:', sum([p.numel() for p in model.parameters()]))
indices = model.prune_intermediate_layers(indices=(-2,), prune_head=True, prune_norm=True) # prune head, norm, last block
print('Pruned params:', sum([p.numel() for p in model.parameters()]))
intermediates = model.forward_intermediates(torch.randn(2,3,256,256), indices=indices, intermediates_only=True) # return penultimate intermediate
for o in intermediates:
print(f'Feat shape: {o.shape}')Original params: 38880232 Pruned params: 35212800 Feat shape: torch.Size([2, 512, 16, 16])