केरस में असंतुलित वर्गों के लिए वर्ग भार कैसे सेट करें?


128

मुझे पता है कि class_weightsफिटिंग में पैरामीटर शब्दकोश के साथ केरस में एक संभावना है , लेकिन मुझे कोई उदाहरण नहीं मिला। क्या कोई ऐसा प्रदान करना चाहेगा?

वैसे, इस मामले में उपयुक्त प्रैक्सिस केवल अल्पसंख्यक वर्ग को आनुपातिक रूप से अपने अंडरप्रिटेशन के लिए भारित करने के लिए है?


क्या केरेस का उपयोग करके एक नया अपडेटेड तरीका है? शब्दकोश तीन वर्गों और कक्षा के लिए क्यों शामिल है: 0: 1.0 1: 50.0 2: 2.0 ???? नहीं होना चाहिए: 2: 1.0 भी?
चक

जवाबों:


112

यदि आप नियमित मामले के बारे में बात कर रहे हैं, जहां आपका नेटवर्क केवल एक आउटपुट का उत्पादन करता है, तो आपकी धारणा सही है। आदेश में के प्रत्येक उदाहरण के इलाज के लिए अपने एल्गोरिथ्म के लिए मजबूर करने कक्षा 1 के 50 उदाहरणों के रूप में कक्षा 0 आप के लिए है:

  1. अपने लेबल और उनके संबंधित वजन के साथ एक शब्दकोश को परिभाषित करें

    class_weight = {0: 1.,
                    1: 50.,
                    2: 2.}
  2. एक पैरामीटर के रूप में शब्दकोश फ़ीड:

    model.fit(X_train, Y_train, nb_epoch=5, batch_size=32, class_weight=class_weight)

संपादित करें: "के प्रत्येक उदाहरण के इलाज के कक्षा 1 के उदाहरण के रूप में 50 वर्ग 0 " मतलब है कि आपके नुकसान समारोह में आप इन उदाहरणों के लिए उच्च मूल्य निर्दिष्ट। इसलिए, नुकसान एक भारित औसत बन जाता है, जहां प्रत्येक नमूने का वजन class_weight और उसके संबंधित वर्ग द्वारा निर्दिष्ट किया जाता है

केरस डॉक्स से: क्लास_वेट : वैकल्पिक शब्द मानचित्रण वर्ग सूचकांकों (पूर्णांकों) से एक वजन (फ्लोट) मान तक, हानि फ़ंक्शन (केवल प्रशिक्षण के दौरान) को भारित करने के लिए उपयोग किया जाता है।


1
यदि आप 3D डेटा के साथ काम कर रहे हैं, तो github.com/fchollet/keras/issues/3653 पर भी एक नज़र डालें ।
झुंड

मेरे लिए यह एक त्रुटि है dic आकार विशेषता नहीं है।
फ्लेवियो फिल्हो

मेरा मानना ​​है कि केरस इस काम को करने का तरीका बदल सकता है, यह अगस्त 2016 के संस्करण के लिए है। मैं एक सप्ताह में आपके लिए सत्यापन
करूंगा

4
@layser क्या यह काम केवल 'श्रेणी_क्रोसेंट्रोपी' नुकसान के लिए करता है? आप 'sigmoid' और 'Binary_crossentropy' नुकसान के लिए वर्ग_वार्ता को कैसे देते हैं?
नमन

1
@layser क्या आप कक्षा 1 के 50 उदाहरणों के रूप में कक्षा 1 के प्रत्येक उदाहरण का इलाज करने के लिए समझा सकते हैं? क्या यह है कि प्रशिक्षण सेट में, कक्षा 1 के अनुरूप पंक्ति को 50 बार दोहराया जाता है ताकि इसे संतुलित किया जा सके या कोई अन्य प्रक्रिया इस प्रकार हो?
दिव्यांशु शेखर

121

आप बस को लागू कर सकता है class_weightसे sklearn:

  1. आइए पहले मॉड्यूल आयात करें

    from sklearn.utils import class_weight
  2. वर्ग वजन की गणना करने के लिए निम्न कार्य करें

    class_weights = class_weight.compute_class_weight('balanced',
                                                     np.unique(y_train),
                                                     y_train)
  3. तीसरी और अंतिम रूप से इसे मॉडल फिटिंग में जोड़ें

    model.fit(X_train, y_train, class_weight=class_weights)

ध्यान दें : मैंने इस पोस्ट को संपादित किया और आयातित मॉड्यूल को अधिलेखित न करने के लिए चर नाम को class_weight से वर्ग_वेट s में बदल दिया । टिप्पणियों से कोड कॉपी करते समय तदनुसार समायोजित करें।


20
मेरे लिए, class_weight.compute_class_weight एक सरणी का निर्माण करता है, मुझे केरस के साथ काम करने के लिए इसे एक तानाशाही में बदलना होगा। अधिक विशेष रूप से, चरण 2 के बाद, उपयोग करेंclass_weight_dict = dict(enumerate(class_weight))
C.Lee

