使用TensorFlow RNN进行文本分类时遇AttributeError错误求助
解决AttributeError: '_IndicatorColumn' object has no attribute 'key'问题
嘿,这个错误我之前也碰到过!问题根源很明确:你把用于多分类标签的IndicatorColumn错误当成了输入文本特征列传给了DynamicRnnEstimator,而这个 estimator 只接受带key属性的序列特征列(比如sequence_categorical_column_*系列),IndicatorColumn是用来处理标签的,根本没有key属性,自然会报错。
下面是具体的修复步骤,结合你的场景一步步来:
1. 明确区分输入特征和标签的处理逻辑
- 文本输入特征:需要先转化为序列分类特征列,再包裹成嵌入列,供RNN处理
- 分类标签:用
IndicatorColumn是正确的,但它是模型的目标输出,不能作为输入特征传入
2. 修正特征列构建代码
假设你的csv里有text(待分类文本)和category(类别标签)两列,参考下面的代码:
import tensorflow as tf import pandas as pd from sklearn import preprocessing from gensim import corpora from nltk.tokenize import WhitespaceTokenizer # 1. 加载数据并预处理文本,生成词汇表 df = pd.read_csv('data.csv') tokenizer = WhitespaceTokenizer() # 分词并构建gensim词典 text_tokens = [tokenizer.tokenize(text) for text in df['text'].values] dictionary = corpora.Dictionary(text_tokens) vocab_size = len(dictionary) # 2. 构建文本序列特征列(这才是RNN要的输入) text_seq_col = tf.feature_column.sequence_categorical_column_with_vocabulary_list( key='text', # 对应输入特征字典里的key vocabulary_list=dictionary.keys(), dtype=tf.string ) # 转化为嵌入列,供RNN提取特征 text_embedding_col = tf.feature_column.embedding_column( categorical_column=text_seq_col, dimension=128 # 根据你的需求调整嵌入维度 ) # 3. 构建标签列(多分类场景用IndicatorColumn) label_encoder = preprocessing.LabelEncoder() df['category_encoded'] = label_encoder.fit_transform(df['category']) num_classes = len(label_encoder.classes_) # 先转成identity列,再包裹成IndicatorColumn label_col = tf.feature_column.indicator_column( tf.feature_column.categorical_column_with_identity( key='category_encoded', num_buckets=num_classes ) )
3. 编写正确的输入函数
输入函数要返回序列特征字典和标签,注意处理变长文本序列:
def input_fn(dataframe, shuffle=True, batch_size=32): # 把文本转化为词典对应的id序列 def text_to_ids(text): return [dictionary.token2id[token] for token in tokenizer.tokenize(text) if token in dictionary.token2id] dataframe['text_ids'] = dataframe['text'].apply(text_to_ids) # 构建特征字典,用tf.ragged.constant处理变长序列 features = { 'text': tf.ragged.constant(dataframe['text_ids'].values), 'category_encoded': tf.constant(dataframe['category_encoded'].values) } # 分离标签和特征 labels = features.pop('category_encoded') # 构建数据集并做批处理 dataset = tf.data.Dataset.from_tensor_slices((features, labels)) if shuffle: dataset = dataset.shuffle(buffer_size=len(dataframe)) # 对变长序列做padding,统一batch内的长度 dataset = dataset.padded_batch( batch_size, padded_shapes={'text': [None]} # None表示该维度是变长的 ) return dataset
4. 初始化并训练模型
确保把序列嵌入列传给sequence_feature_columns,标签列通过multi_class_head指定:
# 构建多分类head multi_class_head = tf.contrib.estimator.multi_class_head(num_classes=num_classes) # 初始化DynamicRnnEstimator estimator = tf.contrib.estimator.DynamicRnnEstimator( head=multi_class_head, sequence_feature_columns=[text_embedding_col], # 这里传的是序列特征列,不是标签列! cell_type='lstm', # 可选lstm/gru等 cell_size=64, # RNN单元数量 optimizer='adam' ) # 开始训练 estimator.train(input_fn=lambda: input_fn(df), steps=1000)
避坑提醒
- 绝对不要把
IndicatorColumn放到sequence_feature_columns参数里,它是标签处理用的,和输入特征完全不是一回事 - 序列特征必须用带
sequence_前缀的特征列,普通的categorical_column不能直接给RNN使用 - 变长文本序列一定要用
tf.ragged.constant或者padded_batch处理,否则数据集会报错
内容的提问来源于stack exchange,提问作者Rudy
相关产品推荐
相关产品推荐

