Làm cách nào để đặt trọng số lớp cho các lớp không cân bằng trong Keras?


130

Tôi biết rằng có một khả năng trong Keras với class_weightstừ điển tham số phù hợp, nhưng tôi không thể tìm thấy bất kỳ ví dụ nào. Ai đó sẽ tốt bụng để cung cấp một?

Nhân tiện, trong trường hợp này, Praxis thích hợp chỉ đơn giản là để tăng trọng số của nhóm thiểu số tỷ lệ thuận với sự đại diện của nó?


Có một phương pháp cập nhật mới bằng cách sử dụng Keras? tại sao từ điển bao gồm ba lớp và cho lớp: 0: 1.0 1: 50.0 2: 2.0 ???? không nên: 2: 1.0 là tốt?
Chuck

Câu trả lời:


112

Nếu bạn đang nói về trường hợp thông thường, trong đó mạng của bạn chỉ tạo ra một đầu ra, thì giả định của bạn là chính xác. Để buộc thuật toán của bạn xử lý mọi trường hợp của lớp 1 là 50 trường hợp của lớp 0, bạn phải:

  1. Xác định một từ điển với nhãn của bạn và trọng lượng liên quan của chúng

    class_weight = {0: 1.,
                    1: 50.,
                    2: 2.}
  2. Nạp từ điển dưới dạng tham số:

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

EDIT: "coi mọi trường hợp của lớp 1 là 50 trường hợp của lớp 0 " có nghĩa là trong hàm mất của bạn, bạn gán giá trị cao hơn cho các trường hợp này. Do đó, tổn thất trở thành trung bình có trọng số, trong đó trọng số của từng mẫu được chỉ định bởi class_ weight và lớp tương ứng của nó.

Từ tài liệu Keras: class_ weight : Chỉ số lớp ánh xạ từ điển tùy chọn (số nguyên) đến giá trị trọng số (float), được sử dụng để cân trọng số cho hàm mất (chỉ trong khi đào tạo).


1
Ngoài ra, hãy xem github.com/fchollet/keras/issues/3653 nếu bạn đang làm việc với dữ liệu 3D.
herve

Đối với tôi nó đưa ra một lỗi dic không có thuộc tính hình dạng.
Flávio Filho

Tôi tin rằng Keras có thể thay đổi cách thức hoạt động của nó, đây là phiên bản của tháng 8 năm 2016. Tôi sẽ xác minh cho bạn sau một tuần nữa
layser

4
@layser Điều này chỉ hoạt động khi mất 'category_crossentropy'? Làm thế nào để bạn cung cấp class_ weight cho máy ảnh cho mất 'sigmoid' và 'binary_crossentropy'?
Naman

1
@layser Bạn có thể giải thích `để coi mọi trường hợp của lớp 1 là 50 trường hợp của lớp 0` không? Có phải là trong tập huấn luyện, hàng tương ứng với lớp 1 được nhân đôi 50 lần để làm cho nó cân bằng hoặc một số quy trình khác theo sau?
Divyanshu Shekhar

122

Bạn chỉ có thể thực hiện class_weighttừ sklearn:

  1. Trước tiên hãy nhập mô-đun

    from sklearn.utils import class_weight
  2. Để tính trọng lượng lớp, hãy làm như sau

    class_weights = class_weight.compute_class_weight('balanced',
                                                     np.unique(y_train),
                                                     y_train)
  3. Thứ ba và cuối cùng thêm nó vào mô hình phù hợp

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

Chú ý : Tôi đã chỉnh sửa bài đăng này và thay đổi tên biến từ class_ weight thành class_ weight s để không ghi đè lên mô-đun đã nhập. Điều chỉnh cho phù hợp khi sao chép mã từ các ý kiến.


21
Đối với tôi, class_weight.compute_class_weight tạo ra một mảng, tôi cần thay đổi nó thành một lệnh để làm việc với Keras. Cụ thể hơn, sau bước 2, hãy sử dụngclass_weight_dict = dict(enumerate(class_weight))
C.Lee

5
Điều này không làm việc cho tôi. Đối với một vấn đề ba lớp trong máy ảnh y_train(300096, 3)mảng numpy. Vì vậy, class_weight=dòng mang lại cho tôi TypeError: loại không thể xóa: 'numpy.ndarray'
Lembik

3
@Lembik Tôi có một vấn đề tương tự, trong đó mỗi hàng y là một vectơ mã hóa một nóng của chỉ mục lớp. Tôi đã sửa nó bằng cách chuyển đổi một đại diện nóng thành một int như thế này : y_ints = [y.argmax() for y in y_train].
tkocmathla

3
Điều gì xảy ra nếu tôi thực hiện ghi nhãn đa lớp để các vectơ y_true của tôi có nhiều số 1 trong đó: [1 0 0 0 1 0 0], ví dụ, một số x có nhãn 0 và 4. Thậm chí, tổng số # của mỗi nhãn không cân bằng. Làm thế nào tôi có thể sử dụng trọng lượng lớp với điều đó?
Aalok

