Keras에서 불균형 클래스의 클래스 가중치를 설정하는 방법은 무엇입니까?


129

Keras에는 class_weights매개 변수 사전 이있을 가능성이 있음을 알고 있지만 예제를 찾을 수 없습니다. 누군가가 그렇게 친절하게 해 줄 것입니까?

그건 그렇고,이 경우 적절한 실습은 단순히 소수의 클래스를 과소 표현에 비례하여 가중치를 부여하는 것입니까?


Keras를 사용하여 새로운 업데이트 된 방법이 있습니까? 왜 사전이 세 개의 클래스와 클래스로 구성되어 있습니까? 0 : 1.0 1 : 50.0 2 : 2.0 ???? 해서는 안됩니다 : 2 : 1.0?

답변:


112

네트워크에서 하나의 출력 만 생성하는 일반적인 경우에 대해 이야기하는 경우 가정이 올바른 것입니다. 알고리즘이 클래스 1 의 모든 인스턴스를 클래스 0 의 50 개 인스턴스로 처리 하도록하려면 다음을 수행해야합니다.

  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 의 모든 인스턴스를 클래스 0 의 50 인스턴스로 처리 "는 손실 함수에서 이러한 인스턴스에 더 높은 값을 할당한다는 것을 의미합니다. 따라서 손실은 가중 평균이되며, 각 샘플의 가중치는 class_weight 및 해당 클래스로 지정됩니다 .

Keras docs에서 : class_weight : 선택적 딕셔너리 클래스 인덱스 (정수)를 가중치 (float) 값으로 매핑하며, 손실 함수의 가중치를 부여하는 데 사용됩니다 (훈련 중에 만).


1
또한 한 번 봐 가지고 github.com/fchollet/keras/issues/3653를 사용하면 3D 데이터로 작업하는 경우.
herve

나에게 그것은 dic에 shape 속성이 없다는 오류를 준다.
Flávio Filho

나는 Keras가 이것이 작동하는 방식을 바꿀 수 있다고 생각합니다. 이것은 2016 년 8 월 버전입니다. 나는 일주일 안에 당신을 확인할 것입니다
레이저

4
@layser 이것은 'category_crossentropy'손실에 대해서만 작동합니까? 'sigmoid'와 'binary_crossentropy'손실에 대해 keras에 class_weight를 어떻게 부여합니까?
Naman

1
@layser 클래스 1의 모든 인스턴스를 클래스 0의 50 개 인스턴스로 취급하도록`를 설명 할 수 있습니까? 훈련 세트에서 클래스 1에 해당하는 행이 균형을 이루거나 다른 프로세스가 따르도록 50 번 복제됩니까?
Divyanshu Shekhar 2016 년

122

class_weightfrom을 간단하게 구현할 수 있습니다 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_weightclass_weight 가져온 모듈을 덮어 쓰지 않도록하기 위해. 주석에서 코드를 복사 할 때 적절하게 조정하십시오.


21
나를 class_weight.compute_class_weight 위해 배열을 생성하려면 Keras와 함께 작동하려면 배열을 dict로 변경해야합니다. 보다 구체적으로, 2 단계 후에class_weight_dict = dict(enumerate(class_weight))
C.Lee

5
이것은 나를 위해 작동하지 않습니다. keras의 3 가지 클래스 문제 y_train(300096, 3)numpy 배열입니다. 그래서 class_weight=선은 나를 형식 오류 제공 : unhashable 유형을 'numpy.ndarray'
Lembik

3
@Lembik 비슷한 문제가 있었는데, y의 각 행은 클래스 인덱스의 one-hot 인코딩 된 벡터입니다. one-hot 표현을 다음과 같이 int로 변환하여 수정했습니다 y_ints = [y.argmax() for y in y_train].
tkocmathla

3
y_true 벡터에 여러 개의 1이 포함되도록 멀티 클래스 레이블링을 수행하는 경우 : [1 0 0 1 0 0] 예를 들어, 일부 x에는 레이블 0과 4가 있습니다. 라벨의 균형이 맞지 않습니다. 클래스 가중치를 어떻게 사용합니까?
Aalok

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 (...)의 param class_weight에 들어가는 것으로 가정합니다.
startoftext

@startoftext 그렇게했지만, 거꾸로 한 것 같습니다. 나는 n_total_samples / n_class_samples각 수업에 사용 했다.
colllin

2
귀하의 예제에서 class 0 (예 2813 예제)과 class 6 (예 7914 예제)의 가중치는 정확히 1.0입니다. 왜 그런 겁니까? 클래스 6은 몇 배 더 큽니다! 클래스 0을 업 스케일하고 클래스 6을 다운 스케일하여 동일한 레벨로 만들려고합니다.
Vladislavs Dovgalecs

9

참고 :이 답변은 구식입니다.

모든 클래스에 동일한 가중치를 부여하려면 다음과 같이 class_weight를 "auto"로 설정하면됩니다.

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

1
class_weight='auto'Keras 문서 나 소스 코드에서 참조를 찾을 수 없습니다 . 어디서 찾았는지 보여줄 수 있습니까?
Fábio Perez

2
이 대답은 아마도 틀렸을 것입니다. 이 문제를 확인하십시오 : github.com/fchollet/keras/issues/5116
Fábio Perez

이상한. 의견을 게시 할 당시 class_balanced = 'auto'를 사용하고 있었지만 지금은 참조를 찾을 수 없습니다. Keras가 빠르게 발전함에 따라 변경되었을 수 있습니다.
David Groppe

에 지정된대로 Keras 문제가 위에서 언급 , 당신은 어떤 임의의 문자열을 전달할 수 class_weight있으며 영향을주지 않습니다. 따라서이 답변은 정확하지 않습니다.
ncasas

3

class_weight는 괜찮지 만 @Aalok이 말했듯이 다중 레이블 클래스가 원 핫 인코딩 인 경우 작동하지 않습니다. 이 경우 sample_weight를 사용 하십시오 .

sample_weight : x와 길이가 같은 선택적 배열로, 각 표본의 모형 손실에 적용 할 가중치를 포함합니다. 시간적 데이터의 경우 모양 (샘플, sequence_length)으로 2D 배열을 전달하여 모든 샘플의 모든 시간 단계에 다른 가중치를 적용 할 수 있습니다. 이 경우 compile ()에 sample_weight_mode = "temporal"을 지정해야합니다.

sample_weights각 학습 샘플에 가중치제공하는 데 사용됩니다 . 즉, 훈련 샘플과 동일한 개수의 요소가있는 1D 배열을 전달해야합니다 (각 샘플의 가중치를 나타냄).

class_weights각 출력 클래스에 가중치 또는 바이어스 를 제공하는 데 사용됩니다 . 즉, 분류하려는 각 클래스에 가중치를 전달해야합니다.

sample_weight는 모양이 평가되므로 numpy 배열을 제공해야합니다.

이 답변을 참조하십시오 : https : //.com/questions/48315094/using-sample-weight-in-keras-for-sequence-labelling


2

에서 솔루션에 추가 https://github.com/keras-team/keras/issues/2115 . 가양 성 및가 음성에 대해 다른 비용을 원할 경우 클래스 가중치 이상이 필요한 경우. 새로운 keras 버전을 사용하면 아래와 같이 각각의 손실 기능을 무시할 수 있습니다. 그 주 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보다 큰 값을 갖습니다.

클래스 가중치는 사전 유형 입력을 허용합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.