5
यह मेरे लिए काम नहीं करता है। कैरस में एक तीन वर्ग की समस्या के y_trainलिए (300096, 3)सुन्न सरणी है। तो class_weight=लाइन मुझे टाइप करती है टाइप: अस्वाभाविक प्रकार: 'numpy.ndarray'
लेम्बिक

3
@ लेम्बिक मुझे एक समान समस्या थी, जहां वाई की प्रत्येक पंक्ति क्लास इंडेक्स का एक-हॉट एन्कोडेड वेक्टर है। मैंने इसे इस तरह एक इंट-हॉट प्रतिनिधित्व को एक इंट में परिवर्तित करके तय किया y_ints = [y.argmax() for y in y_train]:।
tkocmathla

3
क्या होगा अगर मैं मल्टीस्कलैस लेबलिंग कर रहा हूं, ताकि मेरे y_true वैक्टर में कई 1s हों: [1 0 0 0 1 0 0 0] उदाहरण के लिए, जहां कुछ x में 0 और 4 के लेबल हैं। फिर भी, मेरे प्रत्येक के कुल # लेबल संतुलित नहीं हैं। मैं उसके साथ वर्ग भार का उपयोग कैसे करूंगा?
आलोक

22

मैं इस तरह के नियम का उपयोग करता हूं class_weight:

import numpy as np
import math

# labels_dict : {ind_label: count_label}
# mu : parameter to tune 

def create_class_weight(labels_dict,mu=0.15):
    total = np.sum(labels_dict.values())
    keys = labels_dict.keys()
    class_weight = dict()

    for key in keys:
        score = math.log(mu*total/float(labels_dict[key]))
        class_weight[key] = score if score > 1.0 else 1.0

    return class_weight

# random labels_dict
labels_dict = {0: 2813, 1: 78, 2: 2814, 3: 78, 4: 7914, 5: 248, 6: 7914, 7: 248}

create_class_weight(labels_dict)

math.logबहुत असंतुलित वर्गों के लिए वजन को सुचारू करता है! यह रिटर्न:

{0: 1.0,
 1: 3.749820767859636,
 2: 1.0,
 3: 3.749820767859636,
 4: 1.0,
 5: 2.5931008483842453,
 6: 1.0,
 7: 2.5931008483842453}

3
कुल संख्या के नमूने द्वारा वर्ग के लिए नमूनों की गिनती को विभाजित करने के बजाय लॉग का उपयोग क्यों करें? मुझे लगता है कि कुछ ऐसा है जो मुझे समझ में नहीं आता है कि model.fit_generator (...) पर परम class_weight में चला जाता है
startoftext

@startoftext यह है कि मैंने इसे कैसे किया, लेकिन मुझे लगता है कि आपके पास इसका उल्टा है। मैंने n_total_samples / n_class_samplesप्रत्येक वर्ग के लिए उपयोग किया ।
कोलिन

2
आपके उदाहरण में कक्षा 0 (2813 उदाहरण हैं) और कक्षा 6 (7914 उदाहरण हैं) का वजन ठीक 1.0 है। ऐसा क्यों है? कक्षा 6 कुछ बड़ा है! आप चाहते हैं कि कक्षा ० को उत्क्रमित किया जाए और कक्षा ६ को नीचे लाकर उन्हें समान स्तर पर लाया जाए।
व्लादिस्लाव डोवगलकेज

9

नोट: टिप्पणियां देखें, यह उत्तर पुराना है।

सभी वर्गों को समान रूप से भारित करने के लिए, अब आप class_weight को "ऑटो" पर सेट कर सकते हैं, जैसे:

model.fit(X_train, Y_train, nb_epoch=5, batch_size=32, class_weight = 'auto')

1
मुझे class_weight='auto'Keras दस्तावेज़ का कोई संदर्भ नहीं मिला और न ही स्रोत कोड में। क्या आप हमें दिखा सकते हैं कि आपने यह कहां पाया है?
फोबियो पेरेज़

2
यह उत्तर शायद गलत है। इस समस्या की जाँच करें: github.com/fchollet/keras/issues/5116
Fábio Perez

अजीब। जिस समय मैंने टिप्पणी पोस्ट की थी, मैं class_balanced = 'auto' का उपयोग कर रहा था, लेकिन अब मुझे इसका संदर्भ नहीं मिल रहा है। शायद इसे बदल दिया गया है क्योंकि केर तेजी से विकसित हो रहा है।
डेविड ग्रूप

जैसा कि ऊपर दर्शाए गए केरस मुद्दे में निर्दिष्ट है , आप जो भी यादृच्छिक स्ट्रिंग पास कर सकते हैं class_weightऔर इसका कोई प्रभाव नहीं होगा। इसलिए यह उत्तर सही नहीं है।
रात्रि

3

class_weight ठीक है, लेकिन @Aalok ने कहा कि यह काम नहीं करेगा यदि आप एक हॉट एन्कोडिंग मल्टीलेबेल्ड क्लासेस हैं। इस स्थिति में, नमूना_वेट का उपयोग करें :