22

Tôi sử dụng loại quy tắc này cho 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.loglàm mịn các trọng số cho các lớp rất mất cân bằng! Điều này trả về:

{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
Tại sao sử dụng nhật ký thay vì chỉ chia số lượng mẫu cho một lớp cho tổng số mẫu? Tôi giả sử có một cái gì đó tôi không hiểu đi vào lớp param_ weight trên model.fit_generator (...)
startoftext

@startoftext Đó là cách tôi đã làm, nhưng tôi nghĩ bạn đã đảo ngược nó. Tôi đã sử dụng n_total_samples / n_class_samplescho mỗi lớp.
colllin

2
Trong ví dụ của bạn lớp 0 (có 2813 ví dụ) và lớp 6 (có 7914 ví dụ) có trọng số chính xác là 1.0. Tại sao vậy? Lớp 6 lớn hơn vài lần! Bạn sẽ muốn lớp 0 được nâng cấp và lớp 6 được hạ thấp để đưa chúng về cùng cấp.
Vladislavs Dovgalecs

9

LƯU Ý: Xem bình luận, câu trả lời này đã lỗi thời.

Để cân bằng tất cả các lớp, giờ đây bạn có thể chỉ cần đặt class_ weight thành "tự động" như vậy:

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

1
Tôi không thể tìm thấy bất kỳ tài liệu tham khảo nào class_weight='auto'trong tài liệu của Keras cũng như trong mã nguồn. Bạn có thể chỉ cho chúng tôi nơi bạn tìm thấy điều này?
Fábio Perez

2
Câu trả lời này có lẽ sai. Kiểm tra vấn đề này: github.com/fchollet/keras/issues/5116
Fábio Perez

Lạ Tôi đã sử dụng class_bal cân bằng = 'tự động' tại thời điểm tôi đăng nhận xét, nhưng tôi không thể tìm thấy tài liệu tham khảo về nó ngay bây giờ. Có lẽ nó đã được thay đổi khi Keras đang phát triển nhanh chóng.
David Groppe

Như đã chỉ định trong vấn đề Keras được chỉ ra ở trên , bạn có thể chuyển bất kỳ chuỗi ngẫu nhiên nào class_weightvà nó sẽ không có hiệu lực. Câu trả lời này là không chính xác.
ncasas

3

class_ weight vẫn ổn nhưng như @Aalok đã nói điều này sẽ không hoạt động nếu bạn là lớp đa mã hóa một nhãn nóng. Trong trường hợp này, sử dụng sample_ weight :

sample_ weight: mảng tùy chọn có cùng độ dài với x, chứa trọng số để áp dụng cho tổn thất của mô hình cho từng mẫu. Trong trường hợp dữ liệu tạm thời, bạn có thể truyền một mảng 2D có hình dạng (samples, Sequ_length), để áp dụng trọng số khác nhau cho mỗi dấu thời gian của mỗi mẫu. Trong trường hợp này, bạn nên đảm bảo chỉ định sample_ weight_mode = "tạm thời" trong compile ().

sample_weights được sử dụng để cung cấp trọng lượng cho mỗi mẫu đào tạo . Điều đó có nghĩa là bạn nên vượt qua một mảng 1D có cùng số phần tử với các mẫu đào tạo của bạn (cho biết trọng lượng của từng mẫu đó).

class_weights được sử dụng để cung cấp trọng số hoặc độ lệch cho mỗi lớp đầu ra . Điều này có nghĩa là bạn nên vượt qua một trọng số cho mỗi lớp mà bạn đang cố gắng phân loại.

sample_ weight phải được cung cấp một mảng numpy, vì hình dạng của nó sẽ được đánh giá.

Xem thêm câu trả lời này: https://stackoverflow.com/questions/48315094/USE-sample-gra-in-keras-for- resultence-labelling


2

Thêm vào giải pháp tại https://github.com/keras-team/keras/issues/2115 . Nếu bạn cần nhiều hơn trọng số lớp, nơi bạn muốn chi phí khác nhau cho dương tính giả và âm tính giả. Với phiên bản máy ảnh mới bây giờ, bạn có thể ghi đè chức năng mất tương ứng như được đưa ra dưới đây. Lưu ý rằng đó weightslà một ma trận vuông.

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

Tôi đã tìm thấy ví dụ sau về việc mã hóa trọng số lớp trong hàm mất bằng cách sử dụng bộ dữ liệu minist. Xem liên kết tại đây: 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()}

Điều này làm việc với một máy phát điện hoặc tiêu chuẩn. Lớp lớn nhất của bạn sẽ có trọng số là 1 trong khi các lớp khác sẽ có giá trị lớn hơn 1 so với lớp lớn nhất.

trọng số lớp chấp nhận đầu vào loại từ điển

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.