python - Keras 功能 API 从带有 LSTM 层的 Keras Sequential API 产生不同的结果
问题描述
我正在比较使用 Keras 的顺序和功能 API 构建的模型,并发现某些类型的模型会产生非常不同的结果。
我正在为我的模型使用 IMDB 数据集。
如果我创建一个只有Embedding
和Dense
层的模型,结果非常相似。
这是一个例子:
# imports
from tensorflow.keras.layers import Dense, LSTM, Flatten, Embedding
from tensorflow.keras import Input, Model
from tensorflow.keras.models import Sequential
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
顺序 API 的代码:
df = pd.read_csv('url_for_imdb_csv_file_here')
df['sentiment'].replace(['positive', 'negative'], [1, 0], inplace=True)
X_train, X_test, y_train, y_test = train_test_split(df['review'], df['sentiment'], test_size=0.2, random_state=1985)
tokenizer = Tokenizer(num_words=10000)
tokenizer.fit_on_texts(X_train)
train_seq = tokenizer.texts_to_sequences(X_train)
test_seq = tokenizer.texts_to_sequences(X_test)
train_seq = pad_sequences(train_seq, maxlen=250)
test_seq = pad_sequences(test_seq, maxlen=250)
mod = Sequential([
Embedding(10000, 25, input_length=250),
Flatten(),
Dense(25, activation='relu'),
Dense(25, activation='relu'),
Dense(1, activation = 'sigmoid')
])
mod.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
mod.fit(train_seq, y_train.values, validation_split=0.2, epochs=2)
这在两个时期后产生了约 88% 的准确度。
如果我使用功能 API 重新创建相同的模型,我将得到相同的结果。代码如下。
使用顺序 API 的代码
vectorizer = TextVectorization(max_tokens=10000, output_sequence_length=250)
vectorizer.adapt(X_train.values)
text_input = Input(shape=(1,), dtype='string')
x = vectorizer(text_input)
x = Embedding(10000, 25, input_length=250)(x)
x = Flatten()(x)
x = Dense(25, activation='relu')(x)
x = Dense(25, activation='relu')(x)
output = Dense(1, activation='sigmoid')(x)
mod1 = Model(text_input, output)
mod1.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
mod1.fit(X_train.values, y_train.values, validation_split=0.2, epochs=5)
这给了我大约相同的结果。
到目前为止,一切都很好。
但是,当我尝试添加 LSTM 层时,结果明显不同。
这是我正在使用的两个示例。我Dense
用一层换掉LSTM
一层并保持其他一切不变。
新的顺序 API 代码:
mod = Sequential([
Embedding(10000, 25, input_length=250),
LSTM(25),
Dense(25, activation='relu'),
Dense(1, activation = 'sigmoid')
])
mod.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
mod.fit(train_seq, y_train.values, validation_split=0.2, epochs=2)
这给出了与以前的模型大致相同的结果。
但是,当我使用功能 API 重新创建此版本时,准确率在第 2 轮达到 64% 左右的峰值,然后又回落到约 50%。
新功能 API:
vectorizer = TextVectorization(max_tokens=10000, output_sequence_length=250)
vectorizer.adapt(X_train.values)
text_input = Input(shape=(1,), dtype='string')
x = vectorizer(text_input)
x = Embedding(10000, 25, input_length=250)(x)
x = LSTM(25)(x)
x = Dense(25, activation='relu')(x)
output = Dense(1, activation='sigmoid')(x)
mod1 = Model(text_input, output)
这不会产生相同的结果,即使它在我看来与Sequential
示例相同。
有没有我遗漏的东西不能使两者相同,或者这是功能 API 工作方式的特殊性?
谢谢你。
解决方案
推荐阅读
- java - 如何在 opentracing 中更改 trace-id 标头?
- authentication - 这是一个针对单个用户的自定义领域身份验证程序,帮助我解决多个用户问题
- javascript - Javascript 和 PHP 文件上传应用程序重定向并导致下载提示
- c# - 如何从存储过程返回表多行并使用 ADO.NET 在 C# 中访问这些值?
- java - 从数组中选择一个随机字符串
- mongodb - MongoDB为什么多重条件比mysql慢
- slack - 在松弛中设置提醒
- angularjs - 如何在 Typescript 中扩展 ng 的 IModule 接口?
- ios - 如何将 tableview 数据获取到 detailsViewController
- html - 如何在 HTML 表格中添加空白单元格,使行的单元格数量与包含数据的行相同?