नमूना_वेट: एक्स के रूप में एक ही लंबाई के वैकल्पिक सरणी, प्रत्येक नमूने के लिए मॉडल के नुकसान को लागू करने के लिए भार से युक्त। लौकिक डेटा के मामले में, आप प्रत्येक नमूने के प्रत्येक टाइमस्टेप पर एक अलग वजन लागू करने के लिए आकृति (नमूने, अनुक्रम_ गति) के साथ एक 2 डी सरणी पास कर सकते हैं। इस मामले में आपको संकलन () में नमूना_वेट_मोड = "टेम्पोरल" निर्दिष्ट करना चाहिए।

sample_weights का उपयोग प्रत्येक प्रशिक्षण नमूने के लिए एक वजन प्रदान करने के लिए किया जाता है । इसका मतलब है कि आपको अपने प्रशिक्षण नमूनों के समान तत्वों के साथ 1D सरणी पास करनी चाहिए (उन नमूनों में से प्रत्येक के लिए वजन का संकेत)।

class_weights का उपयोग प्रत्येक आउटपुट वर्ग के लिए वजन या पूर्वाग्रह प्रदान करने के लिए किया जाता है । इसका मतलब है कि आपको प्रत्येक वर्ग के लिए एक वजन पास करना चाहिए जिसे आप वर्गीकृत करने की कोशिश कर रहे हैं।

नमूना_वेट को एक सुस्पष्ट सरणी दी जानी चाहिए, क्योंकि इसके आकार का मूल्यांकन किया जाएगा।

इस उत्तर को भी देखें: https://stackoverflow.com/questions/48315094/use-sample-weight-in-keras-for-fterence-labelling


2

Https://github.com/keras-team/keras/issues/2115 पर समाधान में जोड़ना । यदि आपको क्लास वेटिंग से अधिक की आवश्यकता है जहां आप झूठी सकारात्मक और झूठी नकारात्मक के लिए अलग-अलग लागत चाहते हैं। नए कार्स संस्करण के साथ अब आप नीचे दिए गए अनुसार संबंधित नुकसान फ़ंक्शन को ओवरराइड कर सकते हैं। ध्यान दें कि weightsएक वर्ग मैट्रिक्स है।

from tensorflow.python import keras
from itertools import product
import numpy as np
from tensorflow.python.keras.utils import losses_utils

class WeightedCategoricalCrossentropy(keras.losses.CategoricalCrossentropy):

    def __init__(
        self,
        weights,
        from_logits=False,
        label_smoothing=0,
        reduction=losses_utils.ReductionV2.SUM_OVER_BATCH_SIZE,
        name='categorical_crossentropy',
    ):
        super().__init__(
            from_logits, label_smoothing, reduction, name=f"weighted_{name}"
        )
        self.weights = weights

    def call(self, y_true, y_pred):
        weights = self.weights
        nb_cl = len(weights)
        final_mask = keras.backend.zeros_like(y_pred[:, 0])
        y_pred_max = keras.backend.max(y_pred, axis=1)
        y_pred_max = keras.backend.reshape(
            y_pred_max, (keras.backend.shape(y_pred)[0], 1))
        y_pred_max_mat = keras.backend.cast(
            keras.backend.equal(y_pred, y_pred_max), keras.backend.floatx())
        for c_p, c_t in product(range(nb_cl), range(nb_cl)):
            final_mask += (
                weights[c_t, c_p] * y_pred_max_mat[:, c_p] * y_true[:, c_t])
        return super().call(y_true, y_pred) * final_mask

0

मुझे मिनिस्ट्री डेटासेट का उपयोग करके लॉस फ़ंक्शन में क्लास वेट को कोड करने का निम्नलिखित उदाहरण मिला। यहां देखें लिंक: https://github.com/keras-team/keras/issues/2115

def w_categorical_crossentropy(y_true, y_pred, weights):
    nb_cl = len(weights)
    final_mask = K.zeros_like(y_pred[:, 0])
    y_pred_max = K.max(y_pred, axis=1)
    y_pred_max = K.reshape(y_pred_max, (K.shape(y_pred)[0], 1))
    y_pred_max_mat = K.equal(y_pred, y_pred_max)
    for c_p, c_t in product(range(nb_cl), range(nb_cl)):
        final_mask += (weights[c_t, c_p] * y_pred_max_mat[:, c_p] * y_true[:, c_t])
    return K.categorical_crossentropy(y_pred, y_true) * final_mask

0
from collections import Counter
itemCt = Counter(trainGen.classes)
maxCt = float(max(itemCt.values()))
cw = {clsID : maxCt/numImg for clsID, numImg in itemCt.items()}

यह एक जनरेटर या मानक के साथ काम करता है। आपके सबसे बड़े वर्ग का वजन 1 होगा जबकि अन्यों का मान 1 वर्ग से अधिक होगा।

क्लास वेट एक शब्दकोश प्रकार के इनपुट को स्वीकार करता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.