适配TensorFlow LSTM代码实现二分类序列分类
我仔细检查了你的代码,发现几个关键问题需要修正,调整后就能实现你想要的二分类序列分类功能。下面是具体的问题分析和修改建议:
核心问题与修正点
1. 分类类别数设置错误
你初始化模型时传入了num_classes=1,但二分类任务需要设置为num_classes=2——因为softmax输出需要对应两个类别的概率分布,配合sparse_softmax_cross_entropy_with_logits损失函数使用时,标签是0/1的整数形式,不需要one-hot编码。
2. 标签处理逻辑错误
你的代码中用make_classification生成了新的Y,这会覆盖你原本的真实标签数据,完全是多余的操作。正确的做法是直接对原有标签进行整数编码(如果你的原始标签不是0/1的话):
# 替换掉你原来的Y生成代码,用自己的真实标签 label_encoder = LabelEncoder() # 假设你的原始Y是[[1],[0],[1],...],先flatten成一维 integer_encoded = label_encoder.fit_transform(Y.flatten()) Y = integer_encoded.reshape(-1, 1) # 保持形状方便后续处理
3. LSTM输出仅需最后时间步状态
原多对多模型使用了所有时间步的输出,但序列分类只需要最后一个时间步的隐藏状态来做预测。你代码中虽然获取了last_state,但后续还是用了所有时间步的states_reshaped,这会导致计算所有时间步的损失,完全不符合序列分类的需求。需要修改输出层逻辑:
# 取最后一个时间步的隐藏状态(st部分) last_st = self.last_state[0] # last_state是[st, ct],取第一个元素 logits = tf.matmul(last_st, V) + bo predictions = tf.nn.softmax(logits)
4. Embedding层词汇表大小不匹配
你硬编码了embedding层的大小为[100, state_size],但你的特征是int32数组,需要确保词汇表大小等于你的特征中最大索引+1(或者使用len(w2idx),如果你的w2idx是完整的词汇映射),否则当特征中出现大于等于100的索引时会报错:
# 替换成实际的词汇表大小 vocab_size = len(w2idx) # 或者 np.max(X) + 1,如果没有w2idx的话 embs = tf.get_variable('emb', [vocab_size, state_size])
5. 损失函数与标签形状匹配
sparse_softmax_cross_entropy_with_logits要求标签是一维的整数数组,所以在喂数据时需要把ys.flatten()传入,这部分你已经做了,没问题。
修正后的关键代码片段
模型初始化部分
if __name__ == '__main__': # 正确设置num_classes为2 model = LSTM_rnn(state_size = 512, num_classes=2)
LSTM输出层修改
在__graph__函数里,替换原来的logits和predictions部分:
# predictions V = tf.get_variable('V', shape=[state_size, num_classes], initializer=xav_init()) bo = tf.get_variable('bo', shape=[num_classes], initializer=tf.constant_initializer(0.)) # 取最后一个时间步的隐藏状态(st) last_st = self.last_state[0] # self.last_state是[st, ct],取第一个元素 logits = tf.matmul(last_st, V) + bo # 二分类预测:softmax输出两个类别的概率 predictions = tf.nn.softmax(logits) # 优化部分不变 losses = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=ys_) loss = tf.reduce_mean(losses) train_op = tf.train.AdagradOptimizer(learning_rate=0.1).minimize(loss)
标签处理修正
# 读取你的真实数据 X = np.load('data/paulg/idx_x.npy') Y = np.load('data/paulg/idx_y.npy') # 处理标签:转换为0/1的整数编码 label_encoder = LabelEncoder() # 先flatten成一维,再编码 Y_encoded = label_encoder.fit_transform(Y.flatten()) Y = Y_encoded.reshape(-1, 1)
功能验证说明
修正以上问题后,你的模型就能实现二分类序列分类功能:
- 输入是固定长度为20的序列特征
(batch_size, 20) - LSTM处理序列后取最后一个时间步的隐藏状态
- 通过全连接层输出两个类别的logits,经softmax得到概率
- 用
sparse_softmax_cross_entropy_with_logits计算损失,优化模型参数
训练时,每次喂入batch数据,模型会学习序列特征与二分类标签之间的映射关系,最终可以输出每个样本属于类别0或1的概率。
内容的提问来源于stack exchange,提问作者Slyron

