我误用了softmax的二元交叉熵,改为分类交叉熵。并在我自己的回答中对以下问题的详细信息进行了一些审核
我正在尝试使用开源数据:sogou_news_csv(使用 jieba 转换为拼音,用于{Zhang}和Yann LeCun之后的https://arxiv.org/abs/1502.01710“文字理解”之后的文本分类。主要遵循使用字符级CNN的想法,但文中提出的结构)。
我根据字母表集合使用单热编码进行预处理,并使用0填充所有不在字母表集合中的编码。 结果,我获得了形状为(450000,1000,70),(data_size,sequence_length,alphabet_size)的训练数据。
然后我将数据提供到http://www.wildml.com/2015/12/implementing-a-cnn-for-text-classification-in-tensorflow/之后的cnn结构中。
问题
在培训期间,损失和仅仅是更改,我再次尝试对数据进行预处理,tried different learning rate settings
,但没有帮助,那么出了什么问题?
以下是单热编码:
import numpy as np
all_letters = "abcdefghijklmnopqrstuvwxyz0123456789-,;.!?:'\"/\\|_@#$%^&*~`+-=<>()[]{}\n"
n_letters = len(all_letters)
def letterToIndex(letter):
"""
'c' -> 2
"""
return all_letters.find(letter)
def sets2tensors(clean_train, n_letters=n_letters, MAX_SEQUENCE_LENGTH=1000):
"""
From lists of cleaned passages to np.array with shape(len(train),
max_sequence_length, len(dict))
Arg:
obviously
"""
m = len(clean_train)
x_data = np.zeros((m, MAX_SEQUENCE_LENGTH, n_letters))
for ix in range(m):
for no, letter in enumerate(clean_train[ix]):
if no >= 1000:
break
letter_index = letterToIndex(letter)
if letter != -1:
x_data[ix][no][letter_index] = 1
else:
continue
return x_data
这是模特:
num_classes = 5
from keras.models import Sequential
from keras.layers import Activation, GlobalMaxPool1D, Merge, concatenate, Conv1D, Dense, Dropout
from keras.callbacks import EarlyStopping
from keras.optimizers import SGD
submodels = []
for kw in (3, 4, 5): # kernel sizes
submodel = Sequential()
submodel.add(Conv1D(32,
kw,
padding='valid',
activation='relu',
strides=1, input_shape=(1000, n_letters)))
submodel.add(GlobalMaxPool1D())
submodels.append(submodel)
big_model = Sequential()
big_model.add(Merge(submodels, mode="concat"))
big_model.add(Dense(64))
big_model.add(Dropout(0.5))
big_model.add(Activation('relu'))
big_model.add(Dense(num_classes))
big_model.add(Activation('softmax'))
print('Compiling model')
opt = SGD(lr=1e-6) # tried different learning rate from 1e-6 to 1e-1
# changed from binary crossentropy to categorical_crossentropy
big_model.compile(loss='categorical_crossentropy',
optimizer=opt,
metrics=['accuracy'])
一些结果
Train on 5000 samples, validate on 5000 samples
Epoch 1/5
5000/5000 [==============================] - 54s - loss: 0.5198 - acc: 0.7960 - val_loss: 0.5001 - val_acc: 0.8000
Epoch 2/5
5000/5000 [==============================] - 56s - loss: 0.5172 - acc: 0.7959 - val_loss: 0.5000 - val_acc: 0.8000
Epoch 3/5
5000/5000 [==============================] - 56s - loss: 0.5198 - acc: 0.7965 - val_loss: 0.5000 - val_acc: 0.8000
Epoch 4/5
5000/5000 [==============================] - 57s - loss: 0.5222 - acc: 0.7950 - val_loss: 0.4999 - val_acc: 0.8000
Epoch 5/5
5000/5000 [==============================] - 59s - loss: 0.5179 - acc: 0.7960 - val_loss: 0.4999 - val_acc: 0.8000
答案 0 :(得分:1)
我发现问题是我偶然使用了softmax的二进制交叉熵(我用于另一个数据集),这应该是分类交叉熵。最初,我认为这是一个愚蠢的错误,因为我没有仔细检查代码和逻辑。
但后来我发现我并不真正理解这里发生了什么,我的意思是,我知道二元交叉熵和分类交叉熵之间的区别,但我不太了解细节为什么softmax和分类交叉熵不能链接在一起。
幸运的是,我在这里找到了一个非常好的解释(没想到有人真的会问或回答这个问题)
基本上它说的是在二进制交叉熵的情况下,损失函数将单个位的两个不同值视为两个不同的类:如A为1,B为0,尽管存在分类交叉熵情况,但损失函数采用类似[0,0,0,1,0]的向量作为标签,其中位的值代表相应训练示例的置信度或概率那个特殊的班级。
通过上面的描述,当我们将二进制交叉熵应用于softmax时,我们误用了一位在该设置中的含义的定义,因此没有意义。
答案 1 :(得分:0)
您已将SGD优化器设置为0.000001(opt = SGD(lr = 1e-6))
SGD的默认学习率为0.01
keras.optimizers.SGD(lr = 0.01,动量= 0.0,衰减= 0.0,nesterov = False)
我怀疑1e-6是小的,尝试增加它和/或尝试不同的优化器