我正在处理不平衡类的顺序标签问题,我想使用sample_weight
来解决不平衡问题。基本上如果我训练模型大约10个时代,我会得到很好的结果。如果我训练更多的时代,val_loss
不断下降,但我的结果会更糟。我猜测模型只是检测到更多的优势类而不利于较小的类。
该模型有两个输入,用于字嵌入和字符嵌入,输入是0到6的7个可能类之一。
使用填充时,用于单词嵌入的输入图层的形状为(3000, 150)
,并且用于单词嵌入的输入图层为(3000, 150, 15)
。我使用0.3分割来测试和训练数据,这意味着X_train
用于字嵌入的(2000, 150)
和(2000, 150, 15)
用于字符嵌入。 y
包含每个单词的正确类,以维度7的单热矢量编码,因此其形状为(3000, 150, 7)
。 y
同样分为训练和测试集。然后将每个输入馈入双向LSTM。
输出是一个矩阵,其中为2000个训练样本的每个单词分配了7个类别之一,因此大小为(2000, 150, 7)
。
首先,我只是尝试将sample_weight
定义为长度为7的np.array
,其中包含每个类的权重:
count = [list(array).index(1) for arrays in y for array in arrays]
count = dict(Counter(count))
count[0] = 0
total = sum([count[key] for key in count])
count = {k: count[key] / total for key in count}
category_weights = np.zeros(7)
for f in count:
category_weights[f] = count[f]
但是我收到以下错误ValueError: Found a sample_weight array with shape (7,) for an input with shape (2000, 150, 7). sample_weight cannot be broadcast.
查看文档,看起来我应该通过a 2D array with shape (samples, sequence_length)
。所以我创建了一个(3000, 150)
数组,其中包含每个序列的每个单词的权重:
weights = []
for sample in y:
current_weight = []
for line in sample:
current_weight.append(frequency[list(line).index(1)])
weights.append(current_weight)
weights = np.array(weights)
并在sample_weight
中添加sample_weight_mode="temporal"
选项后,通过compile()
参数将其传递给fit函数。
我首先得到一个错误,告诉我维度是错误的,但是在仅为训练样本生成权重后,我最终得到了一个(2000, 150)
数组,我可以用它来拟合我的模型。
答案 0 :(得分:4)
我认为你让sample_weights
和class_weights
感到困惑。检查docs一点,我们可以看到它们之间的差异:
sample_weights
用于为每个训练样本提供权重。这意味着您应该传递一个与您的元素数量相同的一维数组训练样本(表示每个样本的重量)。如果您使用时态数据,您可以改为传递2D数组,使您能够为每个样本的每个时间步长赋予权重。
class_weights
用于为每个输出类提供权重或偏差。这意味着您应该为您尝试分类的每个班级传递一个权重。此外,此参数需要将字典传递给它(不是数组,这就是您遇到该错误的原因)。例如,考虑这种情况:
class_weight = {0 : 1. , 1: 50.}
在这种情况下(二进制分类问题),与类1
相比,您为类0
的样本提供了50倍的权重(或“相关性”)。这样您就可以补偿不平衡的数据集。这是另一个有用的post,它解释了在处理不平衡数据集时要考虑的这个和其他选项。
如果我训练更多的纪元,val_loss会不断下降,但结果会更差。
可能你过度拟合了,正如你所怀疑的那样,你的数据集所具有的不平衡类可能会导致这种情况。补偿班级权重应该有助于缓解这种情况,但是仍然可能有其他因素导致过度拟合,从而超出了这个问题/答案的范围(所以在解决这个问题之后一定要注意那些)。
根据您的帖子判断,在我看来,您需要的是使用class_weight
来平衡您的数据集进行培训,您需要传递一个字典来指示重量比你的7个班级之间。仅当您希望为每个示例提供自定义权重时才考虑使用sample_weight
。
如果您想在这两者之间进行更详细的比较,请考虑检查我在相关问题上发布的this answer。 掠夺者:sample_weight
会覆盖class_weight
,因此您必须使用其中一种,但不能同时使用,所以请注意不要混合它们。
答案 1 :(得分:0)
我在网上搜索了同样的问题,在我的案例中正确使用 sample_weight
后,我确实提高了准确度。
我认为你的理解是正确的,程序也是正确的。您的案例没有改进的一个可能原因是,当您传入 sample_weight
时,较高的值意味着较高的权重。这意味着您不能直接使用字数统计。您可能会考虑使用倒计数频率:
total = sum([count[key] for key in count])
count = {k: count[key] / total for key in count}
for f in count:
category_weights = np.zeros(7)
category_weights[f] = 1 - count[f]