求助:解决TensorFlow中无法将列表转换为张量的问题(CSV数据集适配)
解决TensorFlow中列表转张量失败及LSTM输入适配问题
我看了你的代码和问题描述,核心问题出在数据预处理的方式不对,导致最终的输入数据结构不符合LSTM的要求,同时还有一些未定义的模型参数需要修正。下面一步步帮你解决:
问题根源分析
- 你当前处理
X的方式:把三个sensor列的列表组合成np.matrix后,每个元素依然是Python列表,得到的是一个包含列表的矩阵,而不是TensorFlow能识别的数值型三维数组。 - LSTM要求输入形状是
(样本数, 时间步长, 特征数),但你现在的X结构完全不匹配。 - 模型定义里的
max_sequence_length、embed_dim、pre_trained_wv等参数都没有定义,运行时会直接报错。
分步解决方案
1. 修正数据预处理流程
首先,我们需要把三个sensor的数值列表合并成一个三维数组:
- 每个样本对应一组
sensor1、sensor2、sensor3的列表,假设每个sensor列表的长度是相同的(比如都是N个时间步),那么每个样本的形状应该是(N, 3),整个训练集的形状就是(样本数, N, 3)。 - 用
np.stack来合并三个sensor的列表,而不是用np.matrix。
2. 定义模型所需参数
需要明确LSTM的时间步长(即每个sensor序列的长度)、特征数(这里是3,对应三个传感器),还有输出类别数(根据你的categoria列的独热编码结果,假设是2类)。
3. 调整模型输入形状
根据预处理后的三维输入,模型的输入形状应该设为(时间步长, 特征数),而不是之前的(max_sequence_length,)。
4. 修复预测环节的错误
预测部分的new_text处理逻辑有问题,需要调整为和训练数据一致的预处理方式。
修改后的完整代码
import sys import numpy as np import pandas as pd import os import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from tensorflow.keras.models import Sequential, Model from tensorflow.keras.layers import Dense, LSTM, Input from tensorflow.keras.preprocessing.sequence import pad_sequences # -------------------------- 数据预处理 -------------------------- df = pd.read_csv('set1.csv') # 将字符串形式的列表转为Python列表 s1 = df["sensor1"].apply(eval) s2 = df["sensor2"].apply(eval) s3 = df["sensor3"].apply(eval) # 合并三个传感器数据为三维数组:(样本数, 时间步长, 特征数) # 先检查所有序列长度是否一致,这里假设都是相同长度,如果有不同可以用pad_sequences补全 sequence_length = len(s1.iloc[0]) X = np.stack([np.array(s1.tolist()), np.array(s2.tolist()), np.array(s3.tolist())], axis=-1) # 处理标签:独热编码 Y = pd.get_dummies(data=df.categoria).values num_classes = Y.shape[1] # 划分训练测试集 X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.1, random_state=42) print("Train Shape:", X_train.shape, Y_train.shape) # 应该是 (样本数, sequence_length, 3) print("Test Shape:", X_test.shape, Y_test.shape) # -------------------------- 模型定义 -------------------------- # 定义模型参数 sequence_length = X_train.shape[1] feature_num = X_train.shape[2] lstm_units = 64 # 可以根据需求调整 epochs = 10 batch_size = 32 filename = 'lstm_gesture_weights.h5' def build_model(): # 输入形状适配LSTM:(时间步长, 特征数) model_input = Input(shape=(sequence_length, feature_num), name="input") # LSTM层 lstm = LSTM(lstm_units, dropout=0.2, recurrent_dropout=0.2, name="lstm")(model_input) # 输出层:根据类别数设置Dense单元数 model_output = Dense(num_classes, activation='softmax', name="softmax")(lstm) model = Model(inputs=model_input, outputs=model_output) return model model = build_model() model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) print(model.summary()) # -------------------------- 模型训练/加载 -------------------------- if not os.path.exists('./{}'.format(filename)): hist = model.fit( X_train, Y_train, validation_data=(X_test, Y_test), epochs=epochs, batch_size=batch_size, shuffle=True, verbose=1) model.save_weights(filename) # 绘制损失曲线 plt.figure() plt.plot(hist.history['loss'], lw=2.0, color='b', label='train') plt.plot(hist.history['val_loss'], lw=2.0, color='r', label='val') plt.title('Classificador de Gestos') plt.xlabel('Epochs') plt.ylabel('Cross-Entropy') plt.legend(loc='upper right') plt.show() # 绘制准确率曲线 plt.figure() plt.plot(hist.history['accuracy'], lw=2.0, color='b', label='train') plt.plot(hist.history['val_accuracy'], lw=2.0, color='r', label='val') plt.title('Classificador de Gestos') plt.xlabel('Epochs') plt.ylabel('Acurácia') plt.legend(loc='upper left') plt.show() else: model.load_weights('./{}'.format(filename)) scores = model.evaluate(X_test, Y_test, verbose=0, batch_size=batch_size) print("Acc: %.2f%%" % (scores[1]*100)) # -------------------------- 预测环节 -------------------------- while True: sentence = input("input> ") if sentence == "exit": break # 这里假设输入的是类似csv中的字符串列表,比如"[1,2,3],[4,5,6],[7,8,9]" # 需要根据实际输入格式调整预处理逻辑 try: # 分割三个传感器的数据 s1_input, s2_input, s3_input = sentence.split(',') # 转为列表并转成数组 s1_input = np.array(eval(s1_input.strip())) s2_input = np.array(eval(s2_input.strip())) s3_input = np.array(eval(s3_input.strip())) # 调整形状为(1, sequence_length, 3),匹配模型输入 new_data = np.stack([s1_input, s2_input, s3_input], axis=-1).reshape(1, sequence_length, 3) # 预测 sentiment = model.predict(new_data, batch_size=1, verbose=2)[0] pred_class = np.argmax(sentiment) pred_proba = "%.2f%%" % (sentiment[pred_class]*100) if pred_class == 0: print("movimento para direita => ", pred_proba) else: print("movimento para esquerda => ", pred_proba) except Exception as e: print(f"输入格式错误,请按照示例输入:例如 [1,2,...,N],[3,4,...,N],[5,6,...,N],错误信息:{e}")
额外注意事项
- 如果你的sensor序列长度不一致,需要在预处理时用
pad_sequences统一长度,比如:# 统一序列长度为最长的那个 max_len = max([len(s) for s in s1]) s1_padded = pad_sequences(s1.tolist(), maxlen=max_len, dtype='float32') s2_padded = pad_sequences(s2.tolist(), maxlen=max_len, dtype='float32') s3_padded = pad_sequences(s3.tolist(), maxlen=max_len, dtype='float32') X = np.stack([s1_padded, s2_padded, s3_padded], axis=-1) - 模型的损失函数用
categorical_crossentropy更适合多分类(这里是2类),之前的binary_crossentropy也可以,但categorical_crossentropy更标准。 - 确保导入了所有需要的库,之前的代码里缺少
pandas、os、matplotlib等的导入。
内容的提问来源于stack exchange,提问作者PALTJ
相关产品推荐
相关产品推荐

