Keras 网络永远无法 class 验证最后一个 class
Keras network can never classify the last class
我一直在研究我的项目 Deep Learning Language Detection,这是一个具有这些层的网络,可以识别 16 种编程语言:
这是生成网络的代码:
# Setting up the model
graph_in = Input(shape=(sequence_length, number_of_quantised_characters))
convs = []
for i in range(0, len(filter_sizes)):
conv = Conv1D(filters=num_filters,
kernel_size=filter_sizes[i],
padding='valid',
activation='relu',
strides=1)(graph_in)
pool = MaxPooling1D(pool_size=pooling_sizes[i])(conv)
flatten = Flatten()(pool)
convs.append(flatten)
if len(filter_sizes)>1:
out = Concatenate()(convs)
else:
out = convs[0]
graph = Model(inputs=graph_in, outputs=out)
# main sequential model
model = Sequential()
model.add(Dropout(dropout_prob[0], input_shape=(sequence_length, number_of_quantised_characters)))
model.add(graph)
model.add(Dense(hidden_dims))
model.add(Dropout(dropout_prob[1]))
model.add(Dense(number_of_classes))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adadelta', metrics=['accuracy'])
所以我的最后一门语言 class 是 SQL,在测试阶段,它永远无法正确预测 SQL,因此它的得分为 0%。我认为这是由于 SQL 样本质量差(实际上它们很差),所以我删除了这个 class 并开始训练 15 classes。令我惊讶的是,现在 F# 文件的检测率为 0%,并且 F# 是删除 SQL 后的最后一个 class(即最后一个位置为 1,其余位置为 0 的单热向量)。现在,如果在 16 上训练的网络用于 15,它将达到 98.5% 的非常高的成功率。
我使用的代码非常简单,主要在 defs.py and data_helper.py
中可用
这是使用 16 classes 训练的网络针对 16 classes 进行测试的结果:
Final result: 14827/16016 (0.925761738262)
xml: 995/1001 (0.994005994006)
fsharp: 974/1001 (0.973026973027)
clojure: 993/1001 (0.992007992008)
java: 996/1001 (0.995004995005)
scala: 990/1001 (0.989010989011)
python: 983/1001 (0.982017982018)
sql: 0/1001 (0.0)
js: 991/1001 (0.99000999001)
cpp: 988/1001 (0.987012987013)
css: 987/1001 (0.986013986014)
csharp: 994/1001 (0.993006993007)
go: 989/1001 (0.988011988012)
php: 998/1001 (0.997002997003)
ruby: 995/1001 (0.994005994006)
powershell: 992/1001 (0.991008991009)
bash: 962/1001 (0.961038961039)
这是同一个网络(针对 16 个训练)运行 对 15 classes:
的结果
Final result: 14827/15015 (0.987479187479)
xml: 995/1001 (0.994005994006)
fsharp: 974/1001 (0.973026973027)
clojure: 993/1001 (0.992007992008)
java: 996/1001 (0.995004995005)
scala: 990/1001 (0.989010989011)
python: 983/1001 (0.982017982018)
js: 991/1001 (0.99000999001)
cpp: 988/1001 (0.987012987013)
css: 987/1001 (0.986013986014)
csharp: 994/1001 (0.993006993007)
go: 989/1001 (0.988011988012)
php: 998/1001 (0.997002997003)
ruby: 995/1001 (0.994005994006)
powershell: 992/1001 (0.991008991009)
bash: 962/1001 (0.961038961039)
还有其他人看过吗?我该如何解决?
TL;DR: 问题是你的数据在被分成训练集和验证集之前没有被洗牌。因此,在训练过程中,所有属于class "sql"的样本都在验证集中。如果未在 class.
中提供样本,您的模型将无法学习预测最后一个 class
在get_input_and_labels()
中,首先加载class0的文件,然后是class1,以此类推。既然你设置了n_max_files = 2000
,那就意味着
Y
中的前 2000 个(大约,取决于您实际拥有多少文件)条目将是 class 0 ("go")
- 接下来的 2000 个条目将是 class 1 ("csharp")
- ...
- 最后 2000 个条目将是最后 class ("sql").
不幸的是,Keras 在将数据拆分为训练集和验证集之前不会对数据进行洗牌。因为 validation_split
在您的代码中设置为 0.1,所以大约最后 3000 个样本(包含所有 "sql" 个样本)将在验证集中。
如果您将 validation_split
设置为更高的值(例如 0.2),您会看到更多 classes 得分为 0%:
Final result: 12426/16016 (0.7758491508491508)
go: 926/1001 (0.9250749250749251)
csharp: 966/1001 (0.965034965034965)
java: 973/1001 (0.972027972027972)
js: 929/1001 (0.9280719280719281)
cpp: 986/1001 (0.985014985014985)
ruby: 942/1001 (0.9410589410589411)
powershell: 981/1001 (0.98001998001998)
bash: 882/1001 (0.8811188811188811)
php: 977/1001 (0.9760239760239761)
css: 988/1001 (0.987012987012987)
xml: 994/1001 (0.993006993006993)
python: 986/1001 (0.985014985014985)
scala: 896/1001 (0.8951048951048951)
clojure: 0/1001 (0.0)
fsharp: 0/1001 (0.0)
sql: 0/1001 (0.0)
如果加载后对数据进行随机播放,问题就可以解决。看来你已经有线洗牌数据:
# Shuffle data
shuffle_indices = np.random.permutation(np.arange(len(y)))
x_shuffled = x[shuffle_indices]
y_shuffled = y[shuffle_indices].argmax(axis=1)
但是,当你拟合模型时,你将原来的x
和y
传递给了fit()
而不是x_shuffled
和y_shuffled
。如果将行更改为:
model.fit(x_shuffled, y_shuffled, batch_size=batch_size,
epochs=num_epochs, validation_split=val_split, verbose=1)
测试输出会更合理:
Final result: 15248/16016 (0.952047952047952)
go: 865/1001 (0.8641358641358642)
csharp: 986/1001 (0.985014985014985)
java: 977/1001 (0.9760239760239761)
js: 953/1001 (0.952047952047952)
cpp: 974/1001 (0.973026973026973)
ruby: 985/1001 (0.984015984015984)
powershell: 974/1001 (0.973026973026973)
bash: 942/1001 (0.9410589410589411)
php: 979/1001 (0.978021978021978)
css: 965/1001 (0.964035964035964)
xml: 988/1001 (0.987012987012987)
python: 857/1001 (0.8561438561438561)
scala: 955/1001 (0.954045954045954)
clojure: 985/1001 (0.984015984015984)
fsharp: 950/1001 (0.949050949050949)
sql: 913/1001 (0.9120879120879121)
我一直在研究我的项目 Deep Learning Language Detection,这是一个具有这些层的网络,可以识别 16 种编程语言:
这是生成网络的代码:
# Setting up the model
graph_in = Input(shape=(sequence_length, number_of_quantised_characters))
convs = []
for i in range(0, len(filter_sizes)):
conv = Conv1D(filters=num_filters,
kernel_size=filter_sizes[i],
padding='valid',
activation='relu',
strides=1)(graph_in)
pool = MaxPooling1D(pool_size=pooling_sizes[i])(conv)
flatten = Flatten()(pool)
convs.append(flatten)
if len(filter_sizes)>1:
out = Concatenate()(convs)
else:
out = convs[0]
graph = Model(inputs=graph_in, outputs=out)
# main sequential model
model = Sequential()
model.add(Dropout(dropout_prob[0], input_shape=(sequence_length, number_of_quantised_characters)))
model.add(graph)
model.add(Dense(hidden_dims))
model.add(Dropout(dropout_prob[1]))
model.add(Dense(number_of_classes))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adadelta', metrics=['accuracy'])
所以我的最后一门语言 class 是 SQL,在测试阶段,它永远无法正确预测 SQL,因此它的得分为 0%。我认为这是由于 SQL 样本质量差(实际上它们很差),所以我删除了这个 class 并开始训练 15 classes。令我惊讶的是,现在 F# 文件的检测率为 0%,并且 F# 是删除 SQL 后的最后一个 class(即最后一个位置为 1,其余位置为 0 的单热向量)。现在,如果在 16 上训练的网络用于 15,它将达到 98.5% 的非常高的成功率。
我使用的代码非常简单,主要在 defs.py and data_helper.py
中可用这是使用 16 classes 训练的网络针对 16 classes 进行测试的结果:
Final result: 14827/16016 (0.925761738262)
xml: 995/1001 (0.994005994006)
fsharp: 974/1001 (0.973026973027)
clojure: 993/1001 (0.992007992008)
java: 996/1001 (0.995004995005)
scala: 990/1001 (0.989010989011)
python: 983/1001 (0.982017982018)
sql: 0/1001 (0.0)
js: 991/1001 (0.99000999001)
cpp: 988/1001 (0.987012987013)
css: 987/1001 (0.986013986014)
csharp: 994/1001 (0.993006993007)
go: 989/1001 (0.988011988012)
php: 998/1001 (0.997002997003)
ruby: 995/1001 (0.994005994006)
powershell: 992/1001 (0.991008991009)
bash: 962/1001 (0.961038961039)
这是同一个网络(针对 16 个训练)运行 对 15 classes:
的结果Final result: 14827/15015 (0.987479187479)
xml: 995/1001 (0.994005994006)
fsharp: 974/1001 (0.973026973027)
clojure: 993/1001 (0.992007992008)
java: 996/1001 (0.995004995005)
scala: 990/1001 (0.989010989011)
python: 983/1001 (0.982017982018)
js: 991/1001 (0.99000999001)
cpp: 988/1001 (0.987012987013)
css: 987/1001 (0.986013986014)
csharp: 994/1001 (0.993006993007)
go: 989/1001 (0.988011988012)
php: 998/1001 (0.997002997003)
ruby: 995/1001 (0.994005994006)
powershell: 992/1001 (0.991008991009)
bash: 962/1001 (0.961038961039)
还有其他人看过吗?我该如何解决?
TL;DR: 问题是你的数据在被分成训练集和验证集之前没有被洗牌。因此,在训练过程中,所有属于class "sql"的样本都在验证集中。如果未在 class.
中提供样本,您的模型将无法学习预测最后一个 class在get_input_and_labels()
中,首先加载class0的文件,然后是class1,以此类推。既然你设置了n_max_files = 2000
,那就意味着
Y
中的前 2000 个(大约,取决于您实际拥有多少文件)条目将是 class 0 ("go")- 接下来的 2000 个条目将是 class 1 ("csharp")
- ...
- 最后 2000 个条目将是最后 class ("sql").
不幸的是,Keras 在将数据拆分为训练集和验证集之前不会对数据进行洗牌。因为 validation_split
在您的代码中设置为 0.1,所以大约最后 3000 个样本(包含所有 "sql" 个样本)将在验证集中。
如果您将 validation_split
设置为更高的值(例如 0.2),您会看到更多 classes 得分为 0%:
Final result: 12426/16016 (0.7758491508491508)
go: 926/1001 (0.9250749250749251)
csharp: 966/1001 (0.965034965034965)
java: 973/1001 (0.972027972027972)
js: 929/1001 (0.9280719280719281)
cpp: 986/1001 (0.985014985014985)
ruby: 942/1001 (0.9410589410589411)
powershell: 981/1001 (0.98001998001998)
bash: 882/1001 (0.8811188811188811)
php: 977/1001 (0.9760239760239761)
css: 988/1001 (0.987012987012987)
xml: 994/1001 (0.993006993006993)
python: 986/1001 (0.985014985014985)
scala: 896/1001 (0.8951048951048951)
clojure: 0/1001 (0.0)
fsharp: 0/1001 (0.0)
sql: 0/1001 (0.0)
如果加载后对数据进行随机播放,问题就可以解决。看来你已经有线洗牌数据:
# Shuffle data
shuffle_indices = np.random.permutation(np.arange(len(y)))
x_shuffled = x[shuffle_indices]
y_shuffled = y[shuffle_indices].argmax(axis=1)
但是,当你拟合模型时,你将原来的x
和y
传递给了fit()
而不是x_shuffled
和y_shuffled
。如果将行更改为:
model.fit(x_shuffled, y_shuffled, batch_size=batch_size,
epochs=num_epochs, validation_split=val_split, verbose=1)
测试输出会更合理:
Final result: 15248/16016 (0.952047952047952)
go: 865/1001 (0.8641358641358642)
csharp: 986/1001 (0.985014985014985)
java: 977/1001 (0.9760239760239761)
js: 953/1001 (0.952047952047952)
cpp: 974/1001 (0.973026973026973)
ruby: 985/1001 (0.984015984015984)
powershell: 974/1001 (0.973026973026973)
bash: 942/1001 (0.9410589410589411)
php: 979/1001 (0.978021978021978)
css: 965/1001 (0.964035964035964)
xml: 988/1001 (0.987012987012987)
python: 857/1001 (0.8561438561438561)
scala: 955/1001 (0.954045954045954)
clojure: 985/1001 (0.984015984015984)
fsharp: 950/1001 (0.949050949050949)
sql: 913/1001 (0.9120879120879121)